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 SoupMessageIOState write_state;
57 SoupEncoding write_encoding;
59 SoupMessageBody *write_body;
60 SoupBuffer *write_chunk;
61 gsize write_body_offset;
65 guint read_tag, write_tag, err_tag;
66 GSource *unpause_source;
68 SoupMessageGetHeadersFn get_headers_cb;
69 SoupMessageParseHeadersFn parse_headers_cb;
74 /* Put these around callback invocation if there is code afterward
75 * that depends on the IO having not been cancelled.
77 #define dummy_to_make_emacs_happy {
78 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
79 #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; }
80 #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; }
82 #define RESPONSE_BLOCK_SIZE 8192
85 soup_message_io_cleanup (SoupMessage *msg)
87 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
88 SoupMessageIOData *io;
90 soup_message_io_stop (msg);
98 g_object_unref (io->sock);
100 g_object_unref (io->conn);
102 g_byte_array_free (io->read_meta_buf, TRUE);
104 g_string_free (io->write_buf, TRUE);
106 soup_buffer_free (io->write_chunk);
108 g_slice_free (SoupMessageIOData, io);
112 * soup_message_io_stop:
113 * @msg: a #SoupMessage
115 * Immediately stops I/O on msg; if the connection would be left in an
116 * inconsistent state, it will be closed.
118 * Note: this is a low-level function that does not cause any signals
119 * to be emitted on @msg; it is up to the caller to make sure that
120 * @msg doesn't get "stranded".
123 soup_message_io_stop (SoupMessage *msg)
125 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
126 SoupMessageIOData *io = priv->io_data;
132 g_signal_handler_disconnect (io->sock, io->read_tag);
136 g_signal_handler_disconnect (io->sock, io->write_tag);
140 g_signal_handler_disconnect (io->sock, io->err_tag);
144 if (io->unpause_source) {
145 g_source_destroy (io->unpause_source);
146 io->unpause_source = NULL;
149 if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
150 soup_socket_disconnect (io->sock);
152 SoupConnection *conn = io->conn;
154 soup_connection_release (conn);
155 g_object_unref (conn);
159 #define SOUP_MESSAGE_IO_EOL "\r\n"
160 #define SOUP_MESSAGE_IO_EOL_LEN 2
161 #define SOUP_MESSAGE_IO_DOUBLE_EOL "\r\n\r\n"
162 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
165 soup_message_io_finished (SoupMessage *msg)
168 soup_message_io_cleanup (msg);
169 if (SOUP_MESSAGE_IS_STARTING (msg))
170 soup_message_restarted (msg);
172 soup_message_finished (msg);
173 g_object_unref (msg);
176 static void io_read (SoupSocket *sock, SoupMessage *msg);
179 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
181 if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
182 if (error && error->domain == SOUP_SSL_ERROR) {
183 soup_message_set_status_full (msg,
184 SOUP_STATUS_SSL_FAILED,
187 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
190 g_error_free (error);
192 soup_message_io_finished (msg);
196 io_disconnected (SoupSocket *sock, SoupMessage *msg)
198 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
199 SoupMessageIOData *io = priv->io_data;
201 /* Closing the connection to signify EOF is sometimes ok */
202 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
203 io->read_encoding == SOUP_ENCODING_EOF) {
204 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
209 io_error (sock, msg, NULL);
212 /* Reads data from io->sock into io->read_meta_buf up until @boundary.
213 * (This function is used to read metadata, and read_body_chunk() is
214 * used to read the message body contents.)
216 * read_metadata, read_body_chunk, and write_data all use the same
217 * convention for return values: if they return %TRUE, it means
218 * they've completely finished the requested read/write, and the
219 * caller should move on to the next step. If they return %FALSE, it
220 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
221 * so the caller should give up for now and wait for the socket to
222 * emit a signal, or (b) the socket returned an error, and io_error()
223 * was called to process it and cancel the I/O. So either way, if the
224 * function returns %FALSE, the caller should return immediately.
227 read_metadata (SoupMessage *msg, const char *boundary)
229 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
230 SoupMessageIOData *io = priv->io_data;
231 SoupSocketIOStatus status;
232 guchar read_buf[RESPONSE_BLOCK_SIZE];
233 guint boundary_len = strlen (boundary);
236 GError *error = NULL;
239 status = soup_socket_read_until (io->sock, read_buf,
241 boundary, boundary_len,
242 &nread, &done, NULL, &error);
245 g_byte_array_append (io->read_meta_buf, read_buf, nread);
248 case SOUP_SOCKET_ERROR:
249 case SOUP_SOCKET_EOF:
250 io_error (io->sock, msg, error);
253 case SOUP_SOCKET_WOULD_BLOCK:
261 /* Reads as much message body data as is available on io->sock (but no
262 * further than the end of the current message body or chunk). On a
263 * successful read, emits "got_chunk" (possibly multiple times), and
264 * (unless told not to) appends the chunk to io->read_body.
266 * See the note at read_metadata() for an explanation of the return
270 read_body_chunk (SoupMessage *msg)
272 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
273 SoupMessageIOData *io = priv->io_data;
274 SoupSocketIOStatus status;
275 guchar *stack_buf = NULL;
277 gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
279 GError *error = NULL;
282 while (read_to_eof || io->read_length > 0) {
283 if (priv->chunk_allocator) {
284 buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
286 soup_message_io_pause (msg);
291 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
292 buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
294 RESPONSE_BLOCK_SIZE);
298 len = buffer->length;
300 len = MIN (buffer->length, io->read_length);
302 status = soup_socket_read (io->sock,
303 (guchar *)buffer->data, len,
304 &nread, NULL, &error);
306 if (status == SOUP_SOCKET_OK && nread) {
307 buffer->length = nread;
308 soup_message_body_got_chunk (io->read_body, buffer);
310 io->read_length -= nread;
312 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
313 soup_message_got_chunk (msg, buffer);
314 soup_buffer_free (buffer);
315 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
319 soup_buffer_free (buffer);
324 case SOUP_SOCKET_EOF:
327 /* else fall through */
329 case SOUP_SOCKET_ERROR:
330 io_error (io->sock, msg, error);
333 case SOUP_SOCKET_WOULD_BLOCK:
341 /* Attempts to write @len bytes from @data. See the note at
342 * read_metadata() for an explanation of the return value.
345 write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
347 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
348 SoupMessageIOData *io = priv->io_data;
349 SoupSocketIOStatus status;
351 GError *error = NULL;
355 while (len > io->written) {
356 status = soup_socket_write (io->sock,
359 &nwrote, NULL, &error);
361 case SOUP_SOCKET_EOF:
362 case SOUP_SOCKET_ERROR:
363 io_error (io->sock, msg, error);
366 case SOUP_SOCKET_WOULD_BLOCK:
370 start = data + io->written;
371 io->written += nwrote;
374 if (io->write_length)
375 io->write_length -= nwrote;
377 chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
379 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
380 soup_message_wrote_body_data (msg, chunk);
381 soup_buffer_free (chunk);
382 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
392 static inline SoupMessageIOState
393 io_body_state (SoupEncoding encoding)
395 if (encoding == SOUP_ENCODING_CHUNKED)
396 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
398 return SOUP_MESSAGE_IO_STATE_BODY;
402 * There are two request/response formats: the basic request/response,
403 * possibly with one or more unsolicited informational responses (such
404 * as the WebDAV "102 Processing" response):
407 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
408 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
409 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
410 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
411 * W:DONE / R:BODY <- R:DONE / W:BODY
412 * W:DONE / R:DONE R:DONE / W:DONE
414 * and the "Expect: 100-continue" request/response, with the client
415 * blocking halfway through its request, and then either continuing or
416 * aborting, depending on the server response:
419 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
420 * W:BLOCKING / R:HEADERS <- R:BLOCKING / W:HEADERS
421 * [W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING]
422 * [W:DONE / R:HEADERS <- R:DONE / W:HEADERS]
423 * W:DONE / R:BODY <- R:DONE / W:BODY
424 * W:DONE / R:DONE R:DONE / W:DONE
428 io_write (SoupSocket *sock, SoupMessage *msg)
430 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
431 SoupMessageIOData *io = priv->io_data;
434 switch (io->write_state) {
435 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
439 case SOUP_MESSAGE_IO_STATE_HEADERS:
440 if (!io->write_buf->len) {
441 io->get_headers_cb (msg, io->write_buf,
444 if (!io->write_buf->len) {
445 soup_message_io_pause (msg);
450 if (!write_data (msg, io->write_buf->str,
451 io->write_buf->len, FALSE))
454 g_string_truncate (io->write_buf, 0);
456 if (io->write_encoding != SOUP_ENCODING_CHUNKED) {
457 SoupMessageHeaders *hdrs =
458 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
459 msg->request_headers : msg->response_headers;
460 io->write_length = soup_message_headers_get_content_length (hdrs);
463 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
464 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
465 if (msg->status_code == SOUP_STATUS_CONTINUE) {
466 /* Stop and wait for the body now */
468 SOUP_MESSAGE_IO_STATE_BLOCKING;
469 io->read_state = io_body_state (io->read_encoding);
471 /* We just wrote a 1xx response
472 * header, so stay in STATE_HEADERS.
473 * (The caller will pause us from the
474 * wrote_informational callback if he
475 * is not ready to send the final
479 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
480 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
481 /* Need to wait for the Continue response */
482 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
483 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
485 io->write_state = io_body_state (io->write_encoding);
487 /* If the client was waiting for a Continue
488 * but we sent something else, then they're
491 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
492 io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
493 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
496 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
497 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
498 soup_message_wrote_informational (msg);
499 soup_message_cleanup_response (msg);
501 soup_message_wrote_headers (msg);
502 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
506 case SOUP_MESSAGE_IO_STATE_BLOCKING:
509 /* If io_read reached a point where we could write
510 * again, it would have recursively called io_write.
511 * So (a) we don't need to try to keep writing, and
512 * (b) we can't anyway, because msg may have been
518 case SOUP_MESSAGE_IO_STATE_BODY:
519 if (!io->write_length) {
520 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
522 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
523 soup_message_wrote_body (msg);
524 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
528 if (!io->write_chunk) {
529 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
530 if (!io->write_chunk) {
531 soup_message_io_pause (msg);
534 if (io->write_chunk->length > io->write_length) {
535 /* App is trying to write more than it
536 * claimed it would; we have to truncate.
538 SoupBuffer *truncated =
539 soup_buffer_new_subbuffer (io->write_chunk,
540 0, io->write_length);
541 soup_buffer_free (io->write_chunk);
542 io->write_chunk = truncated;
546 if (!write_data (msg, io->write_chunk->data,
547 io->write_chunk->length, TRUE))
550 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
551 io->write_body_offset += io->write_chunk->length;
552 soup_buffer_free (io->write_chunk);
553 io->write_chunk = NULL;
555 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
556 soup_message_wrote_chunk (msg);
557 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
560 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
561 if (!io->write_chunk) {
562 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
563 if (!io->write_chunk) {
564 soup_message_io_pause (msg);
567 g_string_append_printf (io->write_buf, "%lx\r\n",
568 (unsigned long) io->write_chunk->length);
569 io->write_body_offset += io->write_chunk->length;
572 if (!write_data (msg, io->write_buf->str,
573 io->write_buf->len, FALSE))
576 g_string_truncate (io->write_buf, 0);
578 if (io->write_chunk->length == 0) {
579 /* The last chunk has no CHUNK_END... */
580 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
584 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
588 case SOUP_MESSAGE_IO_STATE_CHUNK:
589 if (!write_data (msg, io->write_chunk->data,
590 io->write_chunk->length, TRUE))
593 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
594 soup_buffer_free (io->write_chunk);
595 io->write_chunk = NULL;
597 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
599 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
600 soup_message_wrote_chunk (msg);
601 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
606 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
607 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
608 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
611 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
615 case SOUP_MESSAGE_IO_STATE_TRAILERS:
616 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
617 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
620 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
622 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
623 soup_message_wrote_body (msg);
624 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
628 case SOUP_MESSAGE_IO_STATE_FINISHING:
630 g_signal_handler_disconnect (io->sock, io->write_tag);
633 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
635 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
636 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
639 soup_message_io_finished (msg);
643 case SOUP_MESSAGE_IO_STATE_DONE:
645 g_return_if_reached ();
652 io_read (SoupSocket *sock, SoupMessage *msg)
654 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
655 SoupMessageIOData *io = priv->io_data;
659 switch (io->read_state) {
660 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
664 case SOUP_MESSAGE_IO_STATE_HEADERS:
665 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
668 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
669 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
670 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
671 io->read_meta_buf->len,
674 g_byte_array_set_size (io->read_meta_buf, 0);
676 if (status != SOUP_STATUS_OK) {
677 /* Either we couldn't parse the headers, or they
678 * indicated something that would mean we wouldn't
679 * be able to parse the body. (Eg, unknown
680 * Transfer-Encoding.). Skip the rest of the
681 * reading, and make sure the connection gets
682 * closed when we're done.
684 soup_message_set_status (msg, status);
685 soup_message_headers_append (msg->request_headers,
686 "Connection", "close");
687 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
691 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
692 SoupMessageHeaders *hdrs =
693 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
694 msg->response_headers : msg->request_headers;
695 io->read_length = soup_message_headers_get_content_length (hdrs);
698 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
699 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
700 if (msg->status_code == SOUP_STATUS_CONTINUE &&
701 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
702 /* Pause the reader, unpause the writer */
704 SOUP_MESSAGE_IO_STATE_BLOCKING;
706 io_body_state (io->write_encoding);
708 /* Just stay in HEADERS */
709 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
711 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
712 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
713 /* The client requested a Continue response. The
714 * got_headers handler may change this to something
717 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
718 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
719 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
721 io->read_state = io_body_state (io->read_encoding);
723 /* If the client was waiting for a Continue
724 * but got something else, then it's done
727 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
728 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
729 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
732 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
733 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
734 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
735 soup_message_got_informational (msg);
736 soup_message_cleanup_response (msg);
737 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
739 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
740 soup_message_got_headers (msg);
741 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
746 case SOUP_MESSAGE_IO_STATE_BLOCKING:
747 io_write (sock, msg);
749 /* As in the io_write case, we *must* return here. */
753 case SOUP_MESSAGE_IO_STATE_BODY:
754 if (!read_body_chunk (msg))
758 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
760 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
761 soup_message_got_body (msg);
762 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
766 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
767 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
770 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
771 g_byte_array_set_size (io->read_meta_buf, 0);
773 if (io->read_length > 0)
774 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
776 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
780 case SOUP_MESSAGE_IO_STATE_CHUNK:
781 if (!read_body_chunk (msg))
784 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
788 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
789 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
792 g_byte_array_set_size (io->read_meta_buf, 0);
793 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
797 case SOUP_MESSAGE_IO_STATE_TRAILERS:
798 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
801 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
804 /* FIXME: process trailers */
805 g_byte_array_set_size (io->read_meta_buf, 0);
809 case SOUP_MESSAGE_IO_STATE_FINISHING:
811 g_signal_handler_disconnect (io->sock, io->read_tag);
814 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
816 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
817 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
818 io_write (sock, msg);
820 soup_message_io_finished (msg);
824 case SOUP_MESSAGE_IO_STATE_DONE:
826 g_return_if_reached ();
832 static SoupMessageIOData *
833 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
834 SoupMessageGetHeadersFn get_headers_cb,
835 SoupMessageParseHeadersFn parse_headers_cb,
838 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
839 SoupMessageIOData *io;
841 io = g_slice_new0 (SoupMessageIOData);
842 io->sock = g_object_ref (sock);
844 io->get_headers_cb = get_headers_cb;
845 io->parse_headers_cb = parse_headers_cb;
846 io->user_data = user_data;
848 io->read_meta_buf = g_byte_array_new ();
849 io->write_buf = g_string_new (NULL);
851 io->read_tag = g_signal_connect (io->sock, "readable",
852 G_CALLBACK (io_read), msg);
853 io->write_tag = g_signal_connect (io->sock, "writable",
854 G_CALLBACK (io_write), msg);
855 io->err_tag = g_signal_connect (io->sock, "disconnected",
856 G_CALLBACK (io_disconnected), msg);
858 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
859 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
862 soup_message_io_cleanup (msg);
868 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
869 SoupConnection *conn,
870 SoupMessageGetHeadersFn get_headers_cb,
871 SoupMessageParseHeadersFn parse_headers_cb,
874 SoupMessageIOData *io;
876 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
877 get_headers_cb, parse_headers_cb, user_data);
880 io->conn = g_object_ref (conn);
882 io->read_body = msg->response_body;
883 io->write_body = msg->request_body;
885 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
886 io_write (sock, msg);
890 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
891 SoupMessageGetHeadersFn get_headers_cb,
892 SoupMessageParseHeadersFn parse_headers_cb,
895 SoupMessageIOData *io;
897 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
898 get_headers_cb, parse_headers_cb, user_data);
900 io->read_body = msg->request_body;
901 io->write_body = msg->response_body;
903 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
908 soup_message_io_pause (SoupMessage *msg)
910 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
911 SoupMessageIOData *io = priv->io_data;
913 g_return_if_fail (io != NULL);
916 g_signal_handler_disconnect (io->sock, io->write_tag);
920 g_signal_handler_disconnect (io->sock, io->read_tag);
924 if (io->unpause_source) {
925 g_source_destroy (io->unpause_source);
926 io->unpause_source = NULL;
931 io_unpause_internal (gpointer msg)
933 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
934 SoupMessageIOData *io = priv->io_data;
936 g_return_val_if_fail (io != NULL, FALSE);
937 io->unpause_source = NULL;
939 if (io->write_tag || io->read_tag)
942 if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
943 io->write_tag = g_signal_connect (io->sock, "writable",
944 G_CALLBACK (io_write), msg);
947 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
948 io->read_tag = g_signal_connect (io->sock, "readable",
949 G_CALLBACK (io_read), msg);
952 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
953 io_write (io->sock, msg);
954 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
955 io_read (io->sock, msg);
961 soup_message_io_unpause (SoupMessage *msg)
963 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
964 SoupMessageIOData *io = priv->io_data;
965 gboolean non_blocking;
966 GMainContext *async_context;
968 g_return_if_fail (io != NULL);
970 g_object_get (io->sock,
971 SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
972 SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
975 if (!io->unpause_source) {
976 io->unpause_source = soup_add_completion (
977 async_context, io_unpause_internal, msg);
980 io_unpause_internal (msg);
982 g_main_context_unref (async_context);
986 * soup_message_io_in_progress:
987 * @msg: a #SoupMessage
989 * Tests whether or not I/O is currently in progress on @msg.
991 * Return value: whether or not I/O is currently in progress.
994 soup_message_io_in_progress (SoupMessage *msg)
996 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
998 return priv->io_data != NULL;