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;
64 guint read_tag, write_tag, err_tag;
66 SoupMessageGetHeadersFn get_headers_cb;
67 SoupMessageParseHeadersFn parse_headers_cb;
72 /* Put these around callback invocation if there is code afterward
73 * that depends on the IO having not been cancelled.
75 #define dummy_to_make_emacs_happy {
76 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
77 #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; }
78 #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; }
80 #define RESPONSE_BLOCK_SIZE 8192
83 soup_message_io_cleanup (SoupMessage *msg)
85 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
86 SoupMessageIOData *io;
88 soup_message_io_stop (msg);
96 g_object_unref (io->sock);
98 g_object_unref (io->conn);
100 g_byte_array_free (io->read_meta_buf, TRUE);
102 g_string_free (io->write_buf, TRUE);
104 soup_buffer_free (io->write_chunk);
106 g_slice_free (SoupMessageIOData, io);
110 * soup_message_io_stop:
111 * @msg: a #SoupMessage
113 * Immediately stops I/O on msg; if the connection would be left in an
114 * inconsistent state, it will be closed.
116 * Note: this is a low-level function that does not cause any signals
117 * to be emitted on @msg; it is up to the caller to make sure that
118 * @msg doesn't get "stranded".
121 soup_message_io_stop (SoupMessage *msg)
123 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
124 SoupMessageIOData *io = priv->io_data;
130 g_signal_handler_disconnect (io->sock, io->read_tag);
134 g_signal_handler_disconnect (io->sock, io->write_tag);
138 g_signal_handler_disconnect (io->sock, io->err_tag);
142 if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
143 soup_socket_disconnect (io->sock);
145 SoupConnection *conn = io->conn;
147 soup_connection_release (conn);
148 g_object_unref (conn);
152 #define SOUP_MESSAGE_IO_EOL "\r\n"
153 #define SOUP_MESSAGE_IO_EOL_LEN 2
154 #define SOUP_MESSAGE_IO_DOUBLE_EOL "\r\n\r\n"
155 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
158 soup_message_io_finished (SoupMessage *msg)
161 soup_message_io_cleanup (msg);
162 if (SOUP_MESSAGE_IS_STARTING (msg))
163 soup_message_restarted (msg);
165 soup_message_finished (msg);
166 g_object_unref (msg);
169 static void io_read (SoupSocket *sock, SoupMessage *msg);
172 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
174 if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
175 if (error && error->domain == SOUP_SSL_ERROR) {
176 soup_message_set_status_full (msg,
177 SOUP_STATUS_SSL_FAILED,
180 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
183 g_error_free (error);
185 soup_message_io_finished (msg);
189 io_disconnected (SoupSocket *sock, SoupMessage *msg)
191 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
192 SoupMessageIOData *io = priv->io_data;
194 /* Closing the connection to signify EOF is sometimes ok */
195 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
196 io->read_encoding == SOUP_ENCODING_EOF) {
197 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
202 io_error (sock, msg, NULL);
205 /* Reads data from io->sock into io->read_meta_buf up until @boundary.
206 * (This function is used to read metadata, and read_body_chunk() is
207 * used to read the message body contents.)
209 * read_metadata, read_body_chunk, and write_data all use the same
210 * convention for return values: if they return %TRUE, it means
211 * they've completely finished the requested read/write, and the
212 * caller should move on to the next step. If they return %FALSE, it
213 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
214 * so the caller should give up for now and wait for the socket to
215 * emit a signal, or (b) the socket returned an error, and io_error()
216 * was called to process it and cancel the I/O. So either way, if the
217 * function returns %FALSE, the caller should return immediately.
220 read_metadata (SoupMessage *msg, const char *boundary)
222 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
223 SoupMessageIOData *io = priv->io_data;
224 SoupSocketIOStatus status;
225 guchar read_buf[RESPONSE_BLOCK_SIZE];
226 guint boundary_len = strlen (boundary);
229 GError *error = NULL;
232 status = soup_socket_read_until (io->sock, read_buf,
234 boundary, boundary_len,
235 &nread, &done, NULL, &error);
238 g_byte_array_append (io->read_meta_buf, read_buf, nread);
241 case SOUP_SOCKET_ERROR:
242 case SOUP_SOCKET_EOF:
243 io_error (io->sock, msg, error);
246 case SOUP_SOCKET_WOULD_BLOCK:
254 /* Reads as much message body data as is available on io->sock (but no
255 * further than the end of the current message body or chunk). On a
256 * successful read, emits "got_chunk" (possibly multiple times), and
257 * if %SOUP_MESSAGE_OVERWRITE_CHUNKS wasn't set, appends the chunk
260 * See the note at read_metadata() for an explanation of the return
264 read_body_chunk (SoupMessage *msg)
266 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
267 SoupMessageIOData *io = priv->io_data;
268 SoupSocketIOStatus status;
269 guchar read_buf[RESPONSE_BLOCK_SIZE];
270 guint len = sizeof (read_buf);
271 gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
273 GError *error = NULL;
276 while (read_to_eof || io->read_length > 0) {
278 len = MIN (len, io->read_length);
280 status = soup_socket_read (io->sock, read_buf, len,
281 &nread, NULL, &error);
288 buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
290 if (!(priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
291 soup_message_body_append_buffer (io->read_body, buffer);
293 io->read_length -= nread;
295 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
296 soup_message_got_chunk (msg, buffer);
297 soup_buffer_free (buffer);
298 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
301 case SOUP_SOCKET_EOF:
304 /* else fall through */
306 case SOUP_SOCKET_ERROR:
307 io_error (io->sock, msg, error);
310 case SOUP_SOCKET_WOULD_BLOCK:
318 /* Attempts to write @len bytes from @data. See the note at
319 * read_metadata() for an explanation of the return value.
322 write_data (SoupMessage *msg, const char *data, guint len)
324 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
325 SoupMessageIOData *io = priv->io_data;
326 SoupSocketIOStatus status;
328 GError *error = NULL;
330 while (len > io->written) {
331 status = soup_socket_write (io->sock,
334 &nwrote, NULL, &error);
336 case SOUP_SOCKET_EOF:
337 case SOUP_SOCKET_ERROR:
338 io_error (io->sock, msg, error);
341 case SOUP_SOCKET_WOULD_BLOCK:
345 io->written += nwrote;
354 static inline SoupMessageIOState
355 io_body_state (SoupEncoding encoding)
357 if (encoding == SOUP_ENCODING_CHUNKED)
358 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
360 return SOUP_MESSAGE_IO_STATE_BODY;
364 * There are two request/response formats: the basic request/response,
365 * possibly with one or more unsolicited informational responses (such
366 * as the WebDAV "102 Processing" response):
369 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
370 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
371 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
372 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
373 * W:DONE / R:BODY <- R:DONE / W:BODY
374 * W:DONE / R:DONE R:DONE / W:DONE
376 * and the "Expect: 100-continue" request/response, with the client
377 * blocking halfway through its request, and then either continuing or
378 * aborting, depending on the server response:
381 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
382 * W:BLOCKING / R:HEADERS <- R:BLOCKING / W:HEADERS
383 * [W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING]
384 * [W:DONE / R:HEADERS <- R:DONE / W:HEADERS]
385 * W:DONE / R:BODY <- R:DONE / W:BODY
386 * W:DONE / R:DONE R:DONE / W:DONE
390 io_write (SoupSocket *sock, SoupMessage *msg)
392 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
393 SoupMessageIOData *io = priv->io_data;
396 switch (io->write_state) {
397 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
401 case SOUP_MESSAGE_IO_STATE_HEADERS:
402 if (!io->write_buf->len) {
403 io->get_headers_cb (msg, io->write_buf,
406 if (!io->write_buf->len) {
407 soup_message_io_pause (msg);
412 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
415 g_string_truncate (io->write_buf, 0);
417 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
418 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
419 if (msg->status_code == SOUP_STATUS_CONTINUE) {
420 /* Stop and wait for the body now */
422 SOUP_MESSAGE_IO_STATE_BLOCKING;
423 io->read_state = io_body_state (io->read_encoding);
425 /* We just wrote a 1xx response
426 * header, so stay in STATE_HEADERS.
427 * (The caller will pause us from the
428 * wrote_informational callback if he
429 * is not ready to send the final
433 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
434 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
435 /* Need to wait for the Continue response */
436 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
437 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
439 io->write_state = io_body_state (io->write_encoding);
441 /* If the client was waiting for a Continue
442 * but we sent something else, then they're
445 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
446 io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
447 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
450 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
451 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
452 soup_message_wrote_informational (msg);
453 soup_message_cleanup_response (msg);
455 soup_message_wrote_headers (msg);
456 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
460 case SOUP_MESSAGE_IO_STATE_BLOCKING:
463 /* If io_read reached a point where we could write
464 * again, it would have recursively called io_write.
465 * So (a) we don't need to try to keep writing, and
466 * (b) we can't anyway, because msg may have been
472 case SOUP_MESSAGE_IO_STATE_BODY:
473 if (!io->write_chunk)
474 io->write_chunk = soup_message_body_flatten (io->write_body);
475 if (!write_data (msg, io->write_chunk->data,
476 io->write_chunk->length))
478 soup_buffer_free (io->write_chunk);
479 io->write_chunk = NULL;
481 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
483 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
484 soup_message_wrote_body (msg);
485 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
489 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
490 if (!io->write_chunk) {
491 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
492 if (!io->write_chunk) {
493 soup_message_io_pause (msg);
496 g_string_append_printf (io->write_buf, "%lx\r\n",
497 (unsigned long) io->write_chunk->length);
498 io->write_body_offset += io->write_chunk->length;
501 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
504 g_string_truncate (io->write_buf, 0);
506 if (io->write_chunk->length == 0) {
507 /* The last chunk has no CHUNK_END... */
508 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
512 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
516 case SOUP_MESSAGE_IO_STATE_CHUNK:
517 if (!write_data (msg, io->write_chunk->data,
518 io->write_chunk->length))
521 soup_buffer_free (io->write_chunk);
522 io->write_chunk = NULL;
524 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
526 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
527 soup_message_wrote_chunk (msg);
528 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
533 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
534 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
535 SOUP_MESSAGE_IO_EOL_LEN))
538 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
542 case SOUP_MESSAGE_IO_STATE_TRAILERS:
543 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
544 SOUP_MESSAGE_IO_EOL_LEN))
547 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
549 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
550 soup_message_wrote_body (msg);
551 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
555 case SOUP_MESSAGE_IO_STATE_FINISHING:
557 g_signal_handler_disconnect (io->sock, io->write_tag);
560 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
562 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
563 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
566 soup_message_io_finished (msg);
570 case SOUP_MESSAGE_IO_STATE_DONE:
572 g_return_if_reached ();
579 io_read (SoupSocket *sock, SoupMessage *msg)
581 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
582 SoupMessageIOData *io = priv->io_data;
586 switch (io->read_state) {
587 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
591 case SOUP_MESSAGE_IO_STATE_HEADERS:
592 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
595 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
596 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
597 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
598 io->read_meta_buf->len,
601 g_byte_array_set_size (io->read_meta_buf, 0);
603 if (status != SOUP_STATUS_OK) {
604 /* Either we couldn't parse the headers, or they
605 * indicated something that would mean we wouldn't
606 * be able to parse the body. (Eg, unknown
607 * Transfer-Encoding.). Skip the rest of the
608 * reading, and make sure the connection gets
609 * closed when we're done.
611 soup_message_set_status (msg, status);
612 soup_message_headers_append (msg->request_headers,
613 "Connection", "close");
614 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
618 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
619 SoupMessageHeaders *hdrs =
620 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
621 msg->response_headers : msg->request_headers;
622 io->read_length = soup_message_headers_get_content_length (hdrs);
625 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
626 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
627 if (msg->status_code == SOUP_STATUS_CONTINUE &&
628 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
629 /* Pause the reader, unpause the writer */
631 SOUP_MESSAGE_IO_STATE_BLOCKING;
633 io_body_state (io->write_encoding);
635 /* Just stay in HEADERS */
636 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
638 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
639 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
640 /* The client requested a Continue response. The
641 * got_headers handler may change this to something
644 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
645 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
646 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
648 io->read_state = io_body_state (io->read_encoding);
650 /* If the client was waiting for a Continue
651 * but got something else, then it's done
654 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
655 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
656 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
659 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
660 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
661 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
662 soup_message_got_informational (msg);
663 soup_message_cleanup_response (msg);
664 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
666 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
667 soup_message_got_headers (msg);
668 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
673 case SOUP_MESSAGE_IO_STATE_BLOCKING:
674 io_write (sock, msg);
676 /* As in the io_write case, we *must* return here. */
680 case SOUP_MESSAGE_IO_STATE_BODY:
681 if (!read_body_chunk (msg))
685 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
687 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
688 soup_message_got_body (msg);
689 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
693 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
694 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
697 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
698 g_byte_array_set_size (io->read_meta_buf, 0);
700 if (io->read_length > 0)
701 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
703 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
707 case SOUP_MESSAGE_IO_STATE_CHUNK:
708 if (!read_body_chunk (msg))
711 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
715 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
716 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
719 g_byte_array_set_size (io->read_meta_buf, 0);
720 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
724 case SOUP_MESSAGE_IO_STATE_TRAILERS:
725 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
728 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
731 /* FIXME: process trailers */
732 g_byte_array_set_size (io->read_meta_buf, 0);
736 case SOUP_MESSAGE_IO_STATE_FINISHING:
738 g_signal_handler_disconnect (io->sock, io->read_tag);
741 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
743 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
744 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
745 io_write (sock, msg);
747 soup_message_io_finished (msg);
751 case SOUP_MESSAGE_IO_STATE_DONE:
753 g_return_if_reached ();
759 static SoupMessageIOData *
760 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
761 SoupMessageGetHeadersFn get_headers_cb,
762 SoupMessageParseHeadersFn parse_headers_cb,
765 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
766 SoupMessageIOData *io;
768 io = g_slice_new0 (SoupMessageIOData);
769 io->sock = g_object_ref (sock);
771 io->get_headers_cb = get_headers_cb;
772 io->parse_headers_cb = parse_headers_cb;
773 io->user_data = user_data;
775 io->read_meta_buf = g_byte_array_new ();
776 io->write_buf = g_string_new (NULL);
778 io->read_tag = g_signal_connect (io->sock, "readable",
779 G_CALLBACK (io_read), msg);
780 io->write_tag = g_signal_connect (io->sock, "writable",
781 G_CALLBACK (io_write), msg);
782 io->err_tag = g_signal_connect (io->sock, "disconnected",
783 G_CALLBACK (io_disconnected), msg);
785 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
786 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
789 soup_message_io_cleanup (msg);
795 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
796 SoupConnection *conn,
797 SoupMessageGetHeadersFn get_headers_cb,
798 SoupMessageParseHeadersFn parse_headers_cb,
801 SoupMessageIOData *io;
803 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
804 get_headers_cb, parse_headers_cb, user_data);
807 io->conn = g_object_ref (conn);
809 io->read_body = msg->response_body;
810 io->write_body = msg->request_body;
812 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
813 io_write (sock, msg);
817 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
818 SoupMessageGetHeadersFn get_headers_cb,
819 SoupMessageParseHeadersFn parse_headers_cb,
822 SoupMessageIOData *io;
824 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
825 get_headers_cb, parse_headers_cb, user_data);
827 io->read_body = msg->request_body;
828 io->write_body = msg->response_body;
830 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
835 soup_message_io_pause (SoupMessage *msg)
837 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
838 SoupMessageIOData *io = priv->io_data;
840 g_return_if_fail (io != NULL);
843 g_signal_handler_disconnect (io->sock, io->write_tag);
847 g_signal_handler_disconnect (io->sock, io->read_tag);
853 io_unpause_internal (gpointer msg)
855 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
856 SoupMessageIOData *io = priv->io_data;
858 g_return_val_if_fail (io != NULL, FALSE);
860 if (io->write_tag || io->read_tag)
863 if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
864 io->write_tag = g_signal_connect (io->sock, "writable",
865 G_CALLBACK (io_write), msg);
868 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
869 io->read_tag = g_signal_connect (io->sock, "readable",
870 G_CALLBACK (io_read), msg);
873 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
874 io_write (io->sock, msg);
875 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
876 io_read (io->sock, msg);
882 soup_message_io_unpause (SoupMessage *msg)
884 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
885 SoupMessageIOData *io = priv->io_data;
886 gboolean non_blocking;
887 GMainContext *async_context;
889 g_return_if_fail (io != NULL);
891 g_object_get (io->sock,
892 SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
893 SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
896 soup_add_idle (async_context, io_unpause_internal, msg);
898 io_unpause_internal (msg);
900 g_main_context_unref (async_context);
904 * soup_message_io_in_progress:
905 * @msg: a #SoupMessage
907 * Tests whether or not I/O is currently in progress on @msg.
909 * Return value: whether or not I/O is currently in progress.
912 soup_message_io_in_progress (SoupMessage *msg)
914 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
916 return priv->io_data != NULL;