/src/libsoup/libsoup/http1/soup-message-io-data.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ |
2 | | /* |
3 | | * soup-message-io-data.c: HTTP message I/O data |
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-message-io-data.h" |
15 | | #include "soup-message-private.h" |
16 | | #include "soup-server-message-private.h" |
17 | | #include "soup.h" |
18 | | |
19 | 0 | #define RESPONSE_BLOCK_SIZE 8192 |
20 | 0 | #define HEADER_SIZE_LIMIT (100 * 1024) |
21 | | |
22 | | void |
23 | | soup_message_io_data_cleanup (SoupMessageIOData *io) |
24 | 0 | { |
25 | 0 | if (io->io_source) { |
26 | 0 | g_source_destroy (io->io_source); |
27 | 0 | g_clear_pointer (&io->io_source, g_source_unref); |
28 | 0 | } |
29 | |
|
30 | 0 | if (io->body_istream) |
31 | 0 | g_object_unref (io->body_istream); |
32 | 0 | if (io->body_ostream) |
33 | 0 | g_object_unref (io->body_ostream); |
34 | |
|
35 | 0 | g_byte_array_free (io->read_header_buf, TRUE); |
36 | |
|
37 | 0 | g_string_free (io->write_buf, TRUE); |
38 | |
|
39 | 0 | if (io->async_wait) { |
40 | 0 | g_cancellable_cancel (io->async_wait); |
41 | 0 | g_clear_object (&io->async_wait); |
42 | 0 | } |
43 | 0 | g_clear_error (&io->async_error); |
44 | 0 | } |
45 | | |
46 | | gboolean |
47 | | soup_message_io_data_read_headers (SoupMessageIOData *io, |
48 | | SoupFilterInputStream *istream, |
49 | | gboolean blocking, |
50 | | GCancellable *cancellable, |
51 | | gushort *extra_bytes, |
52 | | GError **error) |
53 | 0 | { |
54 | 0 | gssize nread, old_len; |
55 | 0 | gboolean got_lf; |
56 | |
|
57 | 0 | while (1) { |
58 | 0 | old_len = io->read_header_buf->len; |
59 | 0 | g_byte_array_set_size (io->read_header_buf, old_len + RESPONSE_BLOCK_SIZE); |
60 | 0 | nread = soup_filter_input_stream_read_line (istream, |
61 | 0 | io->read_header_buf->data + old_len, |
62 | 0 | RESPONSE_BLOCK_SIZE, |
63 | 0 | blocking, |
64 | 0 | &got_lf, |
65 | 0 | cancellable, error); |
66 | 0 | io->read_header_buf->len = old_len + MAX (nread, 0); |
67 | 0 | if (nread == 0) { |
68 | 0 | if (io->read_header_buf->len > 0) { |
69 | 0 | if (extra_bytes) |
70 | 0 | *extra_bytes = 0; |
71 | 0 | break; |
72 | 0 | } |
73 | | |
74 | 0 | g_set_error_literal (error, G_IO_ERROR, |
75 | 0 | G_IO_ERROR_PARTIAL_INPUT, |
76 | 0 | _("Connection terminated unexpectedly")); |
77 | 0 | } |
78 | 0 | if (nread <= 0) |
79 | 0 | return FALSE; |
80 | | |
81 | 0 | if (got_lf) { |
82 | 0 | if (nread == 1 && old_len >= 2 && |
83 | 0 | !strncmp ((char *)io->read_header_buf->data + |
84 | 0 | io->read_header_buf->len - 2, |
85 | 0 | "\n\n", 2)) { |
86 | 0 | io->read_header_buf->len--; |
87 | 0 | if (extra_bytes) |
88 | 0 | *extra_bytes = 1; |
89 | 0 | break; |
90 | 0 | } else if (nread == 2 && old_len >= 3 && |
91 | 0 | !strncmp ((char *)io->read_header_buf->data + |
92 | 0 | io->read_header_buf->len - 3, |
93 | 0 | "\n\r\n", 3)) { |
94 | 0 | io->read_header_buf->len -= 2; |
95 | 0 | if (extra_bytes) |
96 | 0 | *extra_bytes = 2; |
97 | 0 | break; |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 0 | if (io->read_header_buf->len > HEADER_SIZE_LIMIT) { |
102 | 0 | g_set_error_literal (error, G_IO_ERROR, |
103 | 0 | G_IO_ERROR_PARTIAL_INPUT, |
104 | 0 | _("Header too big")); |
105 | 0 | return FALSE; |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | 0 | io->read_header_buf->data[io->read_header_buf->len] = '\0'; |
110 | 0 | return TRUE; |
111 | 0 | } |
112 | | |
113 | | static gboolean |
114 | | message_io_is_paused (GObject *msg) |
115 | 0 | { |
116 | 0 | if (SOUP_IS_MESSAGE (msg)) |
117 | 0 | return soup_message_is_io_paused (SOUP_MESSAGE (msg)); |
118 | | |
119 | 0 | if (SOUP_IS_SERVER_MESSAGE (msg)) |
120 | 0 | return soup_server_message_is_io_paused (SOUP_SERVER_MESSAGE (msg)); |
121 | | |
122 | 0 | return FALSE; |
123 | 0 | } |
124 | | |
125 | | static gboolean |
126 | | message_io_source_check (GSource *source) |
127 | 0 | { |
128 | 0 | SoupMessageIOSource *message_source = (SoupMessageIOSource *)source; |
129 | |
|
130 | 0 | if (message_source->paused) { |
131 | 0 | if (message_io_is_paused (message_source->msg)) |
132 | 0 | return FALSE; |
133 | 0 | return TRUE; |
134 | 0 | } else |
135 | 0 | return FALSE; |
136 | 0 | } |
137 | | |
138 | | GSource * |
139 | | soup_message_io_data_get_source (SoupMessageIOData *io, |
140 | | GObject *msg, |
141 | | GInputStream *istream, |
142 | | GOutputStream *ostream, |
143 | | GCancellable *cancellable, |
144 | | SoupMessageIOSourceFunc callback, |
145 | | gpointer user_data) |
146 | 0 | { |
147 | 0 | GSource *base_source, *source; |
148 | |
|
149 | 0 | if (!io) { |
150 | 0 | base_source = g_timeout_source_new (0); |
151 | 0 | } else if (io->paused) { |
152 | 0 | base_source = cancellable ? g_cancellable_source_new (cancellable) : NULL; |
153 | 0 | } else if (io->async_wait) { |
154 | 0 | base_source = g_cancellable_source_new (io->async_wait); |
155 | 0 | } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->read_state)) { |
156 | 0 | GPollableInputStream *stream; |
157 | |
|
158 | 0 | if (io->body_istream) |
159 | 0 | stream = G_POLLABLE_INPUT_STREAM (io->body_istream); |
160 | 0 | else if (istream) |
161 | 0 | stream = G_POLLABLE_INPUT_STREAM (istream); |
162 | 0 | else |
163 | 0 | g_assert_not_reached (); |
164 | 0 | base_source = g_pollable_input_stream_create_source (stream, cancellable); |
165 | 0 | } else if (SOUP_MESSAGE_IO_STATE_POLLABLE (io->write_state)) { |
166 | 0 | GPollableOutputStream *stream; |
167 | |
|
168 | 0 | if (io->body_ostream) |
169 | 0 | stream = G_POLLABLE_OUTPUT_STREAM (io->body_ostream); |
170 | 0 | else if (ostream) |
171 | 0 | stream = G_POLLABLE_OUTPUT_STREAM (ostream); |
172 | 0 | else |
173 | 0 | g_assert_not_reached (); |
174 | 0 | base_source = g_pollable_output_stream_create_source (stream, cancellable); |
175 | 0 | } else |
176 | 0 | base_source = g_timeout_source_new (0); |
177 | | |
178 | 0 | source = soup_message_io_source_new (base_source, msg, io && io->paused, message_io_source_check); |
179 | 0 | g_source_set_static_name (source, "SoupMessageIOData"); |
180 | 0 | g_source_set_callback (source, (GSourceFunc) callback, user_data, NULL); |
181 | 0 | return source; |
182 | 0 | } |
183 | | |
184 | | void |
185 | | soup_message_io_data_pause (SoupMessageIOData *io) |
186 | 0 | { |
187 | 0 | if (io->io_source) { |
188 | 0 | g_source_destroy (io->io_source); |
189 | 0 | g_clear_pointer (&io->io_source, g_source_unref); |
190 | 0 | } |
191 | |
|
192 | 0 | io->paused = TRUE; |
193 | 0 | } |
194 | | |
195 | | void |
196 | | soup_message_io_data_unpause (SoupMessageIOData *io) |
197 | 0 | { |
198 | 0 | io->paused = FALSE; |
199 | 0 | } |