770c3c228cb126ebd99063a7b83c9f4e0950b92e
[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-message.h"
16 #include "soup-message-private.h"
17 #include "soup-socket.h"
18
19 typedef enum {
20         SOUP_MESSAGE_IO_CLIENT,
21         SOUP_MESSAGE_IO_SERVER
22 } SoupMessageIOMode;
23
24 typedef enum {
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
34 } SoupMessageIOState;
35
36 typedef struct {
37         SoupSocket           *sock;
38         SoupMessageIOMode     mode;
39
40         SoupMessageIOState    read_state;
41         SoupTransferEncoding  read_encoding;
42         GByteArray           *read_buf;
43         GByteArray           *read_meta_buf;
44         SoupDataBuffer       *read_body;
45         guint                 read_length;
46
47         SoupMessageIOState    write_state;
48         SoupTransferEncoding  write_encoding;
49         GString              *write_buf;
50         SoupDataBuffer       *write_body;
51         guint                 written;
52
53         guint read_tag, write_tag, err_tag;
54
55         SoupMessageGetHeadersFn   get_headers_cb;
56         SoupMessageParseHeadersFn parse_headers_cb;
57         gpointer                  user_data;
58 } SoupMessageIOData;
59         
60
61 /* Put these around callback invocation if there is code afterward
62  * that depends on the IO having not been cancelled.
63  */
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; }
68
69 #define RESPONSE_BLOCK_SIZE 8192
70
71 void
72 soup_message_io_cancel (SoupMessage *msg)
73 {
74         SoupMessageIOData *io = msg->priv->io_data;
75
76         if (!io)
77                 return;
78
79         if (io->read_tag)
80                 g_signal_handler_disconnect (io->sock, io->read_tag);
81         if (io->write_tag)
82                 g_signal_handler_disconnect (io->sock, io->write_tag);
83         if (io->err_tag)
84                 g_signal_handler_disconnect (io->sock, io->err_tag);
85
86         if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE)
87                 soup_socket_disconnect (io->sock);
88         g_object_unref (io->sock);
89
90         if (io->read_buf)
91                 g_byte_array_free (io->read_buf, TRUE);
92         g_byte_array_free (io->read_meta_buf, TRUE);
93
94         g_string_free (io->write_buf, TRUE);
95
96         g_free (io);
97         msg->priv->io_data = NULL;
98 }
99
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
104
105 static void
106 soup_message_io_finished (SoupMessage *msg)
107 {
108         g_object_ref (msg);
109         soup_message_io_cancel (msg);
110         soup_message_finished (msg);
111         g_object_unref (msg);
112 }
113
114
115 static void
116 io_error (SoupSocket *sock, SoupMessage *msg)
117 {
118         SoupMessageIOData *io = msg->priv->io_data;
119
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);
125                 return;
126         }
127
128         soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
129         soup_message_io_finished (msg);
130 }
131
132 static gboolean
133 read_metadata (SoupMessage *msg, const char *boundary)
134 {
135         SoupMessageIOData *io = msg->priv->io_data;
136         SoupSocketIOStatus status;
137         char read_buf[RESPONSE_BLOCK_SIZE];
138         guint boundary_len = strlen (boundary), nread;
139         gboolean done;
140
141         do {
142                 status = soup_socket_read_until (io->sock, read_buf,
143                                                  sizeof (read_buf),
144                                                  boundary, boundary_len,
145                                                  &nread, &done);
146                 switch (status) {
147                 case SOUP_SOCKET_OK:
148                         g_byte_array_append (io->read_meta_buf, read_buf, nread);
149                         break;
150
151                 case SOUP_SOCKET_ERROR:
152                 case SOUP_SOCKET_EOF:
153                         io_error (io->sock, msg);
154                         return FALSE;
155
156                 case SOUP_SOCKET_WOULD_BLOCK:
157                         return FALSE;
158                 }
159         } while (!done);
160
161         return TRUE;
162 }
163
164 static gboolean
165 read_body_chunk (SoupMessage *msg)
166 {
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);
172
173         while (read_to_eof || io->read_length > 0) {
174                 if (!read_to_eof)
175                         len = MIN (len, io->read_length);
176
177                 status = soup_socket_read (io->sock, read_buf, len, &nread);
178
179                 switch (status) {
180                 case SOUP_SOCKET_OK:
181                         if (!nread)
182                                 break;
183
184                         io->read_body->owner  = SOUP_BUFFER_STATIC;
185                         io->read_body->body   = read_buf;
186                         io->read_body->length = nread;
187
188                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
189                         soup_message_got_chunk (msg);
190                         SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
191
192                         memset (io->read_body, 0, sizeof (SoupDataBuffer));
193
194                         if (io->read_buf)
195                                 g_byte_array_append (io->read_buf, read_buf, nread);
196                         io->read_length -= nread;
197                         break;
198
199                 case SOUP_SOCKET_EOF:
200                         if (read_to_eof)
201                                 return TRUE;
202                         /* else fall through */
203
204                 case SOUP_SOCKET_ERROR:
205                         io_error (io->sock, msg);
206                         return FALSE;
207
208                 case SOUP_SOCKET_WOULD_BLOCK:
209                         return FALSE;
210                 }
211         }
212
213         return TRUE;
214 }
215
216 static gboolean
217 write_data (SoupMessage *msg, const char *data, guint len)
218 {
219         SoupMessageIOData *io = msg->priv->io_data;
220         SoupSocketIOStatus status;
221         guint nwrote;
222
223         while (len > io->written) {
224                 status = soup_socket_write (io->sock,
225                                             data + io->written,
226                                             len - io->written,
227                                             &nwrote);
228                 switch (status) {
229                 case SOUP_SOCKET_EOF:
230                 case SOUP_SOCKET_ERROR:
231                         io_error (io->sock, msg);
232                         return FALSE;
233
234                 case SOUP_SOCKET_WOULD_BLOCK:
235                         return FALSE;
236
237                 case SOUP_SOCKET_OK:
238                         io->written += nwrote;
239                         break;
240                 }
241         }
242
243         io->written = 0;
244         return TRUE;
245 }
246
247 static inline SoupMessageIOState
248 io_body_state (SoupTransferEncoding encoding)
249 {
250         if (encoding == SOUP_TRANSFER_CHUNKED)
251                 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
252         else
253                 return SOUP_MESSAGE_IO_STATE_BODY;
254 }
255
256 static void io_read (SoupSocket *sock, SoupMessage *msg);
257
258 /*
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):
262  *
263  *     Client                            Server
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
270  *     
271  * and the "Expect: 100-continue" request/response, in which each
272  * writer has to pause and wait for the other at some point:
273  *
274  *     Client                            Server
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
281  */
282
283 static void
284 io_write (SoupSocket *sock, SoupMessage *msg)
285 {
286         SoupMessageIOData *io = msg->priv->io_data;
287
288  write_more:
289         switch (io->write_state) {
290         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
291                 return;
292
293
294         case SOUP_MESSAGE_IO_STATE_HEADERS:
295                 if (!io->write_buf->len) {
296                         io->get_headers_cb (msg, io->write_buf,
297                                             &io->write_encoding,
298                                             io->user_data);
299                         if (!io->write_buf->len) {
300                                 soup_message_io_pause (msg);
301                                 return;
302                         }
303                 }
304
305                 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
306                         return;
307
308                 g_string_truncate (io->write_buf, 0);
309
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 */
314                                 io->write_state =
315                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
316                         } else {
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
322                                  * response.)
323                                  */
324                         }
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;
330                 } else
331                         io->write_state = io_body_state (io->write_encoding);
332
333                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
334                 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
335                         soup_message_wrote_informational (msg);
336                 else
337                         soup_message_wrote_headers (msg);
338                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
339                 break;
340
341
342         case SOUP_MESSAGE_IO_STATE_BLOCKING:
343                 io_read (sock, msg);
344
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
349                  * destroyed.
350                  */
351                 return;
352
353
354         case SOUP_MESSAGE_IO_STATE_BODY:
355                 if (!write_data (msg, io->write_body->body,
356                                  io->write_body->length))
357                         return;
358
359                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
360
361                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
362                 soup_message_wrote_body (msg);
363                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
364                 break;
365
366
367         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
368                 if (!io->write_buf->len) {
369                         SoupDataBuffer *chunk;
370
371                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
372                         chunk = soup_message_pop_chunk (msg);
373                         SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
374
375                         if (!chunk) {
376                                 soup_message_io_pause (msg);
377                                 return;
378                         }
379                         memcpy (io->write_body, chunk, sizeof (SoupDataBuffer));
380                         g_free (chunk);
381
382                         g_string_append_printf (io->write_buf, "%x\r\n",
383                                                 io->write_body->length);
384                 }
385
386                 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
387                         return;
388
389                 g_string_truncate (io->write_buf, 0);
390
391                 if (io->write_body->length == 0) {
392                         /* The last chunk has no CHUNK_END... */
393                         io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
394                         break;
395                 }
396
397                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
398                 /* fall through */
399
400
401         case SOUP_MESSAGE_IO_STATE_CHUNK:
402                 if (!write_data (msg, io->write_body->body,
403                                  io->write_body->length))
404                         return;
405
406                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
407
408                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
409                 soup_message_wrote_chunk (msg);
410                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
411                 /* fall through */
412
413
414         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
415                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
416                                  SOUP_MESSAGE_IO_EOL_LEN))
417                         return;
418
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));
422
423                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
424                 break;
425
426
427         case SOUP_MESSAGE_IO_STATE_TRAILERS:
428                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
429                                  SOUP_MESSAGE_IO_EOL_LEN))
430                         return;
431
432                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
433
434                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
435                 soup_message_wrote_body (msg);
436                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
437                 /* fall through */
438
439
440         case SOUP_MESSAGE_IO_STATE_DONE:
441                 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
442                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
443                         io_read (sock, msg);
444                 } else
445                         soup_message_io_finished (msg);
446                 return;
447
448
449         default:
450                 g_return_if_reached ();
451         }
452
453         goto write_more;
454 }
455
456 static void
457 io_read (SoupSocket *sock, SoupMessage *msg)
458 {
459         SoupMessageIOData *io = msg->priv->io_data;
460         guint status;
461
462  read_more:
463         switch (io->read_state) {
464         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
465                 return;
466
467
468         case SOUP_MESSAGE_IO_STATE_HEADERS:
469                 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
470                         return;
471
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,
476                                                &io->read_encoding,
477                                                &io->read_length,
478                                                io->user_data);
479                 g_byte_array_set_size (io->read_meta_buf, 0);
480
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.
488                          */
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;
493                         break;
494                 }
495
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 */
501                                 io->read_state =
502                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
503                                 io->write_state =
504                                         io_body_state (io->write_encoding);
505                         } else {
506                                 /* Just stay in HEADERS */
507                                 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
508                         }
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;
514                 } else
515                         io->read_state = io_body_state (io->read_encoding);
516
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);
521                 } else
522                         soup_message_got_headers (msg);
523                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
524                 break;
525
526
527         case SOUP_MESSAGE_IO_STATE_BLOCKING:
528                 io_write (sock, msg);
529
530                 /* As in the io_write case, we *must* return here. */
531                 return;
532
533
534         case SOUP_MESSAGE_IO_STATE_BODY:
535                 if (!read_body_chunk (msg))
536                         return;
537
538         got_body:
539                 if (io->read_buf) {
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;
543
544                         g_byte_array_free (io->read_buf, FALSE);
545                         io->read_buf = NULL;
546                 }
547
548                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
549
550                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
551                 soup_message_got_body (msg);
552                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
553                 break;
554
555
556         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
557                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
558                         return;
559
560                 io->read_length = strtoul (io->read_meta_buf->data, NULL, 16);
561                 g_byte_array_set_size (io->read_meta_buf, 0);
562
563                 if (io->read_length > 0)
564                         io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
565                 else
566                         io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
567                 break;
568
569
570         case SOUP_MESSAGE_IO_STATE_CHUNK:
571                 if (!read_body_chunk (msg))
572                         return;
573
574                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
575                 break;
576
577
578         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
579                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
580                         return;
581
582                 g_byte_array_set_size (io->read_meta_buf, 0);
583                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
584                 break;
585
586
587         case SOUP_MESSAGE_IO_STATE_TRAILERS:
588                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
589                         return;
590
591                 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
592                         goto got_body;
593
594                 /* FIXME: process trailers */
595                 g_byte_array_set_size (io->read_meta_buf, 0);
596                 break;
597
598
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);
603                 } else
604                         soup_message_io_finished (msg);
605                 return;
606
607
608         default:
609                 g_return_if_reached ();
610         }
611
612         goto read_more;
613 }
614
615 static SoupMessageIOData *
616 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
617              SoupMessageGetHeadersFn get_headers_cb,
618              SoupMessageParseHeadersFn parse_headers_cb,
619              gpointer user_data)
620 {
621         SoupMessageIOData *io;
622
623         io = g_new0 (SoupMessageIOData, 1);
624         io->sock = g_object_ref (sock);
625         io->mode = mode;
626         io->get_headers_cb   = get_headers_cb;
627         io->parse_headers_cb = parse_headers_cb;
628         io->user_data        = user_data;
629
630         io->read_encoding    = SOUP_TRANSFER_UNKNOWN;
631         io->write_encoding   = SOUP_TRANSFER_UNKNOWN;
632
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);
637
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);
644
645         io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
646         io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
647
648         msg->priv->io_data = io;
649         return io;
650 }
651
652 void
653 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
654                         SoupMessageGetHeadersFn get_headers_cb,
655                         SoupMessageParseHeadersFn parse_headers_cb,
656                         gpointer user_data)
657 {
658         SoupMessageIOData *io;
659
660         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
661                           get_headers_cb, parse_headers_cb, user_data);
662
663         io->read_body       = &msg->response;
664         io->write_body      = &msg->request;
665
666         io->write_state     = SOUP_MESSAGE_IO_STATE_HEADERS;
667         io_write (sock, msg);
668 }
669
670 void
671 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
672                         SoupMessageGetHeadersFn get_headers_cb,
673                         SoupMessageParseHeadersFn parse_headers_cb,
674                         gpointer user_data)
675 {
676         SoupMessageIOData *io;
677
678         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
679                           get_headers_cb, parse_headers_cb, user_data);
680
681         io->read_body       = &msg->request;
682         io->write_body      = &msg->response;
683
684         io->read_state      = SOUP_MESSAGE_IO_STATE_HEADERS;
685         io_read (sock, msg);
686 }
687
688 void  
689 soup_message_io_pause (SoupMessage *msg)
690 {
691         SoupMessageIOData *io = msg->priv->io_data;
692
693         g_return_if_fail (io != NULL);
694
695         if (io->write_tag) {
696                 g_signal_handler_disconnect (io->sock, io->write_tag);
697                 io->write_tag = 0;
698         }
699         if (io->read_tag) {
700                 g_signal_handler_disconnect (io->sock, io->read_tag);
701                 io->read_tag = 0;
702         }
703 }
704
705 void  
706 soup_message_io_unpause (SoupMessage *msg)
707 {
708         SoupMessageIOData *io = msg->priv->io_data;
709
710         g_return_if_fail (io != NULL);
711
712         if (io->write_tag || io->read_tag)
713                 return;
714
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);
719
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);
723         else
724                 io_read (io->sock, msg);
725 }