1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "net.h"
5 #include "str.h"
6 #include "str-sanitize.h"
7 #include "hash.h"
8 #include "array.h"
9 #include "llist.h"
10 #include "time-util.h"
11 #include "istream.h"
12 #include "ostream.h"
13 #include "file-lock.h"
14 #include "dns-lookup.h"
15 #include "http-url.h"
16 #include "http-date.h"
17 #include "http-auth.h"
18 #include "http-response-parser.h"
19 #include "http-transfer.h"
20
21 #include "http-client-private.h"
22
23 const char *http_request_state_names[] = {
24 "new",
25 "queued",
26 "payload_out",
27 "waiting",
28 "got_response",
29 "payload_in",
30 "finished",
31 "aborted"
32 };
33
34 /*
35 * Request
36 */
37
38 static bool
39 http_client_request_send_error(struct http_client_request *req,
40 unsigned int status, const char *error);
41
http_client_request_label(struct http_client_request * req)42 const char *http_client_request_label(struct http_client_request *req)
43 {
44 if (req->label == NULL) {
45 req->label = p_strdup_printf(
46 req->pool, "[Req%u: %s %s%s]", req->id, req->method,
47 http_url_create_host(&req->origin_url), req->target);
48 }
49 return req->label;
50 }
51
http_client_request_update_event(struct http_client_request * req)52 static void http_client_request_update_event(struct http_client_request *req)
53 {
54 event_add_str(req->event, "method", req->method);
55 event_add_str(req->event, "dest_host", req->origin_url.host.name);
56 event_add_int(req->event, "dest_port",
57 http_url_get_port(&req->origin_url));
58 if (req->target != NULL)
59 event_add_str(req->event, "target", req->target);
60 event_set_append_log_prefix(
61 req->event, t_strdup_printf("request %s: ",
62 str_sanitize(http_client_request_label(req), 256)));
63 }
64
65 static struct event_passthrough *
http_client_request_result_event(struct http_client_request * req)66 http_client_request_result_event(struct http_client_request *req)
67 {
68 struct http_client_connection *conn = req->conn;
69
70 if (conn != NULL) {
71 if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) {
72 /* Got here prematurely; use bytes written so far */
73 i_assert(req->request_offset <
74 conn->conn.output->offset);
75 req->bytes_out = conn->conn.output->offset -
76 req->request_offset;
77 }
78 if (conn->incoming_payload != NULL &&
79 (req->state == HTTP_REQUEST_STATE_GOT_RESPONSE ||
80 req->state == HTTP_REQUEST_STATE_PAYLOAD_IN)) {
81 /* Got here prematurely; use bytes read so far */
82 i_assert(conn->in_req_callback ||
83 conn->pending_request == req);
84 i_assert(req->response_offset <
85 conn->conn.input->v_offset);
86 req->bytes_in = conn->conn.input->v_offset -
87 req->response_offset;
88 }
89 }
90
91 struct event_passthrough *e = event_create_passthrough(req->event);
92 if (req->queue != NULL &&
93 req->queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX)
94 e->add_str("dest_ip", net_ip2addr(&req->queue->addr.a.tcp.ip));
95
96 return e->add_int("status_code", req->last_status)->
97 add_int("attempts", req->attempts)->
98 add_int("redirects", req->redirects)->
99 add_int("bytes_in", req->bytes_in)->
100 add_int("bytes_out", req->bytes_out);
101 }
102
103 static struct http_client_request *
http_client_request_new(struct http_client * client,const char * method,http_client_request_callback_t * callback,void * context)104 http_client_request_new(struct http_client *client, const char *method,
105 http_client_request_callback_t *callback, void *context)
106 {
107 static unsigned int id_counter = 0;
108 pool_t pool;
109 struct http_client_request *req;
110
111 pool = pool_alloconly_create("http client request", 2048);
112 req = p_new(pool, struct http_client_request, 1);
113 req->pool = pool;
114 req->refcount = 1;
115 req->client = client;
116 req->id = ++id_counter;
117 req->method = p_strdup(pool, method);
118 req->callback = callback;
119 req->context = context;
120 req->date = (time_t)-1;
121 req->event = event_create(client->event);
122
123 /* Default to client-wide settings: */
124 req->max_attempts = client->set.max_attempts;
125 req->attempt_timeout_msecs = client->set.request_timeout_msecs;
126
127 req->state = HTTP_REQUEST_STATE_NEW;
128 return req;
129 }
130
131 #undef http_client_request
132 struct http_client_request *
http_client_request(struct http_client * client,const char * method,const char * host,const char * target,http_client_request_callback_t * callback,void * context)133 http_client_request(struct http_client *client,
134 const char *method, const char *host, const char *target,
135 http_client_request_callback_t *callback, void *context)
136 {
137 struct http_client_request *req;
138
139 req = http_client_request_new(client, method, callback, context);
140 req->origin_url.host.name = p_strdup(req->pool, host);
141 req->target = (target == NULL ? "/" : p_strdup(req->pool, target));
142 http_client_request_update_event(req);
143 return req;
144 }
145
146 #undef http_client_request_url
147 struct http_client_request *
http_client_request_url(struct http_client * client,const char * method,const struct http_url * target_url,http_client_request_callback_t * callback,void * context)148 http_client_request_url(struct http_client *client,
149 const char *method, const struct http_url *target_url,
150 http_client_request_callback_t *callback, void *context)
151 {
152 struct http_client_request *req;
153
154 req = http_client_request_new(client, method, callback, context);
155 http_url_copy_authority(req->pool, &req->origin_url, target_url);
156 req->target = p_strdup(req->pool, http_url_create_target(target_url));
157 if (target_url->user != NULL && *target_url->user != '\0' &&
158 target_url->password != NULL) {
159 req->username = p_strdup(req->pool, target_url->user);
160 req->password = p_strdup(req->pool, target_url->password);
161 }
162 http_client_request_update_event(req);
163 return req;
164 }
165
166 #undef http_client_request_url_str
167 struct http_client_request *
http_client_request_url_str(struct http_client * client,const char * method,const char * url_str,http_client_request_callback_t * callback,void * context)168 http_client_request_url_str(struct http_client *client,
169 const char *method, const char *url_str,
170 http_client_request_callback_t *callback,
171 void *context)
172 {
173 struct http_client_request *req, *tmpreq;
174 struct http_url *target_url;
175 const char *error;
176
177 req = tmpreq = http_client_request_new(client, method,
178 callback, context);
179
180 if (http_url_parse(url_str, NULL, HTTP_URL_ALLOW_USERINFO_PART,
181 req->pool, &target_url, &error) < 0) {
182 req->label = p_strdup_printf(req->pool, "[Req%u: %s %s]",
183 req->id, req->method, url_str);
184 http_client_request_error(
185 &tmpreq, HTTP_CLIENT_REQUEST_ERROR_INVALID_URL,
186 t_strdup_printf("Invalid HTTP URL: %s", error));
187 http_client_request_update_event(req);
188 return req;
189 }
190
191 req->origin_url = *target_url;
192 req->target = p_strdup(req->pool, http_url_create_target(target_url));
193 if (target_url->user != NULL && *target_url->user != '\0' &&
194 target_url->password != NULL) {
195 req->username = p_strdup(req->pool, target_url->user);
196 req->password = p_strdup(req->pool, target_url->password);
197 }
198 http_client_request_update_event(req);
199 return req;
200 }
201
202 #undef http_client_request_connect
203 struct http_client_request *
http_client_request_connect(struct http_client * client,const char * host,in_port_t port,http_client_request_callback_t * callback,void * context)204 http_client_request_connect(struct http_client *client,
205 const char *host, in_port_t port,
206 http_client_request_callback_t *callback,
207 void *context)
208 {
209 struct http_client_request *req;
210
211 req = http_client_request_new(client, "CONNECT", callback, context);
212 req->origin_url.host.name = p_strdup(req->pool, host);
213 req->origin_url.port = port;
214 req->connect_tunnel = TRUE;
215 req->target = req->origin_url.host.name;
216 http_client_request_update_event(req);
217 return req;
218 }
219
220 #undef http_client_request_connect_ip
221 struct http_client_request *
http_client_request_connect_ip(struct http_client * client,const struct ip_addr * ip,in_port_t port,http_client_request_callback_t * callback,void * context)222 http_client_request_connect_ip(struct http_client *client,
223 const struct ip_addr *ip, in_port_t port,
224 http_client_request_callback_t *callback,
225 void *context)
226 {
227 struct http_client_request *req;
228 const char *hostname;
229
230 i_assert(ip->family != 0);
231 hostname = net_ip2addr(ip);
232
233 req = http_client_request_connect(client, hostname, port,
234 callback, context);
235 req->origin_url.host.ip = *ip;
236 return req;
237 }
238
http_client_request_set_event(struct http_client_request * req,struct event * event)239 void http_client_request_set_event(struct http_client_request *req,
240 struct event *event)
241 {
242 event_unref(&req->event);
243 req->event = event_create(event);
244 event_set_forced_debug(req->event, req->client->set.debug);
245 http_client_request_update_event(req);
246 }
247
http_client_request_add(struct http_client_request * req)248 static void http_client_request_add(struct http_client_request *req)
249 {
250 struct http_client *client = req->client;
251
252 DLLIST_PREPEND(&client->requests_list, req);
253 client->requests_count++;
254 req->listed = TRUE;
255 }
256
http_client_request_remove(struct http_client_request * req)257 static void http_client_request_remove(struct http_client_request *req)
258 {
259 struct http_client *client = req->client;
260
261 if (client == NULL) {
262 i_assert(!req->listed);
263 return;
264 }
265 if (req->listed) {
266 /* Only decrease pending request counter if this request was
267 submitted */
268 DLLIST_REMOVE(&client->requests_list, req);
269 client->requests_count--;
270 }
271 req->listed = FALSE;
272
273 if (client->requests_count == 0 && client->waiting)
274 io_loop_stop(client->ioloop);
275 }
276
http_client_request_ref(struct http_client_request * req)277 void http_client_request_ref(struct http_client_request *req)
278 {
279 i_assert(req->refcount > 0);
280 req->refcount++;
281 }
282
http_client_request_unref(struct http_client_request ** _req)283 bool http_client_request_unref(struct http_client_request **_req)
284 {
285 struct http_client_request *req = *_req;
286 struct http_client *client = req->client;
287
288 i_assert(req->refcount > 0);
289
290 *_req = NULL;
291
292 if (--req->refcount > 0)
293 return TRUE;
294
295 if (client == NULL) {
296 e_debug(req->event, "Free (client already destroyed)");
297 } else {
298 e_debug(req->event, "Free (requests left=%d)",
299 client->requests_count);
300 }
301
302 /* Cannot be destroyed while it is still pending */
303 i_assert(req->conn == NULL);
304
305 if (req->queue != NULL)
306 http_client_queue_drop_request(req->queue, req);
307
308 if (req->destroy_callback != NULL) {
309 req->destroy_callback(req->destroy_context);
310 req->destroy_callback = NULL;
311 }
312
313 http_client_request_remove(req);
314
315 if (client != NULL) {
316 if (client->requests_count == 0 && client->waiting)
317 io_loop_stop(client->ioloop);
318 if (req->delayed_error != NULL)
319 http_client_remove_request_error(req->client, req);
320 }
321 i_stream_unref(&req->payload_input);
322 o_stream_unref(&req->payload_output);
323 str_free(&req->headers);
324 event_unref(&req->event);
325 pool_unref(&req->pool);
326 return FALSE;
327 }
328
http_client_request_destroy(struct http_client_request ** _req)329 void http_client_request_destroy(struct http_client_request **_req)
330 {
331 struct http_client_request *req = *_req, *tmp_req;
332 struct http_client *client = req->client;
333
334 *_req = NULL;
335
336 if (client == NULL) {
337 e_debug(req->event, "Destroy (client already destroyed)");
338 } else {
339 e_debug(req->event, "Destroy (requests left=%d)",
340 client->requests_count);
341 }
342
343
344 if (req->state < HTTP_REQUEST_STATE_FINISHED)
345 req->state = HTTP_REQUEST_STATE_ABORTED;
346 req->callback = NULL;
347
348 if (req->queue != NULL)
349 http_client_queue_drop_request(req->queue, req);
350
351 if (client != NULL && req->delayed_error != NULL)
352 http_client_remove_request_error(req->client, req);
353 req->delayed_error = NULL;
354
355 if (req->destroy_callback != NULL) {
356 void (*callback)(void *) = req->destroy_callback;
357
358 req->destroy_callback = NULL;
359 callback(req->destroy_context);
360 }
361
362 if (req->conn != NULL)
363 http_client_connection_request_destroyed(req->conn, req);
364
365 tmp_req = req;
366 http_client_request_remove(req);
367 if (http_client_request_unref(&tmp_req))
368 req->client = NULL;
369 }
370
http_client_request_set_port(struct http_client_request * req,in_port_t port)371 void http_client_request_set_port(struct http_client_request *req,
372 in_port_t port)
373 {
374 i_assert(req->state == HTTP_REQUEST_STATE_NEW);
375 req->origin_url.port = port;
376 event_add_int(req->event, "port", port);
377 }
378
http_client_request_set_ssl(struct http_client_request * req,bool ssl)379 void http_client_request_set_ssl(struct http_client_request *req, bool ssl)
380 {
381 i_assert(req->state == HTTP_REQUEST_STATE_NEW);
382 req->origin_url.have_ssl = ssl;
383 }
384
http_client_request_set_urgent(struct http_client_request * req)385 void http_client_request_set_urgent(struct http_client_request *req)
386 {
387 i_assert(req->state == HTTP_REQUEST_STATE_NEW);
388 req->urgent = TRUE;
389 }
390
http_client_request_set_preserve_exact_reason(struct http_client_request * req)391 void http_client_request_set_preserve_exact_reason(
392 struct http_client_request *req)
393 {
394 req->preserve_exact_reason = TRUE;
395 }
396
397 static bool
http_client_request_lookup_header_pos(struct http_client_request * req,const char * key,size_t * key_pos_r,size_t * value_pos_r,size_t * next_pos_r)398 http_client_request_lookup_header_pos(struct http_client_request *req,
399 const char *key, size_t *key_pos_r,
400 size_t *value_pos_r, size_t *next_pos_r)
401 {
402 const unsigned char *data, *p;
403 size_t size, line_len;
404 size_t key_len = strlen(key);
405
406 if (req->headers == NULL)
407 return FALSE;
408
409 data = str_data(req->headers);
410 size = str_len(req->headers);
411 while ((p = memchr(data, '\n', size)) != NULL) {
412 line_len = (p+1) - data;
413 if (size > key_len && i_memcasecmp(data, key, key_len) == 0 &&
414 data[key_len] == ':' && data[key_len+1] == ' ') {
415 /* Key was found from header, replace its value */
416 *key_pos_r = str_len(req->headers) - size;
417 *value_pos_r = *key_pos_r + key_len + 2;
418 *next_pos_r = *key_pos_r + line_len;
419 return TRUE;
420 }
421 size -= line_len;
422 data += line_len;
423 }
424 return FALSE;
425 }
426
427 static void
http_client_request_add_header_full(struct http_client_request * req,const char * key,const char * value,bool replace_existing)428 http_client_request_add_header_full(struct http_client_request *req,
429 const char *key, const char *value,
430 bool replace_existing)
431 {
432 size_t key_pos, value_pos, next_pos;
433
434 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
435 /* Allow calling for retries */
436 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE ||
437 req->state == HTTP_REQUEST_STATE_ABORTED);
438 /* Make sure key or value can't break HTTP headers entirely */
439 i_assert(strpbrk(key, ":\r\n") == NULL);
440 i_assert(strpbrk(value, "\r\n") == NULL);
441
442 /* Mark presence of special headers */
443 switch (key[0]) {
444 case 'a': case 'A':
445 if (strcasecmp(key, "Authorization") == 0)
446 req->have_hdr_authorization = TRUE;
447 break;
448 case 'c': case 'C':
449 if (strcasecmp(key, "Connection") == 0)
450 req->have_hdr_connection = TRUE;
451 else if (strcasecmp(key, "Content-Length") == 0)
452 req->have_hdr_body_spec = TRUE;
453 break;
454 case 'd': case 'D':
455 if (strcasecmp(key, "Date") == 0)
456 req->have_hdr_date = TRUE;
457 break;
458 case 'e': case 'E':
459 if (strcasecmp(key, "Expect") == 0)
460 req->have_hdr_expect = TRUE;
461 break;
462 case 'h': case 'H':
463 if (strcasecmp(key, "Host") == 0)
464 req->have_hdr_host = TRUE;
465 break;
466 case 'p': case 'P':
467 i_assert(strcasecmp(key, "Proxy-Authorization") != 0);
468 break;
469 case 't': case 'T':
470 if (strcasecmp(key, "Transfer-Encoding") == 0)
471 req->have_hdr_body_spec = TRUE;
472 break;
473 case 'u': case 'U':
474 if (strcasecmp(key, "User-Agent") == 0)
475 req->have_hdr_user_agent = TRUE;
476 break;
477 }
478 if (req->headers == NULL)
479 req->headers = str_new(default_pool, 256);
480 if (!http_client_request_lookup_header_pos(req, key, &key_pos,
481 &value_pos, &next_pos))
482 str_printfa(req->headers, "%s: %s\r\n", key, value);
483 else if (replace_existing) {
484 /* Don't delete CRLF */
485 size_t old_value_len = next_pos - value_pos - 2;
486 str_replace(req->headers, value_pos, old_value_len, value);
487 }
488 }
489
http_client_request_add_header(struct http_client_request * req,const char * key,const char * value)490 void http_client_request_add_header(struct http_client_request *req,
491 const char *key, const char *value)
492 {
493 http_client_request_add_header_full(req, key, value, TRUE);
494 }
495
http_client_request_add_missing_header(struct http_client_request * req,const char * key,const char * value)496 void http_client_request_add_missing_header(struct http_client_request *req,
497 const char *key, const char *value)
498 {
499 http_client_request_add_header_full(req, key, value, FALSE);
500 }
501
http_client_request_remove_header(struct http_client_request * req,const char * key)502 void http_client_request_remove_header(struct http_client_request *req,
503 const char *key)
504 {
505 size_t key_pos, value_pos, next_pos;
506
507 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
508 /* Allow calling for retries */
509 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE ||
510 req->state == HTTP_REQUEST_STATE_ABORTED);
511
512 if (http_client_request_lookup_header_pos(req, key, &key_pos,
513 &value_pos, &next_pos))
514 str_delete(req->headers, key_pos, next_pos - key_pos);
515 }
516
http_client_request_lookup_header(struct http_client_request * req,const char * key)517 const char *http_client_request_lookup_header(struct http_client_request *req,
518 const char *key)
519 {
520 size_t key_pos, value_pos, next_pos;
521
522 if (!http_client_request_lookup_header_pos(req, key, &key_pos,
523 &value_pos, &next_pos))
524 return NULL;
525
526 /* Don't return CRLF */
527 return t_strndup(str_data(req->headers) + value_pos,
528 next_pos - value_pos - 2);
529 }
530
http_client_request_set_date(struct http_client_request * req,time_t date)531 void http_client_request_set_date(struct http_client_request *req, time_t date)
532 {
533 i_assert(req->state == HTTP_REQUEST_STATE_NEW);
534 req->date = date;
535 }
536
http_client_request_set_payload(struct http_client_request * req,struct istream * input,bool sync)537 void http_client_request_set_payload(struct http_client_request *req,
538 struct istream *input, bool sync)
539 {
540 int ret;
541
542 i_assert(req->state == HTTP_REQUEST_STATE_NEW);
543 i_assert(req->payload_input == NULL);
544
545 i_stream_ref(input);
546 req->payload_input = input;
547 if ((ret = i_stream_get_size(input, TRUE, &req->payload_size)) <= 0) {
548 if (ret < 0) {
549 i_error("i_stream_get_size(%s) failed: %s",
550 i_stream_get_name(input),
551 i_stream_get_error(input));
552 }
553 req->payload_size = 0;
554 req->payload_chunked = TRUE;
555 } else {
556 i_assert(input->v_offset <= req->payload_size);
557 req->payload_size -= input->v_offset;
558 }
559 req->payload_offset = input->v_offset;
560
561 /* Prepare request payload sync using 100 Continue response from server
562 */
563 if ((req->payload_chunked || req->payload_size > 0) && sync)
564 req->payload_sync = TRUE;
565 }
566
http_client_request_set_payload_data(struct http_client_request * req,const unsigned char * data,size_t size)567 void http_client_request_set_payload_data(struct http_client_request *req,
568 const unsigned char *data,
569 size_t size)
570 {
571 struct istream *input;
572 unsigned char *payload_data;
573
574 if (size == 0)
575 return;
576
577 payload_data = p_malloc(req->pool, size);
578 memcpy(payload_data, data, size);
579 input = i_stream_create_from_data(payload_data, size);
580
581 http_client_request_set_payload(req, input, FALSE);
582 i_stream_unref(&input);
583 }
584
http_client_request_set_payload_empty(struct http_client_request * req)585 void http_client_request_set_payload_empty(struct http_client_request *req)
586 {
587 req->payload_empty = TRUE;
588 }
589
http_client_request_set_timeout_msecs(struct http_client_request * req,unsigned int msecs)590 void http_client_request_set_timeout_msecs(struct http_client_request *req,
591 unsigned int msecs)
592 {
593 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
594 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
595
596 req->timeout_msecs = msecs;
597 }
598
http_client_request_set_timeout(struct http_client_request * req,const struct timeval * time)599 void http_client_request_set_timeout(struct http_client_request *req,
600 const struct timeval *time)
601 {
602 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
603 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
604
605 req->timeout_time = *time;
606 req->timeout_msecs = 0;
607 }
608
http_client_request_set_attempt_timeout_msecs(struct http_client_request * req,unsigned int msecs)609 void http_client_request_set_attempt_timeout_msecs(
610 struct http_client_request *req, unsigned int msecs)
611 {
612 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
613 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
614
615 req->attempt_timeout_msecs = msecs;
616 }
617
http_client_request_set_max_attempts(struct http_client_request * req,unsigned int max_attempts)618 void http_client_request_set_max_attempts(struct http_client_request *req,
619 unsigned int max_attempts)
620 {
621 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
622 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
623
624 req->max_attempts = max_attempts;
625 }
626
http_client_request_set_event_headers(struct http_client_request * req,const char * const * headers)627 void http_client_request_set_event_headers(struct http_client_request *req,
628 const char *const *headers)
629 {
630 req->event_headers = p_strarray_dup(req->pool, headers);
631 }
632
http_client_request_set_auth_simple(struct http_client_request * req,const char * username,const char * password)633 void http_client_request_set_auth_simple(struct http_client_request *req,
634 const char *username,
635 const char *password)
636 {
637 req->username = p_strdup(req->pool, username);
638 req->password = p_strdup(req->pool, password);
639 }
640
http_client_request_set_proxy_url(struct http_client_request * req,const struct http_url * proxy_url)641 void http_client_request_set_proxy_url(struct http_client_request *req,
642 const struct http_url *proxy_url)
643 {
644 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
645 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
646
647 req->host_url = http_url_clone_authority(req->pool, proxy_url);
648 req->host_socket = NULL;
649 }
650
http_client_request_set_proxy_socket(struct http_client_request * req,const char * proxy_socket)651 void http_client_request_set_proxy_socket(struct http_client_request *req,
652 const char *proxy_socket)
653 {
654 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
655 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
656
657 req->host_socket = p_strdup(req->pool, proxy_socket);
658 req->host_url = NULL;
659 }
660
http_client_request_delay_until(struct http_client_request * req,time_t time)661 void http_client_request_delay_until(struct http_client_request *req,
662 time_t time)
663 {
664 req->release_time.tv_sec = time;
665 req->release_time.tv_usec = 0;
666 }
667
http_client_request_delay(struct http_client_request * req,time_t seconds)668 void http_client_request_delay(struct http_client_request *req, time_t seconds)
669 {
670 req->release_time = ioloop_timeval;
671 req->release_time.tv_sec += seconds;
672 }
673
http_client_request_delay_msecs(struct http_client_request * req,unsigned int msecs)674 void http_client_request_delay_msecs(struct http_client_request *req,
675 unsigned int msecs)
676 {
677 req->release_time = ioloop_timeval;
678 timeval_add_msecs(&req->release_time, msecs);
679 }
680
http_client_request_delay_from_response(struct http_client_request * req,const struct http_response * response)681 int http_client_request_delay_from_response(
682 struct http_client_request *req, const struct http_response *response)
683 {
684 time_t retry_after = response->retry_after;
685 unsigned int max;
686
687 i_assert(req->client != NULL);
688
689 if (retry_after == (time_t)-1)
690 return 0; /* no delay */
691 if (retry_after < ioloop_time)
692 return 0; /* delay already expired */
693 max = (req->client->set.max_auto_retry_delay == 0 ?
694 req->attempt_timeout_msecs / 1000 :
695 req->client->set.max_auto_retry_delay);
696 if ((unsigned int)(retry_after - ioloop_time) > max)
697 return -1; /* delay too long */
698 req->release_time.tv_sec = retry_after;
699 req->release_time.tv_usec = 0;
700 return 1; /* valid delay */
701 }
702
703 const char *
http_client_request_get_method(const struct http_client_request * req)704 http_client_request_get_method(const struct http_client_request *req)
705 {
706 return req->method;
707 }
708
709 const char *
http_client_request_get_target(const struct http_client_request * req)710 http_client_request_get_target(const struct http_client_request *req)
711 {
712 return req->target;
713 }
714
715 const struct http_url *
http_client_request_get_origin_url(const struct http_client_request * req)716 http_client_request_get_origin_url(const struct http_client_request *req)
717 {
718 return &req->origin_url;
719 }
720
721 enum http_request_state
http_client_request_get_state(const struct http_client_request * req)722 http_client_request_get_state(const struct http_client_request *req)
723 {
724 return req->state;
725 }
726
727 unsigned int
http_client_request_get_attempts(const struct http_client_request * req)728 http_client_request_get_attempts(const struct http_client_request *req)
729 {
730 return req->attempts;
731 }
732
http_client_request_get_stats(struct http_client_request * req,struct http_client_request_stats * stats_r)733 void http_client_request_get_stats(struct http_client_request *req,
734 struct http_client_request_stats *stats_r)
735 {
736 struct http_client *client = req->client;
737 int diff_msecs;
738 uint64_t wait_usecs;
739
740 i_zero(stats_r);
741 if (!req->submitted)
742 return;
743
744 /* Total elapsed time since message was submitted */
745 diff_msecs = timeval_diff_msecs(&ioloop_timeval, &req->submit_time);
746 stats_r->total_msecs = (unsigned int)I_MAX(diff_msecs, 0);
747
748 /* Elapsed time since message was first sent */
749 if (req->first_sent_time.tv_sec > 0) {
750 diff_msecs = timeval_diff_msecs(&ioloop_timeval,
751 &req->first_sent_time);
752 stats_r->first_sent_msecs = (unsigned int)I_MAX(diff_msecs, 0);
753 }
754
755 /* Elapsed time since message was last sent */
756 if (req->sent_time.tv_sec > 0) {
757 diff_msecs = timeval_diff_msecs(&ioloop_timeval,
758 &req->sent_time);
759 stats_r->last_sent_msecs = (unsigned int)I_MAX(diff_msecs, 0);
760 }
761
762 if (req->conn != NULL) {
763 /* Time spent in other ioloops */
764 i_assert(ioloop_global_wait_usecs >=
765 req->sent_global_ioloop_usecs);
766 stats_r->other_ioloop_msecs = (unsigned int)
767 (ioloop_global_wait_usecs -
768 req->sent_global_ioloop_usecs + 999) / 1000;
769
770 /* Time spent in the http-client's own ioloop */
771 if (client != NULL && client->waiting) {
772 wait_usecs =
773 io_wait_timer_get_usecs(req->conn->io_wait_timer);
774 i_assert(wait_usecs >= req->sent_http_ioloop_usecs);
775 stats_r->http_ioloop_msecs = (unsigned int)
776 (wait_usecs -
777 req->sent_http_ioloop_usecs + 999) / 1000;
778
779 i_assert(stats_r->other_ioloop_msecs >=
780 stats_r->http_ioloop_msecs);
781 stats_r->other_ioloop_msecs -= stats_r->http_ioloop_msecs;
782 }
783 }
784
785 /* Total time spent on waiting for file locks */
786 wait_usecs = file_lock_wait_get_total_usecs();
787 i_assert(wait_usecs >= req->sent_lock_usecs);
788 stats_r->lock_msecs = (unsigned int)
789 (wait_usecs - req->sent_lock_usecs + 999) / 1000;
790
791 /* Number of attempts for this request */
792 stats_r->attempts = req->attempts;
793 /* Number of send attempts for this request */
794 stats_r->send_attempts = req->send_attempts;
795 }
796
http_client_request_append_stats_text(struct http_client_request * req,string_t * str)797 void http_client_request_append_stats_text(struct http_client_request *req,
798 string_t *str)
799 {
800 struct http_client_request_stats stats;
801
802 if (!req->submitted) {
803 str_append(str, "not yet submitted");
804 return;
805 }
806
807 http_client_request_get_stats(req, &stats);
808
809 str_printfa(str, "queued %u.%03u secs ago",
810 stats.total_msecs/1000, stats.total_msecs%1000);
811 if (stats.attempts > 0)
812 str_printfa(str, ", %u times retried", stats.attempts);
813
814 if (stats.send_attempts == 0) {
815 str_append(str, ", not yet sent");
816 } else {
817 str_printfa(str, ", %u send attempts in %u.%03u secs",
818 stats.send_attempts, stats.first_sent_msecs/1000,
819 stats.first_sent_msecs%1000);
820 if (stats.send_attempts > 1) {
821 str_printfa(str, ", %u.%03u in last attempt",
822 stats.last_sent_msecs/1000,
823 stats.last_sent_msecs%1000);
824 }
825 }
826
827 if (stats.http_ioloop_msecs > 0) {
828 str_printfa(str, ", %u.%03u in http ioloop",
829 stats.http_ioloop_msecs/1000,
830 stats.http_ioloop_msecs%1000);
831 }
832 str_printfa(str, ", %u.%03u in other ioloops",
833 stats.other_ioloop_msecs/1000,
834 stats.other_ioloop_msecs%1000);
835
836 if (stats.lock_msecs > 0) {
837 str_printfa(str, ", %u.%03u in locks",
838 stats.lock_msecs/1000, stats.lock_msecs%1000);
839 }
840 }
841
842 enum http_response_payload_type
http_client_request_get_payload_type(struct http_client_request * req)843 http_client_request_get_payload_type(struct http_client_request *req)
844 {
845 /* RFC 7230, Section 3.3:
846
847 The presence of a message body in a response depends on both the
848 request method to which it is responding and the response status code
849 (Section 3.1.2 of [RFC7230]). Responses to the HEAD request method
850 (Section 4.3.2 of [RFC7231]) never include a message body because the
851 associated response header fields (e.g., Transfer-Encoding,
852 Content-Length, etc.), if present, indicate only what their values
853 would have been if the request method had been GET (Section 4.3.1 of
854 [RFC7231]). 2xx (Successful) responses to a CONNECT request method
855 (Section 4.3.6 of [RFC7231]) switch to tunnel mode instead of having
856 a message body.
857 */
858 if (strcmp(req->method, "HEAD") == 0)
859 return HTTP_RESPONSE_PAYLOAD_TYPE_NOT_PRESENT;
860 if (strcmp(req->method, "CONNECT") == 0)
861 return HTTP_RESPONSE_PAYLOAD_TYPE_ONLY_UNSUCCESSFUL;
862 return HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
863 }
864
http_client_request_do_submit(struct http_client_request * req)865 static void http_client_request_do_submit(struct http_client_request *req)
866 {
867 struct http_client *client = req->client;
868 struct http_client_host *host;
869 const char *proxy_socket_path = client->set.proxy_socket_path;
870 const struct http_url *proxy_url = client->set.proxy_url;
871 bool have_proxy =
872 ((proxy_socket_path != NULL) || (proxy_url != NULL) ||
873 (req->host_socket != NULL) || (req->host_url != NULL));
874 const char *authority, *target;
875
876 if (req->state == HTTP_REQUEST_STATE_ABORTED)
877 return;
878 i_assert(client != NULL);
879 i_assert(req->state == HTTP_REQUEST_STATE_NEW);
880
881 authority = http_url_create_authority(&req->origin_url);
882 if (req->connect_tunnel) {
883 /* Connect requests require authority form for request target */
884 target = authority;
885 } else {
886 /* Absolute target URL */
887 target = t_strconcat(http_url_create_host(&req->origin_url),
888 req->target, NULL);
889 }
890
891 /* Determine what host to contact to submit this request */
892 if (have_proxy) {
893 if (req->host_socket != NULL) {
894 /* Specific socket proxy */
895 req->host_url = NULL;
896 } else if (req->host_url != NULL) {
897 /* Specific normal proxy */
898 req->host_socket = NULL;
899 } else if (req->origin_url.have_ssl &&
900 !client->set.no_ssl_tunnel &&
901 !req->connect_tunnel) {
902 /* Tunnel to origin server */
903 req->host_url = &req->origin_url;
904 req->ssl_tunnel = TRUE;
905 } else if (proxy_socket_path != NULL) {
906 /* Proxy on unix socket */
907 req->host_socket = proxy_socket_path;
908 req->host_url = NULL;
909 } else {
910 /* Normal proxy server */
911 req->host_url = proxy_url;
912 req->host_socket = NULL;
913 }
914 } else {
915 /* Origin server */
916 req->host_url = &req->origin_url;
917 }
918
919 /* Use submission date if no date is set explicitly */
920 if (req->date == (time_t)-1)
921 req->date = ioloop_time;
922
923 /* Prepare value for Host header */
924 req->authority = p_strdup(req->pool, authority);
925
926 /* Debug label */
927 req->label = p_strdup_printf(req->pool, "[Req%u: %s %s]",
928 req->id, req->method, target);
929
930 /* Update request target */
931 if (req->connect_tunnel || have_proxy)
932 req->target = p_strdup(req->pool, target);
933
934 if (!have_proxy) {
935 /* If we don't have a proxy, CONNECT requests are handled by
936 creating the requested connection directly */
937 req->connect_direct = req->connect_tunnel;
938 if (req->connect_direct)
939 req->urgent = TRUE;
940 }
941
942 if (req->timeout_time.tv_sec == 0) {
943 if (req->timeout_msecs > 0) {
944 req->timeout_time = ioloop_timeval;
945 timeval_add_msecs(&req->timeout_time,
946 req->timeout_msecs);
947 } else if (client->set.request_absolute_timeout_msecs > 0) {
948 req->timeout_time = ioloop_timeval;
949 timeval_add_msecs(&req->timeout_time,
950 client->set.request_absolute_timeout_msecs);
951 }
952 }
953
954 host = http_client_host_get(client, req->host_url);
955 req->state = HTTP_REQUEST_STATE_QUEUED;
956 req->last_status = 0;
957
958 http_client_host_submit_request(host, req);
959 }
960
http_client_request_submit(struct http_client_request * req)961 void http_client_request_submit(struct http_client_request *req)
962 {
963 i_assert(req->client != NULL);
964
965 req->submit_time = ioloop_timeval;
966
967 http_client_request_update_event(req);
968 http_client_request_do_submit(req);
969
970 req->submitted = TRUE;
971 http_client_request_add(req);
972
973 e_debug(req->event, "Submitted (requests left=%d)",
974 req->client->requests_count);
975 }
976
http_client_request_get_peer_addr(const struct http_client_request * req,struct http_client_peer_addr * addr)977 void http_client_request_get_peer_addr(const struct http_client_request *req,
978 struct http_client_peer_addr *addr)
979 {
980 const char *host_socket = req->host_socket;
981 const struct http_url *host_url = req->host_url;
982
983 /* The IP address may be unassigned in the returned peer address, since
984 that is only available at this stage when the target URL has an
985 explicit IP address. */
986 i_zero(addr);
987 if (host_socket != NULL) {
988 addr->type = HTTP_CLIENT_PEER_ADDR_UNIX;
989 addr->a.un.path = host_socket;
990 } else if (req->connect_direct) {
991 addr->type = HTTP_CLIENT_PEER_ADDR_RAW;
992 addr->a.tcp.ip = host_url->host.ip;
993 addr->a.tcp.port =
994 http_url_get_port_default(host_url, HTTPS_DEFAULT_PORT);
995 } else if (host_url->have_ssl) {
996 if (req->ssl_tunnel)
997 addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL;
998 else
999 addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS;
1000 addr->a.tcp.ip = host_url->host.ip;
1001 addr->a.tcp.https_name = host_url->host.name;
1002 addr->a.tcp.port = http_url_get_port(host_url);
1003 } else {
1004 addr->type = HTTP_CLIENT_PEER_ADDR_HTTP;
1005 addr->a.tcp.ip = host_url->host.ip;
1006 addr->a.tcp.port = http_url_get_port(host_url);
1007 }
1008 }
1009
http_client_request_flush_payload(struct http_client_request * req)1010 static int http_client_request_flush_payload(struct http_client_request *req)
1011 {
1012 struct http_client_connection *conn = req->conn;
1013 int ret;
1014
1015 if (req->payload_output != conn->conn.output &&
1016 (ret = o_stream_finish(req->payload_output)) <= 0) {
1017 if (ret < 0)
1018 http_client_connection_handle_output_error(conn);
1019 return ret;
1020 }
1021
1022 return 1;
1023 }
1024
1025 static int
http_client_request_finish_payload_out(struct http_client_request * req)1026 http_client_request_finish_payload_out(struct http_client_request *req)
1027 {
1028 struct http_client_connection *conn = req->conn;
1029 int ret;
1030
1031 i_assert(conn != NULL);
1032 req->payload_finished = TRUE;
1033
1034 /* Drop payload output stream */
1035 if (req->payload_output != NULL) {
1036 ret = http_client_request_flush_payload(req);
1037 if (ret < 0)
1038 return -1;
1039 if (ret == 0) {
1040 e_debug(req->event,
1041 "Not quite finished sending payload");
1042 return 0;
1043 }
1044 o_stream_unref(&req->payload_output);
1045 req->payload_output = NULL;
1046 }
1047
1048 i_assert(req->request_offset < conn->conn.output->offset);
1049 req->bytes_out = conn->conn.output->offset - req->request_offset;
1050
1051 /* Advance state only when request didn't get aborted in the mean time
1052 */
1053 if (req->state != HTTP_REQUEST_STATE_ABORTED) {
1054 i_assert(req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
1055
1056 /* we're now waiting for a response from the server */
1057 req->state = HTTP_REQUEST_STATE_WAITING;
1058 http_client_connection_start_request_timeout(conn);
1059 }
1060
1061 /* Release connection */
1062 conn->output_locked = FALSE;
1063
1064 e_debug(req->event, "Finished sending%s payload",
1065 (req->state == HTTP_REQUEST_STATE_ABORTED ? " aborted" : ""));
1066 return 1;
1067 }
1068
1069 static int
http_client_request_continue_payload(struct http_client_request ** _req,const unsigned char * data,size_t size)1070 http_client_request_continue_payload(struct http_client_request **_req,
1071 const unsigned char *data, size_t size)
1072 {
1073 struct ioloop *prev_ioloop, *client_ioloop, *prev_client_ioloop;
1074 struct http_client_request *req = *_req;
1075 struct http_client_connection *conn = req->conn;
1076 struct http_client *client = req->client;
1077 int ret;
1078
1079 i_assert(client != NULL);
1080 i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
1081 req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
1082 i_assert(req->payload_input == NULL);
1083
1084 if (conn != NULL)
1085 http_client_connection_ref(conn);
1086 http_client_request_ref(req);
1087 req->payload_wait = TRUE;
1088
1089 if (data == NULL) {
1090 req->payload_input = NULL;
1091 if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT)
1092 (void)http_client_request_finish_payload_out(req);
1093 } else {
1094 req->payload_input = i_stream_create_from_data(data, size);
1095 i_stream_set_name(req->payload_input, "<HTTP request payload>");
1096 }
1097 req->payload_size = 0;
1098 req->payload_chunked = TRUE;
1099
1100 if (req->state == HTTP_REQUEST_STATE_NEW)
1101 http_client_request_submit(req);
1102 if (req->state == HTTP_REQUEST_STATE_ABORTED) {
1103 /* Request already failed */
1104 if (req->delayed_error != NULL) {
1105 struct http_client_request *tmpreq = req;
1106
1107 /* Handle delayed error outside ioloop; the caller
1108 expects callbacks occurring, so there is no need for
1109 delay. Also, it is very important that any error
1110 triggers a callback before
1111 http_client_request_send_payload() finishes, since
1112 its return value is not always checked.
1113 */
1114 http_client_remove_request_error(client, req);
1115 http_client_request_error_delayed(&tmpreq);
1116 }
1117 } else {
1118 /* Wait for payload data to be written */
1119
1120 prev_ioloop = current_ioloop;
1121 client_ioloop = io_loop_create();
1122 prev_client_ioloop = http_client_switch_ioloop(client);
1123 if (client->set.dns_client != NULL)
1124 dns_client_switch_ioloop(client->set.dns_client);
1125
1126 client->waiting = TRUE;
1127 while (req->state < HTTP_REQUEST_STATE_PAYLOAD_IN) {
1128 e_debug(req->event, "Waiting for request to finish");
1129
1130 if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) {
1131 o_stream_set_flush_pending(
1132 req->payload_output, TRUE);
1133 }
1134
1135 io_loop_run(client_ioloop);
1136
1137 if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT &&
1138 req->payload_input->eof) {
1139 i_stream_unref(&req->payload_input);
1140 req->payload_input = NULL;
1141 break;
1142 }
1143 }
1144 client->waiting = FALSE;
1145
1146 if (prev_client_ioloop != NULL)
1147 io_loop_set_current(prev_client_ioloop);
1148 else
1149 io_loop_set_current(prev_ioloop);
1150 (void)http_client_switch_ioloop(client);
1151 if (client->set.dns_client != NULL)
1152 dns_client_switch_ioloop(client->set.dns_client);
1153 io_loop_set_current(client_ioloop);
1154 io_loop_destroy(&client_ioloop);
1155 }
1156
1157 switch (req->state) {
1158 case HTTP_REQUEST_STATE_PAYLOAD_IN:
1159 case HTTP_REQUEST_STATE_FINISHED:
1160 ret = 1;
1161 break;
1162 case HTTP_REQUEST_STATE_ABORTED:
1163 ret = -1;
1164 break;
1165 default:
1166 ret = 0;
1167 break;
1168 }
1169
1170 req->payload_wait = FALSE;
1171
1172 /* callback may have messed with our pointer, so unref using local
1173 variable */
1174 if (!http_client_request_unref(&req))
1175 *_req = NULL;
1176
1177 if (conn != NULL)
1178 http_client_connection_unref(&conn);
1179
1180 return ret;
1181 }
1182
http_client_request_send_payload(struct http_client_request ** _req,const unsigned char * data,size_t size)1183 int http_client_request_send_payload(struct http_client_request **_req,
1184 const unsigned char *data, size_t size)
1185 {
1186 struct http_client_request *req = *_req;
1187 int ret;
1188
1189 i_assert(data != NULL);
1190
1191 ret = http_client_request_continue_payload(&req, data, size);
1192 if (ret < 0) {
1193 /* Failed to send payload */
1194 *_req = NULL;
1195 } else if (ret > 0) {
1196 /* Premature end of request;
1197 server sent error before all payload could be sent */
1198 ret = -1;
1199 *_req = NULL;
1200 } else {
1201 /* Not finished sending payload */
1202 i_assert(req != NULL);
1203 }
1204 return ret;
1205 }
1206
http_client_request_finish_payload(struct http_client_request ** _req)1207 int http_client_request_finish_payload(struct http_client_request **_req)
1208 {
1209 struct http_client_request *req = *_req;
1210 int ret;
1211
1212 *_req = NULL;
1213 ret = http_client_request_continue_payload(&req, NULL, 0);
1214 i_assert(ret != 0);
1215 return ret < 0 ? -1 : 0;
1216 }
1217
http_client_request_payload_input(struct http_client_request * req)1218 static void http_client_request_payload_input(struct http_client_request *req)
1219 {
1220 struct http_client_connection *conn = req->conn;
1221
1222 io_remove(&conn->io_req_payload);
1223
1224 (void)http_client_connection_output(conn);
1225 }
1226
http_client_request_send_more(struct http_client_request * req,bool pipelined)1227 int http_client_request_send_more(struct http_client_request *req,
1228 bool pipelined)
1229 {
1230 struct http_client_connection *conn = req->conn;
1231 struct http_client_context *cctx = conn->ppool->peer->cctx;
1232 struct ostream *output = req->payload_output;
1233 enum ostream_send_istream_result res;
1234 const char *error;
1235 uoff_t offset;
1236
1237 if (req->payload_finished)
1238 return http_client_request_finish_payload_out(req);
1239
1240 i_assert(req->payload_input != NULL);
1241 i_assert(req->payload_output != NULL);
1242
1243 io_remove(&conn->io_req_payload);
1244
1245 /* Chunked ostream needs to write to the parent stream's buffer */
1246 offset = req->payload_input->v_offset;
1247 o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
1248 res = o_stream_send_istream(output, req->payload_input);
1249 o_stream_set_max_buffer_size(output, SIZE_MAX);
1250
1251 i_assert(req->payload_input->v_offset >= offset);
1252 e_debug(req->event, "Send more (sent %"PRIuUOFF_T", buffered=%zu)",
1253 (uoff_t)(req->payload_input->v_offset - offset),
1254 o_stream_get_buffer_used_size(output));
1255
1256 switch (res) {
1257 case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
1258 /* Finished sending */
1259 if (!req->payload_chunked &&
1260 (req->payload_input->v_offset - req->payload_offset) !=
1261 req->payload_size) {
1262 error = t_strdup_printf(
1263 "BUG: stream '%s' input size changed: "
1264 "%"PRIuUOFF_T"-%"PRIuUOFF_T" != %"PRIuUOFF_T,
1265 i_stream_get_name(req->payload_input),
1266 req->payload_input->v_offset,
1267 req->payload_offset, req->payload_size);
1268 i_error("%s", error); //FIXME: remove?
1269 http_client_connection_lost(&conn, error);
1270 return -1;
1271 }
1272
1273 if (req->payload_wait) {
1274 /* This chunk of input is finished
1275 (client needs to act; disable timeout) */
1276 i_assert(!pipelined);
1277 conn->output_locked = TRUE;
1278 http_client_connection_stop_request_timeout(conn);
1279 if (req->client != NULL && req->client->waiting)
1280 io_loop_stop(req->client->ioloop);
1281 return 0;
1282 }
1283 /* Finished sending payload */
1284 return http_client_request_finish_payload_out(req);
1285 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
1286 /* Input is blocking (client needs to act; disable timeout) */
1287 conn->output_locked = TRUE;
1288 if (!pipelined)
1289 http_client_connection_stop_request_timeout(conn);
1290 conn->io_req_payload = io_add_istream_to(
1291 cctx->ioloop, req->payload_input,
1292 http_client_request_payload_input, req);
1293 return 1;
1294 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
1295 /* Output is blocking (server needs to act; enable timeout) */
1296 conn->output_locked = TRUE;
1297 if (!pipelined)
1298 http_client_connection_start_request_timeout(conn);
1299 e_debug(req->event, "Partially sent payload");
1300 return 0;
1301 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
1302 /* We're in the middle of sending a request, so the connection
1303 will also have to be aborted */
1304 error = t_strdup_printf("read(%s) failed: %s",
1305 i_stream_get_name(req->payload_input),
1306 i_stream_get_error(req->payload_input));
1307
1308 /* The payload stream assigned to this request is broken, fail
1309 this the request immediately */
1310 http_client_request_error(&req,
1311 HTTP_CLIENT_REQUEST_ERROR_BROKEN_PAYLOAD,
1312 "Broken payload stream");
1313
1314 http_client_connection_lost(&conn, error);
1315 return -1;
1316 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
1317 /* Failed to send request */
1318 http_client_connection_handle_output_error(conn);
1319 return -1;
1320 }
1321 i_unreached();
1322 }
1323
1324 static int
http_client_request_send_real(struct http_client_request * req,bool pipelined)1325 http_client_request_send_real(struct http_client_request *req, bool pipelined)
1326 {
1327 const struct http_client_settings *set = &req->client->set;
1328 struct http_client_connection *conn = req->conn;
1329 string_t *rtext = t_str_new(256);
1330 struct const_iovec iov[3];
1331 int ret;
1332
1333 i_assert(!req->conn->output_locked);
1334 i_assert(req->payload_output == NULL);
1335
1336 /* Create request line */
1337 str_append(rtext, req->method);
1338 str_append(rtext, " ");
1339 str_append(rtext, req->target);
1340 str_append(rtext, " HTTP/1.1\r\n");
1341
1342 /* Create special headers implicitly if not set explicitly using
1343 http_client_request_add_header() */
1344 if (!req->have_hdr_host) {
1345 str_append(rtext, "Host: ");
1346 str_append(rtext, req->authority);
1347 str_append(rtext, "\r\n");
1348 }
1349 if (!req->have_hdr_date) {
1350 str_append(rtext, "Date: ");
1351 str_append(rtext, http_date_create(req->date));
1352 str_append(rtext, "\r\n");
1353 }
1354 if (!req->have_hdr_authorization &&
1355 req->username != NULL && req->password != NULL) {
1356 struct http_auth_credentials auth_creds;
1357
1358 http_auth_basic_credentials_init(&auth_creds,
1359 req->username, req->password);
1360
1361 str_append(rtext, "Authorization: ");
1362 http_auth_create_credentials(rtext, &auth_creds);
1363 str_append(rtext, "\r\n");
1364 }
1365 if (http_client_request_to_proxy(req) &&
1366 set->proxy_username != NULL && set->proxy_password != NULL) {
1367 struct http_auth_credentials auth_creds;
1368
1369 http_auth_basic_credentials_init(&auth_creds,
1370 set->proxy_username, set->proxy_password);
1371
1372 str_append(rtext, "Proxy-Authorization: ");
1373 http_auth_create_credentials(rtext, &auth_creds);
1374 str_append(rtext, "\r\n");
1375 }
1376 if (!req->have_hdr_user_agent && req->client->set.user_agent != NULL) {
1377 str_printfa(rtext, "User-Agent: %s\r\n",
1378 req->client->set.user_agent);
1379 }
1380 if (!req->have_hdr_expect && req->payload_sync) {
1381 str_append(rtext, "Expect: 100-continue\r\n");
1382 }
1383 if (req->payload_input != NULL && req->payload_chunked) {
1384 // FIXME: can't do this for a HTTP/1.0 server
1385 if (!req->have_hdr_body_spec)
1386 str_append(rtext, "Transfer-Encoding: chunked\r\n");
1387 req->payload_output =
1388 http_transfer_chunked_ostream_create(conn->conn.output);
1389 o_stream_set_finish_also_parent(req->payload_output, FALSE);
1390 } else if (req->payload_input != NULL ||
1391 req->payload_empty ||
1392 strcasecmp(req->method, "POST") == 0 ||
1393 strcasecmp(req->method, "PUT") == 0) {
1394
1395 /* Send Content-Length if we have specified a payload or when
1396 one is normally expected, even if it's 0 bytes. */
1397 i_assert(req->payload_input != NULL || req->payload_size == 0);
1398 if (!req->have_hdr_body_spec) {
1399 str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n",
1400 req->payload_size);
1401 }
1402 if (req->payload_input != NULL) {
1403 req->payload_output = conn->conn.output;
1404 o_stream_ref(conn->conn.output);
1405 }
1406 }
1407 if (!req->have_hdr_connection &&
1408 !http_client_request_to_proxy(req)) {
1409 /* RFC 2068, Section 19.7.1:
1410
1411 A client MUST NOT send the Keep-Alive connection token to a
1412 proxy server as HTTP/1.0 proxy servers do not obey the rules
1413 of HTTP/1.1 for parsing the Connection header field.
1414 */
1415 str_append(rtext, "Connection: Keep-Alive\r\n");
1416 }
1417
1418 /* Request line + implicit headers */
1419 iov[0].iov_base = str_data(rtext);
1420 iov[0].iov_len = str_len(rtext);
1421 /* Explicit headers */
1422 if (req->headers != NULL) {
1423 iov[1].iov_base = str_data(req->headers);
1424 iov[1].iov_len = str_len(req->headers);
1425 } else {
1426 iov[1].iov_base = "";
1427 iov[1].iov_len = 0;
1428 }
1429 /* End of header */
1430 iov[2].iov_base = "\r\n";
1431 iov[2].iov_len = 2;
1432
1433 req->state = HTTP_REQUEST_STATE_PAYLOAD_OUT;
1434 req->payload_finished = FALSE;
1435
1436 req->send_attempts++;
1437 if (req->first_sent_time.tv_sec == 0)
1438 req->first_sent_time = ioloop_timeval;
1439 req->sent_time = ioloop_timeval;
1440 req->sent_lock_usecs = file_lock_wait_get_total_usecs();
1441 req->sent_global_ioloop_usecs = ioloop_global_wait_usecs;
1442 req->sent_http_ioloop_usecs =
1443 io_wait_timer_get_usecs(req->conn->io_wait_timer);
1444
1445 ret = 1;
1446 o_stream_cork(conn->conn.output);
1447 req->request_offset = conn->conn.output->offset;
1448
1449 if (o_stream_sendv(conn->conn.output, iov, N_ELEMENTS(iov)) < 0) {
1450 http_client_connection_handle_output_error(conn);
1451 return -1;
1452 }
1453
1454 e_debug(req->event, "Sent header");
1455
1456 if (req->payload_output != NULL) {
1457 if (!req->payload_sync) {
1458 ret = http_client_request_send_more(req, pipelined);
1459 if (ret < 0)
1460 return -1;
1461 } else {
1462 e_debug(req->event, "Waiting for 100-continue");
1463 conn->output_locked = TRUE;
1464 }
1465 } else {
1466 req->state = HTTP_REQUEST_STATE_WAITING;
1467 if (!pipelined)
1468 http_client_connection_start_request_timeout(req->conn);
1469 conn->output_locked = FALSE;
1470 }
1471 if (conn->conn.output != NULL) {
1472 i_assert(req->request_offset < conn->conn.output->offset);
1473 req->bytes_out = conn->conn.output->offset - req->request_offset;
1474 if (o_stream_uncork_flush(conn->conn.output) < 0) {
1475 http_client_connection_handle_output_error(conn);
1476 return -1;
1477 }
1478 }
1479 return ret;
1480 }
1481
http_client_request_send(struct http_client_request * req,bool pipelined)1482 int http_client_request_send(struct http_client_request *req, bool pipelined)
1483 {
1484 int ret;
1485
1486 T_BEGIN {
1487 ret = http_client_request_send_real(req, pipelined);
1488 } T_END;
1489
1490 return ret;
1491 }
1492
http_client_request_callback(struct http_client_request * req,struct http_response * response)1493 bool http_client_request_callback(struct http_client_request *req,
1494 struct http_response *response)
1495 {
1496 http_client_request_callback_t *callback = req->callback;
1497 unsigned int orig_attempts = req->attempts;
1498
1499 req->state = HTTP_REQUEST_STATE_GOT_RESPONSE;
1500 req->last_status = response->status;
1501
1502 req->callback = NULL;
1503 if (callback != NULL) {
1504 struct http_response response_copy = *response;
1505
1506 if (req->attempts > 0 && !req->preserve_exact_reason) {
1507 unsigned int total_msecs =
1508 timeval_diff_msecs(&ioloop_timeval,
1509 &req->submit_time);
1510 response_copy.reason = t_strdup_printf(
1511 "%s (%u retries in %u.%03u secs)",
1512 response_copy.reason, req->attempts,
1513 total_msecs/1000, total_msecs%1000);
1514 }
1515
1516 callback(&response_copy, req->context);
1517 if (req->attempts != orig_attempts) {
1518 /* Retrying */
1519 req->callback = callback;
1520 http_client_request_resubmit(req);
1521 return FALSE;
1522 } else {
1523 /* Release payload early
1524 (prevents server/client deadlock in proxy) */
1525 i_stream_unref(&req->payload_input);
1526 }
1527 }
1528 return TRUE;
1529 }
1530
1531 static bool
http_client_request_send_error(struct http_client_request * req,unsigned int status,const char * error)1532 http_client_request_send_error(struct http_client_request *req,
1533 unsigned int status, const char *error)
1534 {
1535 http_client_request_callback_t *callback;
1536 bool sending = (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
1537 unsigned int orig_attempts = req->attempts;
1538
1539 req->state = HTTP_REQUEST_STATE_ABORTED;
1540
1541 callback = req->callback;
1542 req->callback = NULL;
1543 if (callback != NULL) {
1544 struct http_response response;
1545
1546 http_response_init(&response, status, error);
1547 (void)callback(&response, req->context);
1548
1549 if (req->attempts != orig_attempts) {
1550 /* Retrying */
1551 req->callback = callback;
1552 http_client_request_resubmit(req);
1553 return FALSE;
1554 } else {
1555 /* Release payload early
1556 (prevents server/client deadlock in proxy) */
1557 if (!sending && req->payload_input != NULL)
1558 i_stream_unref(&req->payload_input);
1559 }
1560 }
1561 if (req->payload_wait) {
1562 i_assert(req->client != NULL);
1563 io_loop_stop(req->client->ioloop);
1564 }
1565 return TRUE;
1566 }
1567
http_client_request_error_delayed(struct http_client_request ** _req)1568 void http_client_request_error_delayed(struct http_client_request **_req)
1569 {
1570 struct http_client_request *req = *_req;
1571 const char *error = req->delayed_error;
1572 unsigned int status = req->delayed_error_status;
1573 bool destroy;
1574
1575 i_assert(req->state == HTTP_REQUEST_STATE_ABORTED);
1576
1577 *_req = NULL;
1578 req->delayed_error = NULL;
1579 req->delayed_error_status = 0;
1580
1581 i_assert(error != NULL && status != 0);
1582 destroy = http_client_request_send_error(req, status, error);
1583 if (req->queue != NULL)
1584 http_client_queue_drop_request(req->queue, req);
1585 if (destroy)
1586 http_client_request_destroy(&req);
1587 }
1588
http_client_request_error(struct http_client_request ** _req,unsigned int status,const char * error)1589 void http_client_request_error(struct http_client_request **_req,
1590 unsigned int status, const char *error)
1591 {
1592 struct http_client_request *req = *_req;
1593
1594 *_req = NULL;
1595
1596 i_assert(req->delayed_error_status == 0);
1597 i_assert(req->state < HTTP_REQUEST_STATE_FINISHED);
1598
1599 req->state = HTTP_REQUEST_STATE_ABORTED;
1600 req->last_status = status;
1601
1602 e_debug(http_client_request_result_event(req)->
1603 set_name("http_request_finished")->event(),
1604 "Error: %u %s", status, error);
1605
1606 if (req->queue != NULL)
1607 http_client_queue_drop_request(req->queue, req);
1608
1609 if (req->client != NULL &&
1610 (!req->submitted ||
1611 req->state == HTTP_REQUEST_STATE_GOT_RESPONSE)) {
1612 /* We're still in http_client_request_submit() or in the
1613 callback during a retry attempt. delay reporting the error,
1614 so the caller doesn't have to handle immediate or nested
1615 callbacks. */
1616 req->delayed_error = p_strdup(req->pool, error);
1617 req->delayed_error_status = status;
1618 http_client_delay_request_error(req->client, req);
1619 } else {
1620 if (http_client_request_send_error(req, status, error))
1621 http_client_request_destroy(&req);
1622 }
1623 }
1624
http_client_request_abort(struct http_client_request ** _req)1625 void http_client_request_abort(struct http_client_request **_req)
1626 {
1627 struct http_client_request *req = *_req;
1628 bool sending;
1629
1630 if (req == NULL)
1631 return;
1632
1633 sending = (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
1634
1635 *_req = NULL;
1636
1637 if (req->state >= HTTP_REQUEST_STATE_FINISHED &&
1638 req->delayed_error_status == 0)
1639 return;
1640
1641 req->callback = NULL;
1642 req->state = HTTP_REQUEST_STATE_ABORTED;
1643 if (req->last_status == 0)
1644 req->last_status = HTTP_CLIENT_REQUEST_ERROR_ABORTED;
1645
1646 if (req->state > HTTP_REQUEST_STATE_NEW &&
1647 req->delayed_error_status == 0) {
1648 e_debug(http_client_request_result_event(req)->
1649 set_name("http_request_finished")->event(),
1650 "Aborted");
1651 }
1652
1653 /* Release payload early (prevents server/client deadlock in proxy) */
1654 if (!sending && req->payload_input != NULL)
1655 i_stream_unref(&req->payload_input);
1656
1657 if (req->queue != NULL)
1658 http_client_queue_drop_request(req->queue, req);
1659 if (req->payload_wait) {
1660 i_assert(req->client != NULL);
1661 i_assert(req->client->ioloop != NULL);
1662 io_loop_stop(req->client->ioloop);
1663 }
1664 http_client_request_destroy(&req);
1665 }
1666
http_client_request_finish(struct http_client_request * req)1667 void http_client_request_finish(struct http_client_request *req)
1668 {
1669 if (req->state >= HTTP_REQUEST_STATE_FINISHED)
1670 return;
1671
1672 i_assert(req->refcount > 0);
1673
1674 e_debug(http_client_request_result_event(req)->
1675 set_name("http_request_finished")->event(),
1676 "Finished");
1677
1678 req->callback = NULL;
1679 req->state = HTTP_REQUEST_STATE_FINISHED;
1680
1681 if (req->queue != NULL)
1682 http_client_queue_drop_request(req->queue, req);
1683 if (req->payload_wait) {
1684 i_assert(req->client != NULL);
1685 i_assert(req->client->ioloop != NULL);
1686 io_loop_stop(req->client->ioloop);
1687 }
1688 http_client_request_unref(&req);
1689 }
1690
1691 static int
http_client_request_reset(struct http_client_request * req,bool rewind,const char ** error_r)1692 http_client_request_reset(struct http_client_request *req, bool rewind,
1693 const char **error_r)
1694 {
1695 /* Rewind payload stream */
1696 if (rewind && req->payload_input != NULL && req->payload_size > 0) {
1697 if (req->payload_input->v_offset != req->payload_offset &&
1698 !req->payload_input->seekable) {
1699 *error_r = "Cannot resend payload; "
1700 "stream is not seekable";
1701 return -1;
1702 }
1703 i_stream_seek(req->payload_input, req->payload_offset);
1704 }
1705
1706 /* Drop payload output stream from previous attempt */
1707 o_stream_unref(&req->payload_output);
1708
1709 /* Reset payload state */
1710 req->payload_finished = FALSE;
1711
1712 return 0;
1713 }
1714
http_client_request_redirect(struct http_client_request * req,unsigned int status,const char * location)1715 void http_client_request_redirect(struct http_client_request *req,
1716 unsigned int status, const char *location)
1717 {
1718 struct http_url *url;
1719 const char *error, *target, *origin_url;
1720
1721 i_assert(req->client != NULL);
1722 i_assert(!req->payload_wait);
1723
1724 req->last_status = status;
1725
1726 /* parse URL */
1727 if (http_url_parse(location, NULL, 0,
1728 pool_datastack_create(), &url, &error) < 0) {
1729 http_client_request_error(
1730 &req, HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
1731 t_strdup_printf("Invalid redirect location: %s",
1732 error));
1733 return;
1734 }
1735
1736 i_assert(req->redirects <= req->client->set.max_redirects);
1737 if (++req->redirects > req->client->set.max_redirects) {
1738 if (req->client->set.max_redirects > 0) {
1739 http_client_request_error(
1740 &req,
1741 HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
1742 t_strdup_printf(
1743 "Redirected more than %d times",
1744 req->client->set.max_redirects));
1745 } else {
1746 http_client_request_error(
1747 &req,
1748 HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
1749 "Redirect refused");
1750 }
1751 return;
1752 }
1753
1754 if (http_client_request_reset(req, (status != 303), &error) < 0) {
1755 http_client_request_error(
1756 &req, HTTP_CLIENT_REQUEST_ERROR_ABORTED,
1757 t_strdup_printf("Redirect failed: %s", error));
1758 return;
1759 }
1760
1761 target = http_url_create_target(url);
1762
1763 http_url_copy(req->pool, &req->origin_url, url);
1764 req->target = p_strdup(req->pool, target);
1765
1766 req->host = NULL;
1767
1768 origin_url = http_url_create(&req->origin_url);
1769
1770 e_debug(http_client_request_result_event(req)->
1771 set_name("http_request_redirected")->event(),
1772 "Redirecting to %s%s (redirects=%u)",
1773 origin_url, target, req->redirects);
1774
1775 req->label = p_strdup_printf(req->pool, "[%s %s%s]",
1776 req->method, origin_url, req->target);
1777
1778 /* RFC 7231, Section 6.4.4:
1779
1780 -> A 303 `See Other' redirect status response is handled a bit
1781 differently. Basically, the response content is located elsewhere,
1782 but the original (POST) request is handled already.
1783 */
1784 if (status == 303 && strcasecmp(req->method, "HEAD") != 0 &&
1785 strcasecmp(req->method, "GET") != 0) {
1786 // FIXME: should we provide the means to skip this step? The
1787 // original request was already handled at this point.
1788 req->method = p_strdup(req->pool, "GET");
1789
1790 /* drop payload */
1791 i_stream_unref(&req->payload_input);
1792 req->payload_size = 0;
1793 req->payload_offset = 0;
1794 }
1795
1796 /* Resubmit */
1797 req->state = HTTP_REQUEST_STATE_NEW;
1798 http_client_request_do_submit(req);
1799 }
1800
http_client_request_resubmit(struct http_client_request * req)1801 void http_client_request_resubmit(struct http_client_request *req)
1802 {
1803 const char *error;
1804
1805 i_assert(!req->payload_wait);
1806
1807 e_debug(req->event, "Resubmitting request");
1808
1809 if (http_client_request_reset(req, TRUE, &error) < 0) {
1810 http_client_request_error(
1811 &req, HTTP_CLIENT_REQUEST_ERROR_ABORTED,
1812 t_strdup_printf("Resubmission failed: %s", error));
1813 return;
1814 }
1815
1816 req->peer = NULL;
1817 req->state = HTTP_REQUEST_STATE_QUEUED;
1818 req->redirects = 0;
1819 req->last_status = 0;
1820 http_client_host_submit_request(req->host, req);
1821 }
1822
http_client_request_retry(struct http_client_request * req,unsigned int status,const char * error)1823 void http_client_request_retry(struct http_client_request *req,
1824 unsigned int status, const char *error)
1825 {
1826 if (req->client == NULL || req->client->set.no_auto_retry ||
1827 !http_client_request_try_retry(req))
1828 http_client_request_error(&req, status, error);
1829 }
1830
http_client_request_try_retry(struct http_client_request * req)1831 bool http_client_request_try_retry(struct http_client_request *req)
1832 {
1833 /* Don't ever retry if we're sending data in small blocks via
1834 http_client_request_send_payload() and we're not waiting for a
1835 100 continue (there's no way to rewind the payload for a retry)
1836 */
1837 if (req->payload_wait &&
1838 (!req->payload_sync || req->payload_sync_continue))
1839 return FALSE;
1840 /* Limit the number of attempts for each request */
1841 if (req->attempts+1 >= req->max_attempts)
1842 return FALSE;
1843 req->attempts++;
1844
1845 e_debug(http_client_request_result_event(req)->
1846 set_name("http_request_retried")->event(),
1847 "Retrying (attempts=%d)", req->attempts);
1848
1849 if (req->callback != NULL)
1850 http_client_request_resubmit(req);
1851 return TRUE;
1852 }
1853
1854 #undef http_client_request_set_destroy_callback
http_client_request_set_destroy_callback(struct http_client_request * req,void (* callback)(void *),void * context)1855 void http_client_request_set_destroy_callback(struct http_client_request *req,
1856 void (*callback)(void *),
1857 void *context)
1858 {
1859 req->destroy_callback = callback;
1860 req->destroy_context = context;
1861 }
1862
http_client_request_start_tunnel(struct http_client_request * req,struct http_client_tunnel * tunnel)1863 void http_client_request_start_tunnel(struct http_client_request *req,
1864 struct http_client_tunnel *tunnel)
1865 {
1866 struct http_client_connection *conn = req->conn;
1867
1868 i_assert(req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
1869
1870 http_client_connection_start_tunnel(&conn, tunnel);
1871 }
1872