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
163 soup_message_io_finished (SoupMessage *msg)
166 soup_message_io_cleanup (msg);
167 if (SOUP_MESSAGE_IS_STARTING (msg))
168 soup_message_restarted (msg);
170 soup_message_finished (msg);
171 g_object_unref (msg);
174 static void io_read (SoupSocket *sock, SoupMessage *msg);
177 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
179 if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
180 if (error && error->domain == SOUP_SSL_ERROR) {
181 soup_message_set_status_full (msg,
182 SOUP_STATUS_SSL_FAILED,
185 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
188 g_error_free (error);
190 soup_message_io_finished (msg);
194 io_disconnected (SoupSocket *sock, SoupMessage *msg)
196 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
197 SoupMessageIOData *io = priv->io_data;
199 /* Closing the connection to signify EOF is sometimes ok */
200 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
201 io->read_encoding == SOUP_ENCODING_EOF) {
202 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
207 io_error (sock, msg, NULL);
210 /* Reads data from io->sock into io->read_meta_buf. If @to_blank is
211 * %TRUE, it reads up until a blank line ("CRLF CRLF" or "LF LF").
212 * Otherwise, it reads up until a single CRLF or LF.
214 * This function is used to read metadata, and read_body_chunk() is
215 * used to read the message body contents.
217 * read_metadata, read_body_chunk, and write_data all use the same
218 * convention for return values: if they return %TRUE, it means
219 * they've completely finished the requested read/write, and the
220 * caller should move on to the next step. If they return %FALSE, it
221 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
222 * so the caller should give up for now and wait for the socket to
223 * emit a signal, or (b) the socket returned an error, and io_error()
224 * was called to process it and cancel the I/O. So either way, if the
225 * function returns %FALSE, the caller should return immediately.
228 read_metadata (SoupMessage *msg, gboolean to_blank)
230 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
231 SoupMessageIOData *io = priv->io_data;
232 SoupSocketIOStatus status;
233 guchar read_buf[RESPONSE_BLOCK_SIZE];
236 GError *error = NULL;
239 status = soup_socket_read_until (io->sock, read_buf,
241 "\n", 1, &nread, &got_lf,
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 !strncmp (io->read_meta_buf->data +
262 io->read_meta_buf->len - 2,
265 else if (nread == 2 &&
266 !strncmp (io->read_meta_buf->data +
267 io->read_meta_buf->len - 3,
276 /* Reads as much message body data as is available on io->sock (but no
277 * further than the end of the current message body or chunk). On a
278 * successful read, emits "got_chunk" (possibly multiple times), and
279 * (unless told not to) appends the chunk to io->read_body.
281 * See the note at read_metadata() for an explanation of the return
285 read_body_chunk (SoupMessage *msg)
287 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
288 SoupMessageIOData *io = priv->io_data;
289 SoupSocketIOStatus status;
290 guchar *stack_buf = NULL;
292 gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
294 GError *error = NULL;
297 while (read_to_eof || io->read_length > 0) {
298 if (priv->chunk_allocator) {
299 buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
301 soup_message_io_pause (msg);
306 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
307 buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
309 RESPONSE_BLOCK_SIZE);
313 len = buffer->length;
315 len = MIN (buffer->length, io->read_length);
317 status = soup_socket_read (io->sock,
318 (guchar *)buffer->data, len,
319 &nread, NULL, &error);
321 if (status == SOUP_SOCKET_OK && nread) {
322 buffer->length = nread;
323 soup_message_body_got_chunk (io->read_body, buffer);
325 io->read_length -= nread;
327 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
328 soup_message_got_chunk (msg, buffer);
329 soup_buffer_free (buffer);
330 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
334 soup_buffer_free (buffer);
339 case SOUP_SOCKET_EOF:
342 /* else fall through */
344 case SOUP_SOCKET_ERROR:
345 io_error (io->sock, msg, error);
348 case SOUP_SOCKET_WOULD_BLOCK:
356 /* Attempts to write @len bytes from @data. See the note at
357 * read_metadata() for an explanation of the return value.
360 write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
362 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
363 SoupMessageIOData *io = priv->io_data;
364 SoupSocketIOStatus status;
366 GError *error = NULL;
370 while (len > io->written) {
371 status = soup_socket_write (io->sock,
374 &nwrote, NULL, &error);
376 case SOUP_SOCKET_EOF:
377 case SOUP_SOCKET_ERROR:
378 io_error (io->sock, msg, error);
381 case SOUP_SOCKET_WOULD_BLOCK:
385 start = data + io->written;
386 io->written += nwrote;
389 if (io->write_length)
390 io->write_length -= nwrote;
392 chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
394 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
395 soup_message_wrote_body_data (msg, chunk);
396 soup_buffer_free (chunk);
397 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
407 static inline SoupMessageIOState
408 io_body_state (SoupEncoding encoding)
410 if (encoding == SOUP_ENCODING_CHUNKED)
411 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
413 return SOUP_MESSAGE_IO_STATE_BODY;
417 * There are two request/response formats: the basic request/response,
418 * possibly with one or more unsolicited informational responses (such
419 * as the WebDAV "102 Processing" response):
422 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
423 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
424 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
425 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
426 * W:DONE / R:BODY <- R:DONE / W:BODY
427 * W:DONE / R:DONE R:DONE / W:DONE
429 * and the "Expect: 100-continue" request/response, with the client
430 * blocking halfway through its request, and then either continuing or
431 * aborting, depending on the server response:
434 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
435 * W:BLOCKING / R:HEADERS <- R:BLOCKING / W:HEADERS
436 * [W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING]
437 * [W:DONE / R:HEADERS <- R:DONE / W:HEADERS]
438 * W:DONE / R:BODY <- R:DONE / W:BODY
439 * W:DONE / R:DONE R:DONE / W:DONE
443 io_write (SoupSocket *sock, SoupMessage *msg)
445 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
446 SoupMessageIOData *io = priv->io_data;
449 switch (io->write_state) {
450 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
454 case SOUP_MESSAGE_IO_STATE_HEADERS:
455 if (!io->write_buf->len) {
456 io->get_headers_cb (msg, io->write_buf,
459 if (!io->write_buf->len) {
460 soup_message_io_pause (msg);
465 if (!write_data (msg, io->write_buf->str,
466 io->write_buf->len, FALSE))
469 g_string_truncate (io->write_buf, 0);
471 if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
472 SoupMessageHeaders *hdrs =
473 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
474 msg->request_headers : msg->response_headers;
475 io->write_length = soup_message_headers_get_content_length (hdrs);
478 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
479 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
480 if (msg->status_code == SOUP_STATUS_CONTINUE) {
481 /* Stop and wait for the body now */
483 SOUP_MESSAGE_IO_STATE_BLOCKING;
484 io->read_state = io_body_state (io->read_encoding);
486 /* We just wrote a 1xx response
487 * header, so stay in STATE_HEADERS.
488 * (The caller will pause us from the
489 * wrote_informational callback if he
490 * is not ready to send the final
494 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
495 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
496 /* Need to wait for the Continue response */
497 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
498 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
500 io->write_state = io_body_state (io->write_encoding);
502 /* If the client was waiting for a Continue
503 * but we sent something else, then they're
506 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
507 io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
508 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
511 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
512 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
513 soup_message_wrote_informational (msg);
514 soup_message_cleanup_response (msg);
516 soup_message_wrote_headers (msg);
517 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
521 case SOUP_MESSAGE_IO_STATE_BLOCKING:
524 /* If io_read reached a point where we could write
525 * again, it would have recursively called io_write.
526 * So (a) we don't need to try to keep writing, and
527 * (b) we can't anyway, because msg may have been
533 case SOUP_MESSAGE_IO_STATE_BODY:
534 if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) {
536 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
538 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
539 soup_message_wrote_body (msg);
540 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
544 if (!io->write_chunk) {
545 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
546 if (!io->write_chunk) {
547 soup_message_io_pause (msg);
550 if (io->write_chunk->length > io->write_length &&
551 io->write_encoding != SOUP_ENCODING_EOF) {
552 /* App is trying to write more than it
553 * claimed it would; we have to truncate.
555 SoupBuffer *truncated =
556 soup_buffer_new_subbuffer (io->write_chunk,
557 0, io->write_length);
558 soup_buffer_free (io->write_chunk);
559 io->write_chunk = truncated;
560 } else if (io->write_encoding == SOUP_ENCODING_EOF &&
561 !io->write_chunk->length)
565 if (!write_data (msg, io->write_chunk->data,
566 io->write_chunk->length, TRUE))
569 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
570 io->write_body_offset += io->write_chunk->length;
571 soup_buffer_free (io->write_chunk);
572 io->write_chunk = NULL;
574 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
575 soup_message_wrote_chunk (msg);
576 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
579 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
580 if (!io->write_chunk) {
581 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
582 if (!io->write_chunk) {
583 soup_message_io_pause (msg);
586 g_string_append_printf (io->write_buf, "%lx\r\n",
587 (unsigned long) io->write_chunk->length);
588 io->write_body_offset += io->write_chunk->length;
591 if (!write_data (msg, io->write_buf->str,
592 io->write_buf->len, FALSE))
595 g_string_truncate (io->write_buf, 0);
597 if (io->write_chunk->length == 0) {
598 /* The last chunk has no CHUNK_END... */
599 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
603 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
607 case SOUP_MESSAGE_IO_STATE_CHUNK:
608 if (!write_data (msg, io->write_chunk->data,
609 io->write_chunk->length, TRUE))
612 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
613 soup_buffer_free (io->write_chunk);
614 io->write_chunk = NULL;
616 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
618 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
619 soup_message_wrote_chunk (msg);
620 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
625 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
626 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
627 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
630 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
634 case SOUP_MESSAGE_IO_STATE_TRAILERS:
635 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
636 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
639 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
641 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
642 soup_message_wrote_body (msg);
643 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
647 case SOUP_MESSAGE_IO_STATE_FINISHING:
649 g_signal_handler_disconnect (io->sock, io->write_tag);
652 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
654 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
655 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
658 soup_message_io_finished (msg);
662 case SOUP_MESSAGE_IO_STATE_DONE:
664 g_return_if_reached ();
671 io_read (SoupSocket *sock, SoupMessage *msg)
673 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
674 SoupMessageIOData *io = priv->io_data;
678 switch (io->read_state) {
679 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
683 case SOUP_MESSAGE_IO_STATE_HEADERS:
684 if (!read_metadata (msg, TRUE))
687 /* We need to "rewind" io->read_meta_buf back one line.
688 * That SHOULD be two characters (CR LF), but if the
689 * web server was stupid, it might only be one.
691 if (io->read_meta_buf->len < 3 ||
692 io->read_meta_buf->data[io->read_meta_buf->len - 2] == '\n')
693 io->read_meta_buf->len--;
695 io->read_meta_buf->len -= 2;
696 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
697 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
698 io->read_meta_buf->len,
701 g_byte_array_set_size (io->read_meta_buf, 0);
703 if (status != SOUP_STATUS_OK) {
704 /* Either we couldn't parse the headers, or they
705 * indicated something that would mean we wouldn't
706 * be able to parse the body. (Eg, unknown
707 * Transfer-Encoding.). Skip the rest of the
708 * reading, and make sure the connection gets
709 * closed when we're done.
711 soup_message_set_status (msg, status);
712 soup_message_headers_append (msg->request_headers,
713 "Connection", "close");
714 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
718 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
719 SoupMessageHeaders *hdrs =
720 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
721 msg->response_headers : msg->request_headers;
722 io->read_length = soup_message_headers_get_content_length (hdrs);
725 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
726 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
727 if (msg->status_code == SOUP_STATUS_CONTINUE &&
728 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
729 /* Pause the reader, unpause the writer */
731 SOUP_MESSAGE_IO_STATE_BLOCKING;
733 io_body_state (io->write_encoding);
735 /* Just stay in HEADERS */
736 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
738 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
739 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
740 /* The client requested a Continue response. The
741 * got_headers handler may change this to something
744 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
745 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
746 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
748 io->read_state = io_body_state (io->read_encoding);
750 /* If the client was waiting for a Continue
751 * but got something else, then it's done
754 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
755 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
756 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
759 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
760 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
761 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
762 soup_message_got_informational (msg);
763 soup_message_cleanup_response (msg);
764 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
766 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
767 soup_message_got_headers (msg);
768 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
773 case SOUP_MESSAGE_IO_STATE_BLOCKING:
774 io_write (sock, msg);
776 /* As in the io_write case, we *must* return here. */
780 case SOUP_MESSAGE_IO_STATE_BODY:
781 if (!read_body_chunk (msg))
785 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
787 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
788 soup_message_got_body (msg);
789 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
793 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
794 if (!read_metadata (msg, FALSE))
797 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
798 g_byte_array_set_size (io->read_meta_buf, 0);
800 if (io->read_length > 0)
801 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
803 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
807 case SOUP_MESSAGE_IO_STATE_CHUNK:
808 if (!read_body_chunk (msg))
811 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
815 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
816 if (!read_metadata (msg, FALSE))
819 g_byte_array_set_size (io->read_meta_buf, 0);
820 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
824 case SOUP_MESSAGE_IO_STATE_TRAILERS:
825 if (!read_metadata (msg, FALSE))
828 if (io->read_meta_buf->len <= SOUP_MESSAGE_IO_EOL_LEN)
831 /* FIXME: process trailers */
832 g_byte_array_set_size (io->read_meta_buf, 0);
836 case SOUP_MESSAGE_IO_STATE_FINISHING:
838 g_signal_handler_disconnect (io->sock, io->read_tag);
841 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
843 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
844 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
845 io_write (sock, msg);
847 soup_message_io_finished (msg);
851 case SOUP_MESSAGE_IO_STATE_DONE:
853 g_return_if_reached ();
859 static SoupMessageIOData *
860 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
861 SoupMessageGetHeadersFn get_headers_cb,
862 SoupMessageParseHeadersFn parse_headers_cb,
865 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
866 SoupMessageIOData *io;
868 io = g_slice_new0 (SoupMessageIOData);
869 io->sock = g_object_ref (sock);
871 io->get_headers_cb = get_headers_cb;
872 io->parse_headers_cb = parse_headers_cb;
873 io->user_data = user_data;
875 io->read_meta_buf = g_byte_array_new ();
876 io->write_buf = g_string_new (NULL);
878 io->read_tag = g_signal_connect (io->sock, "readable",
879 G_CALLBACK (io_read), msg);
880 io->write_tag = g_signal_connect (io->sock, "writable",
881 G_CALLBACK (io_write), msg);
882 io->err_tag = g_signal_connect (io->sock, "disconnected",
883 G_CALLBACK (io_disconnected), msg);
885 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
886 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
889 soup_message_io_cleanup (msg);
895 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
896 SoupConnection *conn,
897 SoupMessageGetHeadersFn get_headers_cb,
898 SoupMessageParseHeadersFn parse_headers_cb,
901 SoupMessageIOData *io;
903 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
904 get_headers_cb, parse_headers_cb, user_data);
907 io->conn = g_object_ref (conn);
909 io->read_body = msg->response_body;
910 io->write_body = msg->request_body;
912 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
913 io_write (sock, msg);
917 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
918 SoupMessageGetHeadersFn get_headers_cb,
919 SoupMessageParseHeadersFn parse_headers_cb,
922 SoupMessageIOData *io;
924 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
925 get_headers_cb, parse_headers_cb, user_data);
927 io->read_body = msg->request_body;
928 io->write_body = msg->response_body;
930 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
935 soup_message_io_pause (SoupMessage *msg)
937 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
938 SoupMessageIOData *io = priv->io_data;
940 g_return_if_fail (io != NULL);
943 g_signal_handler_disconnect (io->sock, io->write_tag);
947 g_signal_handler_disconnect (io->sock, io->read_tag);
951 if (io->unpause_source) {
952 g_source_destroy (io->unpause_source);
953 io->unpause_source = NULL;
958 io_unpause_internal (gpointer msg)
960 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
961 SoupMessageIOData *io = priv->io_data;
963 g_return_val_if_fail (io != NULL, FALSE);
964 io->unpause_source = NULL;
966 if (io->write_tag || io->read_tag)
969 if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
970 io->write_tag = g_signal_connect (io->sock, "writable",
971 G_CALLBACK (io_write), msg);
974 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
975 io->read_tag = g_signal_connect (io->sock, "readable",
976 G_CALLBACK (io_read), msg);
979 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
980 io_write (io->sock, msg);
981 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
982 io_read (io->sock, msg);
988 soup_message_io_unpause (SoupMessage *msg)
990 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
991 SoupMessageIOData *io = priv->io_data;
992 gboolean non_blocking;
993 GMainContext *async_context;
995 g_return_if_fail (io != NULL);
997 g_object_get (io->sock,
998 SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
999 SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
1002 if (!io->unpause_source) {
1003 io->unpause_source = soup_add_completion (
1004 async_context, io_unpause_internal, msg);
1007 io_unpause_internal (msg);
1009 g_main_context_unref (async_context);
1013 * soup_message_io_in_progress:
1014 * @msg: a #SoupMessage
1016 * Tests whether or not I/O is currently in progress on @msg.
1018 * Return value: whether or not I/O is currently in progress.
1021 soup_message_io_in_progress (SoupMessage *msg)
1023 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1025 return priv->io_data != NULL;