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 soup_message_io_cancel (SoupMessage *msg)
74 SoupMessageIOData *io = msg->priv->io_data;
80 g_signal_handler_disconnect (io->sock, io->read_tag);
82 g_signal_handler_disconnect (io->sock, io->write_tag);
84 g_signal_handler_disconnect (io->sock, io->err_tag);
86 if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE)
87 soup_socket_disconnect (io->sock);
88 g_object_unref (io->sock);
91 g_byte_array_free (io->read_buf, TRUE);
92 g_byte_array_free (io->read_meta_buf, TRUE);
94 g_string_free (io->write_buf, TRUE);
97 msg->priv->io_data = NULL;
100 #define SOUP_MESSAGE_IO_EOL "\r\n"
101 #define SOUP_MESSAGE_IO_EOL_LEN 2
102 #define SOUP_MESSAGE_IO_DOUBLE_EOL "\r\n\r\n"
103 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
106 soup_message_io_finished (SoupMessage *msg)
109 soup_message_io_cancel (msg);
110 soup_message_finished (msg);
111 g_object_unref (msg);
116 io_error (SoupSocket *sock, SoupMessage *msg)
118 SoupMessageIOData *io = msg->priv->io_data;
120 /* Closing the connection to signify EOF is sometimes ok */
121 if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
122 io->read_encoding == SOUP_TRANSFER_UNKNOWN) {
123 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
124 soup_message_io_finished (msg);
128 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
129 soup_message_io_finished (msg);
133 read_metadata (SoupMessage *msg, const char *boundary)
135 SoupMessageIOData *io = msg->priv->io_data;
136 SoupSocketIOStatus status;
137 char read_buf[RESPONSE_BLOCK_SIZE];
138 guint boundary_len = strlen (boundary), nread;
142 status = soup_socket_read_until (io->sock, read_buf,
144 boundary, boundary_len,
148 g_byte_array_append (io->read_meta_buf, read_buf, nread);
151 case SOUP_SOCKET_ERROR:
152 case SOUP_SOCKET_EOF:
153 io_error (io->sock, msg);
156 case SOUP_SOCKET_WOULD_BLOCK:
165 read_body_chunk (SoupMessage *msg)
167 SoupMessageIOData *io = msg->priv->io_data;
168 SoupSocketIOStatus status;
169 char read_buf[RESPONSE_BLOCK_SIZE];
170 guint nread, len = sizeof (read_buf);
171 gboolean read_to_eof = (io->read_encoding == SOUP_TRANSFER_UNKNOWN);
173 while (read_to_eof || io->read_length > 0) {
175 len = MIN (len, io->read_length);
177 status = soup_socket_read (io->sock, read_buf, len, &nread);
184 io->read_body->owner = SOUP_BUFFER_STATIC;
185 io->read_body->body = read_buf;
186 io->read_body->length = nread;
188 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
189 soup_message_got_chunk (msg);
190 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
192 memset (io->read_body, 0, sizeof (SoupDataBuffer));
195 g_byte_array_append (io->read_buf, read_buf, nread);
196 io->read_length -= nread;
199 case SOUP_SOCKET_EOF:
202 /* else fall through */
204 case SOUP_SOCKET_ERROR:
205 io_error (io->sock, msg);
208 case SOUP_SOCKET_WOULD_BLOCK:
217 write_data (SoupMessage *msg, const char *data, guint len)
219 SoupMessageIOData *io = msg->priv->io_data;
220 SoupSocketIOStatus status;
223 while (len > io->written) {
224 status = soup_socket_write (io->sock,
229 case SOUP_SOCKET_EOF:
230 case SOUP_SOCKET_ERROR:
231 io_error (io->sock, msg);
234 case SOUP_SOCKET_WOULD_BLOCK:
238 io->written += nwrote;
247 static inline SoupMessageIOState
248 io_body_state (SoupTransferEncoding encoding)
250 if (encoding == SOUP_TRANSFER_CHUNKED)
251 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
253 return SOUP_MESSAGE_IO_STATE_BODY;
256 static void io_read (SoupSocket *sock, SoupMessage *msg);
259 * There are two request/response formats: the basic request/response,
260 * possibly with one or more unsolicited informational responses (such
261 * as the WebDAV "102 Processing" response):
264 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
265 * W:BODY / R:NOT_STARTED -> R:BODY / W:NOT_STARTED
266 * [W:DONE / R:HEADERS (1xx) <- R:DONE / W:HEADERS (1xx) ...]
267 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
268 * W:DONE / R:BODY <- R:DONE / W:BODY
269 * W:DONE / R:DONE R:DONE / W:DONE
271 * and the "Expect: 100-continue" request/response, in which each
272 * writer has to pause and wait for the other at some point:
275 * W:HEADERS / R:NOT_STARTED -> R:HEADERS / W:NOT_STARTED
276 * W:BLOCKING / R:HEADERS (100) <- R:BLOCKING / W:HEADERS (100)
277 * W:BODY / R:BLOCKING -> R:BODY / W:BLOCKING
278 * W:DONE / R:HEADERS <- R:DONE / W:HEADERS
279 * W:DONE / R:BODY <- R:DONE / W:BODY
280 * W:DONE / R:DONE R:DONE / W:DONE
284 io_write (SoupSocket *sock, SoupMessage *msg)
286 SoupMessageIOData *io = msg->priv->io_data;
289 switch (io->write_state) {
290 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
294 case SOUP_MESSAGE_IO_STATE_HEADERS:
295 if (!io->write_buf->len) {
296 io->get_headers_cb (msg, io->write_buf,
299 if (!io->write_buf->len) {
300 soup_message_io_pause (msg);
305 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
308 g_string_truncate (io->write_buf, 0);
310 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
311 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
312 if (msg->status_code == SOUP_STATUS_CONTINUE) {
313 /* Stop and wait for the body now */
315 SOUP_MESSAGE_IO_STATE_BLOCKING;
317 /* We just wrote a 1xx response
318 * header, so stay in STATE_HEADERS.
319 * (The caller will pause us from the
320 * wrote_informational callback if he
321 * is not ready to send the final
325 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
326 msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE) {
327 /* Need to wait for the Continue response */
328 io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
329 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
331 io->write_state = io_body_state (io->write_encoding);
333 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
334 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
335 soup_message_wrote_informational (msg);
337 soup_message_wrote_headers (msg);
338 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
342 case SOUP_MESSAGE_IO_STATE_BLOCKING:
345 /* If io_read reached a point where we could write
346 * again, it would have recursively called io_write.
347 * So (a) we don't need to try to keep writing, and
348 * (b) we can't anyway, because msg may have been
354 case SOUP_MESSAGE_IO_STATE_BODY:
355 if (!write_data (msg, io->write_body->body,
356 io->write_body->length))
359 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
361 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
362 soup_message_wrote_body (msg);
363 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
367 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
368 if (!io->write_buf->len) {
369 SoupDataBuffer *chunk;
371 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
372 chunk = soup_message_pop_chunk (msg);
373 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
376 soup_message_io_pause (msg);
379 memcpy (io->write_body, chunk, sizeof (SoupDataBuffer));
382 g_string_append_printf (io->write_buf, "%x\r\n",
383 io->write_body->length);
386 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
389 g_string_truncate (io->write_buf, 0);
391 if (io->write_body->length == 0) {
392 /* The last chunk has no CHUNK_END... */
393 io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
397 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
401 case SOUP_MESSAGE_IO_STATE_CHUNK:
402 if (!write_data (msg, io->write_body->body,
403 io->write_body->length))
406 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
408 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
409 soup_message_wrote_chunk (msg);
410 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
414 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
415 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
416 SOUP_MESSAGE_IO_EOL_LEN))
419 if (io->write_body->owner == SOUP_BUFFER_SYSTEM_OWNED)
420 g_free (io->write_body->body);
421 memset (io->write_body, 0, sizeof (SoupDataBuffer));
423 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
427 case SOUP_MESSAGE_IO_STATE_TRAILERS:
428 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
429 SOUP_MESSAGE_IO_EOL_LEN))
432 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
434 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
435 soup_message_wrote_body (msg);
436 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
440 case SOUP_MESSAGE_IO_STATE_DONE:
441 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
442 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
445 soup_message_io_finished (msg);
450 g_return_if_reached ();
457 io_read (SoupSocket *sock, SoupMessage *msg)
459 SoupMessageIOData *io = msg->priv->io_data;
463 switch (io->read_state) {
464 case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
468 case SOUP_MESSAGE_IO_STATE_HEADERS:
469 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
472 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
473 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
474 status = io->parse_headers_cb (msg, io->read_meta_buf->data,
475 io->read_meta_buf->len,
479 g_byte_array_set_size (io->read_meta_buf, 0);
481 if (status != SOUP_STATUS_OK) {
482 /* Either we couldn't parse the headers, or they
483 * indicated something that would mean we wouldn't
484 * be able to parse the body. (Eg, unknown
485 * Transfer-Encoding.). Skip the rest of the
486 * reading, and make sure the connection gets
487 * closed when we're done.
489 soup_message_set_status (msg, status);
490 soup_message_add_header (msg->request_headers,
491 "Connection", "close");
492 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
496 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
497 SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
498 if (msg->status_code == SOUP_STATUS_CONTINUE &&
499 io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
500 /* Pause the reader, unpause the writer */
502 SOUP_MESSAGE_IO_STATE_BLOCKING;
504 io_body_state (io->write_encoding);
506 /* Just stay in HEADERS */
507 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
509 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
510 (msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
511 /* The client requested a Continue response. */
512 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
513 io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
515 io->read_state = io_body_state (io->read_encoding);
517 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
518 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
519 soup_message_got_informational (msg);
520 soup_message_cleanup_response (msg);
522 soup_message_got_headers (msg);
523 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
527 case SOUP_MESSAGE_IO_STATE_BLOCKING:
528 io_write (sock, msg);
530 /* As in the io_write case, we *must* return here. */
534 case SOUP_MESSAGE_IO_STATE_BODY:
535 if (!read_body_chunk (msg))
540 io->read_body->owner = SOUP_BUFFER_SYSTEM_OWNED;
541 io->read_body->body = io->read_buf->data;
542 io->read_body->length = io->read_buf->len;
544 g_byte_array_free (io->read_buf, FALSE);
548 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
550 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
551 soup_message_got_body (msg);
552 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
556 case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
557 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
560 io->read_length = strtoul (io->read_meta_buf->data, NULL, 16);
561 g_byte_array_set_size (io->read_meta_buf, 0);
563 if (io->read_length > 0)
564 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
566 io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
570 case SOUP_MESSAGE_IO_STATE_CHUNK:
571 if (!read_body_chunk (msg))
574 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
578 case SOUP_MESSAGE_IO_STATE_CHUNK_END:
579 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
582 g_byte_array_set_size (io->read_meta_buf, 0);
583 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
587 case SOUP_MESSAGE_IO_STATE_TRAILERS:
588 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
591 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
594 /* FIXME: process trailers */
595 g_byte_array_set_size (io->read_meta_buf, 0);
599 case SOUP_MESSAGE_IO_STATE_DONE:
600 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
601 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
602 io_write (sock, msg);
604 soup_message_io_finished (msg);
609 g_return_if_reached ();
615 static SoupMessageIOData *
616 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
617 SoupMessageGetHeadersFn get_headers_cb,
618 SoupMessageParseHeadersFn parse_headers_cb,
621 SoupMessageIOData *io;
623 io = g_new0 (SoupMessageIOData, 1);
624 io->sock = g_object_ref (sock);
626 io->get_headers_cb = get_headers_cb;
627 io->parse_headers_cb = parse_headers_cb;
628 io->user_data = user_data;
630 io->read_encoding = SOUP_TRANSFER_UNKNOWN;
631 io->write_encoding = SOUP_TRANSFER_UNKNOWN;
633 io->read_meta_buf = g_byte_array_new ();
634 if (!(msg->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
635 io->read_buf = g_byte_array_new ();
636 io->write_buf = g_string_new (NULL);
638 io->read_tag = g_signal_connect (io->sock, "readable",
639 G_CALLBACK (io_read), msg);
640 io->write_tag = g_signal_connect (io->sock, "writable",
641 G_CALLBACK (io_write), msg);
642 io->err_tag = g_signal_connect (io->sock, "disconnected",
643 G_CALLBACK (io_error), msg);
645 io->read_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
646 io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
648 msg->priv->io_data = io;
653 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
654 SoupMessageGetHeadersFn get_headers_cb,
655 SoupMessageParseHeadersFn parse_headers_cb,
658 SoupMessageIOData *io;
660 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
661 get_headers_cb, parse_headers_cb, user_data);
663 io->read_body = &msg->response;
664 io->write_body = &msg->request;
666 io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
667 io_write (sock, msg);
671 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
672 SoupMessageGetHeadersFn get_headers_cb,
673 SoupMessageParseHeadersFn parse_headers_cb,
676 SoupMessageIOData *io;
678 io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
679 get_headers_cb, parse_headers_cb, user_data);
681 io->read_body = &msg->request;
682 io->write_body = &msg->response;
684 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
689 soup_message_io_pause (SoupMessage *msg)
691 SoupMessageIOData *io = msg->priv->io_data;
693 g_return_if_fail (io != NULL);
696 g_signal_handler_disconnect (io->sock, io->write_tag);
700 g_signal_handler_disconnect (io->sock, io->read_tag);
706 soup_message_io_unpause (SoupMessage *msg)
708 SoupMessageIOData *io = msg->priv->io_data;
710 g_return_if_fail (io != NULL);
712 if (io->write_tag || io->read_tag)
715 io->write_tag = g_signal_connect (io->sock, "writable",
716 G_CALLBACK (io_write), msg);
717 io->read_tag = g_signal_connect (io->sock, "readable",
718 G_CALLBACK (io_read), msg);
720 if (io->write_state != SOUP_MESSAGE_IO_STATE_NOT_STARTED &&
721 io->write_state != SOUP_MESSAGE_IO_STATE_BLOCKING)
722 io_write (io->sock, msg);
724 io_read (io->sock, msg);