Add this to schedule a callback in a GMainContext "right away", as opposed
[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-misc.h"
19 #include "soup-socket.h"
20 #include "soup-ssl.h"
21
22 typedef enum {
23         SOUP_MESSAGE_IO_CLIENT,
24         SOUP_MESSAGE_IO_SERVER
25 } SoupMessageIOMode;
26
27 typedef enum {
28         SOUP_MESSAGE_IO_STATE_NOT_STARTED,
29         SOUP_MESSAGE_IO_STATE_HEADERS,
30         SOUP_MESSAGE_IO_STATE_BLOCKING,
31         SOUP_MESSAGE_IO_STATE_BODY,
32         SOUP_MESSAGE_IO_STATE_CHUNK_SIZE,
33         SOUP_MESSAGE_IO_STATE_CHUNK,
34         SOUP_MESSAGE_IO_STATE_CHUNK_END,
35         SOUP_MESSAGE_IO_STATE_TRAILERS,
36         SOUP_MESSAGE_IO_STATE_FINISHING,
37         SOUP_MESSAGE_IO_STATE_DONE
38 } SoupMessageIOState;
39
40 #define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \
41         (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \
42          state != SOUP_MESSAGE_IO_STATE_BLOCKING && \
43          state != SOUP_MESSAGE_IO_STATE_DONE)
44
45 typedef struct {
46         SoupSocket           *sock;
47         SoupConnection       *conn;
48         SoupMessageIOMode     mode;
49
50         SoupMessageIOState    read_state;
51         SoupEncoding          read_encoding;
52         GByteArray           *read_meta_buf;
53         SoupMessageBody      *read_body;
54         goffset               read_length;
55
56         SoupMessageIOState    write_state;
57         SoupEncoding          write_encoding;
58         GString              *write_buf;
59         SoupMessageBody      *write_body;
60         SoupBuffer           *write_chunk;
61         gsize                 write_body_offset;
62         goffset               write_length;
63         goffset               written;
64
65         guint read_tag, write_tag, err_tag;
66         GSource *unpause_source;
67
68         SoupMessageGetHeadersFn   get_headers_cb;
69         SoupMessageParseHeadersFn parse_headers_cb;
70         gpointer                  user_data;
71 } SoupMessageIOData;
72         
73
74 /* Put these around callback invocation if there is code afterward
75  * that depends on the IO having not been cancelled.
76  */
77 #define dummy_to_make_emacs_happy {
78 #define SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK { gboolean cancelled; g_object_ref (msg);
79 #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; }
80 #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; }
81
82 #define RESPONSE_BLOCK_SIZE 8192
83
84 void
85 soup_message_io_cleanup (SoupMessage *msg)
86 {
87         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
88         SoupMessageIOData *io;
89
90         soup_message_io_stop (msg);
91
92         io = priv->io_data;
93         if (!io)
94                 return;
95         priv->io_data = NULL;
96
97         if (io->sock)
98                 g_object_unref (io->sock);
99         if (io->conn)
100                 g_object_unref (io->conn);
101
102         g_byte_array_free (io->read_meta_buf, TRUE);
103
104         g_string_free (io->write_buf, TRUE);
105         if (io->write_chunk)
106                 soup_buffer_free (io->write_chunk);
107
108         g_slice_free (SoupMessageIOData, io);
109 }
110
111 /**
112  * soup_message_io_stop:
113  * @msg: a #SoupMessage
114  *
115  * Immediately stops I/O on msg; if the connection would be left in an
116  * inconsistent state, it will be closed.
117  *
118  * Note: this is a low-level function that does not cause any signals
119  * to be emitted on @msg; it is up to the caller to make sure that
120  * @msg doesn't get "stranded".
121  **/
122 void
123 soup_message_io_stop (SoupMessage *msg)
124 {
125         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
126         SoupMessageIOData *io = priv->io_data;
127
128         if (!io)
129                 return;
130
131         if (io->read_tag) {
132                 g_signal_handler_disconnect (io->sock, io->read_tag);
133                 io->read_tag = 0;
134         }
135         if (io->write_tag) {
136                 g_signal_handler_disconnect (io->sock, io->write_tag);
137                 io->write_tag = 0;
138         }
139         if (io->err_tag) {
140                 g_signal_handler_disconnect (io->sock, io->err_tag);
141                 io->err_tag = 0;
142         }
143
144         if (io->unpause_source) {
145                 g_source_destroy (io->unpause_source);
146                 io->unpause_source = NULL;
147         }
148
149         if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
150                 soup_socket_disconnect (io->sock);
151         else if (io->conn) {
152                 SoupConnection *conn = io->conn;
153                 io->conn = NULL;
154                 soup_connection_release (conn);
155                 g_object_unref (conn);
156         }
157 }
158
159 #define SOUP_MESSAGE_IO_EOL            "\r\n"
160 #define SOUP_MESSAGE_IO_EOL_LEN        2
161 #define SOUP_MESSAGE_IO_DOUBLE_EOL     "\r\n\r\n"
162 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
163
164 static void
165 soup_message_io_finished (SoupMessage *msg)
166 {
167         g_object_ref (msg);
168         soup_message_io_cleanup (msg);
169         if (SOUP_MESSAGE_IS_STARTING (msg))
170                 soup_message_restarted (msg);
171         else
172                 soup_message_finished (msg);
173         g_object_unref (msg);
174 }
175
176 static void io_read (SoupSocket *sock, SoupMessage *msg);
177
178 static void
179 io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
180 {
181         if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
182                 if (error && error->domain == SOUP_SSL_ERROR) {
183                         soup_message_set_status_full (msg,
184                                                       SOUP_STATUS_SSL_FAILED,
185                                                       error->message);
186                 } else
187                         soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
188         }
189         if (error)
190                 g_error_free (error);
191
192         soup_message_io_finished (msg);
193 }
194
195 static void
196 io_disconnected (SoupSocket *sock, SoupMessage *msg)
197 {
198         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
199         SoupMessageIOData *io = priv->io_data;
200
201         /* Closing the connection to signify EOF is sometimes ok */
202         if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
203             io->read_encoding == SOUP_ENCODING_EOF) {
204                 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
205                 io_read (sock, msg);
206                 return;
207         }
208
209         io_error (sock, msg, NULL);
210 }
211
212 /* Reads data from io->sock into io->read_meta_buf up until @boundary.
213  * (This function is used to read metadata, and read_body_chunk() is
214  * used to read the message body contents.)
215  *
216  * read_metadata, read_body_chunk, and write_data all use the same
217  * convention for return values: if they return %TRUE, it means
218  * they've completely finished the requested read/write, and the
219  * caller should move on to the next step. If they return %FALSE, it
220  * means that either (a) the socket returned SOUP_SOCKET_WOULD_BLOCK,
221  * so the caller should give up for now and wait for the socket to
222  * emit a signal, or (b) the socket returned an error, and io_error()
223  * was called to process it and cancel the I/O. So either way, if the
224  * function returns %FALSE, the caller should return immediately.
225  */
226 static gboolean
227 read_metadata (SoupMessage *msg, const char *boundary)
228 {
229         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
230         SoupMessageIOData *io = priv->io_data;
231         SoupSocketIOStatus status;
232         guchar read_buf[RESPONSE_BLOCK_SIZE];
233         guint boundary_len = strlen (boundary);
234         gsize nread;
235         gboolean done;
236         GError *error = NULL;
237
238         do {
239                 status = soup_socket_read_until (io->sock, read_buf,
240                                                  sizeof (read_buf),
241                                                  boundary, boundary_len,
242                                                  &nread, &done, NULL, &error);
243                 switch (status) {
244                 case SOUP_SOCKET_OK:
245                         g_byte_array_append (io->read_meta_buf, read_buf, nread);
246                         break;
247
248                 case SOUP_SOCKET_ERROR:
249                 case SOUP_SOCKET_EOF:
250                         io_error (io->sock, msg, error);
251                         return FALSE;
252
253                 case SOUP_SOCKET_WOULD_BLOCK:
254                         return FALSE;
255                 }
256         } while (!done);
257
258         return TRUE;
259 }
260
261 /* Reads as much message body data as is available on io->sock (but no
262  * further than the end of the current message body or chunk). On a
263  * successful read, emits "got_chunk" (possibly multiple times), and
264  * (unless told not to) appends the chunk to io->read_body.
265  *
266  * See the note at read_metadata() for an explanation of the return
267  * value.
268  */
269 static gboolean
270 read_body_chunk (SoupMessage *msg)
271 {
272         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
273         SoupMessageIOData *io = priv->io_data;
274         SoupSocketIOStatus status;
275         guchar *stack_buf = NULL;
276         gsize len;
277         gboolean read_to_eof = (io->read_encoding == SOUP_ENCODING_EOF);
278         gsize nread;
279         GError *error = NULL;
280         SoupBuffer *buffer;
281
282         while (read_to_eof || io->read_length > 0) {
283                 if (priv->chunk_allocator) {
284                         buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
285                         if (!buffer) {
286                                 soup_message_io_pause (msg);
287                                 return FALSE;
288                         }
289                 } else {
290                         if (!stack_buf)
291                                 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
292                         buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
293                                                   stack_buf,
294                                                   RESPONSE_BLOCK_SIZE);
295                 }
296
297                 if (read_to_eof)
298                         len = buffer->length;
299                 else
300                         len = MIN (buffer->length, io->read_length);
301
302                 status = soup_socket_read (io->sock,
303                                            (guchar *)buffer->data, len,
304                                            &nread, NULL, &error);
305
306                 if (status == SOUP_SOCKET_OK && nread) {
307                         buffer->length = nread;
308                         soup_message_body_got_chunk (io->read_body, buffer);
309
310                         io->read_length -= nread;
311
312                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
313                         soup_message_got_chunk (msg, buffer);
314                         soup_buffer_free (buffer);
315                         SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
316                         continue;
317                 }
318
319                 soup_buffer_free (buffer);
320                 switch (status) {
321                 case SOUP_SOCKET_OK:
322                         break;
323
324                 case SOUP_SOCKET_EOF:
325                         if (read_to_eof)
326                                 return TRUE;
327                         /* else fall through */
328
329                 case SOUP_SOCKET_ERROR:
330                         io_error (io->sock, msg, error);
331                         return FALSE;
332
333                 case SOUP_SOCKET_WOULD_BLOCK:
334                         return FALSE;
335                 }
336         }
337
338         return TRUE;
339 }
340
341 /* Attempts to write @len bytes from @data. See the note at
342  * read_metadata() for an explanation of the return value.
343  */
344 static gboolean
345 write_data (SoupMessage *msg, const char *data, guint len, gboolean body)
346 {
347         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
348         SoupMessageIOData *io = priv->io_data;
349         SoupSocketIOStatus status;
350         gsize nwrote;
351         GError *error = NULL;
352         SoupBuffer *chunk;
353         const char *start;
354
355         while (len > io->written) {
356                 status = soup_socket_write (io->sock,
357                                             data + io->written,
358                                             len - io->written,
359                                             &nwrote, NULL, &error);
360                 switch (status) {
361                 case SOUP_SOCKET_EOF:
362                 case SOUP_SOCKET_ERROR:
363                         io_error (io->sock, msg, error);
364                         return FALSE;
365
366                 case SOUP_SOCKET_WOULD_BLOCK:
367                         return FALSE;
368
369                 case SOUP_SOCKET_OK:
370                         start = data + io->written;
371                         io->written += nwrote;
372
373                         if (body) {
374                                 if (io->write_length)
375                                         io->write_length -= nwrote;
376
377                                 chunk = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
378                                                          start, nwrote);
379                                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
380                                 soup_message_wrote_body_data (msg, chunk);
381                                 soup_buffer_free (chunk);
382                                 SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
383                         }
384                         break;
385                 }
386         }
387
388         io->written = 0;
389         return TRUE;
390 }
391
392 static inline SoupMessageIOState
393 io_body_state (SoupEncoding encoding)
394 {
395         if (encoding == SOUP_ENCODING_CHUNKED)
396                 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
397         else
398                 return SOUP_MESSAGE_IO_STATE_BODY;
399 }
400
401 /*
402  * There are two request/response formats: the basic request/response,
403  * possibly with one or more unsolicited informational responses (such
404  * as the WebDAV "102 Processing" response):
405  *
406  *     Client                            Server
407  *      W:HEADERS  / R:NOT_STARTED    ->  R:HEADERS  / W:NOT_STARTED
408  *      W:BODY     / R:NOT_STARTED    ->  R:BODY     / W:NOT_STARTED
409  *     [W:DONE     / R:HEADERS (1xx)  <-  R:DONE     / W:HEADERS (1xx) ...]
410  *      W:DONE     / R:HEADERS        <-  R:DONE     / W:HEADERS
411  *      W:DONE     / R:BODY           <-  R:DONE     / W:BODY
412  *      W:DONE     / R:DONE               R:DONE     / W:DONE
413  *     
414  * and the "Expect: 100-continue" request/response, with the client
415  * blocking halfway through its request, and then either continuing or
416  * aborting, depending on the server response:
417  *
418  *     Client                            Server
419  *      W:HEADERS  / R:NOT_STARTED    ->  R:HEADERS  / W:NOT_STARTED
420  *      W:BLOCKING / R:HEADERS        <-  R:BLOCKING / W:HEADERS
421  *     [W:BODY     / R:BLOCKING       ->  R:BODY     / W:BLOCKING]
422  *     [W:DONE     / R:HEADERS        <-  R:DONE     / W:HEADERS]
423  *      W:DONE     / R:BODY           <-  R:DONE     / W:BODY
424  *      W:DONE     / R:DONE               R:DONE     / W:DONE
425  */
426
427 static void
428 io_write (SoupSocket *sock, SoupMessage *msg)
429 {
430         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
431         SoupMessageIOData *io = priv->io_data;
432
433  write_more:
434         switch (io->write_state) {
435         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
436                 return;
437
438
439         case SOUP_MESSAGE_IO_STATE_HEADERS:
440                 if (!io->write_buf->len) {
441                         io->get_headers_cb (msg, io->write_buf,
442                                             &io->write_encoding,
443                                             io->user_data);
444                         if (!io->write_buf->len) {
445                                 soup_message_io_pause (msg);
446                                 return;
447                         }
448                 }
449
450                 if (!write_data (msg, io->write_buf->str,
451                                  io->write_buf->len, FALSE))
452                         return;
453
454                 g_string_truncate (io->write_buf, 0);
455
456                 if (io->write_encoding != SOUP_ENCODING_CHUNKED) {
457                         SoupMessageHeaders *hdrs =
458                                 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
459                                 msg->request_headers : msg->response_headers;
460                         io->write_length = soup_message_headers_get_content_length (hdrs);
461                 }
462
463                 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
464                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
465                         if (msg->status_code == SOUP_STATUS_CONTINUE) {
466                                 /* Stop and wait for the body now */
467                                 io->write_state =
468                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
469                                 io->read_state = io_body_state (io->read_encoding);
470                         } else {
471                                 /* We just wrote a 1xx response
472                                  * header, so stay in STATE_HEADERS.
473                                  * (The caller will pause us from the
474                                  * wrote_informational callback if he
475                                  * is not ready to send the final
476                                  * response.)
477                                  */
478                         }
479                 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
480                            soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
481                         /* Need to wait for the Continue response */
482                         io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
483                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
484                 } else {
485                         io->write_state = io_body_state (io->write_encoding);
486
487                         /* If the client was waiting for a Continue
488                          * but we sent something else, then they're
489                          * now done writing.
490                          */
491                         if (io->mode == SOUP_MESSAGE_IO_SERVER &&
492                             io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
493                                 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
494                 }
495
496                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
497                 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
498                         soup_message_wrote_informational (msg);
499                         soup_message_cleanup_response (msg);
500                 } else
501                         soup_message_wrote_headers (msg);
502                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
503                 break;
504
505
506         case SOUP_MESSAGE_IO_STATE_BLOCKING:
507                 io_read (sock, msg);
508
509                 /* If io_read reached a point where we could write
510                  * again, it would have recursively called io_write.
511                  * So (a) we don't need to try to keep writing, and
512                  * (b) we can't anyway, because msg may have been
513                  * destroyed.
514                  */
515                 return;
516
517
518         case SOUP_MESSAGE_IO_STATE_BODY:
519                 if (!io->write_length) {
520                         io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
521
522                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
523                         soup_message_wrote_body (msg);
524                         SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
525                         break;
526                 }
527
528                 if (!io->write_chunk) {
529                         io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
530                         if (!io->write_chunk) {
531                                 soup_message_io_pause (msg);
532                                 return;
533                         }
534                         if (io->write_chunk->length > io->write_length) {
535                                 /* App is trying to write more than it
536                                  * claimed it would; we have to truncate.
537                                  */
538                                 SoupBuffer *truncated =
539                                         soup_buffer_new_subbuffer (io->write_chunk,
540                                                                    0, io->write_length);
541                                 soup_buffer_free (io->write_chunk);
542                                 io->write_chunk = truncated;
543                         }
544                 }
545
546                 if (!write_data (msg, io->write_chunk->data,
547                                  io->write_chunk->length, TRUE))
548                         return;
549
550                 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
551                 soup_buffer_free (io->write_chunk);
552                 io->write_body_offset += io->write_chunk->length;
553                 io->write_chunk = NULL;
554
555                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
556                 soup_message_wrote_chunk (msg);
557                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
558                 break;
559
560         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
561                 if (!io->write_chunk) {
562                         io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
563                         if (!io->write_chunk) {
564                                 soup_message_io_pause (msg);
565                                 return;
566                         }
567                         g_string_append_printf (io->write_buf, "%lx\r\n",
568                                                 (unsigned long) io->write_chunk->length);
569                         io->write_body_offset += io->write_chunk->length;
570                 }
571
572                 if (!write_data (msg, io->write_buf->str,
573                                  io->write_buf->len, FALSE))
574                         return;
575
576                 g_string_truncate (io->write_buf, 0);
577
578                 if (io->write_chunk->length == 0) {
579                         /* The last chunk has no CHUNK_END... */
580                         io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
581                         break;
582                 }
583
584                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
585                 /* fall through */
586
587
588         case SOUP_MESSAGE_IO_STATE_CHUNK:
589                 if (!write_data (msg, io->write_chunk->data,
590                                  io->write_chunk->length, TRUE))
591                         return;
592
593                 soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
594                 soup_buffer_free (io->write_chunk);
595                 io->write_chunk = NULL;
596
597                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
598
599                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
600                 soup_message_wrote_chunk (msg);
601                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
602
603                 /* fall through */
604
605
606         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
607                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
608                                  SOUP_MESSAGE_IO_EOL_LEN, FALSE))
609                         return;
610
611                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
612                 break;
613
614
615         case SOUP_MESSAGE_IO_STATE_TRAILERS:
616                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
617                                  SOUP_MESSAGE_IO_EOL_LEN, FALSE))
618                         return;
619
620                 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
621
622                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
623                 soup_message_wrote_body (msg);
624                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
625                 /* fall through */
626
627
628         case SOUP_MESSAGE_IO_STATE_FINISHING:
629                 if (io->write_tag) {
630                         g_signal_handler_disconnect (io->sock, io->write_tag);
631                         io->write_tag = 0;
632                 }
633                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
634
635                 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
636                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
637                         io_read (sock, msg);
638                 } else
639                         soup_message_io_finished (msg);
640                 return;
641
642
643         case SOUP_MESSAGE_IO_STATE_DONE:
644         default:
645                 g_return_if_reached ();
646         }
647
648         goto write_more;
649 }
650
651 static void
652 io_read (SoupSocket *sock, SoupMessage *msg)
653 {
654         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
655         SoupMessageIOData *io = priv->io_data;
656         guint status;
657
658  read_more:
659         switch (io->read_state) {
660         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
661                 return;
662
663
664         case SOUP_MESSAGE_IO_STATE_HEADERS:
665                 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
666                         return;
667
668                 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
669                 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
670                 status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
671                                                io->read_meta_buf->len,
672                                                &io->read_encoding,
673                                                io->user_data);
674                 g_byte_array_set_size (io->read_meta_buf, 0);
675
676                 if (status != SOUP_STATUS_OK) {
677                         /* Either we couldn't parse the headers, or they
678                          * indicated something that would mean we wouldn't
679                          * be able to parse the body. (Eg, unknown
680                          * Transfer-Encoding.). Skip the rest of the
681                          * reading, and make sure the connection gets
682                          * closed when we're done.
683                          */
684                         soup_message_set_status (msg, status);
685                         soup_message_headers_append (msg->request_headers,
686                                                      "Connection", "close");
687                         io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
688                         break;
689                 }
690
691                 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
692                         SoupMessageHeaders *hdrs =
693                                 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
694                                 msg->response_headers : msg->request_headers;
695                         io->read_length = soup_message_headers_get_content_length (hdrs);
696                 }
697
698                 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
699                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
700                         if (msg->status_code == SOUP_STATUS_CONTINUE &&
701                             io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
702                                 /* Pause the reader, unpause the writer */
703                                 io->read_state =
704                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
705                                 io->write_state =
706                                         io_body_state (io->write_encoding);
707                         } else {
708                                 /* Just stay in HEADERS */
709                                 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
710                         }
711                 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
712                            soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
713                         /* The client requested a Continue response. The
714                          * got_headers handler may change this to something
715                          * else though.
716                          */
717                         soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
718                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
719                         io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
720                 } else {
721                         io->read_state = io_body_state (io->read_encoding);
722
723                         /* If the client was waiting for a Continue
724                          * but got something else, then it's done
725                          * writing.
726                          */
727                         if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
728                             io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
729                                 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
730                 }
731
732                 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
733                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
734                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
735                         soup_message_got_informational (msg);
736                         soup_message_cleanup_response (msg);
737                         SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
738                 } else {
739                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
740                         soup_message_got_headers (msg);
741                         SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
742                 }
743                 break;
744
745
746         case SOUP_MESSAGE_IO_STATE_BLOCKING:
747                 io_write (sock, msg);
748
749                 /* As in the io_write case, we *must* return here. */
750                 return;
751
752
753         case SOUP_MESSAGE_IO_STATE_BODY:
754                 if (!read_body_chunk (msg))
755                         return;
756
757         got_body:
758                 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
759
760                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
761                 soup_message_got_body (msg);
762                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
763                 break;
764
765
766         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
767                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
768                         return;
769
770                 io->read_length = strtoul ((char *)io->read_meta_buf->data, NULL, 16);
771                 g_byte_array_set_size (io->read_meta_buf, 0);
772
773                 if (io->read_length > 0)
774                         io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
775                 else
776                         io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
777                 break;
778
779
780         case SOUP_MESSAGE_IO_STATE_CHUNK:
781                 if (!read_body_chunk (msg))
782                         return;
783
784                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
785                 break;
786
787
788         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
789                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
790                         return;
791
792                 g_byte_array_set_size (io->read_meta_buf, 0);
793                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
794                 break;
795
796
797         case SOUP_MESSAGE_IO_STATE_TRAILERS:
798                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
799                         return;
800
801                 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
802                         goto got_body;
803
804                 /* FIXME: process trailers */
805                 g_byte_array_set_size (io->read_meta_buf, 0);
806                 break;
807
808
809         case SOUP_MESSAGE_IO_STATE_FINISHING:
810                 if (io->read_tag) {
811                         g_signal_handler_disconnect (io->sock, io->read_tag);
812                         io->read_tag = 0;
813                 }
814                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
815
816                 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
817                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
818                         io_write (sock, msg);
819                 } else
820                         soup_message_io_finished (msg);
821                 return;
822
823
824         case SOUP_MESSAGE_IO_STATE_DONE:
825         default:
826                 g_return_if_reached ();
827         }
828
829         goto read_more;
830 }
831
832 static SoupMessageIOData *
833 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
834              SoupMessageGetHeadersFn get_headers_cb,
835              SoupMessageParseHeadersFn parse_headers_cb,
836              gpointer user_data)
837 {
838         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
839         SoupMessageIOData *io;
840
841         io = g_slice_new0 (SoupMessageIOData);
842         io->sock = g_object_ref (sock);
843         io->mode = mode;
844         io->get_headers_cb   = get_headers_cb;
845         io->parse_headers_cb = parse_headers_cb;
846         io->user_data        = user_data;
847
848         io->read_meta_buf    = g_byte_array_new ();
849         io->write_buf        = g_string_new (NULL);
850
851         io->read_tag  = g_signal_connect (io->sock, "readable",
852                                           G_CALLBACK (io_read), msg);
853         io->write_tag = g_signal_connect (io->sock, "writable",
854                                           G_CALLBACK (io_write), msg);
855         io->err_tag   = g_signal_connect (io->sock, "disconnected",
856                                           G_CALLBACK (io_disconnected), msg);
857
858         io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
859         io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
860
861         if (priv->io_data)
862                 soup_message_io_cleanup (msg);
863         priv->io_data = io;
864         return io;
865 }
866
867 void
868 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
869                         SoupConnection *conn,
870                         SoupMessageGetHeadersFn get_headers_cb,
871                         SoupMessageParseHeadersFn parse_headers_cb,
872                         gpointer user_data)
873 {
874         SoupMessageIOData *io;
875
876         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
877                           get_headers_cb, parse_headers_cb, user_data);
878
879         if (conn)
880                 io->conn = g_object_ref (conn);
881
882         io->read_body       = msg->response_body;
883         io->write_body      = msg->request_body;
884
885         io->write_state     = SOUP_MESSAGE_IO_STATE_HEADERS;
886         io_write (sock, msg);
887 }
888
889 void
890 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
891                         SoupMessageGetHeadersFn get_headers_cb,
892                         SoupMessageParseHeadersFn parse_headers_cb,
893                         gpointer user_data)
894 {
895         SoupMessageIOData *io;
896
897         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
898                           get_headers_cb, parse_headers_cb, user_data);
899
900         io->read_body       = msg->request_body;
901         io->write_body      = msg->response_body;
902
903         io->read_state      = SOUP_MESSAGE_IO_STATE_HEADERS;
904         io_read (sock, msg);
905 }
906
907 void  
908 soup_message_io_pause (SoupMessage *msg)
909 {
910         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
911         SoupMessageIOData *io = priv->io_data;
912
913         g_return_if_fail (io != NULL);
914
915         if (io->write_tag) {
916                 g_signal_handler_disconnect (io->sock, io->write_tag);
917                 io->write_tag = 0;
918         }
919         if (io->read_tag) {
920                 g_signal_handler_disconnect (io->sock, io->read_tag);
921                 io->read_tag = 0;
922         }
923
924         if (io->unpause_source) {
925                 g_source_destroy (io->unpause_source);
926                 io->unpause_source = NULL;
927         }
928 }
929
930 static gboolean
931 io_unpause_internal (gpointer msg)
932 {
933         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
934         SoupMessageIOData *io = priv->io_data;
935
936         g_return_val_if_fail (io != NULL, FALSE);
937         io->unpause_source = NULL;
938
939         if (io->write_tag || io->read_tag)
940                 return FALSE;
941
942         if (io->write_state != SOUP_MESSAGE_IO_STATE_DONE) {
943                 io->write_tag = g_signal_connect (io->sock, "writable",
944                                                   G_CALLBACK (io_write), msg);
945         }
946
947         if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE) {
948                 io->read_tag = g_signal_connect (io->sock, "readable",
949                                                  G_CALLBACK (io_read), msg);
950         }
951
952         if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
953                 io_write (io->sock, msg);
954         else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
955                 io_read (io->sock, msg);
956
957         return FALSE;
958 }
959
960 void
961 soup_message_io_unpause (SoupMessage *msg)
962 {
963         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
964         SoupMessageIOData *io = priv->io_data;
965         gboolean non_blocking;
966         GMainContext *async_context;
967
968         g_return_if_fail (io != NULL);
969
970         g_object_get (io->sock,
971                       SOUP_SOCKET_FLAG_NONBLOCKING, &non_blocking,
972                       SOUP_SOCKET_ASYNC_CONTEXT, &async_context,
973                       NULL);
974         if (non_blocking) {
975                 if (!io->unpause_source) {
976                         io->unpause_source = soup_add_completion (
977                                 async_context, io_unpause_internal, msg);
978                 }
979         } else
980                 io_unpause_internal (msg);
981         if (async_context)
982                 g_main_context_unref (async_context);
983 }
984
985 /**
986  * soup_message_io_in_progress:
987  * @msg: a #SoupMessage
988  *
989  * Tests whether or not I/O is currently in progress on @msg.
990  *
991  * Return value: whether or not I/O is currently in progress.
992  **/
993 gboolean
994 soup_message_io_in_progress (SoupMessage *msg)
995 {
996         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
997
998         return priv->io_data != NULL;
999 }