1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-message-io.c: HTTP message I/O
5 * Copyright (C) 2000-2003, Ximian, Inc.
15 #include "soup-connection.h"
16 #include "soup-message.h"
17 #include "soup-message-private.h"
18 #include "soup-misc.h"
19 #include "soup-socket.h"
23 SOUP_MESSAGE_IO_CLIENT,
24 SOUP_MESSAGE_IO_SERVER
28 SOUP_MESSAGE_IO_STATE_NOT_STARTED,
29 SOUP_MESSAGE_IO_STATE_HEADERS,
30 SOUP_MESSAGE_IO_STATE_BLOCKING,
31 SOUP_MESSAGE_IO_STATE_BODY,
32 SOUP_MESSAGE_IO_STATE_CHUNK_SIZE,
33 SOUP_MESSAGE_IO_STATE_CHUNK,
34 SOUP_MESSAGE_IO_STATE_CHUNK_END,
35 SOUP_MESSAGE_IO_STATE_TRAILERS,
36 SOUP_MESSAGE_IO_STATE_FINISHING,
37 SOUP_MESSAGE_IO_STATE_DONE
40 #define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \
41 (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \
42 state != SOUP_MESSAGE_IO_STATE_BLOCKING && \
43 state != SOUP_MESSAGE_IO_STATE_DONE)
48 SoupMessageIOMode mode;
50 SoupMessageIOState read_state;
51 SoupEncoding read_encoding;
52 GByteArray *read_meta_buf;
53 SoupMessageBody *read_body;
56 gboolean need_content_sniffed, need_got_chunk;
57 SoupMessageBody *sniff_data;
59 SoupMessageIOState write_state;
60 SoupEncoding write_encoding;
62 SoupMessageBody *write_body;
63 SoupBuffer *write_chunk;
64 gsize write_body_offset;
68 guint read_tag, write_tag, err_tag;
69 GSource *unpause_source;
71 SoupMessageGetHeadersFn get_headers_cb;
72 SoupMessageParseHeadersFn parse_headers_cb;
77 /* Put these around callback invocation if there is code afterward
78 * that depends on the IO having not been cancelled.
80 #define dummy_to_make_emacs_happy {
81 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
82 #define SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED cancelled = (priv->io_data != io); g_object_unref (msg); if (cancelled || (!io->read_tag && !io->write_tag)) return; }
83 #define SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED(val) cancelled = (priv->io_data != io); g_object_unref (msg); if (cancelled || (!io->read_tag && !io->write_tag)) return val; }
85 #define RESPONSE_BLOCK_SIZE 8192
88 soup_message_io_cleanup (SoupMessage *msg)
90 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
91 SoupMessageIOData *io;
93 soup_message_io_stop (msg);
101 g_object_unref (io->sock);
103 g_object_unref (io->conn);
105 g_byte_array_free (io->read_meta_buf, TRUE);
107 g_string_free (io->write_buf, TRUE);
109 soup_buffer_free (io->write_chunk);
112 soup_message_body_free (io->sniff_data);
114 g_slice_free (SoupMessageIOData, io);
118 * soup_message_io_stop:
119 * @msg: a #SoupMessage
121 * Immediately stops I/O on msg; if the connection would be left in an
122 * inconsistent state, it will be closed.
124 * Note: this is a low-level function that does not cause any signals
125 * to be emitted on @msg; it is up to the caller to make sure that
126 * @msg doesn't get "stranded".
129 soup_message_io_stop (SoupMessage *msg)
131 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
132 SoupMessageIOData *io = priv->io_data;
138 g_signal_handler_disconnect (io->sock, io->read_tag);
142 g_signal_handler_disconnect (io->sock, io->write_tag);
146 g_signal_handler_disconnect (io->sock, io->err_tag);
150 if (io->unpause_source) {
151 g_source_destroy (io->unpause_source);
152 io->unpause_source = NULL;
155 if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
156 soup_socket_disconnect (io->sock);
158 SoupConnection *conn = io->conn;
160 soup_connection_set_state (conn, SOUP_CONNECTION_IDLE);
161 g_object_unref (conn);
165 #define SOUP_MESSAGE_IO_EOL "\r\n"
166 #define SOUP_MESSAGE_IO_EOL_LEN 2
169 soup_message_io_finished (SoupMessage *msg)
172 soup_message_io_cleanup (msg);
173 if (SOUP_MESSAGE_IS_STARTING (msg))
174 soup_message_restarted (msg);
176 soup_message_finished (msg);
177 g_object_unref (msg);
180 static void io_read (SoupSocket *sock, SoupMessage *msg);
183 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
185 if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
186 if (error && error->domain == SOUP_SSL_ERROR) {
187 soup_message_set_status_full (msg,
188 SOUP_STATUS_SSL_FAILED,
191 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
194 g_error_free (error);
196 soup_message_io_finished (msg);
200 io_disconnected (SoupSocket *sock, SoupMessage *msg)
202 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
203 SoupMessageIOData *io = priv->io_data;
205 /* Closing the connection to signify EOF is sometimes ok */
206 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
207 io->read_encoding == SOUP_ENCODING_EOF) {
208 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
213 io_error (sock, msg, NULL);
217 io_handle_sniffing (SoupMessage *msg, gboolean done_reading)
219 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
220 SoupMessageIOData *io = priv->io_data;
221 SoupBuffer *sniffed_buffer;
222 char *sniffed_mime_type;
223 GHashTable *params = NULL;
228 if (!io->sniff_data) {
229 io->sniff_data = soup_message_body_new ();
230 io->need_content_sniffed = TRUE;
233 if (io->need_content_sniffed) {
234 if (io->sniff_data->length < priv->bytes_for_sniffing &&
238 io->need_content_sniffed = FALSE;
239 sniffed_buffer = soup_message_body_flatten (io->sniff_data);
240 sniffed_mime_type = soup_content_sniffer_sniff (priv->sniffer, msg, sniffed_buffer, ¶ms);
242 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
243 soup_message_content_sniffed (msg, sniffed_mime_type, params);
244 g_free (sniffed_mime_type);
246 g_hash_table_destroy (params);
248 soup_buffer_free (sniffed_buffer);
249 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
252 if (io->need_got_chunk) {
253 io->need_got_chunk = FALSE;
254 sniffed_buffer = soup_message_body_flatten (io->sniff_data);
256 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
257 soup_message_got_chunk (msg, sniffed_buffer);
258 soup_buffer_free (sniffed_buffer);
259 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
265 /* Reads data from io->sock into io->read_meta_buf. If @to_blank is
266 * %TRUE, it reads up until a blank line ("CRLF CRLF" or "LF LF").
267 * Otherwise, it reads up until a single CRLF or LF.
269 * This function is used to read metadata, and read_body_chunk() is
270 * used to read the message body contents.
272 * read_metadata, read_body_chunk, and write_data all use the same
273 * convention for return values: if they return %TRUE, it means
274 * they've completely finished the requested read/write, and the
275 * caller should move on to the next step. If they return %FALSE, it
276 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
277 * so the caller should give up for now and wait for the socket to
278 * emit a signal, or (b) the socket returned an error, and io_error()
279 * was called to process it and cancel the I/O. So either way, if the
280 * function returns %FALSE, the caller should return immediately.
283 read_metadata (SoupMessage *msg, gboolean to_blank)
285 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
286 SoupMessageIOData *io = priv->io_data;
287 SoupSocketIOStatus status;
288 guchar read_buf[RESPONSE_BLOCK_SIZE];
291 GError *error = NULL;
294 status = soup_socket_read_until (io->sock, read_buf,
296 "\n", 1, &nread, &got_lf,
300 g_byte_array_append (io->read_meta_buf, read_buf, nread);
303 case SOUP_SOCKET_ERROR:
304 case SOUP_SOCKET_EOF:
305 io_error (io->sock, msg, error);
308 case SOUP_SOCKET_WOULD_BLOCK:
316 !strncmp ((char *)io->read_meta_buf->data +
317 io->read_meta_buf->len - 2,
320 else if (nread == 2 &&
321 !strncmp ((char *)io->read_meta_buf->data +
322 io->read_meta_buf->len - 3,
331 /* Reads as much message body data as is available on io->sock (but no
332 * further than the end of the current message body or chunk). On a
333 * successful read, emits "got_chunk" (possibly multiple times), and
334 * (unless told not to) appends the chunk to io->read_body.
336 * See the note at read_metadata() for an explanation of the return
340 read_body_chunk (SoupMessage *msg)
342 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
343 SoupMessageIOData *io = priv->io_data;
344 SoupSocketIOStatus status;
345 guchar *stack_buf = NULL;
347 gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
349 GError *error = NULL;
352 if (!io_handle_sniffing (msg, FALSE))
355 while (read_to_eof || io->read_length > 0) {
356 if (priv->chunk_allocator) {
357 buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
359 soup_message_io_pause (msg);
364 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
365 buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
367 RESPONSE_BLOCK_SIZE);
371 len = buffer->length;
373 len = MIN (buffer->length, io->read_length);
375 status = soup_socket_read (io->sock,
376 (guchar *)buffer->data, len,
377 &nread, NULL, &error);
379 if (status == SOUP_SOCKET_OK && nread) {
380 buffer->length = nread;
381 soup_message_body_got_chunk (io->read_body, buffer);
383 io->read_length -= nread;
385 if (io->need_content_sniffed) {
386 soup_message_body_append_buffer (io->sniff_data, buffer);
387 io->need_got_chunk = TRUE;
388 if (!io_handle_sniffing (msg, FALSE))
393 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
394 soup_message_got_chunk (msg, buffer);
395 soup_buffer_free (buffer);
396 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
400 soup_buffer_free (buffer);
405 case SOUP_SOCKET_EOF:
408 /* else fall through */
410 case SOUP_SOCKET_ERROR:
411 io_error (io->sock, msg, error);
414 case SOUP_SOCKET_WOULD_BLOCK:
422 /* Attempts to write @len bytes from @data. See the note at
423 * read_metadata() for an explanation of the return value.
426 write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
428 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
429 SoupMessageIOData *io = priv->io_data;
430 SoupSocketIOStatus status;
432 GError *error = NULL;
436 while (len > io->written) {
437 status = soup_socket_write (io->sock,
440 &nwrote, NULL, &error);
442 case SOUP_SOCKET_EOF:
443 case SOUP_SOCKET_ERROR:
444 io_error (io->sock, msg, error);
447 case SOUP_SOCKET_WOULD_BLOCK:
451 start = data + io->written;
452 io->written += nwrote;
455 if (io->write_length)
456 io->write_length -= nwrote;
458 chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
460 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
461 soup_message_wrote_body_data (msg, chunk);
462 soup_buffer_free (chunk);
463 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
473 static inline SoupMessageIOState
474 io_body_state (SoupEncoding encoding)
476 if (encoding == SOUP_ENCODING_CHUNKED)
477 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
479 return SOUP_MESSAGE_IO_STATE_BODY;
483 * There are two request/response formats: the basic request/response,
484 * possibly with one or more unsolicited informational responses (such
485 * as the WebDAV "102 Processing" response):
488 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
489 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
490 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
491 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
492 * W:DONE / R:BODY <- R:DONE / W:BODY
493 * W:DONE / R:DONE R:DONE / W:DONE
495 * and the "Expect: 100-continue" request/response, with the client
496 * blocking halfway through its request, and then either continuing or
497 * aborting, depending on the server response:
500 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
501 * W:BLOCKING / R:HEADERS <- R:BLOCKING / W:HEADERS
502 * [W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING]
503 * [W:DONE / R:HEADERS <- R:DONE / W:HEADERS]
504 * W:DONE / R:BODY <- R:DONE / W:BODY
505 * W:DONE / R:DONE R:DONE / W:DONE
509 io_write (SoupSocket *sock, SoupMessage *msg)
511 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
512 SoupMessageIOData *io = priv->io_data;
515 switch (io->write_state) {
516 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
520 case SOUP_MESSAGE_IO_STATE_HEADERS:
521 if (!io->write_buf->len) {
522 io->get_headers_cb (msg, io->write_buf,
525 if (!io->write_buf->len) {
526 soup_message_io_pause (msg);
531 if (!write_data (msg, io->write_buf->str,
532 io->write_buf->len, FALSE))
535 g_string_truncate (io->write_buf, 0);
537 if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
538 SoupMessageHeaders *hdrs =
539 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
540 msg->request_headers : msg->response_headers;
541 io->write_length = soup_message_headers_get_content_length (hdrs);
544 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
545 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
546 if (msg->status_code == SOUP_STATUS_CONTINUE) {
547 /* Stop and wait for the body now */
549 SOUP_MESSAGE_IO_STATE_BLOCKING;
550 io->read_state = io_body_state (io->read_encoding);
552 /* We just wrote a 1xx response
553 * header, so stay in STATE_HEADERS.
554 * (The caller will pause us from the
555 * wrote_informational callback if he
556 * is not ready to send the final
560 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
561 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
562 /* Need to wait for the Continue response */
563 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
564 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
566 io->write_state = io_body_state (io->write_encoding);
568 /* If the client was waiting for a Continue
569 * but we sent something else, then they're
572 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
573 io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
574 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
577 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
578 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
579 soup_message_wrote_informational (msg);
580 soup_message_cleanup_response (msg);
582 soup_message_wrote_headers (msg);
583 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
587 case SOUP_MESSAGE_IO_STATE_BLOCKING:
590 /* If io_read reached a point where we could write
591 * again, it would have recursively called io_write.
592 * So (a) we don't need to try to keep writing, and
593 * (b) we can't anyway, because msg may have been
599 case SOUP_MESSAGE_IO_STATE_BODY:
600 if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) {
602 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
604 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
605 soup_message_wrote_body (msg);
606 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
610 if (!io->write_chunk) {
611 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
612 if (!io->write_chunk) {
613 soup_message_io_pause (msg);
616 if (io->write_chunk->length > io->write_length &&
617 io->write_encoding != SOUP_ENCODING_EOF) {
618 /* App is trying to write more than it
619 * claimed it would; we have to truncate.
621 SoupBuffer *truncated =
622 soup_buffer_new_subbuffer (io->write_chunk,
623 0, io->write_length);
624 soup_buffer_free (io->write_chunk);
625 io->write_chunk = truncated;
626 } else if (io->write_encoding == SOUP_ENCODING_EOF &&
627 !io->write_chunk->length)
631 if (!write_data (msg, io->write_chunk->data,
632 io->write_chunk->length, TRUE))
635 if (io->mode == SOUP_MESSAGE_IO_SERVER)
636 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
637 io->write_body_offset += io->write_chunk->length;
638 soup_buffer_free (io->write_chunk);
639 io->write_chunk = NULL;
641 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
642 soup_message_wrote_chunk (msg);
643 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
646 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
647 if (!io->write_chunk) {
648 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
649 if (!io->write_chunk) {
650 soup_message_io_pause (msg);
653 g_string_append_printf (io->write_buf, "%lx\r\n",
654 (unsigned long) io->write_chunk->length);
655 io->write_body_offset += io->write_chunk->length;
658 if (!write_data (msg, io->write_buf->str,
659 io->write_buf->len, FALSE))
662 g_string_truncate (io->write_buf, 0);
664 if (io->write_chunk->length == 0) {
665 /* The last chunk has no CHUNK_END... */
666 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
670 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
674 case SOUP_MESSAGE_IO_STATE_CHUNK:
675 if (!write_data (msg, io->write_chunk->data,
676 io->write_chunk->length, TRUE))
679 if (io->mode == SOUP_MESSAGE_IO_SERVER)
680 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
681 soup_buffer_free (io->write_chunk);
682 io->write_chunk = NULL;
684 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
686 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
687 soup_message_wrote_chunk (msg);
688 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
693 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
694 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
695 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
698 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
702 case SOUP_MESSAGE_IO_STATE_TRAILERS:
703 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
704 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
707 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
709 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
710 soup_message_wrote_body (msg);
711 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
715 case SOUP_MESSAGE_IO_STATE_FINISHING:
717 g_signal_handler_disconnect (io->sock, io->write_tag);
720 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
722 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
723 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
726 soup_message_io_finished (msg);
730 case SOUP_MESSAGE_IO_STATE_DONE:
732 g_return_if_reached ();
739 io_read (SoupSocket *sock, SoupMessage *msg)
741 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
742 SoupMessageIOData *io = priv->io_data;
746 switch (io->read_state) {
747 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
751 case SOUP_MESSAGE_IO_STATE_HEADERS:
752 if (!read_metadata (msg, TRUE))
755 /* We need to "rewind" io->read_meta_buf back one line.
756 * That SHOULD be two characters (CR LF), but if the
757 * web server was stupid, it might only be one.
759 if (io->read_meta_buf->len < 3 ||
760 io->read_meta_buf->data[io->read_meta_buf->len - 2] == '\n')
761 io->read_meta_buf->len--;
763 io->read_meta_buf->len -= 2;
764 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
765 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
766 io->read_meta_buf->len,
769 g_byte_array_set_size (io->read_meta_buf, 0);
771 if (status != SOUP_STATUS_OK) {
772 /* Either we couldn't parse the headers, or they
773 * indicated something that would mean we wouldn't
774 * be able to parse the body. (Eg, unknown
775 * Transfer-Encoding.). Skip the rest of the
776 * reading, and make sure the connection gets
777 * closed when we're done.
779 soup_message_set_status (msg, status);
780 soup_message_headers_append (msg->request_headers,
781 "Connection", "close");
782 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
786 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
787 SoupMessageHeaders *hdrs =
788 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
789 msg->response_headers : msg->request_headers;
790 io->read_length = soup_message_headers_get_content_length (hdrs);
793 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
794 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
795 if (msg->status_code == SOUP_STATUS_CONTINUE &&
796 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
797 /* Pause the reader, unpause the writer */
799 SOUP_MESSAGE_IO_STATE_BLOCKING;
801 io_body_state (io->write_encoding);
803 /* Just stay in HEADERS */
804 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
806 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
807 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
808 /* The client requested a Continue response. The
809 * got_headers handler may change this to something
812 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
813 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
814 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
816 io->read_state = io_body_state (io->read_encoding);
818 /* If the client was waiting for a Continue
819 * but got something else, then it's done
822 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
823 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
824 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
827 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
828 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
829 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
830 soup_message_got_informational (msg);
831 soup_message_cleanup_response (msg);
832 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
834 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
835 soup_message_got_headers (msg);
836 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
841 case SOUP_MESSAGE_IO_STATE_BLOCKING:
842 io_write (sock, msg);
844 /* As in the io_write case, we *must* return here. */
848 case SOUP_MESSAGE_IO_STATE_BODY:
849 if (!read_body_chunk (msg))
853 if (!io_handle_sniffing (msg, TRUE)) {
854 /* If the message was paused (as opposed to
855 * cancelled), we need to make sure we wind up
856 * back here when it's unpaused, even if it
857 * was doing a chunked or EOF-terminated read
860 if (io == priv->io_data) {
861 io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
862 io->read_encoding = SOUP_ENCODING_CONTENT_LENGTH;
868 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
870 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
871 soup_message_got_body (msg);
872 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
876 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
877 if (!read_metadata (msg, FALSE))
880 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
881 g_byte_array_set_size (io->read_meta_buf, 0);
883 if (io->read_length > 0)
884 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
886 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
890 case SOUP_MESSAGE_IO_STATE_CHUNK:
891 if (!read_body_chunk (msg))
894 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
898 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
899 if (!read_metadata (msg, FALSE))
902 g_byte_array_set_size (io->read_meta_buf, 0);
903 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
907 case SOUP_MESSAGE_IO_STATE_TRAILERS:
908 if (!read_metadata (msg, FALSE))
911 if (io->read_meta_buf->len <= SOUP_MESSAGE_IO_EOL_LEN)
914 /* FIXME: process trailers */
915 g_byte_array_set_size (io->read_meta_buf, 0);
919 case SOUP_MESSAGE_IO_STATE_FINISHING:
921 g_signal_handler_disconnect (io->sock, io->read_tag);
924 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
926 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
927 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
928 io_write (sock, msg);
930 soup_message_io_finished (msg);
934 case SOUP_MESSAGE_IO_STATE_DONE:
936 g_return_if_reached ();
942 static SoupMessageIOData *
943 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
944 SoupMessageGetHeadersFn get_headers_cb,
945 SoupMessageParseHeadersFn parse_headers_cb,
948 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
949 SoupMessageIOData *io;
951 io = g_slice_new0 (SoupMessageIOData);
952 io->sock = g_object_ref (sock);
954 io->get_headers_cb = get_headers_cb;
955 io->parse_headers_cb = parse_headers_cb;
956 io->user_data = user_data;
958 io->read_meta_buf = g_byte_array_new ();
959 io->write_buf = g_string_new (NULL);
961 io->read_tag = g_signal_connect (io->sock, "readable",
962 G_CALLBACK (io_read), msg);
963 io->write_tag = g_signal_connect (io->sock, "writable",
964 G_CALLBACK (io_write), msg);
965 io->err_tag = g_signal_connect (io->sock, "disconnected",
966 G_CALLBACK (io_disconnected), msg);
968 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
969 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
972 soup_message_io_cleanup (msg);
978 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
979 SoupConnection *conn,
980 SoupMessageGetHeadersFn get_headers_cb,
981 SoupMessageParseHeadersFn parse_headers_cb,
984 SoupMessageIOData *io;
986 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
987 get_headers_cb, parse_headers_cb, user_data);
990 io->conn = g_object_ref (conn);
992 io->read_body = msg->response_body;
993 io->write_body = msg->request_body;
995 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
996 io_write (sock, msg);
1000 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
1001 SoupMessageGetHeadersFn get_headers_cb,
1002 SoupMessageParseHeadersFn parse_headers_cb,
1005 SoupMessageIOData *io;
1007 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
1008 get_headers_cb, parse_headers_cb, user_data);
1010 io->read_body = msg->request_body;
1011 io->write_body = msg->response_body;
1013 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
1014 io_read (sock, msg);
1018 soup_message_io_pause (SoupMessage *msg)
1020 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1021 SoupMessageIOData *io = priv->io_data;
1023 g_return_if_fail (io != NULL);
1025 if (io->write_tag) {
1026 g_signal_handler_disconnect (io->sock, io->write_tag);
1030 g_signal_handler_disconnect (io->sock, io->read_tag);
1034 if (io->unpause_source) {
1035 g_source_destroy (io->unpause_source);
1036 io->unpause_source = NULL;
1041 io_unpause_internal (gpointer msg)
1043 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1044 SoupMessageIOData *io = priv->io_data;
1046 g_return_val_if_fail (io != NULL, FALSE);
1047 io->unpause_source = NULL;
1049 if (io->write_tag || io->read_tag)
1052 if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
1053 io->write_tag = g_signal_connect (io->sock, "writable",
1054 G_CALLBACK (io_write), msg);
1057 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
1058 io->read_tag = g_signal_connect (io->sock, "readable",
1059 G_CALLBACK (io_read), msg);
1062 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
1063 io_write (io->sock, msg);
1064 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
1065 io_read (io->sock, msg);
1071 soup_message_io_unpause (SoupMessage *msg)
1073 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1074 SoupMessageIOData *io = priv->io_data;
1075 gboolean non_blocking;
1076 GMainContext *async_context;
1078 g_return_if_fail (io != NULL);
1080 g_object_get (io->sock,
1081 SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
1082 SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
1085 if (!io->unpause_source) {
1086 io->unpause_source = soup_add_completion (
1087 async_context, io_unpause_internal, msg);
1090 io_unpause_internal (msg);
1092 g_main_context_unref (async_context);
1096 * soup_message_io_in_progress:
1097 * @msg: a #SoupMessage
1099 * Tests whether or not I/O is currently in progress on @msg.
1101 * Return value: whether or not I/O is currently in progress.
1104 soup_message_io_in_progress (SoupMessage *msg)
1106 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1108 return priv->io_data != NULL;