1 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "istream.h"
5 #include "dns-lookup.h"
6 #include "ostream-wrapper.h"
7
8 #include "http-server-private.h"
9
10 /*
11 * Payload output stream
12 */
13
14 struct http_server_ostream {
15 struct wrapper_ostream wostream;
16
17 struct http_server_connection *conn;
18 struct http_server_response *resp;
19
20 bool response_destroyed:1;
21 };
22
http_server_ostream_output_error(struct wrapper_ostream * wostream)23 static void http_server_ostream_output_error(struct wrapper_ostream *wostream)
24 {
25 struct http_server_ostream *hsostream =
26 (struct http_server_ostream *)wostream;
27 struct http_server_connection *conn = hsostream->conn;
28
29 if (hsostream->response_destroyed)
30 return;
31
32 i_assert(hsostream->resp != NULL);
33 http_server_connection_handle_output_error(conn);
34 }
35
http_server_ostream_output_start(struct wrapper_ostream * wostream)36 static void http_server_ostream_output_start(struct wrapper_ostream *wostream)
37 {
38 struct http_server_ostream *hsostream =
39 (struct http_server_ostream *)wostream;
40 struct http_server_response *resp = hsostream->resp;
41
42 i_assert(hsostream->response_destroyed || resp != NULL);
43
44 if (!hsostream->response_destroyed &&
45 resp->request->state <= HTTP_SERVER_REQUEST_STATE_PROCESSING) {
46 /* implicitly submit the request */
47 http_server_response_submit(resp);
48 }
49 }
50
http_server_ostream_output_available(struct http_server_ostream * hsostream)51 void http_server_ostream_output_available(
52 struct http_server_ostream *hsostream)
53 {
54 struct http_server_response *resp = hsostream->resp;
55
56 i_assert(resp != NULL);
57 i_assert(!hsostream->response_destroyed);
58 wrapper_ostream_output_available(&hsostream->wostream,
59 resp->payload_output);
60 }
61
http_server_ostream_output_ready(struct wrapper_ostream * wostream)62 static bool http_server_ostream_output_ready(struct wrapper_ostream *wostream)
63 {
64 struct http_server_ostream *hsostream =
65 (struct http_server_ostream *)wostream;
66 struct http_server_response *resp = hsostream->resp;
67
68 i_assert(resp != NULL);
69 i_assert(!hsostream->response_destroyed);
70 return (resp->request->state >= HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT);
71 }
72
http_server_ostream_output_finish(struct wrapper_ostream * wostream)73 static int http_server_ostream_output_finish(struct wrapper_ostream *wostream)
74 {
75 struct http_server_ostream *hsostream =
76 (struct http_server_ostream *)wostream;
77 struct http_server_response *resp = hsostream->resp;
78
79 i_assert(resp != NULL);
80 i_assert(!hsostream->response_destroyed);
81
82 e_debug(wostream->event, "Finished response payload stream");
83
84 /* finished sending payload */
85 return http_server_response_finish_payload_out(resp);
86 }
87
http_server_ostream_output_halt(struct wrapper_ostream * wostream)88 static void http_server_ostream_output_halt(struct wrapper_ostream *wostream)
89 {
90 struct http_server_ostream *hsostream =
91 (struct http_server_ostream *)wostream;
92 struct http_server_connection *conn = hsostream->conn;
93 struct http_server_response *resp = hsostream->resp;
94
95 i_assert(hsostream->response_destroyed || resp != NULL);
96
97 if (hsostream->response_destroyed ||
98 resp->request->state < HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT)
99 return;
100
101 http_server_connection_output_halt(conn);
102 }
103
http_server_ostream_output_resume(struct wrapper_ostream * wostream)104 static void http_server_ostream_output_resume(struct wrapper_ostream *wostream)
105 {
106 struct http_server_ostream *hsostream =
107 (struct http_server_ostream *)wostream;
108 struct http_server_connection *conn = hsostream->conn;
109
110 if (hsostream->response_destroyed)
111 return;
112 i_assert(hsostream->resp != NULL);
113
114 http_server_connection_output_resume(conn);
115 }
116
117 static void
http_server_ostream_output_update_timeouts(struct wrapper_ostream * wostream,bool sender_blocking)118 http_server_ostream_output_update_timeouts(struct wrapper_ostream *wostream,
119 bool sender_blocking)
120 {
121 struct http_server_ostream *hsostream =
122 (struct http_server_ostream *)wostream;
123 struct http_server_connection *conn = hsostream->conn;
124
125 if (hsostream->response_destroyed)
126 return;
127 i_assert(hsostream->resp != NULL);
128
129 if (sender_blocking) {
130 http_server_connection_stop_idle_timeout(conn);
131 return;
132 }
133
134 http_server_connection_start_idle_timeout(conn);
135 }
136
http_server_ostream_close(struct wrapper_ostream * wostream)137 static void http_server_ostream_close(struct wrapper_ostream *wostream)
138 {
139 struct http_server_ostream *hsostream =
140 (struct http_server_ostream *)wostream;
141 struct http_server_response *resp = hsostream->resp;
142
143 e_debug(wostream->event, "Response payload stream closed");
144
145 if (hsostream->response_destroyed) {
146 http_server_response_unref(&hsostream->resp);
147 return;
148 }
149 hsostream->response_destroyed = TRUE;
150
151 i_assert(resp != NULL);
152 (void)http_server_response_finish_payload_out(resp);
153 resp->payload_stream = NULL;
154 http_server_response_unref(&hsostream->resp);
155 }
156
http_server_ostream_destroy(struct wrapper_ostream * wostream)157 static void http_server_ostream_destroy(struct wrapper_ostream *wostream)
158 {
159 struct http_server_ostream *hsostream =
160 (struct http_server_ostream *)wostream;
161 struct http_server_response *resp = hsostream->resp;
162 struct http_server_request *req;
163
164 e_debug(wostream->event, "Response payload stream destroyed");
165
166 if (hsostream->response_destroyed) {
167 http_server_response_unref(&hsostream->resp);
168 return;
169 }
170 hsostream->response_destroyed = TRUE;
171 i_assert(resp != NULL);
172
173 req = resp->request;
174 resp->payload_stream = NULL;
175 http_server_request_abort(
176 &req, "Response output stream destroyed prematurely");
177 }
178
179 static struct ioloop *
http_server_ostream_wait_begin(struct wrapper_ostream * wostream,struct ioloop * ioloop)180 http_server_ostream_wait_begin(struct wrapper_ostream *wostream,
181 struct ioloop *ioloop)
182 {
183 struct http_server_ostream *hsostream =
184 (struct http_server_ostream *)wostream;
185 struct http_server_connection *conn = hsostream->conn;
186 struct ioloop *prev_ioloop;
187
188 i_assert(hsostream->resp != NULL);
189 i_assert(!hsostream->response_destroyed);
190
191 http_server_connection_ref(conn);
192
193 /* When the response payload output stream is written from inside the
194 request callback, the incoming payload stream is not destroyed yet,
195 even though it is read to the end. This could lead to problems, so we
196 make an effort to destroy it here.
197 */
198 if (conn->incoming_payload != NULL &&
199 i_stream_read_eof(conn->incoming_payload)) {
200 struct http_server_request *req = hsostream->resp->request;
201 struct istream *payload;
202
203 payload = req->req.payload;
204 req->req.payload = NULL;
205 i_stream_unref(&payload);
206 }
207
208 prev_ioloop = http_server_connection_switch_ioloop_to(conn, ioloop);
209 return prev_ioloop;
210 }
211
212 static void
http_server_ostream_wait_end(struct wrapper_ostream * wostream,struct ioloop * prev_ioloop)213 http_server_ostream_wait_end(struct wrapper_ostream *wostream,
214 struct ioloop *prev_ioloop)
215 {
216 struct http_server_ostream *hsostream =
217 (struct http_server_ostream *)wostream;
218 struct http_server_connection *conn = hsostream->conn;
219
220 (void)http_server_connection_switch_ioloop_to(conn, prev_ioloop);
221 http_server_connection_unref(&conn);
222 }
223
http_server_ostream_continue(struct http_server_ostream * hsostream)224 int http_server_ostream_continue(struct http_server_ostream *hsostream)
225 {
226 struct wrapper_ostream *wostream = &hsostream->wostream;
227 struct http_server_response *resp = hsostream->resp;
228
229 i_assert(hsostream->response_destroyed || resp != NULL);
230
231 i_assert(hsostream->response_destroyed ||
232 resp->request->state >= HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT);
233
234 return wrapper_ostream_continue(wostream);
235 }
236
http_server_ostream_get_size(struct http_server_ostream * hsostream,uoff_t * size_r)237 bool http_server_ostream_get_size(struct http_server_ostream *hsostream,
238 uoff_t *size_r)
239 {
240 return wrapper_ostream_get_buffered_size(&hsostream->wostream, size_r);
241 }
242
243 static void
http_server_ostream_switch_ioloop_to(struct wrapper_ostream * wostream,struct ioloop * ioloop)244 http_server_ostream_switch_ioloop_to(struct wrapper_ostream *wostream,
245 struct ioloop *ioloop)
246 {
247 struct http_server_ostream *hsostream =
248 (struct http_server_ostream *)wostream;
249 struct http_server_connection *conn = hsostream->conn;
250
251 if (hsostream->response_destroyed)
252 return;
253 i_assert(hsostream->resp != NULL);
254
255 http_server_connection_switch_ioloop_to(conn, ioloop);
256 }
257
258 struct ostream *
http_server_ostream_create(struct http_server_response * resp,size_t max_buffer_size,bool blocking)259 http_server_ostream_create(struct http_server_response *resp,
260 size_t max_buffer_size, bool blocking)
261 {
262 struct http_server_ostream *hsostream;
263
264 i_assert(resp->payload_stream == NULL);
265
266 hsostream = i_new(struct http_server_ostream, 1);
267
268 resp->payload_stream = hsostream;
269 http_server_response_ref(resp);
270 hsostream->conn = resp->request->conn;
271 hsostream->resp = resp;
272
273 hsostream->wostream.output_start = http_server_ostream_output_start;
274 hsostream->wostream.output_ready = http_server_ostream_output_ready;
275 hsostream->wostream.output_error = http_server_ostream_output_error;
276 hsostream->wostream.output_finish = http_server_ostream_output_finish;
277 hsostream->wostream.output_halt = http_server_ostream_output_halt;
278 hsostream->wostream.output_resume = http_server_ostream_output_resume;
279 hsostream->wostream.output_update_timeouts =
280 http_server_ostream_output_update_timeouts;
281
282 hsostream->wostream.wait_begin = http_server_ostream_wait_begin;
283 hsostream->wostream.wait_end = http_server_ostream_wait_end;
284
285 hsostream->wostream.switch_ioloop_to =
286 http_server_ostream_switch_ioloop_to;
287
288 hsostream->wostream.close = http_server_ostream_close;
289 hsostream->wostream.destroy = http_server_ostream_destroy;
290
291 return wrapper_ostream_create(&hsostream->wostream, max_buffer_size,
292 blocking, resp->event);
293 }
294
http_server_ostream_response_finished(struct http_server_ostream * hsostream)295 void http_server_ostream_response_finished(
296 struct http_server_ostream *hsostream)
297 {
298 e_debug(hsostream->wostream.event, "Response payload finished");
299
300 wrapper_ostream_output_destroyed(&hsostream->wostream);
301 }
302
http_server_ostream_response_destroyed(struct http_server_ostream * hsostream)303 void http_server_ostream_response_destroyed(
304 struct http_server_ostream *hsostream)
305 {
306 i_assert(hsostream->resp != NULL);
307 hsostream->resp->payload_stream = NULL;
308
309 e_debug(hsostream->wostream.event,
310 "Response payload parent stream lost");
311
312 hsostream->response_destroyed = TRUE;
313 wrapper_ostream_output_destroyed(&hsostream->wostream);
314 wrapper_ostream_notify_error(&hsostream->wostream);
315 }
316
317 struct ostream *
http_server_ostream_get_output(struct http_server_ostream * hsostream)318 http_server_ostream_get_output(struct http_server_ostream *hsostream)
319 {
320 return &hsostream->wostream.ostream.ostream;
321 }
322
http_server_ostream_set_error(struct http_server_ostream * hsostream,int stream_errno,const char * stream_error)323 void http_server_ostream_set_error(struct http_server_ostream *hsostream,
324 int stream_errno, const char *stream_error)
325 {
326 wrapper_ostream_set_error(&hsostream->wostream, stream_errno,
327 stream_error);
328 }
329