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-message-queue.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)
48 SoupMessageQueueItem *item;
49 SoupMessageIOMode mode;
51 SoupMessageIOState read_state;
52 SoupEncoding read_encoding;
53 GByteArray *read_meta_buf;
54 SoupMessageBody *read_body;
58 gboolean need_content_sniffed, need_got_chunk;
59 SoupMessageBody *sniff_data;
61 SoupMessageIOState write_state;
62 SoupEncoding write_encoding;
64 SoupMessageBody *write_body;
65 SoupBuffer *write_chunk;
66 gsize write_body_offset;
70 guint read_tag, write_tag, tls_signal_id;
71 GSource *unpause_source;
73 SoupMessageGetHeadersFn get_headers_cb;
74 SoupMessageParseHeadersFn parse_headers_cb;
76 SoupMessageCompletionFn completion_cb;
77 gpointer completion_data;
81 /* Put these around callback invocation if there is code afterward
82 * that depends on the IO having not been cancelled.
84 #define dummy_to_make_emacs_happy {
85 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
86 #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; }
87 #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; }
89 #define RESPONSE_BLOCK_SIZE 8192
92 soup_message_io_cleanup (SoupMessage *msg)
94 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
95 SoupMessageIOData *io;
97 soup_message_io_stop (msg);
102 priv->io_data = NULL;
104 if (io->tls_signal_id)
105 g_signal_handler_disconnect (io->sock, io->tls_signal_id);
107 g_object_unref (io->sock);
109 soup_message_queue_item_unref (io->item);
111 g_byte_array_free (io->read_meta_buf, TRUE);
113 g_string_free (io->write_buf, TRUE);
115 soup_buffer_free (io->write_chunk);
118 soup_message_body_free (io->sniff_data);
120 g_slice_free (SoupMessageIOData, io);
124 soup_message_io_stop (SoupMessage *msg)
126 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
127 SoupMessageIOData *io = priv->io_data;
133 g_signal_handler_disconnect (io->sock, io->read_tag);
137 g_signal_handler_disconnect (io->sock, io->write_tag);
141 if (io->unpause_source) {
142 g_source_destroy (io->unpause_source);
143 io->unpause_source = NULL;
146 if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
147 soup_socket_disconnect (io->sock);
148 else if (io->item && io->item->conn)
149 soup_connection_set_state (io->item->conn, SOUP_CONNECTION_IDLE);
152 #define SOUP_MESSAGE_IO_EOL "\r\n"
153 #define SOUP_MESSAGE_IO_EOL_LEN 2
156 soup_message_io_finished (SoupMessage *msg)
158 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
159 SoupMessageIOData *io = priv->io_data;
160 SoupMessageCompletionFn completion_cb = io->completion_cb;
161 gpointer completion_data = io->completion_data;
164 soup_message_io_cleanup (msg);
166 completion_cb (msg, completion_data);
167 g_object_unref (msg);
170 static void io_read (SoupSocket *sock, SoupMessage *msg);
173 request_is_idempotent (SoupMessage *msg)
176 return (msg->method == SOUP_METHOD_GET);
180 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
182 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
183 SoupMessageIOData *io = priv->io_data;
185 if (error && error->domain == G_TLS_ERROR) {
186 soup_message_set_status_full (msg,
187 SOUP_STATUS_SSL_FAILED,
189 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
190 io->read_state <= SOUP_MESSAGE_IO_STATE_HEADERS &&
191 io->read_meta_buf->len == 0 &&
192 soup_connection_get_ever_used (io->item->conn) &&
193 !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) &&
194 request_is_idempotent (msg)) {
195 /* Connection got closed, but we can safely try again */
196 io->item->state = SOUP_MESSAGE_RESTARTING;
197 } else if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
198 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
201 g_error_free (error);
203 soup_message_io_finished (msg);
207 io_handle_sniffing (SoupMessage *msg, gboolean done_reading)
209 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
210 SoupMessageIOData *io = priv->io_data;
211 SoupBuffer *sniffed_buffer;
212 char *sniffed_mime_type;
213 GHashTable *params = NULL;
218 if (!io->sniff_data) {
219 io->sniff_data = soup_message_body_new ();
220 io->need_content_sniffed = TRUE;
223 if (io->need_content_sniffed) {
224 if (io->sniff_data->length < priv->bytes_for_sniffing &&
228 io->need_content_sniffed = FALSE;
229 sniffed_buffer = soup_message_body_flatten (io->sniff_data);
230 sniffed_mime_type = soup_content_sniffer_sniff (priv->sniffer, msg, sniffed_buffer, ¶ms);
232 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
233 soup_message_content_sniffed (msg, sniffed_mime_type, params);
234 g_free (sniffed_mime_type);
236 g_hash_table_destroy (params);
238 soup_buffer_free (sniffed_buffer);
239 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
242 if (io->need_got_chunk) {
243 io->need_got_chunk = FALSE;
244 sniffed_buffer = soup_message_body_flatten (io->sniff_data);
246 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
247 soup_message_got_chunk (msg, sniffed_buffer);
248 soup_buffer_free (sniffed_buffer);
249 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
255 /* Reads data from io->sock into io->read_meta_buf. If @to_blank is
256 * %TRUE, it reads up until a blank line ("CRLF CRLF" or "LF LF").
257 * Otherwise, it reads up until a single CRLF or LF.
259 * This function is used to read metadata, and read_body_chunk() is
260 * used to read the message body contents.
262 * read_metadata, read_body_chunk, and write_data all use the same
263 * convention for return values: if they return %TRUE, it means
264 * they've completely finished the requested read/write, and the
265 * caller should move on to the next step. If they return %FALSE, it
266 * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
267 * so the caller should give up for now and wait for the socket to
268 * emit a signal, or (b) the socket returned an error, and io_error()
269 * was called to process it and cancel the I/O. So either way, if the
270 * function returns %FALSE, the caller should return immediately.
273 read_metadata (SoupMessage *msg, gboolean to_blank)
275 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
276 SoupMessageIOData *io = priv->io_data;
277 SoupSocketIOStatus status;
278 guchar read_buf[RESPONSE_BLOCK_SIZE];
281 GError *error = NULL;
284 status = soup_socket_read_until (io->sock, read_buf,
286 "\n", 1, &nread, &got_lf,
290 g_byte_array_append (io->read_meta_buf, read_buf, nread);
293 case SOUP_SOCKET_EOF:
294 /* More lame server handling... deal with
295 * servers that don't send the final chunk.
297 if (io->read_state == SOUP_MESSAGE_IO_STATE_CHUNK_SIZE &&
298 io->read_meta_buf->len == 0) {
299 g_byte_array_append (io->read_meta_buf,
300 (guchar *)"0\r\n", 3);
303 } else if (io->read_state == SOUP_MESSAGE_IO_STATE_TRAILERS &&
304 io->read_meta_buf->len == 0) {
305 g_byte_array_append (io->read_meta_buf,
306 (guchar *)"\r\n", 2);
310 /* else fall through */
312 case SOUP_SOCKET_ERROR:
313 io_error (io->sock, msg, error);
316 case SOUP_SOCKET_WOULD_BLOCK:
324 !strncmp ((char *)io->read_meta_buf->data +
325 io->read_meta_buf->len - 2,
328 else if (nread == 2 &&
329 !strncmp ((char *)io->read_meta_buf->data +
330 io->read_meta_buf->len - 3,
340 content_decode_one (SoupBuffer *buf, GConverter *converter, GError **error)
342 gsize outbuf_length, outbuf_used, outbuf_cur, input_used, input_cur;
344 GConverterResult result;
346 outbuf_length = MAX (buf->length * 2, 1024);
347 outbuf = g_malloc (outbuf_length);
348 outbuf_cur = input_cur = 0;
351 result = g_converter_convert (
353 buf->data + input_cur, buf->length - input_cur,
354 outbuf + outbuf_cur, outbuf_length - outbuf_cur,
355 0, &input_used, &outbuf_used, error);
356 input_cur += input_used;
357 outbuf_cur += outbuf_used;
359 if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NO_SPACE) ||
360 (!*error && outbuf_cur == outbuf_length)) {
361 g_clear_error (error);
363 outbuf = g_realloc (outbuf, outbuf_length);
365 /* GZlibDecompressor can't ever return
366 * G_IO_ERROR_PARTIAL_INPUT unless we pass it
367 * input_length = 0, which we don't. Other
368 * converters might of course, so eventually
369 * this code needs to be rewritten to deal
375 } while (input_cur < buf->length && result != G_CONVERTER_FINISHED);
378 return soup_buffer_new (SOUP_MEMORY_TAKE, outbuf, outbuf_cur);
386 content_decode (SoupMessage *msg, SoupBuffer *buf)
388 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
391 GError *error = NULL;
394 for (d = priv->decoders; d; d = d->next) {
397 decoded = content_decode_one (buf, decoder, &error);
399 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED))
400 g_warning ("Content-Decoding error: %s\n", error->message);
401 g_error_free (error);
403 soup_message_set_flags (msg, priv->msg_flags & ~SOUP_MESSAGE_CONTENT_DECODED);
407 soup_buffer_free (buf);
418 /* Reads as much message body data as is available on io->sock (but no
419 * further than the end of the current message body or chunk). On a
420 * successful read, emits "got_chunk" (possibly multiple times), and
421 * (unless told not to) appends the chunk to io->read_body.
423 * See the note at read_metadata() for an explanation of the return
427 read_body_chunk (SoupMessage *msg)
429 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
430 SoupMessageIOData *io = priv->io_data;
431 SoupSocketIOStatus status;
432 guchar *stack_buf = NULL;
434 gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
436 GError *error = NULL;
439 if (!io_handle_sniffing (msg, FALSE))
442 while (read_to_eof || io->read_length > 0) {
443 if (priv->chunk_allocator) {
444 buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
446 soup_message_io_pause (msg);
451 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
452 buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
454 RESPONSE_BLOCK_SIZE);
458 len = buffer->length;
460 len = MIN (buffer->length, io->read_length);
462 status = soup_socket_read (io->sock,
463 (guchar *)buffer->data, len,
464 &nread, NULL, &error);
466 if (status == SOUP_SOCKET_OK && nread) {
467 buffer->length = nread;
468 io->read_length -= nread;
470 buffer = content_decode (msg, buffer);
474 soup_message_body_got_chunk (io->read_body, buffer);
476 if (io->need_content_sniffed) {
477 soup_message_body_append_buffer (io->sniff_data, buffer);
478 soup_buffer_free (buffer);
479 io->need_got_chunk = TRUE;
480 if (!io_handle_sniffing (msg, FALSE))
485 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
486 soup_message_got_chunk (msg, buffer);
487 soup_buffer_free (buffer);
488 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
492 soup_buffer_free (buffer);
497 case SOUP_SOCKET_EOF:
498 if (io->read_eof_ok) {
502 /* else fall through */
504 case SOUP_SOCKET_ERROR:
505 io_error (io->sock, msg, error);
508 case SOUP_SOCKET_WOULD_BLOCK:
516 /* Attempts to write @len bytes from @data. See the note at
517 * read_metadata() for an explanation of the return value.
520 write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
522 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
523 SoupMessageIOData *io = priv->io_data;
524 SoupSocketIOStatus status;
526 GError *error = NULL;
530 while (len > io->written) {
531 status = soup_socket_write (io->sock,
534 &nwrote, NULL, &error);
536 case SOUP_SOCKET_EOF:
537 case SOUP_SOCKET_ERROR:
538 io_error (io->sock, msg, error);
541 case SOUP_SOCKET_WOULD_BLOCK:
545 start = data + io->written;
546 io->written += nwrote;
549 if (io->write_length)
550 io->write_length -= nwrote;
552 chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
554 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
555 soup_message_wrote_body_data (msg, chunk);
556 soup_buffer_free (chunk);
557 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
567 static inline SoupMessageIOState
568 io_body_state (SoupEncoding encoding)
570 if (encoding == SOUP_ENCODING_CHUNKED)
571 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
573 return SOUP_MESSAGE_IO_STATE_BODY;
577 * There are two request/response formats: the basic request/response,
578 * possibly with one or more unsolicited informational responses (such
579 * as the WebDAV "102 Processing" response):
582 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
583 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
584 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
585 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
586 * W:DONE / R:BODY <- R:DONE / W:BODY
587 * W:DONE / R:DONE R:DONE / W:DONE
589 * and the "Expect: 100-continue" request/response, with the client
590 * blocking halfway through its request, and then either continuing or
591 * aborting, depending on the server response:
594 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
595 * W:BLOCKING / R:HEADERS <- R:BLOCKING / W:HEADERS
596 * [W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING]
597 * [W:DONE / R:HEADERS <- R:DONE / W:HEADERS]
598 * W:DONE / R:BODY <- R:DONE / W:BODY
599 * W:DONE / R:DONE R:DONE / W:DONE
603 io_write (SoupSocket *sock, SoupMessage *msg)
605 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
606 SoupMessageIOData *io = priv->io_data;
609 switch (io->write_state) {
610 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
614 case SOUP_MESSAGE_IO_STATE_HEADERS:
615 if (!io->write_buf->len) {
616 io->get_headers_cb (msg, io->write_buf,
619 if (!io->write_buf->len) {
620 soup_message_io_pause (msg);
625 if (!write_data (msg, io->write_buf->str,
626 io->write_buf->len, FALSE))
629 g_string_truncate (io->write_buf, 0);
631 if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
632 SoupMessageHeaders *hdrs =
633 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
634 msg->request_headers : msg->response_headers;
635 io->write_length = soup_message_headers_get_content_length (hdrs);
638 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
639 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
640 if (msg->status_code == SOUP_STATUS_CONTINUE) {
641 /* Stop and wait for the body now */
643 SOUP_MESSAGE_IO_STATE_BLOCKING;
644 io->read_state = io_body_state (io->read_encoding);
646 /* We just wrote a 1xx response
647 * header, so stay in STATE_HEADERS.
648 * (The caller will pause us from the
649 * wrote_informational callback if he
650 * is not ready to send the final
654 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
655 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
656 /* Need to wait for the Continue response */
657 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
658 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
660 io->write_state = io_body_state (io->write_encoding);
662 /* If the client was waiting for a Continue
663 * but we sent something else, then they're
666 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
667 io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
668 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
671 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
672 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
673 soup_message_wrote_informational (msg);
674 soup_message_cleanup_response (msg);
676 soup_message_wrote_headers (msg);
677 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
681 case SOUP_MESSAGE_IO_STATE_BLOCKING:
684 /* If io_read reached a point where we could write
685 * again, it would have recursively called io_write.
686 * So (a) we don't need to try to keep writing, and
687 * (b) we can't anyway, because msg may have been
693 case SOUP_MESSAGE_IO_STATE_BODY:
694 if (!io->write_length && io->write_encoding != SOUP_ENCODING_EOF) {
696 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
698 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
699 soup_message_wrote_body (msg);
700 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
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 if (io->write_chunk->length > io->write_length &&
711 io->write_encoding != SOUP_ENCODING_EOF) {
712 /* App is trying to write more than it
713 * claimed it would; we have to truncate.
715 SoupBuffer *truncated =
716 soup_buffer_new_subbuffer (io->write_chunk,
717 0, io->write_length);
718 soup_buffer_free (io->write_chunk);
719 io->write_chunk = truncated;
720 } else if (io->write_encoding == SOUP_ENCODING_EOF &&
721 !io->write_chunk->length)
725 if (!write_data (msg, io->write_chunk->data,
726 io->write_chunk->length, TRUE))
729 if (io->mode == SOUP_MESSAGE_IO_SERVER)
730 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
731 io->write_body_offset += io->write_chunk->length;
732 soup_buffer_free (io->write_chunk);
733 io->write_chunk = NULL;
735 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
736 soup_message_wrote_chunk (msg);
737 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
740 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
741 if (!io->write_chunk) {
742 io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
743 if (!io->write_chunk) {
744 soup_message_io_pause (msg);
747 g_string_append_printf (io->write_buf, "%lx\r\n",
748 (unsigned long) io->write_chunk->length);
749 io->write_body_offset += io->write_chunk->length;
752 if (!write_data (msg, io->write_buf->str,
753 io->write_buf->len, FALSE))
756 g_string_truncate (io->write_buf, 0);
758 if (io->write_chunk->length == 0) {
759 /* The last chunk has no CHUNK_END... */
760 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
764 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
768 case SOUP_MESSAGE_IO_STATE_CHUNK:
769 if (!write_data (msg, io->write_chunk->data,
770 io->write_chunk->length, TRUE))
773 if (io->mode == SOUP_MESSAGE_IO_SERVER)
774 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
775 soup_buffer_free (io->write_chunk);
776 io->write_chunk = NULL;
778 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
780 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
781 soup_message_wrote_chunk (msg);
782 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
787 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
788 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
789 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
792 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
796 case SOUP_MESSAGE_IO_STATE_TRAILERS:
797 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
798 SOUP_MESSAGE_IO_EOL_LEN, FALSE))
801 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
803 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
804 soup_message_wrote_body (msg);
805 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
809 case SOUP_MESSAGE_IO_STATE_FINISHING:
811 g_signal_handler_disconnect (io->sock, io->write_tag);
814 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
816 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
817 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
820 soup_message_io_finished (msg);
824 case SOUP_MESSAGE_IO_STATE_DONE:
826 g_return_if_reached ();
833 io_read (SoupSocket *sock, SoupMessage *msg)
835 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
836 SoupMessageIOData *io = priv->io_data;
840 switch (io->read_state) {
841 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
845 case SOUP_MESSAGE_IO_STATE_HEADERS:
846 if (!read_metadata (msg, TRUE))
849 /* We need to "rewind" io->read_meta_buf back one line.
850 * That SHOULD be two characters (CR LF), but if the
851 * web server was stupid, it might only be one.
853 if (io->read_meta_buf->len < 3 ||
854 io->read_meta_buf->data[io->read_meta_buf->len - 2] == '\n')
855 io->read_meta_buf->len--;
857 io->read_meta_buf->len -= 2;
858 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
859 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
860 io->read_meta_buf->len,
863 g_byte_array_set_size (io->read_meta_buf, 0);
865 if (status != SOUP_STATUS_OK) {
866 /* Either we couldn't parse the headers, or they
867 * indicated something that would mean we wouldn't
868 * be able to parse the body. (Eg, unknown
869 * Transfer-Encoding.). Skip the rest of the
870 * reading, and make sure the connection gets
871 * closed when we're done.
873 soup_message_set_status (msg, status);
874 soup_message_headers_append (msg->request_headers,
875 "Connection", "close");
876 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
880 if (io->read_encoding == SOUP_ENCODING_EOF)
881 io->read_eof_ok = TRUE;
883 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
884 SoupMessageHeaders *hdrs =
885 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
886 msg->response_headers : msg->request_headers;
887 io->read_length = soup_message_headers_get_content_length (hdrs);
889 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
890 !soup_message_is_keepalive (msg)) {
891 /* Some servers suck and send
892 * incorrect Content-Length values, so
893 * allow EOF termination in this case
894 * (iff the message is too short) too.
896 io->read_eof_ok = TRUE;
900 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
901 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
902 if (msg->status_code == SOUP_STATUS_CONTINUE &&
903 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
904 /* Pause the reader, unpause the writer */
906 SOUP_MESSAGE_IO_STATE_BLOCKING;
908 io_body_state (io->write_encoding);
910 /* Just stay in HEADERS */
911 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
913 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
914 soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
915 /* The client requested a Continue response. The
916 * got_headers handler may change this to something
919 soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
920 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
921 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
923 io->read_state = io_body_state (io->read_encoding);
925 /* If the client was waiting for a Continue
926 * but got something else, then it's done
929 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
930 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
931 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
934 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
935 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
936 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
937 soup_message_got_informational (msg);
938 soup_message_cleanup_response (msg);
939 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
941 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
942 soup_message_got_headers (msg);
943 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
948 case SOUP_MESSAGE_IO_STATE_BLOCKING:
949 io_write (sock, msg);
951 /* As in the io_write case, we *must* return here. */
955 case SOUP_MESSAGE_IO_STATE_BODY:
956 if (!read_body_chunk (msg))
960 if (!io_handle_sniffing (msg, TRUE)) {
961 /* If the message was paused (as opposed to
962 * cancelled), we need to make sure we wind up
963 * back here when it's unpaused, even if it
964 * was doing a chunked or EOF-terminated read
967 if (io == priv->io_data) {
968 io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
969 io->read_encoding = SOUP_ENCODING_CONTENT_LENGTH;
975 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
977 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
978 soup_message_got_body (msg);
979 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
983 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
984 if (!read_metadata (msg, FALSE))
987 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
988 g_byte_array_set_size (io->read_meta_buf, 0);
990 if (io->read_length > 0)
991 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
993 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
997 case SOUP_MESSAGE_IO_STATE_CHUNK:
998 if (!read_body_chunk (msg))
1001 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
1005 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
1006 if (!read_metadata (msg, FALSE))
1009 g_byte_array_set_size (io->read_meta_buf, 0);
1010 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
1014 case SOUP_MESSAGE_IO_STATE_TRAILERS:
1015 if (!read_metadata (msg, FALSE))
1018 if (io->read_meta_buf->len <= SOUP_MESSAGE_IO_EOL_LEN)
1021 /* FIXME: process trailers */
1022 g_byte_array_set_size (io->read_meta_buf, 0);
1026 case SOUP_MESSAGE_IO_STATE_FINISHING:
1028 g_signal_handler_disconnect (io->sock, io->read_tag);
1031 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
1033 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
1034 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
1035 io_write (sock, msg);
1037 soup_message_io_finished (msg);
1041 case SOUP_MESSAGE_IO_STATE_DONE:
1043 g_return_if_reached ();
1050 socket_tls_certificate_changed (GObject *sock, GParamSpec *pspec,
1053 GTlsCertificate *certificate;
1054 GTlsCertificateFlags errors;
1057 SOUP_SOCKET_TLS_CERTIFICATE, &certificate,
1058 SOUP_SOCKET_TLS_ERRORS, &errors,
1061 SOUP_MESSAGE_TLS_CERTIFICATE, certificate,
1062 SOUP_MESSAGE_TLS_ERRORS, errors,
1065 g_object_unref (certificate);
1068 static SoupMessageIOData *
1069 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
1070 SoupMessageGetHeadersFn get_headers_cb,
1071 SoupMessageParseHeadersFn parse_headers_cb,
1072 gpointer header_data,
1073 SoupMessageCompletionFn completion_cb,
1074 gpointer completion_data)
1076 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1077 SoupMessageIOData *io;
1079 io = g_slice_new0 (SoupMessageIOData);
1080 io->sock = g_object_ref (sock);
1082 io->get_headers_cb = get_headers_cb;
1083 io->parse_headers_cb = parse_headers_cb;
1084 io->header_data = header_data;
1085 io->completion_cb = completion_cb;
1086 io->completion_data = completion_data;
1088 io->read_meta_buf = g_byte_array_new ();
1089 io->write_buf = g_string_new (NULL);
1091 io->read_tag = g_signal_connect (io->sock, "readable",
1092 G_CALLBACK (io_read), msg);
1093 io->write_tag = g_signal_connect (io->sock, "writable",
1094 G_CALLBACK (io_write), msg);
1096 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
1097 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
1099 if (soup_socket_is_ssl (io->sock)) {
1100 io->tls_signal_id = g_signal_connect (io->sock, "notify::tls-certificate",
1101 G_CALLBACK (socket_tls_certificate_changed), msg);
1105 soup_message_io_cleanup (msg);
1111 soup_message_io_client (SoupMessageQueueItem *item,
1112 SoupMessageGetHeadersFn get_headers_cb,
1113 SoupMessageParseHeadersFn parse_headers_cb,
1114 gpointer header_data,
1115 SoupMessageCompletionFn completion_cb,
1116 gpointer completion_data)
1118 SoupMessageIOData *io;
1119 SoupSocket *sock = soup_connection_get_socket (item->conn);
1121 io = new_iostate (item->msg, sock, SOUP_MESSAGE_IO_CLIENT,
1122 get_headers_cb, parse_headers_cb, header_data,
1123 completion_cb, completion_data);
1126 soup_message_queue_item_ref (item);
1128 io->read_body = item->msg->response_body;
1129 io->write_body = item->msg->request_body;
1131 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
1132 io_write (sock, item->msg);
1136 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
1137 SoupMessageGetHeadersFn get_headers_cb,
1138 SoupMessageParseHeadersFn parse_headers_cb,
1139 gpointer header_data,
1140 SoupMessageCompletionFn completion_cb,
1141 gpointer completion_data)
1143 SoupMessageIOData *io;
1145 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
1146 get_headers_cb, parse_headers_cb, header_data,
1147 completion_cb, completion_data);
1149 io->read_body = msg->request_body;
1150 io->write_body = msg->response_body;
1152 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
1153 io_read (sock, msg);
1157 soup_message_io_pause (SoupMessage *msg)
1159 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1160 SoupMessageIOData *io = priv->io_data;
1162 g_return_if_fail (io != NULL);
1164 if (io->write_tag) {
1165 g_signal_handler_disconnect (io->sock, io->write_tag);
1169 g_signal_handler_disconnect (io->sock, io->read_tag);
1173 if (io->unpause_source) {
1174 g_source_destroy (io->unpause_source);
1175 io->unpause_source = NULL;
1180 io_unpause_internal (gpointer msg)
1182 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1183 SoupMessageIOData *io = priv->io_data;
1185 g_return_val_if_fail (io != NULL, FALSE);
1186 io->unpause_source = NULL;
1188 if (io->write_tag || io->read_tag)
1191 if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
1192 io->write_tag = g_signal_connect (io->sock, "writable",
1193 G_CALLBACK (io_write), msg);
1196 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
1197 io->read_tag = g_signal_connect (io->sock, "readable",
1198 G_CALLBACK (io_read), msg);
1201 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
1202 io_write (io->sock, msg);
1203 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
1204 io_read (io->sock, msg);
1210 soup_message_io_unpause (SoupMessage *msg)
1212 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1213 SoupMessageIOData *io = priv->io_data;
1214 gboolean non_blocking;
1215 GMainContext *async_context;
1217 g_return_if_fail (io != NULL);
1219 g_object_get (io->sock,
1220 SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
1221 SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
1224 if (!io->unpause_source) {
1225 io->unpause_source = soup_add_completion (
1226 async_context, io_unpause_internal, msg);
1229 io_unpause_internal (msg);
1231 g_main_context_unref (async_context);
1235 * soup_message_io_in_progress:
1236 * @msg: a #SoupMessage
1238 * Tests whether or not I/O is currently in progress on @msg.
1240 * Return value: whether or not I/O is currently in progress.
1243 soup_message_io_in_progress (SoupMessage *msg)
1245 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1247 return priv->io_data != NULL;