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