Remove build warning
[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 <glib/gi18n-lib.h>
13
14 #include "soup.h"
15 #include "soup-body-input-stream.h"
16 #include "soup-body-output-stream.h"
17 #include "soup-client-input-stream.h"
18 #include "soup-connection.h"
19 #include "soup-content-processor.h"
20 #include "soup-content-sniffer-stream.h"
21 #include "soup-filter-input-stream.h"
22 #include "soup-message-private.h"
23 #include "soup-message-queue.h"
24 #include "soup-misc-private.h"
25 #include "TIZEN.h"
26
27 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
28 #include <sys/prctl.h>
29 #include <stdio.h>
30 #ifndef PR_TASK_PERF_USER_TRACE
31 #define PR_TASK_PERF_USER_TRACE 666
32 #endif
33
34 #define MAX_STRING_LEN 256
35
36 static void prctl_with_url(const char *prestr, const char *url)
37 {
38         char s[MAX_STRING_LEN] = "";
39         int len_max = 120;
40         int len_pre = strlen(prestr);
41         int len_url = strlen(url);
42
43         strncpy(s, prestr, len_pre);
44         if(len_pre + len_url < len_max) {
45                 strncpy(s+len_pre, url, len_url);
46         }
47         else {
48                 int len_part = len_max - len_pre - 10;
49                 strncpy(s+len_pre, url, len_part);
50                 strncpy(s+len_pre+len_part, "...", MAX_STRING_LEN-len_pre-len_part-1);
51                 strncpy(s+len_pre+len_part+3, url+len_url-7, 7);
52         }
53         prctl(PR_TASK_PERF_USER_TRACE, s, strlen(s));
54 }
55
56 static void prctl_with_url_and_free(const char *prestr, char *url)
57 {
58         prctl_with_url(prestr, url);
59         g_free(url);
60 }
61 #endif
62
63 typedef enum {
64         SOUP_MESSAGE_IO_CLIENT,
65         SOUP_MESSAGE_IO_SERVER
66 } SoupMessageIOMode;
67
68 typedef enum {
69         SOUP_MESSAGE_IO_STATE_NOT_STARTED,
70         SOUP_MESSAGE_IO_STATE_ANY = SOUP_MESSAGE_IO_STATE_NOT_STARTED,
71         SOUP_MESSAGE_IO_STATE_HEADERS,
72         SOUP_MESSAGE_IO_STATE_BLOCKING,
73         SOUP_MESSAGE_IO_STATE_BODY_START,
74         SOUP_MESSAGE_IO_STATE_BODY,
75         SOUP_MESSAGE_IO_STATE_BODY_DATA,
76         SOUP_MESSAGE_IO_STATE_BODY_DONE,
77         SOUP_MESSAGE_IO_STATE_FINISHING,
78         SOUP_MESSAGE_IO_STATE_DONE
79 } SoupMessageIOState;
80
81 #define SOUP_MESSAGE_IO_STATE_ACTIVE(state) \
82         (state != SOUP_MESSAGE_IO_STATE_NOT_STARTED && \
83          state != SOUP_MESSAGE_IO_STATE_BLOCKING && \
84          state != SOUP_MESSAGE_IO_STATE_DONE)
85 #define SOUP_MESSAGE_IO_STATE_POLLABLE(state) \
86         (SOUP_MESSAGE_IO_STATE_ACTIVE (state) && \
87          state != SOUP_MESSAGE_IO_STATE_BODY_DONE)
88
89 typedef struct {
90         SoupMessageQueueItem *item;
91         SoupMessageIOMode     mode;
92         GCancellable         *cancellable;
93
94         GIOStream              *iostream;
95         SoupFilterInputStream  *istream;
96         GInputStream           *body_istream;
97         GOutputStream          *ostream;
98         GOutputStream          *body_ostream;
99         GMainContext           *async_context;
100
101         SoupMessageIOState    read_state;
102         SoupEncoding          read_encoding;
103         GByteArray           *read_header_buf;
104         SoupMessageBody      *read_body;
105         goffset               read_length;
106
107         SoupMessageIOState    write_state;
108         SoupEncoding          write_encoding;
109         GString              *write_buf;
110         SoupMessageBody      *write_body;
111         SoupBuffer           *write_chunk;
112         goffset               write_body_offset;
113         goffset               write_length;
114         goffset               written;
115
116         GSource *io_source;
117         GSource *unpause_source;
118         gboolean paused;
119
120         SoupMessageGetHeadersFn   get_headers_cb;
121         SoupMessageParseHeadersFn parse_headers_cb;
122         gpointer                  header_data;
123         SoupMessageCompletionFn   completion_cb;
124         gpointer                  completion_data;
125 } SoupMessageIOData;
126         
127 #if ENABLE(TIZEN_USE_EXPANDED_RESPONSE_BLOCK)
128 #define RESPONSE_BLOCK_SIZE 32768
129 #else
130 #define RESPONSE_BLOCK_SIZE 8192
131 #endif
132
133 void
134 soup_message_io_cleanup (SoupMessage *msg)
135 {
136         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
137         SoupMessageIOData *io;
138
139         soup_message_io_stop (msg);
140
141         io = priv->io_data;
142         if (!io)
143                 return;
144         priv->io_data = NULL;
145
146         if (io->iostream)
147                 g_object_unref (io->iostream);
148         if (io->body_istream)
149                 g_object_unref (io->body_istream);
150         if (io->body_ostream)
151                 g_object_unref (io->body_ostream);
152         if (io->async_context)
153                 g_main_context_unref (io->async_context);
154         if (io->item)
155                 soup_message_queue_item_unref (io->item);
156
157         g_byte_array_free (io->read_header_buf, TRUE);
158
159         g_string_free (io->write_buf, TRUE);
160         if (io->write_chunk)
161                 soup_buffer_free (io->write_chunk);
162
163         g_slice_free (SoupMessageIOData, io);
164 }
165
166 void
167 soup_message_io_stop (SoupMessage *msg)
168 {
169         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
170         SoupMessageIOData *io = priv->io_data;
171
172         if (!io)
173                 return;
174
175         if (io->io_source) {
176                 g_source_destroy (io->io_source);
177                 g_source_unref (io->io_source);
178                 io->io_source = NULL;
179         }
180
181         if (io->unpause_source) {
182                 g_source_destroy (io->unpause_source);
183                 g_source_unref (io->unpause_source);
184                 io->unpause_source = NULL;
185         }
186
187         if (io->mode == SOUP_MESSAGE_IO_SERVER) {
188                 if (io->write_state < SOUP_MESSAGE_IO_STATE_FINISHING)
189                         g_io_stream_close (io->iostream, NULL, NULL);
190         }
191 }
192
193 void
194 soup_message_io_finished (SoupMessage *msg)
195 {
196         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
197         SoupMessageIOData *io = priv->io_data;
198         SoupMessageCompletionFn completion_cb;
199         gpointer completion_data;
200
201         if (!io)
202                 return;
203
204         completion_cb = io->completion_cb;
205         completion_data = io->completion_data;
206
207         g_object_ref (msg);
208         soup_message_io_cleanup (msg);
209         if (completion_cb)
210                 completion_cb (msg, completion_data);
211         g_object_unref (msg);
212 }
213
214 static gboolean
215 read_headers (SoupMessage *msg, gboolean blocking,
216               GCancellable *cancellable, GError **error)
217 {
218         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
219         SoupMessageIOData *io = priv->io_data;
220         gssize nread, old_len;
221         gboolean got_lf;
222
223         while (1) {
224                 old_len = io->read_header_buf->len;
225                 g_byte_array_set_size (io->read_header_buf, old_len + RESPONSE_BLOCK_SIZE);
226                 nread = soup_filter_input_stream_read_line (io->istream,
227                                                             io->read_header_buf->data + old_len,
228                                                             RESPONSE_BLOCK_SIZE,
229                                                             blocking,
230                                                             &got_lf,
231                                                             cancellable, error);
232                 io->read_header_buf->len = old_len + MAX (nread, 0);
233                 if (nread == 0) {
234                         soup_message_set_status (msg, SOUP_STATUS_MALFORMED);
235                         g_set_error_literal (error, G_IO_ERROR,
236                                              G_IO_ERROR_PARTIAL_INPUT,
237                                              _("Connection terminated unexpectedly"));
238                 }
239                 if (nread <= 0)
240                         return FALSE;
241
242                 if (got_lf) {
243                         if (nread == 1 && old_len >= 2 &&
244                             !strncmp ((char *)io->read_header_buf->data +
245                                       io->read_header_buf->len - 2,
246                                       "\n\n", 2))
247                                 break;
248                         else if (nread == 2 && old_len >= 3 &&
249                                  !strncmp ((char *)io->read_header_buf->data +
250                                            io->read_header_buf->len - 3,
251                                            "\n\r\n", 3))
252                                 break;
253                 }
254         }
255
256         /* We need to "rewind" io->read_header_buf back one line.
257          * That SHOULD be two characters (CR LF), but if the
258          * web server was stupid, it might only be one.
259          */
260         if (io->read_header_buf->len < 3 ||
261             io->read_header_buf->data[io->read_header_buf->len - 2] == '\n')
262                 io->read_header_buf->len--;
263         else
264                 io->read_header_buf->len -= 2;
265         io->read_header_buf->data[io->read_header_buf->len] = '\0';
266
267         return TRUE;
268 }
269
270 static gint
271 processing_stage_cmp (gconstpointer a,
272                     gconstpointer b)
273 {
274         SoupProcessingStage stage_a = soup_content_processor_get_processing_stage (SOUP_CONTENT_PROCESSOR (a));
275         SoupProcessingStage stage_b = soup_content_processor_get_processing_stage (SOUP_CONTENT_PROCESSOR (b));
276
277         if (stage_a > stage_b)
278                 return 1;
279         if (stage_a == stage_b)
280                 return 0;
281         return -1;
282 }
283
284 GInputStream *
285 soup_message_setup_body_istream (GInputStream *body_stream,
286                                  SoupMessage *msg,
287                                  SoupSession *session,
288                                  SoupProcessingStage start_at_stage)
289 {
290         GInputStream *istream;
291         GSList *p, *processors;
292
293         istream = g_object_ref (body_stream);
294
295         processors = soup_session_get_features (session, SOUP_TYPE_CONTENT_PROCESSOR);
296         processors = g_slist_sort (processors, processing_stage_cmp);
297
298         for (p = processors; p; p = p->next) {
299                 GInputStream *wrapper;
300                 SoupContentProcessor *processor;
301
302                 processor = SOUP_CONTENT_PROCESSOR (p->data);
303                 if (soup_message_disables_feature (msg, p->data) ||
304                     soup_content_processor_get_processing_stage (processor) < start_at_stage)
305                         continue;
306
307                 wrapper = soup_content_processor_wrap_input (processor, istream, msg, NULL);
308                 if (wrapper) {
309                         g_object_unref (istream);
310                         istream = wrapper;
311                 }
312         }
313
314         g_slist_free (processors);
315
316         return istream;
317 }
318
319 /*
320  * There are two request/response formats: the basic request/response,
321  * possibly with one or more unsolicited informational responses (such
322  * as the WebDAV "102 Processing" response):
323  *
324  *     Client                            Server
325  *      W:HEADERS  / R:NOT_STARTED    ->  R:HEADERS  / W:NOT_STARTED
326  *      W:BODY     / R:NOT_STARTED    ->  R:BODY     / W:NOT_STARTED
327  *     [W:DONE     / R:HEADERS (1xx)  <-  R:DONE     / W:HEADERS (1xx) ...]
328  *      W:DONE     / R:HEADERS        <-  R:DONE     / W:HEADERS
329  *      W:DONE     / R:BODY           <-  R:DONE     / W:BODY
330  *      W:DONE     / R:DONE               R:DONE     / W:DONE
331  *     
332  * and the "Expect: 100-continue" request/response, with the client
333  * blocking halfway through its request, and then either continuing or
334  * aborting, depending on the server response:
335  *
336  *     Client                            Server
337  *      W:HEADERS  / R:NOT_STARTED    ->  R:HEADERS  / W:NOT_STARTED
338  *      W:BLOCKING / R:HEADERS        <-  R:BLOCKING / W:HEADERS
339  *     [W:BODY     / R:BLOCKING       ->  R:BODY     / W:BLOCKING]
340  *     [W:DONE     / R:HEADERS        <-  R:DONE     / W:HEADERS]
341  *      W:DONE     / R:BODY           <-  R:DONE     / W:BODY
342  *      W:DONE     / R:DONE               R:DONE     / W:DONE
343  */
344
345 /* Attempts to push forward the writing side of @msg's I/O. Returns
346  * %TRUE if it manages to make some progress, and it is likely that
347  * further progress can be made. Returns %FALSE if it has reached a
348  * stopping point of some sort (need input from the application,
349  * socket not writable, write is complete, etc).
350  */
351 static gboolean
352 io_write (SoupMessage *msg, gboolean blocking,
353           GCancellable *cancellable, GError **error)
354 {
355         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
356         SoupMessageIOData *io = priv->io_data;
357         SoupBuffer *chunk;
358         gssize nwrote;
359 #if ENABLE(TIZEN_DLOG)
360         char *uri = NULL;
361 #endif
362
363         switch (io->write_state) {
364         case SOUP_MESSAGE_IO_STATE_HEADERS:
365                 if (!io->write_buf->len) {
366                         io->get_headers_cb (msg, io->write_buf,
367                                             &io->write_encoding,
368                                             io->header_data);
369                 }
370
371 #if ENABLE(TIZEN_DLOG)
372                 uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE);
373                 TIZEN_LOGI("Request URL: %s", uri);
374 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
375                 prctl_with_url("[BGN] soup_io_w : ", uri);
376 #endif
377                 g_free(uri);
378 #endif
379
380                 while (io->written < io->write_buf->len) {
381                         nwrote = g_pollable_stream_write (io->ostream,
382                                                           io->write_buf->str + io->written,
383                                                           io->write_buf->len - io->written,
384                                                           blocking,
385                                                           cancellable, error);
386                         if (nwrote == -1)
387                                 return FALSE;
388                         io->written += nwrote;
389                 }
390
391                 io->written = 0;
392                 g_string_truncate (io->write_buf, 0);
393
394                 if (io->mode == SOUP_MESSAGE_IO_SERVER &&
395                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
396                         if (msg->status_code == SOUP_STATUS_CONTINUE) {
397                                 /* Stop and wait for the body now */
398                                 io->write_state =
399                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
400                                 io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START;
401                         } else {
402                                 /* We just wrote a 1xx response
403                                  * header, so stay in STATE_HEADERS.
404                                  * (The caller will pause us from the
405                                  * wrote_informational callback if he
406                                  * is not ready to send the final
407                                  * response.)
408                                  */
409                         }
410
411                         soup_message_wrote_informational (msg);
412                         soup_message_cleanup_response (msg);
413                         break;
414                 }
415
416                 if (io->write_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
417                         SoupMessageHeaders *hdrs =
418                                 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
419                                 msg->request_headers : msg->response_headers;
420                         io->write_length = soup_message_headers_get_content_length (hdrs);
421                 }
422
423                 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
424                     soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
425                         /* Need to wait for the Continue response */
426                         io->write_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
427                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
428                 } else {
429                         io->write_state = SOUP_MESSAGE_IO_STATE_BODY_START;
430
431                         /* If the client was waiting for a Continue
432                          * but we sent something else, then they're
433                          * now done writing.
434                          */
435                         if (io->mode == SOUP_MESSAGE_IO_SERVER &&
436                             io->read_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
437                                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
438                 }
439
440                 soup_message_wrote_headers (msg);
441                 break;
442
443
444         case SOUP_MESSAGE_IO_STATE_BODY_START:
445                 io->body_ostream = soup_body_output_stream_new (io->ostream,
446                                                                 io->write_encoding,
447                                                                 io->write_length);
448                 io->write_state = SOUP_MESSAGE_IO_STATE_BODY;
449                 break;
450
451
452         case SOUP_MESSAGE_IO_STATE_BODY:
453                 if (!io->write_length &&
454                     io->write_encoding != SOUP_ENCODING_EOF &&
455                     io->write_encoding != SOUP_ENCODING_CHUNKED) {
456                         io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
457                         break;
458                 }
459
460                 if (!io->write_chunk) {
461                         io->write_chunk = soup_message_body_get_chunk (io->write_body, io->write_body_offset);
462                         if (!io->write_chunk) {
463                                 g_return_val_if_fail (!io->item || !io->item->new_api, FALSE);
464                                 soup_message_io_pause (msg);
465                                 return FALSE;
466                         }
467                         if (!io->write_chunk->length) {
468                                 io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
469                                 break;
470                         }
471                 }
472
473                 nwrote = g_pollable_stream_write (io->body_ostream,
474                                                   io->write_chunk->data + io->written,
475                                                   io->write_chunk->length - io->written,
476                                                   blocking,
477                                                   cancellable, error);
478                 if (nwrote == -1)
479                         return FALSE;
480
481                 chunk = soup_buffer_new_subbuffer (io->write_chunk,
482                                                    io->written, nwrote);
483                 io->written += nwrote;
484                 if (io->write_length)
485                         io->write_length -= nwrote;
486
487                 if (io->written == io->write_chunk->length)
488                         io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DATA;
489
490                 soup_message_wrote_body_data (msg, chunk);
491                 soup_buffer_free (chunk);
492                 break;
493
494
495         case SOUP_MESSAGE_IO_STATE_BODY_DATA:
496                 io->written = 0;
497                 if (io->write_chunk->length == 0) {
498                         io->write_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
499                         break;
500                 }
501
502                 if (io->mode == SOUP_MESSAGE_IO_SERVER ||
503                     priv->msg_flags & SOUP_MESSAGE_CAN_REBUILD)
504                         soup_message_body_wrote_chunk (io->write_body, io->write_chunk);
505                 io->write_body_offset += io->write_chunk->length;
506                 soup_buffer_free (io->write_chunk);
507                 io->write_chunk = NULL;
508
509                 io->write_state = SOUP_MESSAGE_IO_STATE_BODY;
510                 soup_message_wrote_chunk (msg);
511                 break;
512
513
514         case SOUP_MESSAGE_IO_STATE_BODY_DONE:
515                 if (io->body_ostream) {
516                         if (!g_output_stream_close (io->body_ostream, cancellable, error))
517                                 return FALSE;
518                         g_clear_object (&io->body_ostream);
519                 }
520
521                 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
522                 soup_message_wrote_body (msg);
523                 break;
524
525
526         case SOUP_MESSAGE_IO_STATE_FINISHING:
527                 io->write_state = SOUP_MESSAGE_IO_STATE_DONE;
528
529                 if (io->mode == SOUP_MESSAGE_IO_CLIENT)
530                         io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
531                 break;
532
533
534         default:
535                 g_return_val_if_reached (FALSE);
536         }
537
538         return TRUE;
539 }
540
541 /* Attempts to push forward the reading side of @msg's I/O. Returns
542  * %TRUE if it manages to make some progress, and it is likely that
543  * further progress can be made. Returns %FALSE if it has reached a
544  * stopping point of some sort (need input from the application,
545  * socket not readable, read is complete, etc).
546  */
547 static gboolean
548 io_read (SoupMessage *msg, gboolean blocking,
549          GCancellable *cancellable, GError **error)
550 {
551         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
552         SoupMessageIOData *io = priv->io_data;
553         guchar *stack_buf = NULL;
554         gssize nread;
555         SoupBuffer *buffer;
556         guint status;
557 #if ENABLE(TIZEN_DLOG)
558         char *uri = NULL;
559 #endif
560
561         switch (io->read_state) {
562         case SOUP_MESSAGE_IO_STATE_HEADERS:
563                 if (!read_headers (msg, blocking, cancellable, error))
564                         return FALSE;
565
566                 status = io->parse_headers_cb (msg, (char *)io->read_header_buf->data,
567                                                io->read_header_buf->len,
568                                                &io->read_encoding,
569                                                io->header_data, error);
570                 g_byte_array_set_size (io->read_header_buf, 0);
571
572 #if ENABLE(TIZEN_DLOG)
573                 uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE);
574                 TIZEN_LOGI("Response URL: %s", uri);
575 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
576                 prctl_with_url("[BGN] soup_io_r_hdr : ", uri);
577 #endif
578                 g_free(uri);
579 #endif
580
581                 if (status != SOUP_STATUS_OK) {
582                         /* Either we couldn't parse the headers, or they
583                          * indicated something that would mean we wouldn't
584                          * be able to parse the body. (Eg, unknown
585                          * Transfer-Encoding.). Skip the rest of the
586                          * reading, and make sure the connection gets
587                          * closed when we're done.
588                          */
589                         soup_message_set_status (msg, status);
590                         soup_message_headers_append (msg->request_headers,
591                                                      "Connection", "close");
592                         io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
593 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
594                         prctl_with_url_and_free("[END] soup_io_r_hdr,not ok : ",soup_uri_to_string(soup_message_get_uri(msg), FALSE));
595 #endif
596                         break;
597                 }
598
599                 if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
600                     SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
601                         if (msg->status_code == SOUP_STATUS_CONTINUE &&
602                             io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING) {
603                                 /* Pause the reader, unpause the writer */
604                                 io->read_state =
605                                         SOUP_MESSAGE_IO_STATE_BLOCKING;
606                                 io->write_state =
607                                         SOUP_MESSAGE_IO_STATE_BODY_START;
608                         } else {
609                                 /* Just stay in HEADERS */
610                                 io->read_state = SOUP_MESSAGE_IO_STATE_HEADERS;
611                         }
612
613                         /* Informational responses have no bodies, so
614                          * bail out here rather than parsing encoding, etc
615                          */
616                         soup_message_got_informational (msg);
617                         soup_message_cleanup_response (msg);
618                         break;
619                 } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
620                            soup_message_headers_get_expectations (msg->request_headers) & SOUP_EXPECTATION_CONTINUE) {
621                         /* The client requested a Continue response. The
622                          * got_headers handler may change this to something
623                          * else though.
624                          */
625                         soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
626                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
627                         io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
628                 } else {
629                         io->read_state = SOUP_MESSAGE_IO_STATE_BODY_START;
630
631                         /* If the client was waiting for a Continue
632                          * but got something else, then it's done
633                          * writing.
634                          */
635                         if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
636                             io->write_state == SOUP_MESSAGE_IO_STATE_BLOCKING)
637                                 io->write_state = SOUP_MESSAGE_IO_STATE_FINISHING;
638                 }
639
640                 if (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH) {
641                         SoupMessageHeaders *hdrs =
642                                 (io->mode == SOUP_MESSAGE_IO_CLIENT) ?
643                                 msg->response_headers : msg->request_headers;
644                         io->read_length = soup_message_headers_get_content_length (hdrs);
645
646                         if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
647                             !soup_message_is_keepalive (msg)) {
648                                 /* Some servers suck and send
649                                  * incorrect Content-Length values, so
650                                  * allow EOF termination in this case
651                                  * (iff the message is too short) too.
652                                  */
653                                 io->read_encoding = SOUP_ENCODING_EOF;
654                         }
655                 } else
656                         io->read_length = -1;
657
658                 soup_message_got_headers (msg);
659                 break;
660
661
662         case SOUP_MESSAGE_IO_STATE_BODY_START:
663                 if (!io->body_istream) {
664                         GInputStream *body_istream = soup_body_input_stream_new (G_INPUT_STREAM (io->istream),
665                                                                                  io->read_encoding,
666                                                                                  io->read_length);
667
668                         /* TODO: server-side messages do not have a io->item. This means
669                          * that we cannot use content processors for them right now.
670                          */
671                         if (io->mode == SOUP_MESSAGE_IO_CLIENT) {
672                                 io->body_istream = soup_message_setup_body_istream (body_istream, msg,
673                                                                                     io->item->session,
674                                                                                     SOUP_STAGE_MESSAGE_BODY);
675                                 g_object_unref (body_istream);
676                         } else {
677                                 io->body_istream = body_istream;
678                         }
679                 }
680
681                 if (priv->sniffer) {
682                         SoupContentSnifferStream *sniffer_stream = SOUP_CONTENT_SNIFFER_STREAM (io->body_istream);
683                         const char *content_type;
684                         GHashTable *params;
685 #if ENABLE (TIZEN_UPDATE_CACHE_ENTRY_CONTENT_TYPE_HEADER)
686                         gboolean composite_type = FALSE;
687 #endif
688
689                         if (!soup_content_sniffer_stream_is_ready (sniffer_stream, blocking,
690                                                                    cancellable, error))
691                                 return FALSE;
692
693                         content_type = soup_content_sniffer_stream_sniff (sniffer_stream, &params);
694                         soup_message_content_sniffed (msg, content_type, params);
695 #if ENABLE (TIZEN_UPDATE_CACHE_ENTRY_CONTENT_TYPE_HEADER)
696                         if (content_type && msg->status_code != SOUP_STATUS_NOT_MODIFIED) {
697                                 if (params) {
698                                         GHashTableIter iter;
699                                         gpointer key, value;
700
701                                         g_hash_table_iter_init (&iter, params);
702                                         while (g_hash_table_iter_next (&iter, &key, &value)) {
703                                                 composite_type = TRUE;
704                                                 break;
705                                         }
706                                 }
707                                 if (!composite_type)
708                                         soup_cache_entry_set_content_type (io->item->session, msg, content_type);
709                         }
710 #endif
711                 }
712
713                 io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
714                 break;
715
716
717         case SOUP_MESSAGE_IO_STATE_BODY:
718                 if (priv->chunk_allocator) {
719                         buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
720                         if (!buffer) {
721                                 g_return_val_if_fail (!io->item || !io->item->new_api, FALSE);
722                                 soup_message_io_pause (msg);
723                                 return FALSE;
724                         }
725                 } else {
726                         if (!stack_buf)
727                                 stack_buf = alloca (RESPONSE_BLOCK_SIZE);
728                         buffer = soup_buffer_new (SOUP_MEMORY_TEMPORARY,
729                                                   stack_buf,
730                                                   RESPONSE_BLOCK_SIZE);
731                 }
732
733                 nread = g_pollable_stream_read (io->body_istream,
734                                                 (guchar *)buffer->data,
735                                                 buffer->length,
736                                                 blocking,
737                                                 cancellable, error);
738                 if (nread > 0) {
739                         buffer->length = nread;
740                         soup_message_body_got_chunk (io->read_body, buffer);
741                         soup_message_got_chunk (msg, buffer);
742                         soup_buffer_free (buffer);
743                         break;
744                 }
745
746                 soup_buffer_free (buffer);
747                 if (nread == -1)
748                         return FALSE;
749
750                 /* else nread == 0 */
751                 io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
752                 break;
753
754
755         case SOUP_MESSAGE_IO_STATE_BODY_DONE:
756                 io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
757                 soup_message_got_body (msg);
758                 break;
759
760
761         case SOUP_MESSAGE_IO_STATE_FINISHING:
762                 io->read_state = SOUP_MESSAGE_IO_STATE_DONE;
763
764                 if (io->mode == SOUP_MESSAGE_IO_SERVER)
765                         io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
766                 break;
767
768
769         default:
770                 g_return_val_if_reached (FALSE);
771         }
772
773         return TRUE;
774 }
775
776 typedef struct {
777         GSource source;
778         SoupMessage *msg;
779         gboolean paused;
780 } SoupMessageSource;
781
782 static gboolean
783 message_source_check (GSource *source)
784 {
785         SoupMessageSource *message_source = (SoupMessageSource *)source;
786
787         if (message_source->paused) {
788                 SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (message_source->msg);
789                 SoupMessageIOData *io = priv->io_data;
790
791                 if (!io || io->paused)
792                         return FALSE;
793                 else
794                         return TRUE;
795         } else
796                 return FALSE;
797 }
798
799 static gboolean
800 message_source_prepare (GSource *source,
801                         gint    *timeout)
802 {
803         *timeout = -1;
804         return message_source_check (source);
805 }
806
807 static gboolean
808 message_source_dispatch (GSource     *source,
809                          GSourceFunc  callback,
810                          gpointer     user_data)
811 {
812         SoupMessageSourceFunc func = (SoupMessageSourceFunc)callback;
813         SoupMessageSource *message_source = (SoupMessageSource *)source;
814
815         return (*func) (message_source->msg, user_data);
816 }
817
818 static void
819 message_source_finalize (GSource *source)
820 {
821         SoupMessageSource *message_source = (SoupMessageSource *)source;
822
823         g_object_unref (message_source->msg);
824 }
825
826 static gboolean
827 message_source_closure_callback (SoupMessage *msg,
828                                  gpointer     data)
829 {
830         GClosure *closure = data;
831         GValue param = G_VALUE_INIT;
832         GValue result_value = G_VALUE_INIT;
833         gboolean result;
834
835         g_value_init (&result_value, G_TYPE_BOOLEAN);
836
837         g_value_init (&param, SOUP_TYPE_MESSAGE);
838         g_value_set_object (&param, msg);
839
840         g_closure_invoke (closure, &result_value, 1, &param, NULL);
841
842         result = g_value_get_boolean (&result_value);
843         g_value_unset (&result_value);
844         g_value_unset (&param);
845
846         return result;
847 }
848
849 static GSourceFuncs message_source_funcs =
850 {
851         message_source_prepare,
852         message_source_check,
853         message_source_dispatch,
854         message_source_finalize,
855         (GSourceFunc)message_source_closure_callback,
856         (GSourceDummyMarshal)g_cclosure_marshal_generic,
857 };
858
859 GSource *
860 soup_message_io_get_source (SoupMessage *msg, GCancellable *cancellable,
861                             SoupMessageSourceFunc callback, gpointer user_data)
862 {
863         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
864         SoupMessageIOData *io = priv->io_data;
865         GSource *base_source, *source;
866         SoupMessageSource *message_source;
867
868         if (!io) {
869                 base_source = g_timeout_source_new (0);
870         } else if (io->paused) {
871                 base_source = NULL;
872         } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) {
873                 GPollableInputStream *istream;
874
875                 if (io->body_istream)
876                         istream = G_POLLABLE_INPUT_STREAM (io->body_istream);
877                 else
878                         istream = G_POLLABLE_INPUT_STREAM (io->istream);
879                 base_source = g_pollable_input_stream_create_source (istream, cancellable);
880         } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) {
881                 GPollableOutputStream *ostream;
882
883                 if (io->body_ostream)
884                         ostream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream);
885                 else
886                         ostream = G_POLLABLE_OUTPUT_STREAM (io->ostream);
887                 base_source = g_pollable_output_stream_create_source (ostream, cancellable);
888         } else
889                 base_source = g_timeout_source_new (0);
890
891         source = g_source_new (&message_source_funcs,
892                                sizeof (SoupMessageSource));
893         g_source_set_name (source, "SoupMessageSource");
894         message_source = (SoupMessageSource *)source;
895         message_source->msg = g_object_ref (msg);
896         message_source->paused = io && io->paused;
897
898         if (base_source) {
899                 g_source_set_dummy_callback (base_source);
900                 g_source_add_child_source (source, base_source);
901                 g_source_unref (base_source);
902         }
903         g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL);
904         return source;
905 }
906
907 static gboolean
908 request_is_restartable (SoupMessage *msg, GError *error)
909 {
910         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
911         SoupMessageIOData *io = priv->io_data;
912
913         if (!io)
914                 return FALSE;
915
916         return (io->mode == SOUP_MESSAGE_IO_CLIENT &&
917                 io->read_state <= SOUP_MESSAGE_IO_STATE_HEADERS &&
918                 io->read_header_buf->len == 0 &&
919                 soup_connection_get_ever_used (io->item->conn) &&
920                 !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) &&
921                 !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) &&
922                 error->domain != G_TLS_ERROR &&
923                 SOUP_METHOD_IS_IDEMPOTENT (msg->method));
924 }
925
926 static gboolean
927 io_run_until (SoupMessage *msg, gboolean blocking,
928               SoupMessageIOState read_state, SoupMessageIOState write_state,
929               GCancellable *cancellable, GError **error)
930 {
931         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
932         SoupMessageIOData *io = priv->io_data;
933         gboolean progress = TRUE, done;
934         GError *my_error = NULL;
935
936         if (g_cancellable_set_error_if_cancelled (cancellable, error))
937                 return FALSE;
938         else if (!io) {
939                 g_set_error_literal (error, G_IO_ERROR,
940                                      G_IO_ERROR_CANCELLED,
941                                      _("Operation was cancelled"));
942                 return FALSE;
943         }
944
945         g_object_ref (msg);
946
947         while (progress && priv->io_data == io && !io->paused &&
948                (io->read_state < read_state || io->write_state < write_state)) {
949
950                 if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->read_state))
951                         progress = io_read (msg, blocking, cancellable, &my_error);
952                 else if (SOUP_MESSAGE_IO_STATE_ACTIVE (io->write_state))
953                         progress = io_write (msg, blocking, cancellable, &my_error);
954                 else
955                         progress = FALSE;
956         }
957
958         if (my_error) {
959                 if (request_is_restartable (msg, my_error)) {
960                         /* Connection got closed, but we can safely try again */
961                         g_error_free (my_error);
962                         g_set_error_literal (error, SOUP_HTTP_ERROR,
963                                              SOUP_STATUS_TRY_AGAIN, "");
964                         g_object_unref (msg);
965                         return FALSE;
966                 }
967
968                 g_propagate_error (error, my_error);
969                 g_object_unref (msg);
970                 return FALSE;
971         } else if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
972                 g_object_unref (msg);
973                 return FALSE;
974         } else if (priv->io_data != io) {
975                 g_set_error_literal (error, G_IO_ERROR,
976                                      G_IO_ERROR_CANCELLED,
977                                      _("Operation was cancelled"));
978                 g_object_unref (msg);
979                 return FALSE;
980         }
981
982         done = (io->read_state >= read_state &&
983                 io->write_state >= write_state);
984
985         if (!blocking && !done) {
986                 g_set_error_literal (error, G_IO_ERROR,
987                                      G_IO_ERROR_WOULD_BLOCK,
988                                      _("Operation would block"));
989                 g_object_unref (msg);
990                 return FALSE;
991         }
992
993         g_object_unref (msg);
994         return done;
995 }
996
997 static void io_run (SoupMessage *msg, gboolean blocking);
998
999 static gboolean
1000 io_run_ready (SoupMessage *msg, gpointer user_data)
1001 {
1002         io_run (msg, FALSE);
1003         return FALSE;
1004 }
1005
1006 static void
1007 io_run (SoupMessage *msg, gboolean blocking)
1008 {
1009         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1010         SoupMessageIOData *io = priv->io_data;
1011         GError *error = NULL;
1012         GCancellable *cancellable;
1013
1014         if (io->io_source) {
1015                 g_source_destroy (io->io_source);
1016                 g_source_unref (io->io_source);
1017                 io->io_source = NULL;
1018         }
1019
1020         g_object_ref (msg);
1021         cancellable = io->cancellable ? g_object_ref (io->cancellable) : NULL;
1022
1023         if (io_run_until (msg, blocking,
1024                           SOUP_MESSAGE_IO_STATE_DONE,
1025                           SOUP_MESSAGE_IO_STATE_DONE,
1026                           cancellable, &error)) {
1027                 soup_message_io_finished (msg);
1028         } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
1029                 g_clear_error (&error);
1030                 io->io_source = soup_message_io_get_source (msg, NULL, io_run_ready, msg);
1031                 g_source_attach (io->io_source, io->async_context);
1032         } else if (error && priv->io_data == io) {
1033                 if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN))
1034                         io->item->state = SOUP_MESSAGE_RESTARTING;
1035                 else if (error->domain == G_TLS_ERROR) {
1036                         soup_message_set_status_full (msg,
1037                                                       SOUP_STATUS_SSL_FAILED,
1038                                                       error->message);
1039                 } else if (!SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
1040                         soup_message_set_status (msg, SOUP_STATUS_IO_ERROR);
1041
1042                 g_error_free (error);
1043                 soup_message_io_finished (msg);
1044         } else if (error)
1045                 g_error_free (error);
1046
1047         g_object_unref (msg);
1048         g_clear_object (&cancellable);
1049 }
1050
1051 gboolean
1052 soup_message_io_run_until_write (SoupMessage *msg, gboolean blocking,
1053                                  GCancellable *cancellable, GError **error)
1054 {
1055         return io_run_until (msg, blocking,
1056                              SOUP_MESSAGE_IO_STATE_ANY,
1057                              SOUP_MESSAGE_IO_STATE_BODY,
1058                              cancellable, error);
1059 }
1060
1061 gboolean
1062 soup_message_io_run_until_read (SoupMessage *msg, gboolean blocking,
1063                                 GCancellable *cancellable, GError **error)
1064 {
1065         return io_run_until (msg, blocking,
1066                              SOUP_MESSAGE_IO_STATE_BODY,
1067                              SOUP_MESSAGE_IO_STATE_ANY,
1068                              cancellable, error);
1069 }
1070
1071 gboolean
1072 soup_message_io_run_until_finish (SoupMessage   *msg,
1073                                   gboolean       blocking,
1074                                   GCancellable  *cancellable,
1075                                   GError       **error)
1076 {
1077         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1078         SoupMessageIOData *io = priv->io_data;
1079         gboolean success;
1080
1081         g_object_ref (msg);
1082
1083         if (io) {
1084                 g_return_val_if_fail (io->mode == SOUP_MESSAGE_IO_CLIENT, FALSE);
1085
1086                 if (io->read_state < SOUP_MESSAGE_IO_STATE_BODY_DONE)
1087                         io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
1088         }
1089
1090         success = io_run_until (msg, blocking,
1091                                 SOUP_MESSAGE_IO_STATE_DONE,
1092                                 SOUP_MESSAGE_IO_STATE_DONE,
1093                                 cancellable, error);
1094
1095         g_object_unref (msg);
1096         return success;
1097 }
1098
1099 static void
1100 client_stream_eof (SoupClientInputStream *stream, gpointer user_data)
1101 {
1102         SoupMessage *msg = user_data;
1103         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1104         SoupMessageIOData *io = priv->io_data;
1105
1106         if (io && io->read_state == SOUP_MESSAGE_IO_STATE_BODY)
1107                 io->read_state = SOUP_MESSAGE_IO_STATE_BODY_DONE;
1108 }
1109
1110 GInputStream *
1111 soup_message_io_get_response_istream (SoupMessage  *msg,
1112                                       GError      **error)
1113 {
1114         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1115         SoupMessageIOData *io = priv->io_data;
1116         GInputStream *client_stream;
1117
1118         g_return_val_if_fail (io->mode == SOUP_MESSAGE_IO_CLIENT, NULL);
1119
1120         if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
1121                 g_set_error_literal (error, SOUP_HTTP_ERROR,
1122                                      msg->status_code, msg->reason_phrase);
1123                 return NULL;
1124         }
1125
1126         client_stream = soup_client_input_stream_new (io->body_istream, msg);
1127         g_signal_connect (client_stream, "eof",
1128                           G_CALLBACK (client_stream_eof), msg);
1129
1130         return client_stream;
1131 }
1132
1133
1134 static SoupMessageIOData *
1135 new_iostate (SoupMessage *msg, GIOStream *iostream,
1136              GMainContext *async_context, SoupMessageIOMode mode,
1137              SoupMessageGetHeadersFn get_headers_cb,
1138              SoupMessageParseHeadersFn parse_headers_cb,
1139              gpointer header_data,
1140              SoupMessageCompletionFn completion_cb,
1141              gpointer completion_data)
1142 {
1143         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1144         SoupMessageIOData *io;
1145
1146         io = g_slice_new0 (SoupMessageIOData);
1147         io->mode = mode;
1148         io->get_headers_cb   = get_headers_cb;
1149         io->parse_headers_cb = parse_headers_cb;
1150         io->header_data      = header_data;
1151         io->completion_cb    = completion_cb;
1152         io->completion_data  = completion_data;
1153
1154         io->iostream = g_object_ref (iostream);
1155         io->istream = SOUP_FILTER_INPUT_STREAM (g_io_stream_get_input_stream (iostream));
1156         io->ostream = g_io_stream_get_output_stream (iostream);
1157
1158         if (async_context)
1159                 io->async_context = g_main_context_ref (async_context);
1160
1161         io->read_header_buf = g_byte_array_new ();
1162         io->write_buf       = g_string_new (NULL);
1163
1164         io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
1165         io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
1166
1167         if (priv->io_data)
1168                 soup_message_io_cleanup (msg);
1169         priv->io_data = io;
1170         return io;
1171 }
1172
1173 void
1174 soup_message_io_client (SoupMessageQueueItem *item,
1175                         GIOStream *iostream,
1176                         GMainContext *async_context,
1177                         SoupMessageGetHeadersFn get_headers_cb,
1178                         SoupMessageParseHeadersFn parse_headers_cb,
1179                         gpointer header_data,
1180                         SoupMessageCompletionFn completion_cb,
1181                         gpointer completion_data)
1182 {
1183         SoupMessageIOData *io;
1184
1185         io = new_iostate (item->msg, iostream, async_context,
1186                           SOUP_MESSAGE_IO_CLIENT,
1187                           get_headers_cb, parse_headers_cb, header_data,
1188                           completion_cb, completion_data);
1189
1190         io->item = item;
1191         soup_message_queue_item_ref (item);
1192         io->cancellable = item->cancellable;
1193
1194         io->read_body       = item->msg->response_body;
1195         io->write_body      = item->msg->request_body;
1196
1197         io->write_state     = SOUP_MESSAGE_IO_STATE_HEADERS;
1198
1199         if (!item->new_api) {
1200                 gboolean blocking =
1201                         SOUP_IS_SESSION_SYNC (item->session) ||
1202                         (!SOUP_IS_SESSION_ASYNC (item->session) && !item->async);
1203                 io_run (item->msg, blocking);
1204         }
1205 }
1206
1207 void
1208 soup_message_io_server (SoupMessage *msg,
1209                         GIOStream *iostream, GMainContext *async_context,
1210                         SoupMessageGetHeadersFn get_headers_cb,
1211                         SoupMessageParseHeadersFn parse_headers_cb,
1212                         gpointer header_data,
1213                         SoupMessageCompletionFn completion_cb,
1214                         gpointer completion_data)
1215 {
1216         SoupMessageIOData *io;
1217
1218         io = new_iostate (msg, iostream, async_context,
1219                           SOUP_MESSAGE_IO_SERVER,
1220                           get_headers_cb, parse_headers_cb, header_data,
1221                           completion_cb, completion_data);
1222
1223         io->read_body       = msg->request_body;
1224         io->write_body      = msg->response_body;
1225
1226         io->read_state      = SOUP_MESSAGE_IO_STATE_HEADERS;
1227         io_run (msg, FALSE);
1228 }
1229
1230 void  
1231 soup_message_io_pause (SoupMessage *msg)
1232 {
1233         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1234         SoupMessageIOData *io = priv->io_data;
1235
1236         g_return_if_fail (io != NULL);
1237
1238         if (io->item && io->item->new_api)
1239                 g_return_if_fail (io->read_state < SOUP_MESSAGE_IO_STATE_BODY);
1240
1241         if (io->io_source) {
1242                 g_source_destroy (io->io_source);
1243                 g_source_unref (io->io_source);
1244                 io->io_source = NULL;
1245         }
1246
1247         if (io->unpause_source) {
1248                 g_source_destroy (io->unpause_source);
1249                 g_source_unref (io->unpause_source);
1250                 io->unpause_source = NULL;
1251         }
1252
1253         io->paused = TRUE;
1254 }
1255
1256 static gboolean
1257 io_unpause_internal (gpointer msg)
1258 {
1259         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1260         SoupMessageIOData *io = priv->io_data;
1261
1262         g_return_val_if_fail (io != NULL, FALSE);
1263
1264         g_clear_pointer (&io->unpause_source, g_source_unref);
1265         io->paused = FALSE;
1266
1267         if (io->io_source)
1268                 return FALSE;
1269
1270         io_run (msg, FALSE);
1271         return FALSE;
1272 }
1273
1274 void
1275 soup_message_io_unpause (SoupMessage *msg)
1276 {
1277         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1278         SoupMessageIOData *io = priv->io_data;
1279
1280         g_return_if_fail (io != NULL);
1281
1282         if (io->item && io->item->new_api) {
1283                 g_return_if_fail (io->read_state < SOUP_MESSAGE_IO_STATE_BODY);
1284                 io->paused = FALSE;
1285                 return;
1286         }
1287
1288         if (!io->unpause_source) {
1289                 io->unpause_source = soup_add_completion_reffed (io->async_context,
1290                                                                  io_unpause_internal, msg);
1291         }
1292 }
1293
1294 /**
1295  * soup_message_io_in_progress:
1296  * @msg: a #SoupMessage
1297  *
1298  * Tests whether or not I/O is currently in progress on @msg.
1299  *
1300  * Return value: whether or not I/O is currently in progress.
1301  **/
1302 gboolean
1303 soup_message_io_in_progress (SoupMessage *msg)
1304 {
1305         SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
1306
1307         return priv->io_data != NULL;
1308 }