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-coding.h"
16 #include "soup-connection.h"
17 #include "soup-message.h"
18 #include "soup-message-private.h"
19 #include "soup-misc.h"
20 #include "soup-socket.h"
24 SOUP_MESSAGE_IO_CLIENT,
25 SOUP_MESSAGE_IO_SERVER
29 SOUP_MESSAGE_IO_STATE_NOT_STARTED,
30 SOUP_MESSAGE_IO_STATE_HEADERS,
31 SOUP_MESSAGE_IO_STATE_BLOCKING,
32 SOUP_MESSAGE_IO_STATE_BODY,
33 SOUP_MESSAGE_IO_STATE_CHUNK_SIZE,
34 SOUP_MESSAGE_IO_STATE_CHUNK,
35 SOUP_MESSAGE_IO_STATE_CHUNK_END,
36 SOUP_MESSAGE_IO_STATE_TRAILERS,
37 SOUP_MESSAGE_IO_STATE_FINISHING,
38 SOUP_MESSAGE_IO_STATE_DONE
41 #define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \
42 (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \
43 state != SOUP_MESSAGE_IO_STATE_BLOCKING && \
44 state != SOUP_MESSAGE_IO_STATE_DONE)
49 SoupMessageIOMode mode;
51 SoupMessageIOState read_state;
52 SoupEncoding read_encoding;
53 GByteArray *read_meta_buf;
54 SoupMessageBody *read_body;
57 gboolean need_content_sniffed, need_got_chunk;
58 SoupMessageBody *sniff_data;
60 SoupMessageIOState write_state;
61 SoupEncoding write_encoding;
63 SoupMessageBody *write_body;
64 SoupBuffer *write_chunk;
65 gsize write_body_offset;
69 guint read_tag, write_tag, err_tag;
70 GSource *unpause_source;
72 SoupMessageGetHeadersFn get_headers_cb;
73 SoupMessageParseHeadersFn parse_headers_cb;
78 /* Put these around callback invocation if there is code afterward
79 * that depends on the IO having not been cancelled.
81 #define dummy_to_make_emacs_happy {
82 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
83 #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; }
84 #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; }
86 #define RESPONSE_BLOCK_SIZE 8192
89 soup_message_io_cleanup (SoupMessage *msg)
91 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
92 SoupMessageIOData *io;
94 soup_message_io_stop (msg);
102 g_object_unref (io->sock);
104 g_object_unref (io->conn);
106 g_byte_array_free (io->read_meta_buf, TRUE);
108 g_string_free (io->write_buf, TRUE);
110 soup_buffer_free (io->write_chunk);
113 soup_message_body_free (io->sniff_data);
115 g_slice_free (SoupMessageIOData, io);
119 * soup_message_io_stop:
120 * @msg: a #SoupMessage
122 * Immediately stops I/O on msg; if the connection would be left in an
123 * inconsistent state, it will be closed.
125 * Note: this is a low-level function that does not cause any signals
126 * to be emitted on @msg; it is up to the caller to make sure that
127 * @msg doesn't get "stranded".
130 soup_message_io_stop (SoupMessage *msg)
132 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
133 SoupMessageIOData *io = priv->io_data;
139 g_signal_handler_disconnect (io->sock, io->read_tag);
143 g_signal_handler_disconnect (io->sock, io->write_tag);
147 g_signal_handler_disconnect (io->sock, io->err_tag);
151 if (io->unpause_source) {
152 g_source_destroy (io->unpause_source);
153 io->unpause_source = NULL;
156 if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
157 soup_socket_disconnect (io->sock);
159 SoupConnection *conn = io->conn;
161 soup_connection_set_state (conn, SOUP_CONNECTION_IDLE);
162 g_object_unref (conn);
166 #define SOUP_MESSAGE_IO_EOL "\r\n"
167 #define SOUP_MESSAGE_IO_EOL_LEN 2
170 soup_message_io_finished (SoupMessage *msg)
173 soup_message_io_cleanup (msg);
174 if (SOUP_MESSAGE_IS_STARTING (msg))
175 soup_message_restarted (msg);
177 soup_message_finished (msg);
178 g_object_unref (msg);
181 static void io_read (SoupSocket *sock, SoupMessage *msg);
184 request_is_idempotent (SoupMessage *msg)
187 return (msg->method == SOUP_METHOD_GET);
191 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
193 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
194 SoupMessageIOData *io = priv->io_data;
196 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
197 io->read_state <= SOUP_MESSAGE_IO_STATE_HEADERS &&
198 io->read_meta_buf->len == 0 &&
199 !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) &&
200 request_is_idempotent (msg)) {
201 /* Connection got closed, but we can safely try again */
202 priv->io_status = SOUP_MESSAGE_IO_STATUS_QUEUED;
203 } else if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
204 if (error && error->domain == SOUP_SSL_ERROR) {
205 soup_message_set_status_full (msg,
206 SOUP_STATUS_SSL_FAILED,
209 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
212 g_error_free (error);
214 soup_message_io_finished (msg);
218 io_disconnected (SoupSocket *sock, SoupMessage *msg)
220 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
221 SoupMessageIOData *io = priv->io_data;
223 /* Closing the connection to signify EOF is sometimes ok */
224 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
225 io->read_encoding == SOUP_ENCODING_EOF) {
226 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
231 io_error (sock, msg, NULL);
235 io_handle_sniffing (SoupMessage *msg, gboolean done_reading)
237 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
238 SoupMessageIOData *io = priv->io_data;
239 SoupBuffer *sniffed_buffer;
240 char *sniffed_mime_type;
241 GHashTable *params = NULL;
246 if (!io->sniff_data) {
247 io->sniff_data = soup_message_body_new ();
248 io->need_content_sniffed = TRUE;
251 if (io->need_content_sniffed) {
252 if (io->sniff_data->length < priv->bytes_for_sniffing &&
256 io->need_content_sniffed = FALSE;
257 sniffed_buffer = soup_message_body_flatten (io->sniff_data);
258 sniffed_mime_type = soup_content_sniffer_sniff (priv->sniffer, msg, sniffed_buffer, ¶ms);
260 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
261 soup_message_content_sniffed (msg, sniffed_mime_type, params);
262 g_free (sniffed_mime_type);
264 g_hash_table_destroy (params);
266 soup_buffer_free (sniffed_buffer);
267 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
270 if (io->need_got_chunk) {
271 io->need_got_chunk = FALSE;
272 sniffed_buffer = soup_message_body_flatten (io->sniff_data);
274 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
275 soup_message_got_chunk (msg, sniffed_buffer);
276 soup_buffer_free (sniffed_buffer);
277 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
283 /* Reads data from io->sock into io->read_meta_buf. If @to_blank is
284 * %TRUE, it reads up until a blank line ("CRLF CRLF" or "LF LF").
285 * Otherwise, it reads up until a single CRLF or LF.
287 * This function is used to read metadata, and read_body_chunk() is
288 * used to read the message body contents.
290 * read_metadata, read_body_chunk, and write_data all use the same
291 * convention for return values: if they return %TRUE, it means
292 * they've completely finished the requested read/write, and the
293 * caller should move on to the next step. If they return %FALSE, it
294 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
295 * so the caller should give up for now and wait for the socket to
296 * emit a signal, or (b) the socket returned an error, and io_error()
297 * was called to process it and cancel the I/O. So either way, if the
298 * function returns %FALSE, the caller should return immediately.
301 read_metadata (SoupMessage *msg, gboolean to_blank)
303 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
304 SoupMessageIOData *io = priv->io_data;
305 SoupSocketIOStatus status;
306 guchar read_buf[RESPONSE_BLOCK_SIZE];
309 GError *error = NULL;
312 status = soup_socket_read_until (io->sock, read_buf,
314 "\n", 1, &nread, &got_lf,
318 g_byte_array_append (io->read_meta_buf, read_buf, nread);
321 case SOUP_SOCKET_ERROR:
322 case SOUP_SOCKET_EOF:
323 io_error (io->sock, msg, error);
326 case SOUP_SOCKET_WOULD_BLOCK:
334 !strncmp ((char *)io->read_meta_buf->data +
335 io->read_meta_buf->len - 2,
338 else if (nread == 2 &&
339 !strncmp ((char *)io->read_meta_buf->data +
340 io->read_meta_buf->len - 3,
350 content_decode (SoupMessage *msg, SoupBuffer *buf)
352 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
355 GError *error = NULL;
358 for (d = priv->decoders; d; d = d->next) {
361 decoded = soup_coding_apply (decoder, buf->data, buf->length,
364 if (g_error_matches (error, SOUP_CODING_ERROR, SOUP_CODING_ERROR_INTERNAL_ERROR))
365 g_warning ("Content-Decoding error: %s\n", error->message);
366 g_error_free (error);
368 soup_message_set_flags (msg, priv->msg_flags & ~SOUP_MESSAGE_CONTENT_DECODED);
372 soup_buffer_free (buf);
383 /* Reads as much message body data as is available on io->sock (but no
384 * further than the end of the current message body or chunk). On a
385 * successful read, emits "got_chunk" (possibly multiple times), and
386 * (unless told not to) appends the chunk to io->read_body.
388 * See the note at read_metadata() for an explanation of the return
392 read_body_chunk (SoupMessage *msg)
394 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
395 SoupMessageIOData *io = priv->io_data;
396 SoupSocketIOStatus status;
397 guchar *stack_buf = NULL;
399 gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
401 GError *error = NULL;
404 if (!io_handle_sniffing (msg, FALSE))
407 while (read_to_eof || io->read_length > 0) {
408 if (priv->chunk_allocator) {
409 buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
411 soup_message_io_pause (msg);
416 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
417 buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
419 RESPONSE_BLOCK_SIZE);
423 len = buffer->length;
425 len = MIN (buffer->length, io->read_length);
427 status = soup_socket_read (io->sock,
428 (guchar *)buffer->data, len,
429 &nread, NULL, &error);
431 if (status == SOUP_SOCKET_OK && nread) {
432 buffer->length = nread;
433 io->read_length -= nread;
435 buffer = content_decode (msg, buffer);
439 soup_message_body_got_chunk (io->read_body, buffer);
441 if (io->need_content_sniffed) {
442 soup_message_body_append_buffer (io->sniff_data, buffer);
443 soup_buffer_free (buffer);
444 io->need_got_chunk = TRUE;
445 if (!io_handle_sniffing (msg, FALSE))
450 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
451 soup_message_got_chunk (msg, buffer);
452 soup_buffer_free (buffer);
453 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
457 soup_buffer_free (buffer);
462 case SOUP_SOCKET_EOF:
465 /* else fall through */
467 case SOUP_SOCKET_ERROR:
468 io_error (io->sock, msg, error);
471 case SOUP_SOCKET_WOULD_BLOCK:
479 /* Attempts to write @len bytes from @data. See the note at
480 * read_metadata() for an explanation of the return value.
483 write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
485 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
486 SoupMessageIOData *io = priv->io_data;
487 SoupSocketIOStatus status;
489 GError *error = NULL;
493 while (len > io->written) {
494 status = soup_socket_write (io->sock,
497 &nwrote, NULL, &error);
499 case SOUP_SOCKET_EOF:
500 case SOUP_SOCKET_ERROR:
501 io_error (io->sock, msg, error);
504 case SOUP_SOCKET_WOULD_BLOCK:
508 start = data + io->written;
509 io->written += nwrote;
512 if (io->write_length)
513 io->write_length -= nwrote;
515 chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
517 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
518 soup_message_wrote_body_data (msg, chunk);
519 soup_buffer_free (chunk);
520 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
530 static inline SoupMessageIOState
531 io_body_state (SoupEncoding encoding)
533 if (encoding == SOUP_ENCODING_CHUNKED)
534 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
536 return SOUP_MESSAGE_IO_STATE_BODY;
540 * There are two request/response formats: the basic request/response,
541 * possibly with one or more unsolicited informational responses (such
542 * as the WebDAV "102 Processing" response):
545 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
546 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
547 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
548 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
549 * W:DONE / R:BODY <- R:DONE / W:BODY
550 * W:DONE / R:DONE R:DONE / W:DONE
552 * and the "Expect: 100-continue" request/response, with the client
553 * blocking halfway through its request, and then either continuing or
554 * aborting, depending on the server response:
557 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
558 * W:BLOCKING / R:HEADERS <- R:BLOCKING / W:HEADERS
559 * [W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING]
560 * [W:DONE / R:HEADERS <- R:DONE / W:HEADERS]
561 * W:DONE / R:BODY <- R:DONE / W:BODY
562 * W:DONE / R:DONE R:DONE / W:DONE
566 io_write (SoupSocket *sock, SoupMessage *msg)
568 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
569 SoupMessageIOData *io = priv->io_data;
572 switch (io->write_state) {
573 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
577 case SOUP_MESSAGE_IO_STATE_HEADERS:
578 if (!io->write_buf->len) {
579 io->get_headers_cb (msg, io->write_buf,
582 if (!io->write_buf->len) {
583 soup_message_io_pause (msg);
588 if (!write_data (msg, io->write_buf->str,
589 io->write_buf->len, FALSE))
592 g_string_truncate (io->write_buf, 0);
594 if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
595 SoupMessageHeaders *hdrs =
596 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
597 msg->request_headers : msg->response_headers;
598 io->write_length = soup_message_headers_get_content_length (hdrs);
601 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
602 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
603 if (msg->status_code == SOUP_STATUS_CONTINUE) {
604 /* Stop and wait for the body now */
606 SOUP_MESSAGE_IO_STATE_BLOCKING;
607 io->read_state = io_body_state (io->read_encoding);
609 /* We just wrote a 1xx response
610 * header, so stay in STATE_HEADERS.
611 * (The caller will pause us from the
612 * wrote_informational callback if he
613 * is not ready to send the final
617 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
618 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
619 /* Need to wait for the Continue response */
620 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
621 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
623 io->write_state = io_body_state (io->write_encoding);
625 /* If the client was waiting for a Continue
626 * but we sent something else, then they're
629 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
630 io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
631 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
634 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
635 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
636 soup_message_wrote_informational (msg);
637 soup_message_cleanup_response (msg);
639 soup_message_wrote_headers (msg);
640 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
644 case SOUP_MESSAGE_IO_STATE_BLOCKING:
647 /* If io_read reached a point where we could write
648 * again, it would have recursively called io_write.
649 * So (a) we don't need to try to keep writing, and
650 * (b) we can't anyway, because msg may have been
656 case SOUP_MESSAGE_IO_STATE_BODY:
657 if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) {
659 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
661 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
662 soup_message_wrote_body (msg);
663 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
667 if (!io->write_chunk) {
668 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
669 if (!io->write_chunk) {
670 soup_message_io_pause (msg);
673 if (io->write_chunk->length > io->write_length &&
674 io->write_encoding != SOUP_ENCODING_EOF) {
675 /* App is trying to write more than it
676 * claimed it would; we have to truncate.
678 SoupBuffer *truncated =
679 soup_buffer_new_subbuffer (io->write_chunk,
680 0, io->write_length);
681 soup_buffer_free (io->write_chunk);
682 io->write_chunk = truncated;
683 } else if (io->write_encoding == SOUP_ENCODING_EOF &&
684 !io->write_chunk->length)
688 if (!write_data (msg, io->write_chunk->data,
689 io->write_chunk->length, TRUE))
692 if (io->mode == SOUP_MESSAGE_IO_SERVER)
693 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
694 io->write_body_offset += io->write_chunk->length;
695 soup_buffer_free (io->write_chunk);
696 io->write_chunk = NULL;
698 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
699 soup_message_wrote_chunk (msg);
700 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
703 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
704 if (!io->write_chunk) {
705 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
706 if (!io->write_chunk) {
707 soup_message_io_pause (msg);
710 g_string_append_printf (io->write_buf, "%lx\r\n",
711 (unsigned long) io->write_chunk->length);
712 io->write_body_offset += io->write_chunk->length;
715 if (!write_data (msg, io->write_buf->str,
716 io->write_buf->len, FALSE))
719 g_string_truncate (io->write_buf, 0);
721 if (io->write_chunk->length == 0) {
722 /* The last chunk has no CHUNK_END... */
723 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
727 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
731 case SOUP_MESSAGE_IO_STATE_CHUNK:
732 if (!write_data (msg, io->write_chunk->data,
733 io->write_chunk->length, TRUE))
736 if (io->mode == SOUP_MESSAGE_IO_SERVER)
737 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
738 soup_buffer_free (io->write_chunk);
739 io->write_chunk = NULL;
741 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
743 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
744 soup_message_wrote_chunk (msg);
745 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
750 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
751 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
752 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
755 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
759 case SOUP_MESSAGE_IO_STATE_TRAILERS:
760 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
761 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
764 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
766 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
767 soup_message_wrote_body (msg);
768 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
772 case SOUP_MESSAGE_IO_STATE_FINISHING:
774 g_signal_handler_disconnect (io->sock, io->write_tag);
777 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
779 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
780 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
783 soup_message_io_finished (msg);
787 case SOUP_MESSAGE_IO_STATE_DONE:
789 g_return_if_reached ();
796 io_read (SoupSocket *sock, SoupMessage *msg)
798 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
799 SoupMessageIOData *io = priv->io_data;
803 switch (io->read_state) {
804 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
808 case SOUP_MESSAGE_IO_STATE_HEADERS:
809 if (!read_metadata (msg, TRUE))
812 /* We need to "rewind" io->read_meta_buf back one line.
813 * That SHOULD be two characters (CR LF), but if the
814 * web server was stupid, it might only be one.
816 if (io->read_meta_buf->len < 3 ||
817 io->read_meta_buf->data[io->read_meta_buf->len - 2] == '\n')
818 io->read_meta_buf->len--;
820 io->read_meta_buf->len -= 2;
821 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
822 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
823 io->read_meta_buf->len,
826 g_byte_array_set_size (io->read_meta_buf, 0);
828 if (status != SOUP_STATUS_OK) {
829 /* Either we couldn't parse the headers, or they
830 * indicated something that would mean we wouldn't
831 * be able to parse the body. (Eg, unknown
832 * Transfer-Encoding.). Skip the rest of the
833 * reading, and make sure the connection gets
834 * closed when we're done.
836 soup_message_set_status (msg, status);
837 soup_message_headers_append (msg->request_headers,
838 "Connection", "close");
839 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
843 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
844 SoupMessageHeaders *hdrs =
845 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
846 msg->response_headers : msg->request_headers;
847 io->read_length = soup_message_headers_get_content_length (hdrs);
850 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
851 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
852 if (msg->status_code == SOUP_STATUS_CONTINUE &&
853 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
854 /* Pause the reader, unpause the writer */
856 SOUP_MESSAGE_IO_STATE_BLOCKING;
858 io_body_state (io->write_encoding);
860 /* Just stay in HEADERS */
861 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
863 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
864 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
865 /* The client requested a Continue response. The
866 * got_headers handler may change this to something
869 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
870 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
871 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
873 io->read_state = io_body_state (io->read_encoding);
875 /* If the client was waiting for a Continue
876 * but got something else, then it's done
879 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
880 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
881 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
884 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
885 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
886 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
887 soup_message_got_informational (msg);
888 soup_message_cleanup_response (msg);
889 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
891 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
892 soup_message_got_headers (msg);
893 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
898 case SOUP_MESSAGE_IO_STATE_BLOCKING:
899 io_write (sock, msg);
901 /* As in the io_write case, we *must* return here. */
905 case SOUP_MESSAGE_IO_STATE_BODY:
906 if (!read_body_chunk (msg))
910 if (!io_handle_sniffing (msg, TRUE)) {
911 /* If the message was paused (as opposed to
912 * cancelled), we need to make sure we wind up
913 * back here when it's unpaused, even if it
914 * was doing a chunked or EOF-terminated read
917 if (io == priv->io_data) {
918 io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
919 io->read_encoding = SOUP_ENCODING_CONTENT_LENGTH;
925 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
927 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
928 soup_message_got_body (msg);
929 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
933 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
934 if (!read_metadata (msg, FALSE))
937 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
938 g_byte_array_set_size (io->read_meta_buf, 0);
940 if (io->read_length > 0)
941 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
943 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
947 case SOUP_MESSAGE_IO_STATE_CHUNK:
948 if (!read_body_chunk (msg))
951 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
955 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
956 if (!read_metadata (msg, FALSE))
959 g_byte_array_set_size (io->read_meta_buf, 0);
960 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
964 case SOUP_MESSAGE_IO_STATE_TRAILERS:
965 if (!read_metadata (msg, FALSE))
968 if (io->read_meta_buf->len <= SOUP_MESSAGE_IO_EOL_LEN)
971 /* FIXME: process trailers */
972 g_byte_array_set_size (io->read_meta_buf, 0);
976 case SOUP_MESSAGE_IO_STATE_FINISHING:
978 g_signal_handler_disconnect (io->sock, io->read_tag);
981 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
983 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
984 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
985 io_write (sock, msg);
987 soup_message_io_finished (msg);
991 case SOUP_MESSAGE_IO_STATE_DONE:
993 g_return_if_reached ();
999 static SoupMessageIOData *
1000 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
1001 SoupMessageGetHeadersFn get_headers_cb,
1002 SoupMessageParseHeadersFn parse_headers_cb,
1005 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1006 SoupMessageIOData *io;
1008 io = g_slice_new0 (SoupMessageIOData);
1009 io->sock = g_object_ref (sock);
1011 io->get_headers_cb = get_headers_cb;
1012 io->parse_headers_cb = parse_headers_cb;
1013 io->user_data = user_data;
1015 io->read_meta_buf = g_byte_array_new ();
1016 io->write_buf = g_string_new (NULL);
1018 io->read_tag = g_signal_connect (io->sock, "readable",
1019 G_CALLBACK (io_read), msg);
1020 io->write_tag = g_signal_connect (io->sock, "writable",
1021 G_CALLBACK (io_write), msg);
1022 io->err_tag = g_signal_connect (io->sock, "disconnected",
1023 G_CALLBACK (io_disconnected), msg);
1025 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
1026 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
1029 soup_message_io_cleanup (msg);
1035 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
1036 SoupConnection *conn,
1037 SoupMessageGetHeadersFn get_headers_cb,
1038 SoupMessageParseHeadersFn parse_headers_cb,
1041 SoupMessageIOData *io;
1043 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
1044 get_headers_cb, parse_headers_cb, user_data);
1047 io->conn = g_object_ref (conn);
1049 io->read_body = msg->response_body;
1050 io->write_body = msg->request_body;
1052 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
1053 io_write (sock, msg);
1057 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
1058 SoupMessageGetHeadersFn get_headers_cb,
1059 SoupMessageParseHeadersFn parse_headers_cb,
1062 SoupMessageIOData *io;
1064 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
1065 get_headers_cb, parse_headers_cb, user_data);
1067 io->read_body = msg->request_body;
1068 io->write_body = msg->response_body;
1070 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
1071 io_read (sock, msg);
1075 soup_message_io_pause (SoupMessage *msg)
1077 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1078 SoupMessageIOData *io = priv->io_data;
1080 g_return_if_fail (io != NULL);
1082 if (io->write_tag) {
1083 g_signal_handler_disconnect (io->sock, io->write_tag);
1087 g_signal_handler_disconnect (io->sock, io->read_tag);
1091 if (io->unpause_source) {
1092 g_source_destroy (io->unpause_source);
1093 io->unpause_source = NULL;
1098 io_unpause_internal (gpointer msg)
1100 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1101 SoupMessageIOData *io = priv->io_data;
1103 g_return_val_if_fail (io != NULL, FALSE);
1104 io->unpause_source = NULL;
1106 if (io->write_tag || io->read_tag)
1109 if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
1110 io->write_tag = g_signal_connect (io->sock, "writable",
1111 G_CALLBACK (io_write), msg);
1114 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
1115 io->read_tag = g_signal_connect (io->sock, "readable",
1116 G_CALLBACK (io_read), msg);
1119 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
1120 io_write (io->sock, msg);
1121 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
1122 io_read (io->sock, msg);
1128 soup_message_io_unpause (SoupMessage *msg)
1130 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1131 SoupMessageIOData *io = priv->io_data;
1132 gboolean non_blocking;
1133 GMainContext *async_context;
1135 g_return_if_fail (io != NULL);
1137 g_object_get (io->sock,
1138 SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
1139 SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
1142 if (!io->unpause_source) {
1143 io->unpause_source = soup_add_completion (
1144 async_context, io_unpause_internal, msg);
1147 io_unpause_internal (msg);
1149 g_main_context_unref (async_context);
1153 * soup_message_io_in_progress:
1154 * @msg: a #SoupMessage
1156 * Tests whether or not I/O is currently in progress on @msg.
1158 * Return value: whether or not I/O is currently in progress.
1161 soup_message_io_in_progress (SoupMessage *msg)
1163 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1165 return priv->io_data != NULL;