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-message.h"
16 #include "soup-message-private.h"
17 #include "soup-socket.h"
20 SOUP_MESSAGE_IO_CLIENT,
21 SOUP_MESSAGE_IO_SERVER
25 SOUP_MESSAGE_IO_STATE_NOT_STARTED,
26 SOUP_MESSAGE_IO_STATE_HEADERS,
27 SOUP_MESSAGE_IO_STATE_BLOCKING,
28 SOUP_MESSAGE_IO_STATE_BODY,
29 SOUP_MESSAGE_IO_STATE_CHUNK_SIZE,
30 SOUP_MESSAGE_IO_STATE_CHUNK,
31 SOUP_MESSAGE_IO_STATE_CHUNK_END,
32 SOUP_MESSAGE_IO_STATE_TRAILERS,
33 SOUP_MESSAGE_IO_STATE_DONE
38 SoupMessageIOMode mode;
40 SoupMessageIOState read_state;
41 SoupTransferEncoding read_encoding;
43 GByteArray *read_meta_buf;
44 SoupDataBuffer *read_body;
47 SoupMessageIOState write_state;
48 SoupTransferEncoding write_encoding;
50 SoupDataBuffer *write_body;
53 guint read_tag, write_tag, err_tag;
55 SoupMessageGetHeadersFn get_headers_cb;
56 SoupMessageParseHeadersFn parse_headers_cb;
61 /* Put these around callback invocation if there is code afterward
62 * that depends on the IO having not been cancelled.
64 #define dummy_to_make_emacs_happy {
65 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
66 #define SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED cancelled = (msg->priv->io_data != io); g_object_unref (msg); if (cancelled || !io->read_tag || !io->write_tag) return; }
67 #define SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED(val) cancelled = (msg->priv->io_data != io); g_object_unref (msg); if (cancelled || !io->read_tag || !io->write_tag) return val; }
69 #define RESPONSE_BLOCK_SIZE 8192
72 io_cleanup (SoupMessage *msg)
74 SoupMessageIOData *io = msg->priv->io_data;
79 soup_message_io_stop (msg);
82 g_object_unref (io->sock);
85 g_byte_array_free (io->read_buf, TRUE);
86 g_byte_array_free (io->read_meta_buf, TRUE);
88 g_string_free (io->write_buf, TRUE);
91 msg->priv->io_data = NULL;
95 soup_message_io_stop (SoupMessage *msg)
97 SoupMessageIOData *io = msg->priv->io_data;
103 g_signal_handler_disconnect (io->sock, io->read_tag);
107 g_signal_handler_disconnect (io->sock, io->write_tag);
111 g_signal_handler_disconnect (io->sock, io->err_tag);
115 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE)
116 soup_socket_disconnect (io->sock);
119 #define SOUP_MESSAGE_IO_EOL "\r\n"
120 #define SOUP_MESSAGE_IO_EOL_LEN 2
121 #define SOUP_MESSAGE_IO_DOUBLE_EOL "\r\n\r\n"
122 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
125 soup_message_io_finished (SoupMessage *msg)
129 if (SOUP_MESSAGE_IS_STARTING (msg))
130 soup_message_restarted (msg);
132 soup_message_finished (msg);
133 g_object_unref (msg);
138 io_error (SoupSocket *sock, SoupMessage *msg)
140 SoupMessageIOData *io = msg->priv->io_data;
142 /* Closing the connection to signify EOF is sometimes ok */
143 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
144 io->read_encoding == SOUP_TRANSFER_UNKNOWN) {
145 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
146 soup_message_io_finished (msg);
150 if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
151 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
152 soup_message_io_finished (msg);
156 read_metadata (SoupMessage *msg, const char *boundary)
158 SoupMessageIOData *io = msg->priv->io_data;
159 SoupSocketIOStatus status;
160 char read_buf[RESPONSE_BLOCK_SIZE];
161 guint boundary_len = strlen (boundary), nread;
165 status = soup_socket_read_until (io->sock, read_buf,
167 boundary, boundary_len,
171 g_byte_array_append (io->read_meta_buf, read_buf, nread);
174 case SOUP_SOCKET_ERROR:
175 case SOUP_SOCKET_EOF:
176 io_error (io->sock, msg);
179 case SOUP_SOCKET_WOULD_BLOCK:
188 read_body_chunk (SoupMessage *msg)
190 SoupMessageIOData *io = msg->priv->io_data;
191 SoupSocketIOStatus status;
192 char read_buf[RESPONSE_BLOCK_SIZE];
193 guint nread, len = sizeof (read_buf);
194 gboolean read_to_eof = (io->read_encoding == SOUP_TRANSFER_UNKNOWN);
196 while (read_to_eof || io->read_length > 0) {
198 len = MIN (len, io->read_length);
200 status = soup_socket_read (io->sock, read_buf, len, &nread);
207 io->read_body->owner = SOUP_BUFFER_STATIC;
208 io->read_body->body = read_buf;
209 io->read_body->length = nread;
211 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
212 soup_message_got_chunk (msg);
213 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
215 memset (io->read_body, 0, sizeof (SoupDataBuffer));
218 g_byte_array_append (io->read_buf, read_buf, nread);
219 io->read_length -= nread;
222 case SOUP_SOCKET_EOF:
225 /* else fall through */
227 case SOUP_SOCKET_ERROR:
228 io_error (io->sock, msg);
231 case SOUP_SOCKET_WOULD_BLOCK:
240 write_data (SoupMessage *msg, const char *data, guint len)
242 SoupMessageIOData *io = msg->priv->io_data;
243 SoupSocketIOStatus status;
246 while (len > io->written) {
247 status = soup_socket_write (io->sock,
252 case SOUP_SOCKET_EOF:
253 case SOUP_SOCKET_ERROR:
254 io_error (io->sock, msg);
257 case SOUP_SOCKET_WOULD_BLOCK:
261 io->written += nwrote;
270 static inline SoupMessageIOState
271 io_body_state (SoupTransferEncoding encoding)
273 if (encoding == SOUP_TRANSFER_CHUNKED)
274 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
276 return SOUP_MESSAGE_IO_STATE_BODY;
279 static void io_read (SoupSocket *sock, SoupMessage *msg);
282 * There are two request/response formats: the basic request/response,
283 * possibly with one or more unsolicited informational responses (such
284 * as the WebDAV "102 Processing" response):
287 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
288 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
289 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
290 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
291 * W:DONE / R:BODY <- R:DONE / W:BODY
292 * W:DONE / R:DONE R:DONE / W:DONE
294 * and the "Expect: 100-continue" request/response, in which each
295 * writer has to pause and wait for the other at some point:
298 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
299 * W:BLOCKING / R:HEADERS (100) <- R:BLOCKING / W:HEADERS (100)
300 * W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING
301 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
302 * W:DONE / R:BODY <- R:DONE / W:BODY
303 * W:DONE / R:DONE R:DONE / W:DONE
307 io_write (SoupSocket *sock, SoupMessage *msg)
309 SoupMessageIOData *io = msg->priv->io_data;
312 switch (io->write_state) {
313 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
317 case SOUP_MESSAGE_IO_STATE_HEADERS:
318 if (!io->write_buf->len) {
319 io->get_headers_cb (msg, io->write_buf,
322 if (!io->write_buf->len) {
323 soup_message_io_pause (msg);
328 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
331 g_string_truncate (io->write_buf, 0);
333 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
334 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
335 if (msg->status_code == SOUP_STATUS_CONTINUE) {
336 /* Stop and wait for the body now */
338 SOUP_MESSAGE_IO_STATE_BLOCKING;
340 /* We just wrote a 1xx response
341 * header, so stay in STATE_HEADERS.
342 * (The caller will pause us from the
343 * wrote_informational callback if he
344 * is not ready to send the final
348 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
349 msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE) {
350 /* Need to wait for the Continue response */
351 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
352 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
354 io->write_state = io_body_state (io->write_encoding);
356 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
357 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
358 soup_message_wrote_informational (msg);
360 soup_message_wrote_headers (msg);
361 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
365 case SOUP_MESSAGE_IO_STATE_BLOCKING:
368 /* If io_read reached a point where we could write
369 * again, it would have recursively called io_write.
370 * So (a) we don't need to try to keep writing, and
371 * (b) we can't anyway, because msg may have been
377 case SOUP_MESSAGE_IO_STATE_BODY:
378 if (!write_data (msg, io->write_body->body,
379 io->write_body->length))
382 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
384 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
385 soup_message_wrote_body (msg);
386 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
390 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
391 if (!io->write_buf->len) {
392 SoupDataBuffer *chunk;
394 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
395 chunk = soup_message_pop_chunk (msg);
396 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
399 soup_message_io_pause (msg);
402 memcpy (io->write_body, chunk, sizeof (SoupDataBuffer));
405 g_string_append_printf (io->write_buf, "%x\r\n",
406 io->write_body->length);
409 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
412 g_string_truncate (io->write_buf, 0);
414 if (io->write_body->length == 0) {
415 /* The last chunk has no CHUNK_END... */
416 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
420 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
424 case SOUP_MESSAGE_IO_STATE_CHUNK:
425 if (!write_data (msg, io->write_body->body,
426 io->write_body->length))
429 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
431 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
432 soup_message_wrote_chunk (msg);
433 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
437 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
438 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
439 SOUP_MESSAGE_IO_EOL_LEN))
442 if (io->write_body->owner == SOUP_BUFFER_SYSTEM_OWNED)
443 g_free (io->write_body->body);
444 memset (io->write_body, 0, sizeof (SoupDataBuffer));
446 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
450 case SOUP_MESSAGE_IO_STATE_TRAILERS:
451 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
452 SOUP_MESSAGE_IO_EOL_LEN))
455 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
457 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
458 soup_message_wrote_body (msg);
459 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
463 case SOUP_MESSAGE_IO_STATE_DONE:
464 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
465 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
468 soup_message_io_finished (msg);
473 g_return_if_reached ();
480 io_read (SoupSocket *sock, SoupMessage *msg)
482 SoupMessageIOData *io = msg->priv->io_data;
486 switch (io->read_state) {
487 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
491 case SOUP_MESSAGE_IO_STATE_HEADERS:
492 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
495 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
496 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
497 status = io->parse_headers_cb (msg, io->read_meta_buf->data,
498 io->read_meta_buf->len,
502 g_byte_array_set_size (io->read_meta_buf, 0);
504 if (status != SOUP_STATUS_OK) {
505 /* Either we couldn't parse the headers, or they
506 * indicated something that would mean we wouldn't
507 * be able to parse the body. (Eg, unknown
508 * Transfer-Encoding.). Skip the rest of the
509 * reading, and make sure the connection gets
510 * closed when we're done.
512 soup_message_set_status (msg, status);
513 soup_message_add_header (msg->request_headers,
514 "Connection", "close");
515 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
519 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
520 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
521 if (msg->status_code == SOUP_STATUS_CONTINUE &&
522 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
523 /* Pause the reader, unpause the writer */
525 SOUP_MESSAGE_IO_STATE_BLOCKING;
527 io_body_state (io->write_encoding);
529 /* Just stay in HEADERS */
530 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
532 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
533 (msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
534 /* The client requested a Continue response. */
535 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
536 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
538 io->read_state = io_body_state (io->read_encoding);
540 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
541 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
542 soup_message_got_informational (msg);
543 soup_message_cleanup_response (msg);
545 soup_message_got_headers (msg);
546 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
550 case SOUP_MESSAGE_IO_STATE_BLOCKING:
551 io_write (sock, msg);
553 /* As in the io_write case, we *must* return here. */
557 case SOUP_MESSAGE_IO_STATE_BODY:
558 if (!read_body_chunk (msg))
563 io->read_body->owner = SOUP_BUFFER_SYSTEM_OWNED;
564 io->read_body->body = io->read_buf->data;
565 io->read_body->length = io->read_buf->len;
567 g_byte_array_free (io->read_buf, FALSE);
571 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
573 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
574 soup_message_got_body (msg);
575 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
579 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
580 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
583 io->read_length = strtoul (io->read_meta_buf->data, NULL, 16);
584 g_byte_array_set_size (io->read_meta_buf, 0);
586 if (io->read_length > 0)
587 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
589 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
593 case SOUP_MESSAGE_IO_STATE_CHUNK:
594 if (!read_body_chunk (msg))
597 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
601 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
602 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
605 g_byte_array_set_size (io->read_meta_buf, 0);
606 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
610 case SOUP_MESSAGE_IO_STATE_TRAILERS:
611 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
614 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
617 /* FIXME: process trailers */
618 g_byte_array_set_size (io->read_meta_buf, 0);
622 case SOUP_MESSAGE_IO_STATE_DONE:
623 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
624 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
625 io_write (sock, msg);
627 soup_message_io_finished (msg);
632 g_return_if_reached ();
638 static SoupMessageIOData *
639 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
640 SoupMessageGetHeadersFn get_headers_cb,
641 SoupMessageParseHeadersFn parse_headers_cb,
644 SoupMessageIOData *io;
646 io = g_new0 (SoupMessageIOData, 1);
647 io->sock = g_object_ref (sock);
649 io->get_headers_cb = get_headers_cb;
650 io->parse_headers_cb = parse_headers_cb;
651 io->user_data = user_data;
653 io->read_encoding = SOUP_TRANSFER_UNKNOWN;
654 io->write_encoding = SOUP_TRANSFER_UNKNOWN;
656 io->read_meta_buf = g_byte_array_new ();
657 if (!(msg->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
658 io->read_buf = g_byte_array_new ();
659 io->write_buf = g_string_new (NULL);
661 io->read_tag = g_signal_connect (io->sock, "readable",
662 G_CALLBACK (io_read), msg);
663 io->write_tag = g_signal_connect (io->sock, "writable",
664 G_CALLBACK (io_write), msg);
665 io->err_tag = g_signal_connect (io->sock, "disconnected",
666 G_CALLBACK (io_error), msg);
668 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
669 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
671 if (msg->priv->io_data)
673 msg->priv->io_data = io;
678 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
679 SoupMessageGetHeadersFn get_headers_cb,
680 SoupMessageParseHeadersFn parse_headers_cb,
683 SoupMessageIOData *io;
685 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
686 get_headers_cb, parse_headers_cb, user_data);
688 io->read_body = &msg->response;
689 io->write_body = &msg->request;
691 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
692 io_write (sock, msg);
696 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
697 SoupMessageGetHeadersFn get_headers_cb,
698 SoupMessageParseHeadersFn parse_headers_cb,
701 SoupMessageIOData *io;
703 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
704 get_headers_cb, parse_headers_cb, user_data);
706 io->read_body = &msg->request;
707 io->write_body = &msg->response;
709 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
714 soup_message_io_pause (SoupMessage *msg)
716 SoupMessageIOData *io = msg->priv->io_data;
718 g_return_if_fail (io != NULL);
721 g_signal_handler_disconnect (io->sock, io->write_tag);
725 g_signal_handler_disconnect (io->sock, io->read_tag);
731 soup_message_io_unpause (SoupMessage *msg)
733 SoupMessageIOData *io = msg->priv->io_data;
735 g_return_if_fail (io != NULL);
737 if (io->write_tag || io->read_tag)
740 io->write_tag = g_signal_connect (io->sock, "writable",
741 G_CALLBACK (io_write), msg);
742 io->read_tag = g_signal_connect (io->sock, "readable",
743 G_CALLBACK (io_read), msg);
745 if (io->write_state != SOUP_MESSAGE_IO_STATE_NOT_STARTED &&
746 io->write_state != SOUP_MESSAGE_IO_STATE_BLOCKING)
747 io_write (io->sock, msg);
749 io_read (io->sock, msg);