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-socket.h"
22 SOUP_MESSAGE_IO_CLIENT,
23 SOUP_MESSAGE_IO_SERVER
27 SOUP_MESSAGE_IO_STATE_NOT_STARTED,
28 SOUP_MESSAGE_IO_STATE_HEADERS,
29 SOUP_MESSAGE_IO_STATE_BLOCKING,
30 SOUP_MESSAGE_IO_STATE_BODY,
31 SOUP_MESSAGE_IO_STATE_CHUNK_SIZE,
32 SOUP_MESSAGE_IO_STATE_CHUNK,
33 SOUP_MESSAGE_IO_STATE_CHUNK_END,
34 SOUP_MESSAGE_IO_STATE_TRAILERS,
35 SOUP_MESSAGE_IO_STATE_DONE
41 SoupMessageIOMode mode;
43 SoupMessageIOState read_state;
44 SoupTransferEncoding read_encoding;
46 GByteArray *read_meta_buf;
47 SoupDataBuffer *read_body;
50 SoupMessageIOState write_state;
51 SoupTransferEncoding write_encoding;
53 SoupDataBuffer *write_body;
56 guint read_tag, write_tag, err_tag;
58 SoupMessageGetHeadersFn get_headers_cb;
59 SoupMessageParseHeadersFn parse_headers_cb;
64 /* Put these around callback invocation if there is code afterward
65 * that depends on the IO having not been cancelled.
67 #define dummy_to_make_emacs_happy {
68 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
69 #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; }
70 #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; }
72 #define RESPONSE_BLOCK_SIZE 8192
75 io_cleanup (SoupMessage *msg)
77 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
78 SoupMessageIOData *io;
80 soup_message_io_stop (msg);
88 g_object_unref (io->sock);
90 g_object_unref (io->conn);
93 g_byte_array_free (io->read_buf, TRUE);
94 g_byte_array_free (io->read_meta_buf, TRUE);
96 g_string_free (io->write_buf, TRUE);
102 * soup_message_io_stop:
103 * @msg: a #SoupMessage
105 * Immediately stops I/O on msg; if the connection would be left in an
106 * inconsistent state, it will be closed.
109 soup_message_io_stop (SoupMessage *msg)
111 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
112 SoupMessageIOData *io = priv->io_data;
118 g_signal_handler_disconnect (io->sock, io->read_tag);
122 g_signal_handler_disconnect (io->sock, io->write_tag);
126 g_signal_handler_disconnect (io->sock, io->err_tag);
130 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE)
131 soup_socket_disconnect (io->sock);
133 SoupConnection *conn = io->conn;
135 soup_connection_release (conn);
136 g_object_unref (conn);
140 #define SOUP_MESSAGE_IO_EOL "\r\n"
141 #define SOUP_MESSAGE_IO_EOL_LEN 2
142 #define SOUP_MESSAGE_IO_DOUBLE_EOL "\r\n\r\n"
143 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
146 soup_message_io_finished (SoupMessage *msg)
150 if (SOUP_MESSAGE_IS_STARTING (msg))
151 soup_message_restarted (msg);
153 soup_message_finished (msg);
154 g_object_unref (msg);
159 io_error (SoupSocket *sock, SoupMessage *msg)
161 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
162 SoupMessageIOData *io = priv->io_data;
164 /* Closing the connection to signify EOF is sometimes ok */
165 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
166 io->read_encoding == SOUP_TRANSFER_UNKNOWN) {
167 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
168 soup_message_io_finished (msg);
172 if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
173 GError *err = g_object_get_data (G_OBJECT (sock),
174 "SoupSocket-last_error");
176 if (err && err->domain == SOUP_SSL_ERROR) {
177 soup_message_set_status_full (msg,
178 SOUP_STATUS_SSL_FAILED,
181 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
184 soup_message_io_finished (msg);
187 /* Reads data from io->sock into io->read_meta_buf up until @boundary.
188 * (This function is used to read metadata, and read_body_chunk() is
189 * used to read the message body contents.)
191 * read_metadata, read_body_chunk, and write_data all use the same
192 * convention for return values: if they return %TRUE, it means
193 * they've completely finished the requested read/write, and the
194 * caller should move on to the next step. If they return %FALSE, it
195 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
196 * so the caller should give up for now and wait for the socket to
197 * emit a signal, or (b) the socket returned an error, and io_error()
198 * was called to process it and cancel the I/O. So either way, if the
199 * function returns %FALSE, the caller should return immediately.
202 read_metadata (SoupMessage *msg, const char *boundary)
204 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
205 SoupMessageIOData *io = priv->io_data;
206 SoupSocketIOStatus status;
207 guchar read_buf[RESPONSE_BLOCK_SIZE];
208 guint boundary_len = strlen (boundary);
213 status = soup_socket_read_until (io->sock, read_buf,
215 boundary, boundary_len,
219 g_byte_array_append (io->read_meta_buf, read_buf, nread);
222 case SOUP_SOCKET_ERROR:
223 case SOUP_SOCKET_EOF:
224 io_error (io->sock, msg);
227 case SOUP_SOCKET_WOULD_BLOCK:
235 /* Reads as much message body data as is available on io->sock (but no
236 * further than the end of the current message body or chunk). On a
237 * successful read, emits "got_chunk" (possibly multiple times), and
238 * if io->read_buf is non-%NULL (meaning that the message doesn't have
239 * %SOUP_MESSAGE_OVERWRITE_CHUNKS set), the data will be appended to
242 * See the note at read_metadata() for an explanation of the return
246 read_body_chunk (SoupMessage *msg)
248 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
249 SoupMessageIOData *io = priv->io_data;
250 SoupSocketIOStatus status;
251 guchar read_buf[RESPONSE_BLOCK_SIZE];
252 guint len = sizeof (read_buf);
253 gboolean read_to_eof = (io->read_encoding == SOUP_TRANSFER_UNKNOWN);
256 while (read_to_eof || io->read_length > 0) {
258 len = MIN (len, io->read_length);
260 status = soup_socket_read (io->sock, read_buf, len, &nread);
267 io->read_body->owner = SOUP_BUFFER_STATIC;
268 io->read_body->body = (char *)read_buf;
269 io->read_body->length = nread;
271 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
272 soup_message_got_chunk (msg);
273 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
275 memset (io->read_body, 0, sizeof (SoupDataBuffer));
278 g_byte_array_append (io->read_buf, read_buf, nread);
279 io->read_length -= nread;
282 case SOUP_SOCKET_EOF:
285 /* else fall through */
287 case SOUP_SOCKET_ERROR:
288 io_error (io->sock, msg);
291 case SOUP_SOCKET_WOULD_BLOCK:
299 /* Attempts to write @len bytes from @data. See the note at
300 * read_metadata() for an explanation of the return value.
303 write_data (SoupMessage *msg, const char *data, guint len)
305 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
306 SoupMessageIOData *io = priv->io_data;
307 SoupSocketIOStatus status;
310 while (len > io->written) {
311 status = soup_socket_write (io->sock,
316 case SOUP_SOCKET_EOF:
317 case SOUP_SOCKET_ERROR:
318 io_error (io->sock, msg);
321 case SOUP_SOCKET_WOULD_BLOCK:
325 io->written += nwrote;
334 static inline SoupMessageIOState
335 io_body_state (SoupTransferEncoding encoding)
337 if (encoding == SOUP_TRANSFER_CHUNKED)
338 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
340 return SOUP_MESSAGE_IO_STATE_BODY;
343 static void io_read (SoupSocket *sock, SoupMessage *msg);
346 * There are two request/response formats: the basic request/response,
347 * possibly with one or more unsolicited informational responses (such
348 * as the WebDAV "102 Processing" response):
351 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
352 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
353 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
354 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
355 * W:DONE / R:BODY <- R:DONE / W:BODY
356 * W:DONE / R:DONE R:DONE / W:DONE
358 * and the "Expect: 100-continue" request/response, in which each
359 * writer has to pause and wait for the other at some point:
362 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
363 * W:BLOCKING / R:HEADERS (100) <- R:BLOCKING / W:HEADERS (100)
364 * W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING
365 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
366 * W:DONE / R:BODY <- R:DONE / W:BODY
367 * W:DONE / R:DONE R:DONE / W:DONE
371 io_write (SoupSocket *sock, SoupMessage *msg)
373 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
374 SoupMessageIOData *io = priv->io_data;
377 switch (io->write_state) {
378 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
382 case SOUP_MESSAGE_IO_STATE_HEADERS:
383 if (!io->write_buf->len) {
384 io->get_headers_cb (msg, io->write_buf,
387 if (!io->write_buf->len) {
388 soup_message_io_pause (msg);
393 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
396 g_string_truncate (io->write_buf, 0);
398 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
399 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
400 if (msg->status_code == SOUP_STATUS_CONTINUE) {
401 /* Stop and wait for the body now */
403 SOUP_MESSAGE_IO_STATE_BLOCKING;
404 io->read_state = io_body_state (io->read_encoding);
406 /* We just wrote a 1xx response
407 * header, so stay in STATE_HEADERS.
408 * (The caller will pause us from the
409 * wrote_informational callback if he
410 * is not ready to send the final
414 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
415 priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE) {
416 /* Need to wait for the Continue response */
417 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
418 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
420 io->write_state = io_body_state (io->write_encoding);
422 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
423 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
424 soup_message_wrote_informational (msg);
426 soup_message_wrote_headers (msg);
427 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
431 case SOUP_MESSAGE_IO_STATE_BLOCKING:
434 /* If io_read reached a point where we could write
435 * again, it would have recursively called io_write.
436 * So (a) we don't need to try to keep writing, and
437 * (b) we can't anyway, because msg may have been
443 case SOUP_MESSAGE_IO_STATE_BODY:
444 if (!write_data (msg, io->write_body->body,
445 io->write_body->length))
448 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
450 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
451 soup_message_wrote_body (msg);
452 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
456 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
457 if (!io->write_buf->len) {
458 SoupDataBuffer *chunk;
460 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
461 chunk = soup_message_pop_chunk (msg);
462 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
465 soup_message_io_pause (msg);
468 memcpy (io->write_body, chunk, sizeof (SoupDataBuffer));
471 g_string_append_printf (io->write_buf, "%x\r\n",
472 io->write_body->length);
475 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
478 g_string_truncate (io->write_buf, 0);
480 if (io->write_body->length == 0) {
481 /* The last chunk has no CHUNK_END... */
482 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
486 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
490 case SOUP_MESSAGE_IO_STATE_CHUNK:
491 if (!write_data (msg, io->write_body->body,
492 io->write_body->length))
495 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
497 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
498 soup_message_wrote_chunk (msg);
499 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
503 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
504 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
505 SOUP_MESSAGE_IO_EOL_LEN))
508 if (io->write_body->owner == SOUP_BUFFER_SYSTEM_OWNED)
509 g_free (io->write_body->body);
510 memset (io->write_body, 0, sizeof (SoupDataBuffer));
512 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
516 case SOUP_MESSAGE_IO_STATE_TRAILERS:
517 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
518 SOUP_MESSAGE_IO_EOL_LEN))
521 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
523 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
524 soup_message_wrote_body (msg);
525 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
529 case SOUP_MESSAGE_IO_STATE_DONE:
530 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
531 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
534 soup_message_io_finished (msg);
539 g_return_if_reached ();
546 io_read (SoupSocket *sock, SoupMessage *msg)
548 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
549 SoupMessageIOData *io = priv->io_data;
553 switch (io->read_state) {
554 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
558 case SOUP_MESSAGE_IO_STATE_HEADERS:
559 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
562 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
563 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
564 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
565 io->read_meta_buf->len,
569 g_byte_array_set_size (io->read_meta_buf, 0);
571 if (status != SOUP_STATUS_OK) {
572 /* Either we couldn't parse the headers, or they
573 * indicated something that would mean we wouldn't
574 * be able to parse the body. (Eg, unknown
575 * Transfer-Encoding.). Skip the rest of the
576 * reading, and make sure the connection gets
577 * closed when we're done.
579 soup_message_set_status (msg, status);
580 soup_message_add_header (msg->request_headers,
581 "Connection", "close");
582 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
586 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
587 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
588 if (msg->status_code == SOUP_STATUS_CONTINUE &&
589 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
590 /* Pause the reader, unpause the writer */
592 SOUP_MESSAGE_IO_STATE_BLOCKING;
594 io_body_state (io->write_encoding);
596 /* Just stay in HEADERS */
597 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
599 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
600 (priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
601 /* The client requested a Continue response. */
602 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
604 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
605 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
607 io->read_state = io_body_state (io->read_encoding);
609 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
610 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code) &&
611 !(priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
612 soup_message_got_informational (msg);
613 soup_message_cleanup_response (msg);
615 soup_message_got_headers (msg);
616 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
620 case SOUP_MESSAGE_IO_STATE_BLOCKING:
621 io_write (sock, msg);
623 /* As in the io_write case, we *must* return here. */
627 case SOUP_MESSAGE_IO_STATE_BODY:
628 if (!read_body_chunk (msg))
633 io->read_body->owner = SOUP_BUFFER_SYSTEM_OWNED;
634 io->read_body->body = (char *)io->read_buf->data;
635 io->read_body->length = io->read_buf->len;
637 g_byte_array_free (io->read_buf, FALSE);
641 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
643 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
644 soup_message_got_body (msg);
645 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
649 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
650 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
653 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
654 g_byte_array_set_size (io->read_meta_buf, 0);
656 if (io->read_length > 0)
657 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
659 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
663 case SOUP_MESSAGE_IO_STATE_CHUNK:
664 if (!read_body_chunk (msg))
667 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
671 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
672 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
675 g_byte_array_set_size (io->read_meta_buf, 0);
676 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
680 case SOUP_MESSAGE_IO_STATE_TRAILERS:
681 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
684 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
687 /* FIXME: process trailers */
688 g_byte_array_set_size (io->read_meta_buf, 0);
692 case SOUP_MESSAGE_IO_STATE_DONE:
693 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
694 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
695 io_write (sock, msg);
697 soup_message_io_finished (msg);
702 g_return_if_reached ();
708 static SoupMessageIOData *
709 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
710 SoupMessageGetHeadersFn get_headers_cb,
711 SoupMessageParseHeadersFn parse_headers_cb,
714 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
715 SoupMessageIOData *io;
717 io = g_new0 (SoupMessageIOData, 1);
718 io->sock = g_object_ref (sock);
720 io->get_headers_cb = get_headers_cb;
721 io->parse_headers_cb = parse_headers_cb;
722 io->user_data = user_data;
724 io->read_encoding = SOUP_TRANSFER_UNKNOWN;
725 io->write_encoding = SOUP_TRANSFER_UNKNOWN;
727 io->read_meta_buf = g_byte_array_new ();
728 if (!(priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
729 io->read_buf = g_byte_array_new ();
730 io->write_buf = g_string_new (NULL);
732 io->read_tag = g_signal_connect (io->sock, "readable",
733 G_CALLBACK (io_read), msg);
734 io->write_tag = g_signal_connect (io->sock, "writable",
735 G_CALLBACK (io_write), msg);
736 io->err_tag = g_signal_connect (io->sock, "disconnected",
737 G_CALLBACK (io_error), msg);
739 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
740 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
749 * soup_message_io_client:
750 * @msg: a #SoupMessage
751 * @sock: socket to send @msg across
752 * @conn: the connection that owns @sock (or %NULL)
753 * @get_headers_cb: callback function to generate request headers
754 * @parse_headers_cb: callback function to parse response headers
755 * @user_data: data to pass to the callbacks
757 * Begins the process of sending @msg across @sock.
759 * Don't call this. Use soup_message_send_request().
762 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
763 SoupConnection *conn,
764 SoupMessageGetHeadersFn get_headers_cb,
765 SoupMessageParseHeadersFn parse_headers_cb,
768 SoupMessageIOData *io;
770 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
771 get_headers_cb, parse_headers_cb, user_data);
774 io->conn = g_object_ref (conn);
776 io->read_body = &msg->response;
777 io->write_body = &msg->request;
779 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
780 io_write (sock, msg);
784 * soup_message_io_server:
785 * @msg: an empty #SoupServerMessage
786 * @sock: socket to receive a request on
787 * @get_headers_cb: callback function to generate response headers
788 * @parse_headers_cb: callback function to parse request headers
789 * @user_data: data to pass to the callbacks
791 * Begins the process of receiving a request from @sock into @msg.
793 * Don't use this. Use soup_message_receive_request() instead.
796 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
797 SoupMessageGetHeadersFn get_headers_cb,
798 SoupMessageParseHeadersFn parse_headers_cb,
801 SoupMessageIOData *io;
803 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
804 get_headers_cb, parse_headers_cb, user_data);
806 io->read_body = &msg->request;
807 io->write_body = &msg->response;
809 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
814 * soup_message_io_pause:
815 * @msg: a #SoupMessage
817 * Pauses I/O on @msg.
820 soup_message_io_pause (SoupMessage *msg)
822 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
823 SoupMessageIOData *io = priv->io_data;
825 g_return_if_fail (io != NULL);
828 g_signal_handler_disconnect (io->sock, io->write_tag);
832 g_signal_handler_disconnect (io->sock, io->read_tag);
838 * soup_message_io_unpause:
839 * @msg: a #SoupMessage
841 * Resumes I/O on @msg.
844 soup_message_io_unpause (SoupMessage *msg)
846 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
847 SoupMessageIOData *io = priv->io_data;
849 g_return_if_fail (io != NULL);
851 if (io->write_tag || io->read_tag)
854 io->write_tag = g_signal_connect (io->sock, "writable",
855 G_CALLBACK (io_write), msg);
856 io->read_tag = g_signal_connect (io->sock, "readable",
857 G_CALLBACK (io_read), msg);
859 if (io->write_state != SOUP_MESSAGE_IO_STATE_NOT_STARTED &&
860 io->write_state != SOUP_MESSAGE_IO_STATE_BLOCKING)
861 io_write (io->sock, msg);
863 io_read (io->sock, msg);