Call soup_message_io_stop so we don't get a callback on the io after it's
[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 static void
72 io_cleanup (SoupMessage *msg)
73 {
74         SoupMessageIOData *io = msg->priv->io_data;
75
76         if (!io)
77                 return;
78
79         soup_message_io_stop (msg);
80
81         if (io->sock)
82                 g_object_unref (io->sock);
83
84         if (io->read_buf)
85                 g_byte_array_free (io->read_buf, TRUE);
86         g_byte_array_free (io->read_meta_buf, TRUE);
87
88         g_string_free (io->write_buf, TRUE);
89
90         g_free (io);
91         msg->priv->io_data = NULL;
92 }
93
94 void
95 soup_message_io_stop (SoupMessage *msg)
96 {
97         SoupMessageIOData *io = msg->priv->io_data;
98
99         if (!io)
100                 return;
101
102         if (io->read_tag) {
103                 g_signal_handler_disconnect (io->sock, io->read_tag);
104                 io->read_tag = 0;
105         }
106         if (io->write_tag) {
107                 g_signal_handler_disconnect (io->sock, io->write_tag);
108                 io->write_tag = 0;
109         }
110         if (io->err_tag) {
111                 g_signal_handler_disconnect (io->sock, io->err_tag);
112                 io->err_tag = 0;
113         }
114
115         if (io->read_state != SOUP_MESSAGE_IO_STATE_DONE)
116                 soup_socket_disconnect (io->sock);
117 }
118
119 #define SOUP_MESSAGE_IO_EOL            "\r\n"
120 #define SOUP_MESSAGE_IO_EOL_LEN        2
121 #define SOUP_MESSAGE_IO_DOUBLE_EOL     "\r\n\r\n"
122 #define SOUP_MESSAGE_IO_DOUBLE_EOL_LEN 4
123
124 static void
125 soup_message_io_finished (SoupMessage *msg)
126 {
127         g_object_ref (msg);
128         io_cleanup (msg);
129         if (SOUP_MESSAGE_IS_STARTING (msg))
130                 soup_message_restarted (msg);
131         else
132                 soup_message_finished (msg);
133         g_object_unref (msg);
134 }
135
136
137 static void
138 io_error (SoupSocket *sock, SoupMessage *msg)
139 {
140         SoupMessageIOData *io = msg->priv->io_data;
141
142         /* Closing the connection to signify EOF is sometimes ok */
143         if (io->read_state == SOUP_MESSAGE_IO_STATE_BODY &&
144             io->read_encoding == SOUP_TRANSFER_UNKNOWN) {
145                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
146                 soup_message_io_finished (msg);
147                 return;
148         }
149
150         if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
151                 soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
152         soup_message_io_finished (msg);
153 }
154
155 static gboolean
156 read_metadata (SoupMessage *msg, const char *boundary)
157 {
158         SoupMessageIOData *io = msg->priv->io_data;
159         SoupSocketIOStatus status;
160         char read_buf[RESPONSE_BLOCK_SIZE];
161         guint boundary_len = strlen (boundary), nread;
162         gboolean done;
163
164         do {
165                 status = soup_socket_read_until (io->sock, read_buf,
166                                                  sizeof (read_buf),
167                                                  boundary, boundary_len,
168                                                  &nread, &done);
169                 switch (status) {
170                 case SOUP_SOCKET_OK:
171                         g_byte_array_append (io->read_meta_buf, read_buf, nread);
172                         break;
173
174                 case SOUP_SOCKET_ERROR:
175                 case SOUP_SOCKET_EOF:
176                         io_error (io->sock, msg);
177                         return FALSE;
178
179                 case SOUP_SOCKET_WOULD_BLOCK:
180                         return FALSE;
181                 }
182         } while (!done);
183
184         return TRUE;
185 }
186
187 static gboolean
188 read_body_chunk (SoupMessage *msg)
189 {
190         SoupMessageIOData *io = msg->priv->io_data;
191         SoupSocketIOStatus status;
192         char read_buf[RESPONSE_BLOCK_SIZE];
193         guint nread, len = sizeof (read_buf);
194         gboolean read_to_eof = (io->read_encoding == SOUP_TRANSFER_UNKNOWN);
195
196         while (read_to_eof || io->read_length > 0) {
197                 if (!read_to_eof)
198                         len = MIN (len, io->read_length);
199
200                 status = soup_socket_read (io->sock, read_buf, len, &nread);
201
202                 switch (status) {
203                 case SOUP_SOCKET_OK:
204                         if (!nread)
205                                 break;
206
207                         io->read_body->owner  = SOUP_BUFFER_STATIC;
208                         io->read_body->body   = read_buf;
209                         io->read_body->length = nread;
210
211                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
212                         soup_message_got_chunk (msg);
213                         SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
214
215                         memset (io->read_body, 0, sizeof (SoupDataBuffer));
216
217                         if (io->read_buf)
218                                 g_byte_array_append (io->read_buf, read_buf, nread);
219                         io->read_length -= nread;
220                         break;
221
222                 case SOUP_SOCKET_EOF:
223                         if (read_to_eof)
224                                 return TRUE;
225                         /* else fall through */
226
227                 case SOUP_SOCKET_ERROR:
228                         io_error (io->sock, msg);
229                         return FALSE;
230
231                 case SOUP_SOCKET_WOULD_BLOCK:
232                         return FALSE;
233                 }
234         }
235
236         return TRUE;
237 }
238
239 static gboolean
240 write_data (SoupMessage *msg, const char *data, guint len)
241 {
242         SoupMessageIOData *io = msg->priv->io_data;
243         SoupSocketIOStatus status;
244         guint nwrote;
245
246         while (len > io->written) {
247                 status = soup_socket_write (io->sock,
248                                             data + io->written,
249                                             len - io->written,
250                                             &nwrote);
251                 switch (status) {
252                 case SOUP_SOCKET_EOF:
253                 case SOUP_SOCKET_ERROR:
254                         io_error (io->sock, msg);
255                         return FALSE;
256
257                 case SOUP_SOCKET_WOULD_BLOCK:
258                         return FALSE;
259
260                 case SOUP_SOCKET_OK:
261                         io->written += nwrote;
262                         break;
263                 }
264         }
265
266         io->written = 0;
267         return TRUE;
268 }
269
270 static inline SoupMessageIOState
271 io_body_state (SoupTransferEncoding encoding)
272 {
273         if (encoding == SOUP_TRANSFER_CHUNKED)
274                 return SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
275         else
276                 return SOUP_MESSAGE_IO_STATE_BODY;
277 }
278
279 static void io_read (SoupSocket *sock, SoupMessage *msg);
280
281 /*
282  * There are two request/response formats: the basic request/response,
283  * possibly with one or more unsolicited informational responses (such
284  * as the WebDAV "102 Processing" response):
285  *
286  *     Client                            Server
287  *      W:HEADERS  / R:NOT_STARTED    ->  R:HEADERS  / W:NOT_STARTED
288  *      W:BODY     / R:NOT_STARTED    ->  R:BODY     / W:NOT_STARTED
289  *     [W:DONE     / R:HEADERS (1xx)  <-  R:DONE     / W:HEADERS (1xx) ...]
290  *      W:DONE     / R:HEADERS        <-  R:DONE     / W:HEADERS
291  *      W:DONE     / R:BODY           <-  R:DONE     / W:BODY
292  *      W:DONE     / R:DONE               R:DONE     / W:DONE
293  *     
294  * and the "Expect: 100-continue" request/response, in which each
295  * writer has to pause and wait for the other at some point:
296  *
297  *     Client                            Server
298  *      W:HEADERS  / R:NOT_STARTED    ->  R:HEADERS  / W:NOT_STARTED
299  *      W:BLOCKING / R:HEADERS (100)  <-  R:BLOCKING / W:HEADERS (100)
300  *      W:BODY     / R:BLOCKING       ->  R:BODY     / W:BLOCKING
301  *      W:DONE     / R:HEADERS        <-  R:DONE     / W:HEADERS
302  *      W:DONE     / R:BODY           <-  R:DONE     / W:BODY
303  *      W:DONE     / R:DONE               R:DONE     / W:DONE
304  */
305
306 static void
307 io_write (SoupSocket *sock, SoupMessage *msg)
308 {
309         SoupMessageIOData *io = msg->priv->io_data;
310
311  write_more:
312         switch (io->write_state) {
313         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
314                 return;
315
316
317         case SOUP_MESSAGE_IO_STATE_HEADERS:
318                 if (!io->write_buf->len) {
319                         io->get_headers_cb (msg, io->write_buf,
320                                             &io->write_encoding,
321                                             io->user_data);
322                         if (!io->write_buf->len) {
323                                 soup_message_io_pause (msg);
324                                 return;
325                         }
326                 }
327
328                 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
329                         return;
330
331                 g_string_truncate (io->write_buf, 0);
332
333                 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
334                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
335                         if (msg->status_code == SOUP_STATUS_CONTINUE) {
336                                 /* Stop and wait for the body now */
337                                 io->write_state =
338                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
339                         } else {
340                                 /* We just wrote a 1xx response
341                                  * header, so stay in STATE_HEADERS.
342                                  * (The caller will pause us from the
343                                  * wrote_informational callback if he
344                                  * is not ready to send the final
345                                  * response.)
346                                  */
347                         }
348                 } else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
349                            msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE) {
350                         /* Need to wait for the Continue response */
351                         io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
352                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
353                 } else
354                         io->write_state = io_body_state (io->write_encoding);
355
356                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
357                 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code))
358                         soup_message_wrote_informational (msg);
359                 else
360                         soup_message_wrote_headers (msg);
361                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
362                 break;
363
364
365         case SOUP_MESSAGE_IO_STATE_BLOCKING:
366                 io_read (sock, msg);
367
368                 /* If io_read reached a point where we could write
369                  * again, it would have recursively called io_write.
370                  * So (a) we don't need to try to keep writing, and
371                  * (b) we can't anyway, because msg may have been
372                  * destroyed.
373                  */
374                 return;
375
376
377         case SOUP_MESSAGE_IO_STATE_BODY:
378                 if (!write_data (msg, io->write_body->body,
379                                  io->write_body->length))
380                         return;
381
382                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
383
384                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
385                 soup_message_wrote_body (msg);
386                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
387                 break;
388
389
390         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
391                 if (!io->write_buf->len) {
392                         SoupDataBuffer *chunk;
393
394                         SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
395                         chunk = soup_message_pop_chunk (msg);
396                         SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
397
398                         if (!chunk) {
399                                 soup_message_io_pause (msg);
400                                 return;
401                         }
402                         memcpy (io->write_body, chunk, sizeof (SoupDataBuffer));
403                         g_free (chunk);
404
405                         g_string_append_printf (io->write_buf, "%x\r\n",
406                                                 io->write_body->length);
407                 }
408
409                 if (!write_data (msg, io->write_buf->str, io->write_buf->len))
410                         return;
411
412                 g_string_truncate (io->write_buf, 0);
413
414                 if (io->write_body->length == 0) {
415                         /* The last chunk has no CHUNK_END... */
416                         io->write_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
417                         break;
418                 }
419
420                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK;
421                 /* fall through */
422
423
424         case SOUP_MESSAGE_IO_STATE_CHUNK:
425                 if (!write_data (msg, io->write_body->body,
426                                  io->write_body->length))
427                         return;
428
429                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
430
431                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
432                 soup_message_wrote_chunk (msg);
433                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
434                 /* fall through */
435
436
437         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
438                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
439                                  SOUP_MESSAGE_IO_EOL_LEN))
440                         return;
441
442                 if (io->write_body->owner == SOUP_BUFFER_SYSTEM_OWNED)
443                         g_free (io->write_body->body);
444                 memset (io->write_body, 0, sizeof (SoupDataBuffer));
445
446                 io->write_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
447                 break;
448
449
450         case SOUP_MESSAGE_IO_STATE_TRAILERS:
451                 if (!write_data (msg, SOUP_MESSAGE_IO_EOL,
452                                  SOUP_MESSAGE_IO_EOL_LEN))
453                         return;
454
455                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
456
457                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
458                 soup_message_wrote_body (msg);
459                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
460                 /* fall through */
461
462
463         case SOUP_MESSAGE_IO_STATE_DONE:
464                 if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
465                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
466                         io_read (sock, msg);
467                 } else
468                         soup_message_io_finished (msg);
469                 return;
470
471
472         default:
473                 g_return_if_reached ();
474         }
475
476         goto write_more;
477 }
478
479 static void
480 io_read (SoupSocket *sock, SoupMessage *msg)
481 {
482         SoupMessageIOData *io = msg->priv->io_data;
483         guint status;
484
485  read_more:
486         switch (io->read_state) {
487         case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
488                 return;
489
490
491         case SOUP_MESSAGE_IO_STATE_HEADERS:
492                 if (!read_metadata (msg, SOUP_MESSAGE_IO_DOUBLE_EOL))
493                         return;
494
495                 io->read_meta_buf->len -= SOUP_MESSAGE_IO_EOL_LEN;
496                 io->read_meta_buf->data[io->read_meta_buf->len] = '\0';
497                 status = io->parse_headers_cb (msg, io->read_meta_buf->data,
498                                                io->read_meta_buf->len,
499                                                &io->read_encoding,
500                                                &io->read_length,
501                                                io->user_data);
502                 g_byte_array_set_size (io->read_meta_buf, 0);
503
504                 if (status != SOUP_STATUS_OK) {
505                         /* Either we couldn't parse the headers, or they
506                          * indicated something that would mean we wouldn't
507                          * be able to parse the body. (Eg, unknown
508                          * Transfer-Encoding.). Skip the rest of the
509                          * reading, and make sure the connection gets
510                          * closed when we're done.
511                          */
512                         soup_message_set_status (msg, status);
513                         soup_message_add_header (msg->request_headers,
514                                                  "Connection", "close");
515                         io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
516                         break;
517                 }
518
519                 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
520                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
521                         if (msg->status_code == SOUP_STATUS_CONTINUE &&
522                             io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
523                                 /* Pause the reader, unpause the writer */
524                                 io->read_state =
525                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
526                                 io->write_state =
527                                         io_body_state (io->write_encoding);
528                         } else {
529                                 /* Just stay in HEADERS */
530                                 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
531                         }
532                 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
533                            (msg->priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
534                         /* The client requested a Continue response. */
535                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
536                         io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
537                 } else
538                         io->read_state = io_body_state (io->read_encoding);
539
540                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
541                 if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
542                         soup_message_got_informational (msg);
543                         soup_message_cleanup_response (msg);
544                 } else
545                         soup_message_got_headers (msg);
546                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
547                 break;
548
549
550         case SOUP_MESSAGE_IO_STATE_BLOCKING:
551                 io_write (sock, msg);
552
553                 /* As in the io_write case, we *must* return here. */
554                 return;
555
556
557         case SOUP_MESSAGE_IO_STATE_BODY:
558                 if (!read_body_chunk (msg))
559                         return;
560
561         got_body:
562                 if (io->read_buf) {
563                         io->read_body->owner = SOUP_BUFFER_SYSTEM_OWNED;
564                         io->read_body->body = io->read_buf->data;
565                         io->read_body->length = io->read_buf->len;
566
567                         g_byte_array_free (io->read_buf, FALSE);
568                         io->read_buf = NULL;
569                 }
570
571                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
572
573                 SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
574                 soup_message_got_body (msg);
575                 SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
576                 break;
577
578
579         case SOUP_MESSAGE_IO_STATE_CHUNK_SIZE:
580                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
581                         return;
582
583                 io->read_length = strtoul (io->read_meta_buf->data, NULL, 16);
584                 g_byte_array_set_size (io->read_meta_buf, 0);
585
586                 if (io->read_length > 0)
587                         io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK;
588                 else
589                         io->read_state = SOUP_MESSAGE_IO_STATE_TRAILERS;
590                 break;
591
592
593         case SOUP_MESSAGE_IO_STATE_CHUNK:
594                 if (!read_body_chunk (msg))
595                         return;
596
597                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_END;
598                 break;
599
600
601         case SOUP_MESSAGE_IO_STATE_CHUNK_END:
602                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
603                         return;
604
605                 g_byte_array_set_size (io->read_meta_buf, 0);
606                 io->read_state = SOUP_MESSAGE_IO_STATE_CHUNK_SIZE;
607                 break;
608
609
610         case SOUP_MESSAGE_IO_STATE_TRAILERS:
611                 if (!read_metadata (msg, SOUP_MESSAGE_IO_EOL))
612                         return;
613
614                 if (io->read_meta_buf->len == SOUP_MESSAGE_IO_EOL_LEN)
615                         goto got_body;
616
617                 /* FIXME: process trailers */
618                 g_byte_array_set_size (io->read_meta_buf, 0);
619                 break;
620
621
622         case SOUP_MESSAGE_IO_STATE_DONE:
623                 if (io->mode == SOUP_MESSAGE_IO_SERVER) {
624                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
625                         io_write (sock, msg);
626                 } else
627                         soup_message_io_finished (msg);
628                 return;
629
630
631         default:
632                 g_return_if_reached ();
633         }
634
635         goto read_more;
636 }
637
638 static SoupMessageIOData *
639 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
640              SoupMessageGetHeadersFn get_headers_cb,
641              SoupMessageParseHeadersFn parse_headers_cb,
642              gpointer user_data)
643 {
644         SoupMessageIOData *io;
645
646         io = g_new0 (SoupMessageIOData, 1);
647         io->sock = g_object_ref (sock);
648         io->mode = mode;
649         io->get_headers_cb   = get_headers_cb;
650         io->parse_headers_cb = parse_headers_cb;
651         io->user_data        = user_data;
652
653         io->read_encoding    = SOUP_TRANSFER_UNKNOWN;
654         io->write_encoding   = SOUP_TRANSFER_UNKNOWN;
655
656         io->read_meta_buf    = g_byte_array_new ();
657         if (!(msg->priv->msg_flags & SOUP_MESSAGE_OVERWRITE_CHUNKS))
658                 io->read_buf = g_byte_array_new ();
659         io->write_buf        = g_string_new (NULL);
660
661         io->read_tag  = g_signal_connect (io->sock, "readable",
662                                           G_CALLBACK (io_read), msg);
663         io->write_tag = g_signal_connect (io->sock, "writable",
664                                           G_CALLBACK (io_write), msg);
665         io->err_tag   = g_signal_connect (io->sock, "disconnected",
666                                           G_CALLBACK (io_error), msg);
667
668         io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
669         io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
670
671         if (msg->priv->io_data)
672                 io_cleanup (msg);
673         msg->priv->io_data = io;
674         return io;
675 }
676
677 void
678 soup_message_io_client (SoupMessage *msg, SoupSocket *sock,
679                         SoupMessageGetHeadersFn get_headers_cb,
680                         SoupMessageParseHeadersFn parse_headers_cb,
681                         gpointer user_data)
682 {
683         SoupMessageIOData *io;
684
685         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
686                           get_headers_cb, parse_headers_cb, user_data);
687
688         io->read_body       = &msg->response;
689         io->write_body      = &msg->request;
690
691         io->write_state     = SOUP_MESSAGE_IO_STATE_HEADERS;
692         io_write (sock, msg);
693 }
694
695 void
696 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
697                         SoupMessageGetHeadersFn get_headers_cb,
698                         SoupMessageParseHeadersFn parse_headers_cb,
699                         gpointer user_data)
700 {
701         SoupMessageIOData *io;
702
703         io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
704                           get_headers_cb, parse_headers_cb, user_data);
705
706         io->read_body       = &msg->request;
707         io->write_body      = &msg->response;
708
709         io->read_state      = SOUP_MESSAGE_IO_STATE_HEADERS;
710         io_read (sock, msg);
711 }
712
713 void  
714 soup_message_io_pause (SoupMessage *msg)
715 {
716         SoupMessageIOData *io = msg->priv->io_data;
717
718         g_return_if_fail (io != NULL);
719
720         if (io->write_tag) {
721                 g_signal_handler_disconnect (io->sock, io->write_tag);
722                 io->write_tag = 0;
723         }
724         if (io->read_tag) {
725                 g_signal_handler_disconnect (io->sock, io->read_tag);
726                 io->read_tag = 0;
727         }
728 }
729
730 void  
731 soup_message_io_unpause (SoupMessage *msg)
732 {
733         SoupMessageIOData *io = msg->priv->io_data;
734
735         g_return_if_fail (io != NULL);
736
737         if (io->write_tag || io->read_tag)
738                 return;
739
740         io->write_tag = g_signal_connect (io->sock, "writable",
741                                           G_CALLBACK (io_write), msg);
742         io->read_tag = g_signal_connect (io->sock, "readable",
743                                          G_CALLBACK (io_read), msg);
744
745         if (io->write_state != SOUP_MESSAGE_IO_STATE_NOT_STARTED &&
746             io->write_state != SOUP_MESSAGE_IO_STATE_BLOCKING)
747                 io_write (io->sock, msg);
748         else
749                 io_read (io->sock, msg);
750 }