1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "str.h"
5 #include "array.h"
6 #include "istream.h"
7 #include "ostream-private.h"
8 #include "http-date.h"
9 #include "http-transfer.h"
10 #include "http-server-private.h"
11
12 struct http_server_response_payload {
13 struct http_server_response *resp;
14 struct const_iovec *iov;
15 unsigned int iov_count, iov_idx;
16 size_t iov_pos;
17 };
18
19 /*
20 * Response
21 */
22
http_server_response_update_event(struct http_server_response * resp)23 static void http_server_response_update_event(struct http_server_response *resp)
24 {
25 event_add_int(resp->event, "status", resp->status);
26 event_set_append_log_prefix(resp->event,
27 t_strdup_printf("%u response: ",
28 resp->status));
29 }
30
31 struct http_server_response *
http_server_response_create(struct http_server_request * req,unsigned int status,const char * reason)32 http_server_response_create(struct http_server_request *req,
33 unsigned int status, const char *reason)
34 {
35 struct http_server_response *resp;
36
37 i_assert(req->state < HTTP_SERVER_REQUEST_STATE_SENT_RESPONSE);
38
39 if (req->response == NULL) {
40 resp = req->response = p_new(req->pool,
41 struct http_server_response, 1);
42 } else {
43 /* Was already composing a response, but decided to
44 start a new one (would usually be a failure response)
45 */
46 resp = req->response;
47
48 ARRAY_TYPE(string) perm_headers = resp->perm_headers;
49 i_zero(&resp->perm_headers);
50
51 http_server_response_request_free(resp);
52 i_zero(resp);
53
54 resp->perm_headers = perm_headers;
55 }
56
57 resp->request = req;
58 resp->status = status;
59 resp->reason = p_strdup(req->pool, reason);
60 resp->headers = str_new(default_pool, 256);
61 resp->date = (time_t)-1;
62 resp->event = event_create(req->event);
63 http_server_response_update_event(resp);
64
65 if (array_is_created(&resp->perm_headers)) {
66 unsigned int i, count;
67 char *const *headers = array_get(&resp->perm_headers, &count);
68 for (i = 0; i < count; i += 2)
69 http_server_response_add_header(resp, headers[i],
70 headers[i+1]);
71 }
72 return resp;
73 }
74
http_server_response_request_free(struct http_server_response * resp)75 void http_server_response_request_free(struct http_server_response *resp)
76 {
77 e_debug(resp->event, "Free");
78
79 /* Cannot be destroyed while payload output stream still exists */
80 i_assert(resp->payload_stream == NULL);
81
82 i_stream_unref(&resp->payload_input);
83 o_stream_unref(&resp->payload_output);
84 event_unref(&resp->event);
85 str_free(&resp->headers);
86
87 if (array_is_created(&resp->perm_headers)) {
88 char *headers;
89
90 array_foreach_elem(&resp->perm_headers, headers)
91 i_free(headers);
92 array_free(&resp->perm_headers);
93 }
94 }
95
http_server_response_request_destroy(struct http_server_response * resp)96 void http_server_response_request_destroy(struct http_server_response *resp)
97 {
98 e_debug(resp->event, "Destroy");
99
100 if (resp->payload_stream != NULL)
101 http_server_ostream_response_destroyed(resp->payload_stream);
102 }
103
http_server_response_request_abort(struct http_server_response * resp,const char * reason)104 void http_server_response_request_abort(struct http_server_response *resp,
105 const char *reason)
106 {
107 if (reason == NULL)
108 e_debug(resp->event, "Abort");
109 else
110 e_debug(resp->event, "Abort: %s", reason);
111
112 if (resp->payload_stream != NULL) {
113 http_server_ostream_set_error(resp->payload_stream,
114 EPIPE, reason);
115 }
116 }
117
http_server_response_ref(struct http_server_response * resp)118 void http_server_response_ref(struct http_server_response *resp)
119 {
120 http_server_request_ref(resp->request);
121 }
122
http_server_response_unref(struct http_server_response ** _resp)123 bool http_server_response_unref(struct http_server_response **_resp)
124 {
125 struct http_server_response *resp = *_resp;
126 struct http_server_request *req;
127
128 *_resp = NULL;
129 if (resp == NULL)
130 return FALSE;
131
132 req = resp->request;
133 return http_server_request_unref(&req);
134 }
135
http_server_response_add_header(struct http_server_response * resp,const char * key,const char * value)136 void http_server_response_add_header(struct http_server_response *resp,
137 const char *key, const char *value)
138 {
139 i_assert(!resp->submitted);
140 i_assert(strchr(key, '\r') == NULL && strchr(key, '\n') == NULL);
141 i_assert(strchr(value, '\r') == NULL && strchr(value, '\n') == NULL);
142
143 /* Mark presence of special headers */
144 switch (key[0]) {
145 case 'c': case 'C':
146 if (strcasecmp(key, "Connection") == 0)
147 resp->have_hdr_connection = TRUE;
148 else if (strcasecmp(key, "Content-Length") == 0)
149 resp->have_hdr_body_spec = TRUE;
150 break;
151 case 'd': case 'D':
152 if (strcasecmp(key, "Date") == 0)
153 resp->have_hdr_date = TRUE;
154 break;
155 case 't': case 'T':
156 if (strcasecmp(key, "Transfer-Encoding") == 0)
157 resp->have_hdr_body_spec = TRUE;
158 break;
159 }
160 str_printfa(resp->headers, "%s: %s\r\n", key, value);
161 }
162
http_server_response_update_status(struct http_server_response * resp,unsigned int status,const char * reason)163 void http_server_response_update_status(struct http_server_response *resp,
164 unsigned int status,
165 const char *reason)
166 {
167 i_assert(!resp->submitted);
168 resp->status = status;
169 /* Free not called because pool is alloconly */
170 resp->reason = p_strdup(resp->request->pool, reason);
171 }
172
http_server_response_set_date(struct http_server_response * resp,time_t date)173 void http_server_response_set_date(struct http_server_response *resp,
174 time_t date)
175 {
176 i_assert(!resp->submitted);
177
178 resp->date = date;
179 }
180
http_server_response_set_payload(struct http_server_response * resp,struct istream * input)181 void http_server_response_set_payload(struct http_server_response *resp,
182 struct istream *input)
183 {
184 int ret;
185
186 i_assert(!resp->submitted);
187 i_assert(resp->payload_input == NULL);
188 i_assert(resp->payload_stream == NULL);
189
190 i_stream_ref(input);
191 resp->payload_input = input;
192 if ((ret = i_stream_get_size(input, TRUE, &resp->payload_size)) <= 0) {
193 if (ret < 0) {
194 e_error(resp->event, "i_stream_get_size(%s) failed: %s",
195 i_stream_get_name(input),
196 i_stream_get_error(input));
197 }
198 resp->payload_size = 0;
199 resp->payload_chunked = TRUE;
200 } else {
201 i_assert(input->v_offset <= resp->payload_size);
202 resp->payload_size -= input->v_offset;
203 }
204 resp->payload_offset = input->v_offset;
205 }
206
http_server_response_set_payload_data(struct http_server_response * resp,const unsigned char * data,size_t size)207 void http_server_response_set_payload_data(struct http_server_response *resp,
208 const unsigned char *data,
209 size_t size)
210 {
211 struct istream *input;
212 unsigned char *payload_data;
213
214 i_assert(!resp->submitted);
215 i_assert(resp->payload_input == NULL);
216 i_assert(resp->payload_stream == NULL);
217
218 if (size == 0)
219 return;
220
221 payload_data = p_malloc(resp->request->pool, size);
222 memcpy(payload_data, data, size);
223 input = i_stream_create_from_data(payload_data, size);
224
225 http_server_response_set_payload(resp, input);
226 i_stream_unref(&input);
227 }
228
229 struct ostream *
http_server_response_get_payload_output(struct http_server_response * resp,size_t max_buffer_size,bool blocking)230 http_server_response_get_payload_output(struct http_server_response *resp,
231 size_t max_buffer_size, bool blocking)
232 {
233 struct http_server_request *req = resp->request;
234 struct http_server_connection *conn = req->conn;
235 struct ostream *output;
236
237 i_assert(conn != NULL);
238 i_assert(!resp->submitted);
239 i_assert(resp->payload_input == NULL);
240 i_assert(resp->payload_stream == NULL);
241
242 output = http_server_ostream_create(resp, max_buffer_size, blocking);
243 o_stream_set_name(output,
244 t_strdup_printf("(conn %s: request %s: %u response payload)",
245 conn->conn.label,
246 http_server_request_label(req), resp->status));
247 return output;
248 }
249
http_server_response_add_auth(struct http_server_response * resp,const struct http_auth_challenge * chlng)250 void http_server_response_add_auth(struct http_server_response *resp,
251 const struct http_auth_challenge *chlng)
252 {
253 struct http_auth_challenge *new;
254 pool_t pool = resp->request->pool;
255
256 if (!array_is_created(&resp->auth_challenges))
257 p_array_init(&resp->auth_challenges, pool, 4);
258
259 new = array_append_space(&resp->auth_challenges);
260 http_auth_challenge_copy(pool, new, chlng);
261 }
262
http_server_response_add_auth_basic(struct http_server_response * resp,const char * realm)263 void http_server_response_add_auth_basic(struct http_server_response *resp,
264 const char *realm)
265 {
266 struct http_auth_challenge chlng;
267
268 http_auth_basic_challenge_init(&chlng, realm);
269 http_server_response_add_auth(resp, &chlng);
270 }
271
272 static void
http_server_response_do_submit(struct http_server_response * resp)273 http_server_response_do_submit(struct http_server_response *resp)
274 {
275 i_assert(!resp->submitted);
276 if (resp->date == (time_t)-1)
277 resp->date = ioloop_time;
278 resp->submitted = TRUE;
279 http_server_request_submit_response(resp->request);
280 }
281
http_server_response_submit(struct http_server_response * resp)282 void http_server_response_submit(struct http_server_response *resp)
283 {
284 e_debug(resp->event, "Submitted");
285
286 http_server_response_do_submit(resp);
287 }
288
http_server_response_submit_close(struct http_server_response * resp)289 void http_server_response_submit_close(struct http_server_response *resp)
290 {
291 http_server_request_connection_close(resp->request, TRUE);
292 http_server_response_submit(resp);
293 }
294
http_server_response_submit_tunnel(struct http_server_response * resp,http_server_tunnel_callback_t callback,void * context)295 void http_server_response_submit_tunnel(struct http_server_response *resp,
296 http_server_tunnel_callback_t callback,
297 void *context)
298 {
299 e_debug(resp->event, "Started tunnelling");
300
301 resp->tunnel_callback = callback;
302 resp->tunnel_context = context;
303 http_server_request_connection_close(resp->request, TRUE);
304 http_server_response_do_submit(resp);
305 }
306
307 static int
http_server_response_flush_payload(struct http_server_response * resp)308 http_server_response_flush_payload(struct http_server_response *resp)
309 {
310 struct http_server_request *req = resp->request;
311 struct http_server_connection *conn = req->conn;
312 int ret;
313
314 if (resp->payload_output != conn->conn.output &&
315 (ret = o_stream_finish(resp->payload_output)) <= 0) {
316 if (ret < 0)
317 http_server_connection_handle_output_error(conn);
318 else
319 http_server_connection_start_idle_timeout(conn);
320 return ret;
321 }
322
323 return 1;
324 }
325
http_server_response_request_finished(struct http_server_response * resp)326 void http_server_response_request_finished(struct http_server_response *resp)
327 {
328 e_debug(resp->event, "Finished");
329
330 if (resp->payload_stream != NULL)
331 http_server_ostream_response_finished(resp->payload_stream);
332 }
333
http_server_response_finish_payload_out(struct http_server_response * resp)334 int http_server_response_finish_payload_out(struct http_server_response *resp)
335 {
336 struct http_server_request *req = resp->request;
337 struct http_server_connection *conn = req->conn;
338 int ret;
339
340 if (req->state >= HTTP_SERVER_REQUEST_STATE_FINISHED)
341 return 1;
342
343 resp->payload_finished = TRUE;
344
345 if (resp->payload_output != NULL) {
346 ret = http_server_response_flush_payload(resp);
347 if (ret < 0)
348 return -1;
349 if (ret == 0) {
350 e_debug(resp->event,
351 "Not quite finished sending payload");
352 return 0;
353 }
354 o_stream_unref(&resp->payload_output);
355 resp->payload_output = NULL;
356 }
357
358 e_debug(resp->event, "Finished sending payload");
359
360 http_server_connection_ref(conn);
361 conn->output_locked = FALSE;
362 if (conn->conn.output != NULL && !conn->conn.output->closed) {
363 if (resp->payload_corked &&
364 o_stream_uncork_flush(conn->conn.output) < 0)
365 http_server_connection_handle_output_error(conn);
366 o_stream_set_flush_callback(conn->conn.output,
367 http_server_connection_output,
368 conn);
369 }
370
371 if (conn->request_queue_head == NULL ||
372 (conn->request_queue_head->state !=
373 HTTP_SERVER_REQUEST_STATE_PROCESSING))
374 http_server_connection_start_idle_timeout(conn);
375
376 http_server_request_finished(resp->request);
377 http_server_connection_unref(&conn);
378 return 1;
379 }
380
381 static int
http_server_response_output_payload(struct http_server_response ** _resp,const unsigned char * data,size_t size)382 http_server_response_output_payload(struct http_server_response **_resp,
383 const unsigned char *data, size_t size)
384 {
385 struct http_server_response *resp = *_resp;
386 struct http_server_request *req = resp->request;
387 struct ostream *output;
388 ssize_t sret;
389 int ret;
390
391 i_assert(req->state < HTTP_SERVER_REQUEST_STATE_SUBMITTED_RESPONSE ||
392 req->state == HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT);
393
394 http_server_response_ref(resp);
395
396 if (resp->payload_stream == NULL) {
397 output = http_server_response_get_payload_output(
398 resp, IO_BLOCK_SIZE, TRUE);
399 } else {
400 output = http_server_ostream_get_output(resp->payload_stream);
401 }
402
403 if (data != NULL) {
404 if ((sret = o_stream_send(output, data, size)) < 0) {
405 *_resp = NULL;
406 o_stream_destroy(&output);
407 http_server_response_unref(&resp);
408 return -1;
409 }
410 i_assert((size_t)sret == size);
411 } else {
412 if ((ret = o_stream_finish(output)) < 0) {
413 *_resp = NULL;
414 o_stream_destroy(&output);
415 http_server_response_unref(&resp);
416 return -1;
417 }
418 i_assert(ret > 0);
419 }
420
421 switch (req->state) {
422 case HTTP_SERVER_REQUEST_STATE_FINISHED:
423 ret = 1;
424 break;
425 case HTTP_SERVER_REQUEST_STATE_ABORTED:
426 e_debug(resp->event,
427 "Request aborted while sending blocking payload");
428 ret = -1;
429 break;
430 default:
431 ret = 0;
432 break;
433 }
434
435 if (data == NULL)
436 o_stream_destroy(&output);
437
438 /* Callback may have messed with our pointer, so unref using local
439 variable */
440 if (!http_server_response_unref(&resp))
441 *_resp = NULL;
442
443 /* Return status */
444 return ret;
445 }
446
http_server_response_send_payload(struct http_server_response ** _resp,const unsigned char * data,size_t size)447 int http_server_response_send_payload(struct http_server_response **_resp,
448 const unsigned char *data, size_t size)
449 {
450 struct http_server_response *resp = *_resp;
451 int ret;
452
453 resp->payload_corked = TRUE;
454
455 i_assert(data != NULL);
456
457 ret = http_server_response_output_payload(&resp, data, size);
458 if (ret < 0)
459 *_resp = NULL;
460 else {
461 i_assert(ret == 0);
462 i_assert(resp != NULL);
463 }
464 return ret;
465 }
466
http_server_response_finish_payload(struct http_server_response ** _resp)467 int http_server_response_finish_payload(struct http_server_response **_resp)
468 {
469 struct http_server_response *resp = *_resp;
470 int ret;
471
472 *_resp = NULL;
473 ret = http_server_response_output_payload(&resp, NULL, 0);
474 i_assert(ret != 0);
475 return ret < 0 ? -1 : 0;
476 }
477
http_server_response_abort_payload(struct http_server_response ** _resp)478 void http_server_response_abort_payload(struct http_server_response **_resp)
479 {
480 struct http_server_response *resp = *_resp;
481 struct http_server_request *req = resp->request;
482
483 *_resp = NULL;
484
485 http_server_request_abort(&req, "Aborted sending response payload");
486 }
487
488 static void
http_server_response_payload_input(struct http_server_response * resp)489 http_server_response_payload_input(struct http_server_response *resp)
490 {
491 struct http_server_connection *conn = resp->request->conn;
492
493 io_remove(&conn->io_resp_payload);
494
495 (void)http_server_connection_output(conn);
496 }
497
http_server_response_send_more(struct http_server_response * resp)498 int http_server_response_send_more(struct http_server_response *resp)
499 {
500 struct http_server_connection *conn = resp->request->conn;
501 struct ostream *output = resp->payload_output;
502 enum ostream_send_istream_result res;
503
504 i_assert(resp->payload_output != NULL);
505
506 if (resp->payload_finished) {
507 e_debug(resp->event, "Finish sending payload (more)");
508 return http_server_response_finish_payload_out(resp);
509 }
510
511 if (resp->payload_stream != NULL) {
512 conn->output_locked = TRUE;
513 return http_server_ostream_continue(resp->payload_stream);
514 }
515
516 i_assert(resp->payload_input != NULL);
517 io_remove(&conn->io_resp_payload);
518
519 /* Chunked ostream needs to write to the parent stream's buffer */
520 o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
521 res = o_stream_send_istream(output, resp->payload_input);
522 o_stream_set_max_buffer_size(output, SIZE_MAX);
523
524 switch (res) {
525 case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
526 /* Finished sending */
527 if (!resp->payload_chunked &&
528 (resp->payload_input->v_offset - resp->payload_offset) !=
529 resp->payload_size) {
530 e_error(resp->event,
531 "Payload stream %s size changed unexpectedly",
532 i_stream_get_name(resp->payload_input));
533 http_server_connection_close(
534 &conn, "Payload read failure");
535 return -1;
536 }
537 /* Finished sending payload */
538 e_debug(resp->event, "Finish sending payload");
539 return http_server_response_finish_payload_out(resp);
540 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
541 /* Input is blocking (server needs to act; disable timeout) */
542 conn->output_locked = TRUE;
543 http_server_connection_stop_idle_timeout(conn);
544 conn->io_resp_payload = io_add_istream(resp->payload_input,
545 http_server_response_payload_input, resp);
546 return 1;
547 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
548 /* Output is blocking (client needs to act; enable timeout) */
549 conn->output_locked = TRUE;
550 http_server_connection_start_idle_timeout(conn);
551 o_stream_set_flush_pending(output, TRUE);
552 //e_debug(resp->event, "Partially sent payload");
553 return 0;
554 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
555 /* We're in the middle of sending a response, so the connection
556 will also have to be aborted */
557 e_error(resp->event, "read(%s) failed: %s",
558 i_stream_get_name(resp->payload_input),
559 i_stream_get_error(resp->payload_input));
560 http_server_connection_close(&conn,
561 "Payload read failure");
562 return -1;
563 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
564 /* Failed to send response */
565 http_server_connection_handle_output_error(conn);
566 return -1;
567 }
568 i_unreached();
569 }
570
http_server_response_send_real(struct http_server_response * resp)571 static int http_server_response_send_real(struct http_server_response *resp)
572 {
573 struct http_server_request *req = resp->request;
574 struct http_server_connection *conn = req->conn;
575 string_t *rtext = t_str_new(256);
576 struct const_iovec iov[3];
577 uoff_t content_length = 0;
578 bool chunked = FALSE, send_content_length = FALSE, close = FALSE;
579 bool is_head = http_request_method_is(&req->req, "HEAD");
580 int ret;
581
582 i_assert(!conn->output_locked);
583
584 /* Determine response payload to send */
585 if (resp->payload_input != NULL) {
586 i_assert(resp->tunnel_callback == NULL &&
587 resp->status / 100 != 1 &&
588 resp->status != 204 && resp->status != 304);
589 if (resp->payload_chunked) {
590 if (http_server_request_version_equals(req, 1, 0)) {
591 /* Connection close marks end of payload
592 */
593 close = TRUE;
594 } else {
595 /* Input stream with unknown size */
596 chunked = TRUE;
597 }
598 } else {
599 /* Send Content-Length if we have specified a payload,
600 even if it's 0 bytes. */
601 content_length = resp->payload_size;
602 send_content_length = TRUE;
603 }
604 } else if (resp->payload_stream != NULL) {
605 /* HTTP payload output stream */
606 if (!http_server_ostream_get_size(resp->payload_stream,
607 &content_length)) {
608 /* size not known at this point */
609 chunked = TRUE;
610 } else {
611 /* output stream already finished, so data is
612 pre-buffered */
613 send_content_length = TRUE;
614 }
615 } else if (resp->tunnel_callback == NULL && resp->status / 100 != 1 &&
616 resp->status != 204 && resp->status != 304 && !is_head) {
617 /* RFC 7230, Section 3.3: Message Body
618
619 Responses to the HEAD request method (Section 4.3.2 of
620 [RFC7231]) never include a message body because the
621 associated response header fields (e.g., Transfer-Encoding,
622 Content-Length, etc.), if present, indicate only what their
623 values would have been if the request method had been GET
624 (Section 4.3.1 of [RFC7231]). 2xx (Successful) responses to a
625 CONNECT request method (Section 4.3.6 of [RFC7231]) switch to
626 tunnel mode instead of having a message body. All 1xx
627 (Informational), 204 (No Content), and 304 (Not Modified)
628 responses do not include a message body. All other responses
629 do include a message body, although the body might be of zero
630 length.
631
632 RFC 7230, Section 3.3.2: Content-Length
633
634 A server MUST NOT send a Content-Length header field in any
635 2xx (Successful) response to a CONNECT request (Section 4.3.6
636 of [RFC7231]).
637
638 -> Create empty body if it is missing.
639 */
640 send_content_length = TRUE;
641 }
642
643 /* Initialize output payload stream if needed */
644 if (is_head) {
645 e_debug(resp->event, "A HEAD response has no payload");
646 } else if (chunked) {
647 i_assert(resp->payload_input != NULL ||
648 resp->payload_stream != NULL);
649
650 e_debug(resp->event, "Will send payload in chunks");
651
652 resp->payload_output =
653 http_transfer_chunked_ostream_create(conn->conn.output);
654 } else if (send_content_length) {
655 i_assert(resp->payload_input != NULL || content_length == 0 ||
656 resp->payload_stream != NULL);
657
658 e_debug(resp->event,
659 "Will send payload with explicit size %"PRIuUOFF_T,
660 content_length);
661
662 if (content_length > 0) {
663 resp->payload_output = conn->conn.output;
664 o_stream_ref(conn->conn.output);
665 }
666 } else if (close) {
667 i_assert(resp->payload_input != NULL);
668
669 e_debug(resp->event,
670 "Will close connection after sending payload "
671 "(HTTP/1.0)");
672
673 resp->payload_output = conn->conn.output;
674 o_stream_ref(conn->conn.output);
675 } else {
676 e_debug(resp->event, "Response has no payload");
677 }
678
679 /* Create status line */
680 str_append(rtext, "HTTP/1.1 ");
681 str_printfa(rtext, "%u", resp->status);
682 str_append(rtext, " ");
683 str_append(rtext, resp->reason);
684
685 /* Create special headers implicitly if not set explicitly using
686 http_server_response_add_header() */
687 if (!resp->have_hdr_date) {
688 str_append(rtext, "\r\nDate: ");
689 str_append(rtext, http_date_create(resp->date));
690 str_append(rtext, "\r\n");
691 }
692 if (array_is_created(&resp->auth_challenges)) {
693 str_append(rtext, "WWW-Authenticate: ");
694 http_auth_create_challenges(rtext, &resp->auth_challenges);
695 str_append(rtext, "\r\n");
696 }
697 if (chunked) {
698 if (!resp->have_hdr_body_spec)
699 str_append(rtext, "Transfer-Encoding: chunked\r\n");
700 } else if (send_content_length) {
701 if (!resp->have_hdr_body_spec) {
702 str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n",
703 content_length);
704 }
705 }
706 if (!resp->have_hdr_connection) {
707 close = (close || req->req.connection_close ||
708 req->connection_close || req->conn->input_broken);
709 if (close && resp->tunnel_callback == NULL)
710 str_append(rtext, "Connection: close\r\n");
711 else if (http_server_request_version_equals(req, 1, 0))
712 str_append(rtext, "Connection: Keep-Alive\r\n");
713 }
714
715 /* Status line + implicit headers */
716 iov[0].iov_base = str_data(rtext);
717 iov[0].iov_len = str_len(rtext);
718 /* Explicit headers */
719 iov[1].iov_base = str_data(resp->headers);
720 iov[1].iov_len = str_len(resp->headers);
721 /* End of header */
722 iov[2].iov_base = "\r\n";
723 iov[2].iov_len = 2;
724
725 req->state = HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT;
726 o_stream_cork(conn->conn.output);
727
728 if (o_stream_sendv(conn->conn.output, iov, N_ELEMENTS(iov)) < 0) {
729 http_server_connection_handle_output_error(conn);
730 return -1;
731 }
732
733 e_debug(resp->event, "Sent header");
734
735 if (resp->payload_stream != NULL)
736 http_server_ostream_output_available(resp->payload_stream);
737 if (resp->payload_output != NULL) {
738 /* Non-blocking payload */
739 ret = http_server_response_send_more(resp);
740 if (ret < 0)
741 return -1;
742 } else {
743 /* No payload to send */
744 e_debug(resp->event, "No payload to send");
745 if (resp->payload_stream != NULL) {
746 ret = http_server_ostream_continue(resp->payload_stream);
747 if (ret < 0)
748 return -1;
749 }
750 conn->output_locked = FALSE;
751 ret = http_server_response_finish_payload_out(resp);
752 if (ret < 0)
753 return -1;
754 }
755
756 if (conn->conn.output != NULL && !resp->payload_corked &&
757 o_stream_uncork_flush(conn->conn.output) < 0) {
758 http_server_connection_handle_output_error(conn);
759 return -1;
760 }
761 return ret;
762 }
763
http_server_response_send(struct http_server_response * resp)764 int http_server_response_send(struct http_server_response *resp)
765 {
766 int ret;
767
768 T_BEGIN {
769 ret = http_server_response_send_real(resp);
770 } T_END;
771 return ret;
772 }
773
http_server_response_get_status(struct http_server_response * resp,int * status_r,const char ** reason_r)774 void http_server_response_get_status(struct http_server_response *resp,
775 int *status_r, const char **reason_r)
776 {
777 i_assert(resp != NULL);
778 *status_r = resp->status;
779 *reason_r = resp->reason;
780 }
781
http_server_response_get_total_size(struct http_server_response * resp)782 uoff_t http_server_response_get_total_size(struct http_server_response *resp)
783 {
784 i_assert(resp != NULL);
785 return resp->payload_size + str_len(resp->headers);
786 }
787
http_server_response_add_permanent_header(struct http_server_response * resp,const char * key,const char * value)788 void http_server_response_add_permanent_header(struct http_server_response *resp,
789 const char *key, const char *value)
790 {
791 http_server_response_add_header(resp, key, value);
792
793 if (!array_is_created(&resp->perm_headers))
794 i_array_init(&resp->perm_headers, 4);
795 char *key_dup = i_strdup(key);
796 char *value_dup = i_strdup(value);
797 array_push_back(&resp->perm_headers, &key_dup);
798 array_push_back(&resp->perm_headers, &value_dup);
799 }
800