fix most signed/unsigned mismatch warnings
[platform/upstream/libsoup.git] / libsoup / soup-message-io.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-message-io.c: HTTP message I/O
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "soup-connection.h"
16 #include "soup-message.h"
17 #include "soup-message-private.h"
18 #include "soup-socket.h"
19 #include "soup-ssl.h"
20
21 typedef enum {
22         SOUP_MESSAGE_IO_CLIENT,
23         SOUP_MESSAGE_IO_SERVER
24 } SoupMessageIOMode;
25
26 typedef enum {
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
36 } SoupMessageIOState;
37
38 typedef struct {
39         SoupSocket           *sock;
40         SoupConnection       *conn;
41         SoupMessageIOMode     mode;
42
43         SoupMessageIOState    read_state;
44         SoupTransferEncoding  read_encoding;
45         GByteArray           *read_buf;
46         GByteArray           *read_meta_buf;
47         SoupDataBuffer       *read_body;
48         guint                 read_length;
49
50         SoupMessageIOState    write_state;
51         SoupTransferEncoding  write_encoding;
52         GString              *write_buf;
53         SoupDataBuffer       *write_body;
54         guint                 written;
55
56         guint read_tag, write_tag, err_tag;
57
58         SoupMessageGetHeadersFn   get_headers_cb;
59         SoupMessageParseHeadersFn parse_headers_cb;
60         gpointer                  user_data;
61 } SoupMessageIOData;
62         
63
64 /* Put these around callback invocation if there is code afterward
65  * that depends on the IO having not been cancelled.
66  */
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; }
71
72 #define RESPONSE_BLOCK_SIZE 8192
73
74 static void
75 io_cleanup (SoupMessage *msg)
76 {
77         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
78         SoupMessageIOData *io;
79
80         soup_message_io_stop (msg);
81
82         io = priv->io_data;
83         if (!io)
84                 return;
85         priv->io_data = NULL;
86
87         if (io->sock)
88                 g_object_unref (io->sock);
89         if (io->conn)
90                 g_object_unref (io->conn);
91
92         if (io->read_buf)
93                 g_byte_array_free (io->read_buf, TRUE);
94         g_byte_array_free (io->read_meta_buf, TRUE);
95
96         g_string_free (io->write_buf, TRUE);
97
98         g_free (io);
99 }
100
101 /**
102  * soup_message_io_stop:
103  * @msg: a #SoupMessage
104  *
105  * Immediately stops I/O on msg; if the connection would be left in an
106  * inconsistent state, it will be closed.
107  **/
108 void
109 soup_message_io_stop (SoupMessage *msg)
110 {
111         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
112         SoupMessageIOData *io = priv->io_data;
113
114         if (!io)
115                 return;
116
117         if (io->read_tag) {
118                 g_signal_handler_disconnect (io->sock, io->read_tag);
119                 io->read_tag = 0;
120         }
121         if (io->write_tag) {
122                 g_signal_handler_disconnect (io->sock, io->write_tag);
123                 io->write_tag = 0;
124         }
125         if (io->err_tag) {
126                 g_signal_handler_disconnect (io->sock, io->err_tag);
127                 io->err_tag = 0;
128         }
129
130         if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE)
131                 soup_socket_disconnect (io->sock);
132         else if (io->conn) {
133                 SoupConnection *conn = io->conn;
134                 io->conn = NULL;
135                 soup_connection_release (conn);
136                 g_object_unref (conn);
137         }
138 }
139
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
144
145 static void
146 soup_message_io_finished (SoupMessage *msg)
147 {
148         g_object_ref (msg);
149         io_cleanup (msg);
150         if (SOUP_MESSAGE_IS_STARTING (msg))
151                 soup_message_restarted (msg);
152         else
153                 soup_message_finished (msg);
154         g_object_unref (msg);
155 }
156
157
158 static void
159 io_error (SoupSocket *sock, SoupMessage *msg)
160 {
161         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
162         SoupMessageIOData *io = priv->io_data;
163
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);
169                 return;
170         }
171
172         if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
173                 GError *err = g_object_get_data (G_OBJECT (sock),
174                                                  "SoupSocket-last_error");
175
176                 if (err && err->domain == SOUP_SSL_ERROR) {
177                         soup_message_set_status_full (msg,
178                                                       SOUP_STATUS_SSL_FAILED,
179                                                       err->message);
180                 } else
181                         soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
182         }
183
184         soup_message_io_finished (msg);
185 }
186
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.)
190  *
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.
200  */
201 static gboolean
202 read_metadata (SoupMessage *msg, const char *boundary)
203 {
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);
209         gsize nread;
210         gboolean done;
211
212         do {
213                 status = soup_socket_read_until (io->sock, read_buf,
214                                                  sizeof (read_buf),
215                                                  boundary, boundary_len,
216                                                  &nread, &done);
217                 switch (status) {
218                 case SOUP_SOCKET_OK:
219                         g_byte_array_append (io->read_meta_buf, read_buf, nread);
220                         break;
221
222                 case SOUP_SOCKET_ERROR:
223                 case SOUP_SOCKET_EOF:
224                         io_error (io->sock, msg);
225                         return FALSE;
226
227                 case SOUP_SOCKET_WOULD_BLOCK:
228                         return FALSE;
229                 }
230         } while (!done);
231
232         return TRUE;
233 }
234
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
240  * it.
241  *
242  * See the note at read_metadata() for an explanation of the return
243  * value.
244  */
245 static gboolean
246 read_body_chunk (SoupMessage *msg)
247 {
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);
254         gsize nread;
255
256         while (read_to_eof || io->read_length > 0) {
257                 if (!read_to_eof)
258                         len = MIN (len, io->read_length);
259
260                 status = soup_socket_read (io->sock, read_buf, len, &nread);
261
262                 switch (status) {
263                 case SOUP_SOCKET_OK:
264                         if (!nread)
265                                 break;
266
267                         io->read_body->owner  = SOUP_BUFFER_STATIC;
268                         io->read_body->body   = (char *)read_buf;
269                         io->read_body->length = nread;
270
271                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
272                         soup_message_got_chunk (msg);
273                         SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
274
275                         memset (io->read_body, 0, sizeof (SoupDataBuffer));
276
277                         if (io->read_buf)
278                                 g_byte_array_append (io->read_buf, read_buf, nread);
279                         io->read_length -= nread;
280                         break;
281
282                 case SOUP_SOCKET_EOF:
283                         if (read_to_eof)
284                                 return TRUE;
285                         /* else fall through */
286
287                 case SOUP_SOCKET_ERROR:
288                         io_error (io->sock, msg);
289                         return FALSE;
290
291                 case SOUP_SOCKET_WOULD_BLOCK:
292                         return FALSE;
293                 }
294         }
295
296         return TRUE;
297 }
298
299 /* Attempts to write @len bytes from @data. See the note at
300  * read_metadata() for an explanation of the return value.
301  */
302 static gboolean
303 write_data (SoupMessage *msg, const char *data, guint len)
304 {
305         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
306         SoupMessageIOData *io = priv->io_data;
307         SoupSocketIOStatus status;
308         gsize nwrote;
309
310         while (len > io->written) {
311                 status = soup_socket_write (io->sock,
312                                             data + io->written,
313                                             len - io->written,
314                                             &nwrote);
315                 switch (status) {
316                 case SOUP_SOCKET_EOF:
317                 case SOUP_SOCKET_ERROR:
318                         io_error (io->sock, msg);
319                         return FALSE;
320
321                 case SOUP_SOCKET_WOULD_BLOCK:
322                         return FALSE;
323
324                 case SOUP_SOCKET_OK:
325                         io->written += nwrote;
326                         break;
327                 }
328         }
329
330         io->written = 0;
331         return TRUE;
332 }
333
334 static inline SoupMessageIOState
335 io_body_state (SoupTransferEncoding encoding)
336 {
337         if (encoding == SOUP_TRANSFER_CHUNKED)
338                 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
339         else
340                 return SOUP_MESSAGE_IO_STATE_BODY;
341 }
342
343 static void io_read (SoupSocket *sock, SoupMessage *msg);
344
345 /*
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):
349  *
350  *     Client                            Server
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
357  *     
358  * and the "Expect: 100-continue" request/response, in which each
359  * writer has to pause and wait for the other at some point:
360  *
361  *     Client                            Server
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
368  */
369
370 static void
371 io_write (SoupSocket *sock, SoupMessage *msg)
372 {
373         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
374         SoupMessageIOData *io = priv->io_data;
375
376  write_more:
377         switch (io->write_state) {
378         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
379                 return;
380
381
382         case SOUP_MESSAGE_IO_STATE_HEADERS:
383                 if (!io->write_buf->len) {
384                         io->get_headers_cb (msg, io->write_buf,
385                                             &io->write_encoding,
386                                             io->user_data);
387                         if (!io->write_buf->len) {
388                                 soup_message_io_pause (msg);
389                                 return;
390                         }
391                 }
392
393                 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
394                         return;
395
396                 g_string_truncate (io->write_buf, 0);
397
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 */
402                                 io->write_state =
403                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
404                                 io->read_state = io_body_state (io->read_encoding);
405                         } else {
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
411                                  * response.)
412                                  */
413                         }
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;
419                 } else
420                         io->write_state = io_body_state (io->write_encoding);
421
422                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
423                 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
424                         soup_message_wrote_informational (msg);
425                 else
426                         soup_message_wrote_headers (msg);
427                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
428                 break;
429
430
431         case SOUP_MESSAGE_IO_STATE_BLOCKING:
432                 io_read (sock, msg);
433
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
438                  * destroyed.
439                  */
440                 return;
441
442
443         case SOUP_MESSAGE_IO_STATE_BODY:
444                 if (!write_data (msg, io->write_body->body,
445                                  io->write_body->length))
446                         return;
447
448                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
449
450                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
451                 soup_message_wrote_body (msg);
452                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
453                 break;
454
455
456         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
457                 if (!io->write_buf->len) {
458                         SoupDataBuffer *chunk;
459
460                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
461                         chunk = soup_message_pop_chunk (msg);
462                         SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
463
464                         if (!chunk) {
465                                 soup_message_io_pause (msg);
466                                 return;
467                         }
468                         memcpy (io->write_body, chunk, sizeof (SoupDataBuffer));
469                         g_free (chunk);
470
471                         g_string_append_printf (io->write_buf, "%x\r\n",
472                                                 io->write_body->length);
473                 }
474
475                 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
476                         return;
477
478                 g_string_truncate (io->write_buf, 0);
479
480                 if (io->write_body->length == 0) {
481                         /* The last chunk has no CHUNK_END... */
482                         io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
483                         break;
484                 }
485
486                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
487                 /* fall through */
488
489
490         case SOUP_MESSAGE_IO_STATE_CHUNK:
491                 if (!write_data (msg, io->write_body->body,
492                                  io->write_body->length))
493                         return;
494
495                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
496
497                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
498                 soup_message_wrote_chunk (msg);
499                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
500                 /* fall through */
501
502
503         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
504                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
505                                  SOUP_MESSAGE_IO_EOL_LEN))
506                         return;
507
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));
511
512                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
513                 break;
514
515
516         case SOUP_MESSAGE_IO_STATE_TRAILERS:
517                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
518                                  SOUP_MESSAGE_IO_EOL_LEN))
519                         return;
520
521                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
522
523                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
524                 soup_message_wrote_body (msg);
525                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
526                 /* fall through */
527
528
529         case SOUP_MESSAGE_IO_STATE_DONE:
530                 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
531                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
532                         io_read (sock, msg);
533                 } else
534                         soup_message_io_finished (msg);
535                 return;
536
537
538         default:
539                 g_return_if_reached ();
540         }
541
542         goto write_more;
543 }
544
545 static void
546 io_read (SoupSocket *sock, SoupMessage *msg)
547 {
548         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
549         SoupMessageIOData *io = priv->io_data;
550         guint status;
551
552  read_more:
553         switch (io->read_state) {
554         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
555                 return;
556
557
558         case SOUP_MESSAGE_IO_STATE_HEADERS:
559                 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
560                         return;
561
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,
566                                                &io->read_encoding,
567                                                &io->read_length,
568                                                io->user_data);
569                 g_byte_array_set_size (io->read_meta_buf, 0);
570
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.
578                          */
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;
583                         break;
584                 }
585
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 */
591                                 io->read_state =
592                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
593                                 io->write_state =
594                                         io_body_state (io->write_encoding);
595                         } else {
596                                 /* Just stay in HEADERS */
597                                 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
598                         }
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);
603                         
604                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
605                         io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
606                 } else
607                         io->read_state = io_body_state (io->read_encoding);
608
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);
614                 } else
615                         soup_message_got_headers (msg);
616                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
617                 break;
618
619
620         case SOUP_MESSAGE_IO_STATE_BLOCKING:
621                 io_write (sock, msg);
622
623                 /* As in the io_write case, we *must* return here. */
624                 return;
625
626
627         case SOUP_MESSAGE_IO_STATE_BODY:
628                 if (!read_body_chunk (msg))
629                         return;
630
631         got_body:
632                 if (io->read_buf) {
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;
636
637                         g_byte_array_free (io->read_buf, FALSE);
638                         io->read_buf = NULL;
639                 }
640
641                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
642
643                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
644                 soup_message_got_body (msg);
645                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
646                 break;
647
648
649         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
650                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
651                         return;
652
653                 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
654                 g_byte_array_set_size (io->read_meta_buf, 0);
655
656                 if (io->read_length > 0)
657                         io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
658                 else
659                         io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
660                 break;
661
662
663         case SOUP_MESSAGE_IO_STATE_CHUNK:
664                 if (!read_body_chunk (msg))
665                         return;
666
667                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
668                 break;
669
670
671         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
672                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
673                         return;
674
675                 g_byte_array_set_size (io->read_meta_buf, 0);
676                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
677                 break;
678
679
680         case SOUP_MESSAGE_IO_STATE_TRAILERS:
681                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
682                         return;
683
684                 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
685                         goto got_body;
686
687                 /* FIXME: process trailers */
688                 g_byte_array_set_size (io->read_meta_buf, 0);
689                 break;
690
691
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);
696                 } else
697                         soup_message_io_finished (msg);
698                 return;
699
700
701         default:
702                 g_return_if_reached ();
703         }
704
705         goto read_more;
706 }
707
708 static SoupMessageIOData *
709 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
710              SoupMessageGetHeadersFn get_headers_cb,
711              SoupMessageParseHeadersFn parse_headers_cb,
712              gpointer user_data)
713 {
714         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
715         SoupMessageIOData *io;
716
717         io = g_new0 (SoupMessageIOData, 1);
718         io->sock = g_object_ref (sock);
719         io->mode = mode;
720         io->get_headers_cb   = get_headers_cb;
721         io->parse_headers_cb = parse_headers_cb;
722         io->user_data        = user_data;
723
724         io->read_encoding    = SOUP_TRANSFER_UNKNOWN;
725         io->write_encoding   = SOUP_TRANSFER_UNKNOWN;
726
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);
731
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);
738
739         io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
740         io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
741
742         if (priv->io_data)
743                 io_cleanup (msg);
744         priv->io_data = io;
745         return io;
746 }
747
748 /**
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
756  *
757  * Begins the process of sending @msg across @sock.
758  *
759  * Don't call this. Use soup_message_send_request().
760  **/
761 void
762 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
763                         SoupConnection *conn,
764                         SoupMessageGetHeadersFn get_headers_cb,
765                         SoupMessageParseHeadersFn parse_headers_cb,
766                         gpointer user_data)
767 {
768         SoupMessageIOData *io;
769
770         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
771                           get_headers_cb, parse_headers_cb, user_data);
772
773         if (conn)
774                 io->conn = g_object_ref (conn);
775
776         io->read_body       = &msg->response;
777         io->write_body      = &msg->request;
778
779         io->write_state     = SOUP_MESSAGE_IO_STATE_HEADERS;
780         io_write (sock, msg);
781 }
782
783 /**
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
790  *
791  * Begins the process of receiving a request from @sock into @msg.
792  *
793  * Don't use this. Use soup_message_receive_request() instead.
794  **/
795 void
796 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
797                         SoupMessageGetHeadersFn get_headers_cb,
798                         SoupMessageParseHeadersFn parse_headers_cb,
799                         gpointer user_data)
800 {
801         SoupMessageIOData *io;
802
803         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
804                           get_headers_cb, parse_headers_cb, user_data);
805
806         io->read_body       = &msg->request;
807         io->write_body      = &msg->response;
808
809         io->read_state      = SOUP_MESSAGE_IO_STATE_HEADERS;
810         io_read (sock, msg);
811 }
812
813 /**
814  * soup_message_io_pause:
815  * @msg: a #SoupMessage
816  *
817  * Pauses I/O on @msg.
818  **/
819 void  
820 soup_message_io_pause (SoupMessage *msg)
821 {
822         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
823         SoupMessageIOData *io = priv->io_data;
824
825         g_return_if_fail (io != NULL);
826
827         if (io->write_tag) {
828                 g_signal_handler_disconnect (io->sock, io->write_tag);
829                 io->write_tag = 0;
830         }
831         if (io->read_tag) {
832                 g_signal_handler_disconnect (io->sock, io->read_tag);
833                 io->read_tag = 0;
834         }
835 }
836
837 /**
838  * soup_message_io_unpause:
839  * @msg: a #SoupMessage
840  *
841  * Resumes I/O on @msg.
842  **/
843 void  
844 soup_message_io_unpause (SoupMessage *msg)
845 {
846         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
847         SoupMessageIOData *io = priv->io_data;
848
849         g_return_if_fail (io != NULL);
850
851         if (io->write_tag || io->read_tag)
852                 return;
853
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);
858
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);
862         else
863                 io_read (io->sock, msg);
864 }