http-client-request.c revision 0af543c1f5407f2fafd8685642e55385abade14a
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "net.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "str.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "hash.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "array.h"
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch#include "llist.h"
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch#include "time-util.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "ostream.h"
0d5c9a80e91a4073d5fd6820e9ddce2755221f64Stephan Bosch#include "dns-lookup.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-url.h"
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch#include "http-date.h"
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch#include "http-auth.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-response-parser.h"
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen#include "http-transfer.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "http-client-private.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainenconst char *http_request_state_names[] = {
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "new",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "queued",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "payload_out",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "waiting",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "got_response",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "payload_in",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "finished",
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen "aborted"
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen};
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/*
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch * Logging
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic inline void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_client_request_debug(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const char *format, ...) ATTR_FORMAT(2, 3);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic inline void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_client_request_debug(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const char *format, ...)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch va_list args;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (req->client->set.debug) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch va_start(args, format);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_debug("http-client: request %s: %s",
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_label(req), t_strdup_vprintf(format, args));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch va_end(args);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/*
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch * Request
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Boschstatic void
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Boschhttp_client_request_send_error(struct http_client_request *req,
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Bosch unsigned int status, const char *error);
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Bosch
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Boschconst char *
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Boschhttp_client_request_label(struct http_client_request *req)
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch{
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch if (req->label == NULL) {
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch req->label = p_strdup_printf(req->pool,
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch "[Req%u: %s %s%s]", req->id,
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch req->method, http_url_create(&req->origin_url), req->target);
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch }
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch return req->label;
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch}
7abab3b191860a3d77af5192b0649833c8a0c803Stephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschstatic struct http_client_request *
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschhttp_client_request_new(struct http_client *client, const char *method,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_callback_t *callback, void *context)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
47a53a80656dc400ff8effdc1432a69fbf5ae8baTimo Sirainen static unsigned int id_counter = 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_t pool;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_request *req;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool = pool_alloconly_create("http client request", 2048);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req = p_new(pool, struct http_client_request, 1);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->pool = pool;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->refcount = 1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->client = client;
47a53a80656dc400ff8effdc1432a69fbf5ae8baTimo Sirainen req->id = ++id_counter;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->method = p_strdup(pool, method);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->callback = callback;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->context = context;
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch req->date = (time_t)-1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_NEW;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return req;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch#undef http_client_request
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschstruct http_client_request *
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschhttp_client_request(struct http_client *client,
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch const char *method, const char *host, const char *target,
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch http_client_request_callback_t *callback, void *context)
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch{
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch struct http_client_request *req;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req = http_client_request_new(client, method, callback, context);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch req->origin_url.host.name = p_strdup(req->pool, host);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->target = (target == NULL ? "/" : p_strdup(req->pool, target));
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch return req;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch}
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch#undef http_client_request_url
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschstruct http_client_request *
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschhttp_client_request_url(struct http_client *client,
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch const char *method, const struct http_url *target_url,
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch http_client_request_callback_t *callback, void *context)
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch{
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch struct http_client_request *req;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req = http_client_request_new(client, method, callback, context);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch http_url_copy_authority(req->pool, &req->origin_url, target_url);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->target = p_strdup(req->pool, http_url_create_target(target_url));
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch if (target_url->user != NULL && *target_url->user != '\0' &&
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch target_url->password != NULL) {
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->username = p_strdup(req->pool, target_url->user);
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->password = p_strdup(req->pool, target_url->password);
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch }
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch return req;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch}
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch#undef http_client_request_connect
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschstruct http_client_request *
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschhttp_client_request_connect(struct http_client *client,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch const char *host, in_port_t port,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch http_client_request_callback_t *callback,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch void *context)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch{
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch struct http_client_request *req;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch req = http_client_request_new(client, "CONNECT", callback, context);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch req->origin_url.host.name = p_strdup(req->pool, host);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch req->origin_url.port = port;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch req->connect_tunnel = TRUE;
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch req->target = req->origin_url.host.name;
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch return req;
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch}
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch#undef http_client_request_connect_ip
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Boschstruct http_client_request *
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Boschhttp_client_request_connect_ip(struct http_client *client,
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch const struct ip_addr *ip, in_port_t port,
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch http_client_request_callback_t *callback,
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch void *context)
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch{
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch struct http_client_request *req;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch const char *hostname;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch i_assert(ip->family != 0);
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch hostname = net_ip2addr(ip);
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch req = http_client_request_connect
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch (client, hostname, port, callback, context);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch req->origin_url.host.ip = *ip;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch return req;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch}
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Boschstatic void
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Boschhttp_client_request_add(struct http_client_request *req)
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch{
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch struct http_client *client = req->client;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch DLLIST_PREPEND(&client->requests_list, req);
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch client->requests_count++;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch req->listed = TRUE;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch}
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Boschstatic void
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Boschhttp_client_request_remove(struct http_client_request *req)
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch{
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch struct http_client *client = req->client;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch if (req->listed) {
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch /* only decrease pending request counter if this request was submitted */
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch DLLIST_REMOVE(&client->requests_list, req);
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch client->requests_count--;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch }
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch req->listed = FALSE;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch if (client->requests_count == 0 && client->ioloop != NULL)
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch io_loop_stop(client->ioloop);
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch}
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_ref(struct http_client_request *req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
e9228a3918aa0243eff4aae1ff5462bd3198417fTimo Sirainen i_assert(req->refcount > 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->refcount++;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainenbool http_client_request_unref(struct http_client_request **_req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_request *req = *_req;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client *client = req->client;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(req->refcount > 0);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen *_req = NULL;
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (--req->refcount > 0)
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen return TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch http_client_request_debug(req, "Free (requests left=%d)",
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch client->requests_count);
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* cannot be destroyed while it is still pending */
3e9055cee8e331a84522dd1e65d0d0e09a4e8803Stephan Bosch i_assert(req->conn == NULL);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->queue != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_drop_request(req->queue, req);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen if (req->destroy_callback != NULL) {
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen req->destroy_callback(req->destroy_context);
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen req->destroy_callback = NULL;
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen }
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch http_client_request_remove(req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch if (client->requests_count == 0 && client->ioloop != NULL)
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen io_loop_stop(client->ioloop);
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainen
129596c93692b21d6c6b1313b389774af24c2983Stephan Bosch if (req->delayed_error != NULL)
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch http_client_remove_request_error(req->client, req);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_input != NULL)
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen i_stream_unref(&req->payload_input);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_output != NULL)
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen o_stream_unref(&req->payload_output);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if (req->headers != NULL)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch str_free(&req->headers);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pool_unref(&req->pool);
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen return FALSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
79f8a20424633e806447bc9375a5ab403aabc758Stephan Boschvoid http_client_request_destroy(struct http_client_request **_req)
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch{
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch struct http_client_request *req = *_req;
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch struct http_client *client = req->client;
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen *_req = NULL;
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch http_client_request_debug(req, "Destroy (requests left=%d)",
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch client->requests_count);
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch if (req->state < HTTP_REQUEST_STATE_FINISHED)
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch req->state = HTTP_REQUEST_STATE_ABORTED;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch req->callback = NULL;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch if (req->queue != NULL)
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch http_client_queue_drop_request(req->queue, req);
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch if (req->destroy_callback != NULL) {
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch void (*callback)(void *) = req->destroy_callback;
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch req->destroy_callback = NULL;
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch callback(req->destroy_context);
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch }
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch http_client_request_remove(req);
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen http_client_request_unref(&req);
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch}
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_set_port(struct http_client_request *req,
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch in_port_t port)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->origin_url.port = port;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_set_ssl(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch bool ssl)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->origin_url.have_ssl = ssl;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_set_urgent(struct http_client_request *req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->urgent = TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainenvoid http_client_request_set_preserve_exact_reason(struct http_client_request *req)
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen{
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen req->preserve_exact_reason = TRUE;
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen}
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_add_header(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const char *key, const char *value)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
49287618521ff2c69385456de116e5d1581426c0Timo Sirainen i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
49287618521ff2c69385456de116e5d1581426c0Timo Sirainen /* allow calling for retries */
49287618521ff2c69385456de116e5d1581426c0Timo Sirainen req->state == HTTP_REQUEST_STATE_GOT_RESPONSE ||
49287618521ff2c69385456de116e5d1581426c0Timo Sirainen req->state == HTTP_REQUEST_STATE_ABORTED);
49287618521ff2c69385456de116e5d1581426c0Timo Sirainen
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* mark presence of special headers */
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch switch (key[0]) {
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch case 'a': case 'A':
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch if (strcasecmp(key, "Authorization") == 0)
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->have_hdr_authorization = TRUE;
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch break;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch case 'c': case 'C':
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (strcasecmp(key, "Connection") == 0)
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch req->have_hdr_connection = TRUE;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch else if (strcasecmp(key, "Content-Length") == 0)
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch req->have_hdr_body_spec = TRUE;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch break;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch case 'd': case 'D':
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (strcasecmp(key, "Date") == 0)
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch req->have_hdr_date = TRUE;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch break;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch case 'e': case 'E':
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (strcasecmp(key, "Expect") == 0)
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch req->have_hdr_expect = TRUE;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch break;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch case 'h': case 'H':
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (strcasecmp(key, "Host") == 0)
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch req->have_hdr_host = TRUE;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch break;
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch case 'p': case 'P':
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch i_assert(strcasecmp(key, "Proxy-Authorization") != 0);
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch break;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch case 't': case 'T':
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (strcasecmp(key, "Transfer-Encoding") == 0)
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch req->have_hdr_body_spec = TRUE;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch break;
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen case 'u': case 'U':
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen if (strcasecmp(key, "User-Agent") == 0)
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen req->have_hdr_user_agent = TRUE;
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen break;
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch }
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch if (req->headers == NULL)
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->headers = str_new(default_pool, 256);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch str_printfa(req->headers, "%s: %s\r\n", key, value);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainenvoid http_client_request_remove_header(struct http_client_request *req,
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen const char *key)
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen{
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen const unsigned char *data, *p;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen size_t size, line_len, line_start_pos;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen unsigned int key_len = strlen(key);
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen /* allow calling for retries */
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen req->state == HTTP_REQUEST_STATE_GOT_RESPONSE ||
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen req->state == HTTP_REQUEST_STATE_ABORTED);
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen data = str_data(req->headers);
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen size = str_len(req->headers);
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen while ((p = memchr(data, '\n', size)) != NULL) {
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen line_len = (p+1) - data;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen if (size > key_len && i_memcasecmp(data, key, key_len) == 0 &&
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen data[key_len] == ':' && data[key_len+1] == ' ') {
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen /* key was found from header, replace its value */
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen line_start_pos = str_len(req->headers) - size;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen str_delete(req->headers, line_start_pos, line_len);
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen break;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen }
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen size -= line_len;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen data += line_len;
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen }
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen}
84740b03d3ee9e96a2e446a54729188764c99292Timo Sirainen
6d573191bea1a64d6046be070487a5705a2d0204Stephan Boschvoid http_client_request_set_date(struct http_client_request *req,
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch time_t date)
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch{
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW);
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch req->date = date;
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch}
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_set_payload(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct istream *input, bool sync)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainen int ret;
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen i_assert(req->payload_input == NULL);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_stream_ref(input);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->payload_input = input;
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainen if ((ret = i_stream_get_size(input, TRUE, &req->payload_size)) <= 0) {
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainen if (ret < 0) {
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen i_error("i_stream_get_size(%s) failed: %s",
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen i_stream_get_name(input),
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen i_stream_get_error(input));
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainen }
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->payload_size = 0;
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->payload_chunked = TRUE;
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen }
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->payload_offset = input->v_offset;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* prepare request payload sync using 100 Continue response from server */
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if ((req->payload_chunked || req->payload_size > 0) && sync)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->payload_sync = TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Boschvoid http_client_request_set_payload_data(struct http_client_request *req,
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch const unsigned char *data, size_t size)
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch{
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch struct istream *input;
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch unsigned char *payload_data;
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch if (size == 0)
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch return;
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch payload_data = p_malloc(req->pool, size);
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch memcpy(payload_data, data, size);
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch input = i_stream_create_from_data(payload_data, size);
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch http_client_request_set_payload(req, input, FALSE);
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch i_stream_unref(&input);
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch}
7a13cd2268a5a99d2975a1648d6d14ffe1b6ccb0Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschvoid http_client_request_set_timeout_msecs(struct http_client_request *req,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int msecs)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->timeout_msecs = msecs;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch}
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschvoid http_client_request_set_timeout(struct http_client_request *req,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch const struct timeval *time)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->timeout_time = *time;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->timeout_msecs = 0;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch}
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Boschvoid http_client_request_set_auth_simple(struct http_client_request *req,
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch const char *username, const char *password)
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch{
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->username = p_strdup(req->pool, username);
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->password = p_strdup(req->pool, password);
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch}
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch
befccf297cba74009dfd0447a0dcea018af756feStephan Boschvoid http_client_request_set_proxy_url(struct http_client_request *req,
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch const struct http_url *proxy_url)
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch{
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->host_url = http_url_clone_authority(req->pool, proxy_url);
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->host_socket = NULL;
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch}
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch
befccf297cba74009dfd0447a0dcea018af756feStephan Boschvoid http_client_request_set_proxy_socket(struct http_client_request *req,
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch const char *proxy_socket)
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch{
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->host_socket = p_strdup(req->pool, proxy_socket);
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->host_url = NULL;
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch}
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschvoid http_client_request_delay_until(struct http_client_request *req,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch time_t time)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_sec = time;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_usec = 0;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschvoid http_client_request_delay(struct http_client_request *req,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch time_t seconds)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time = ioloop_timeval;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_sec += seconds;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Boschvoid http_client_request_delay_msecs(struct http_client_request *req,
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch unsigned int msecs)
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch{
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch req->release_time = ioloop_timeval;
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch timeval_add_msecs(&req->release_time, msecs);
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch}
de0181258ab66b527ad8dc7e51a8efa76b4658d0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschint http_client_request_delay_from_response(struct http_client_request *req,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch const struct http_response *response)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch time_t retry_after = response->retry_after;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch unsigned int max;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch if (retry_after == (time_t)-1)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch return 0; /* no delay */
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch if (retry_after < ioloop_time)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch return 0; /* delay already expired */
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch max = (req->client->set.max_auto_retry_delay == 0 ?
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->client->set.request_timeout_msecs / 1000 :
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->client->set.max_auto_retry_delay);
19db4c57fd7acc9e54e5724ccfa0633a5665dfefTimo Sirainen if ((unsigned int)(retry_after - ioloop_time) > max)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch return -1; /* delay too long */
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_sec = retry_after;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_usec = 0;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch return 1; /* valid delay */
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
2a9cadfccc8fb2c609eedbb929952b49181b6d25Stephan Boschconst char *
2a9cadfccc8fb2c609eedbb929952b49181b6d25Stephan Boschhttp_client_request_get_method(const struct http_client_request *req)
42630b23d5a1b03cf6db4eaa2eb21e3ec4033b2cTimo Sirainen{
42630b23d5a1b03cf6db4eaa2eb21e3ec4033b2cTimo Sirainen return req->method;
42630b23d5a1b03cf6db4eaa2eb21e3ec4033b2cTimo Sirainen}
42630b23d5a1b03cf6db4eaa2eb21e3ec4033b2cTimo Sirainen
2a9cadfccc8fb2c609eedbb929952b49181b6d25Stephan Boschconst char *
2a9cadfccc8fb2c609eedbb929952b49181b6d25Stephan Boschhttp_client_request_get_target(const struct http_client_request *req)
b2a3fbfe1b436123bbe1849eeeef9bb0c28b1f90Timo Sirainen{
b2a3fbfe1b436123bbe1849eeeef9bb0c28b1f90Timo Sirainen return req->target;
b2a3fbfe1b436123bbe1849eeeef9bb0c28b1f90Timo Sirainen}
b2a3fbfe1b436123bbe1849eeeef9bb0c28b1f90Timo Sirainen
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainenenum http_request_state
2a9cadfccc8fb2c609eedbb929952b49181b6d25Stephan Boschhttp_client_request_get_state(const struct http_client_request *req)
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen{
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen return req->state;
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen}
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschenum http_response_payload_type
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschhttp_client_request_get_payload_type(struct http_client_request *req)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch{
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3:
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch The presence of a message body in a response depends on both the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch request method to which it is responding and the response status code
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch (Section 3.1.2 of [RFC7230]). Responses to the HEAD request method
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch (Section 4.3.2 of [RFC7231]) never include a message body because the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch associated response header fields (e.g., Transfer-Encoding,
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Content-Length, etc.), if present, indicate only what their values
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch would have been if the request method had been GET (Section 4.3.1 of
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch [RFC7231]). 2xx (Successful) responses to a CONNECT request method
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch (Section 4.3.6 of [RFC7231]) switch to tunnel mode instead of having a
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch message body.
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if (strcmp(req->method, "HEAD") == 0)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch return HTTP_RESPONSE_PAYLOAD_TYPE_NOT_PRESENT;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if (strcmp(req->method, "CONNECT") == 0)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch return HTTP_RESPONSE_PAYLOAD_TYPE_ONLY_UNSUCCESSFUL;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch return HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch}
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschstatic void http_client_request_do_submit(struct http_client_request *req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch struct http_client *client = req->client;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_host *host;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch const char *proxy_socket_path = client->set.proxy_socket_path;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch const struct http_url *proxy_url = client->set.proxy_url;
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch bool have_proxy = (proxy_socket_path != NULL) || (proxy_url != NULL) ||
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch (req->host_socket != NULL) || (req->host_url != NULL);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch const char *authority, *target;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW);
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch authority = http_url_create_authority(&req->origin_url);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if (req->connect_tunnel) {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch /* connect requests require authority form for request target */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch target = authority;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch } else {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch /* absolute target url */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch target = t_strconcat
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch (http_url_create_host(&req->origin_url), req->target, NULL);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch }
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch /* determine what host to contact to submit this request */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (have_proxy) {
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch if (req->host_socket != NULL) { /* specific socket proxy */
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->host_url = NULL;
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch } else if (req->host_url != NULL) { /* specific normal proxy */
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch req->host_socket = NULL;
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch } else if (req->origin_url.have_ssl &&
befccf297cba74009dfd0447a0dcea018af756feStephan Bosch !client->set.no_ssl_tunnel && !req->connect_tunnel) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch req->host_url = &req->origin_url; /* tunnel to origin server */
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch req->ssl_tunnel = TRUE;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch } else if (proxy_socket_path != NULL) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch req->host_socket = proxy_socket_path; /* proxy on unix socket */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch req->host_url = NULL;
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch } else {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch req->host_url = proxy_url; /* normal proxy server */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch req->host_socket = NULL;
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch }
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch } else {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch req->host_url = &req->origin_url; /* origin server */
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch }
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch /* use submission date if no date is set explicitly */
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch if (req->date == (time_t)-1)
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch req->date = ioloop_time;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch /* prepare value for Host header */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch req->authority = p_strdup(req->pool, authority);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch /* debug label */
47a53a80656dc400ff8effdc1432a69fbf5ae8baTimo Sirainen req->label = p_strdup_printf(req->pool, "[Req%u: %s %s]", req->id, req->method, target);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch /* update request target */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (req->connect_tunnel || have_proxy)
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->target = p_strdup(req->pool, target);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (!have_proxy) {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch /* if we don't have a proxy, CONNECT requests are handled by creating
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch the requested connection directly */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch req->connect_direct = req->connect_tunnel;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if (req->connect_direct)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch req->urgent = TRUE;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch }
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->timeout_time.tv_sec == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->timeout_msecs > 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->timeout_time = ioloop_timeval;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch timeval_add_msecs(&req->timeout_time, req->timeout_msecs);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else if ( client->set.request_absolute_timeout_msecs > 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->timeout_time = ioloop_timeval;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch timeval_add_msecs(&req->timeout_time, client->set.request_absolute_timeout_msecs);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch host = http_client_host_get(req->client, req->host_url);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_QUEUED;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
57962a937b214be3a131f78005509afaa26fe4bfTimo Sirainen http_client_host_submit_request(host, req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschvoid http_client_request_submit(struct http_client_request *req)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch{
31fa529029f35f65451fb1d119ed1d5435b62e46Timo Sirainen req->submit_time = ioloop_timeval;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_request_do_submit(req);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch http_client_request_debug(req, "Submitted");
a991cfe2157e58ee43bc580f517ce9ef0dfb7acfStephan Bosch
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen req->submitted = TRUE;
6ab81c81be13f33486746deeffe02a1ef2bcc821Stephan Bosch http_client_request_add(req);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch}
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Boschvoid
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Boschhttp_client_request_get_peer_addr(const struct http_client_request *req,
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch struct http_client_peer_addr *addr)
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch{
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch const char *host_socket = req->host_socket;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch const struct http_url *host_url = req->host_url;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
8192e6fcab193e174a3258457e967a6fcc60b05eStephan Bosch /* the IP address may be unassigned in the returned peer address, since
8192e6fcab193e174a3258457e967a6fcc60b05eStephan Bosch that is only available at this stage when the target URL has an
8192e6fcab193e174a3258457e967a6fcc60b05eStephan Bosch explicit IP address. */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch memset(addr, 0, sizeof(*addr));
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (host_socket != NULL) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->type = HTTP_CLIENT_PEER_ADDR_UNIX;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->a.un.path = host_socket;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch } else if (req->connect_direct) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->type = HTTP_CLIENT_PEER_ADDR_RAW;
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch addr->a.tcp.ip = host_url->host.ip;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->a.tcp.port =
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch (host_url->port != 0 ? host_url->port : HTTPS_DEFAULT_PORT);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch } else if (host_url->have_ssl) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (req->ssl_tunnel)
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch else
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS;
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch addr->a.tcp.ip = host_url->host.ip;
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch addr->a.tcp.https_name = host_url->host.name;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->a.tcp.port =
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch (host_url->port != 0 ? host_url->port : HTTPS_DEFAULT_PORT);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch } else {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->type = HTTP_CLIENT_PEER_ADDR_HTTP;
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch addr->a.tcp.ip = host_url->host.ip;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch addr->a.tcp.port =
0af543c1f5407f2fafd8685642e55385abade14aTimo Sirainen (host_url->port != 0 ? host_url->port : HTTP_DEFAULT_PORT);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch}
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschstatic void
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainenhttp_client_request_finish_payload_out(struct http_client_request *req)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch{
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen i_assert(req->conn != NULL);
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch /* drop payload output stream */
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->payload_output != NULL) {
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch o_stream_unref(&req->payload_output);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_output = NULL;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch }
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch /* advance state only when request didn't get aborted in the mean time */
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch if (req->state != HTTP_REQUEST_STATE_ABORTED) {
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch /* we're now waiting for a response from the server */
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch req->state = HTTP_REQUEST_STATE_WAITING;
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch http_client_connection_start_request_timeout(req->conn);
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch }
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch /* release connection */
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->conn->output_locked = FALSE;
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch http_client_request_debug(req, "Finished sending%s payload",
aab7256cdcfb7abd01c822e3df8dd77a30c572e0Stephan Bosch (req->state == HTTP_REQUEST_STATE_ABORTED ? " aborted" : ""));
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch}
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainenstatic int
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainenhttp_client_request_continue_payload(struct http_client_request **_req,
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch const unsigned char *data, size_t size)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch{
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch struct ioloop *prev_ioloop = current_ioloop;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch struct http_client_request *req = *_req;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch struct http_client_connection *conn = req->conn;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch struct http_client *client = req->client;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch int ret;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_NEW ||
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch i_assert(req->payload_input == NULL);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (conn != NULL)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_connection_ref(conn);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_request_ref(req);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_wait = TRUE;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (data == NULL) {
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_input = NULL;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT)
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen http_client_request_finish_payload_out(req);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch } else {
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_input = i_stream_create_from_data(data, size);
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen i_stream_set_name(req->payload_input, "<HTTP request payload>");
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch }
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_size = 0;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_chunked = TRUE;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->state == HTTP_REQUEST_STATE_NEW)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_request_submit(req);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch /* Wait for payload data to be written */
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch i_assert(client->ioloop == NULL);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch client->ioloop = io_loop_create();
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_switch_ioloop(client);
0d5c9a80e91a4073d5fd6820e9ddce2755221f64Stephan Bosch if (client->set.dns_client != NULL)
0d5c9a80e91a4073d5fd6820e9ddce2755221f64Stephan Bosch dns_client_switch_ioloop(client->set.dns_client);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen while (req->state < HTTP_REQUEST_STATE_PAYLOAD_IN) {
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_request_debug(req, "Waiting for request to finish");
fb025942616dfec7770455a7092d01f2e516314dTimo Sirainen
fb025942616dfec7770455a7092d01f2e516314dTimo Sirainen if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT)
fb025942616dfec7770455a7092d01f2e516314dTimo Sirainen o_stream_set_flush_pending(req->payload_output, TRUE);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch io_loop_run(client->ioloop);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT &&
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_input->eof) {
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch i_stream_unref(&req->payload_input);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_input = NULL;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch break;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch }
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch }
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
35f3b7e05afecacd0332c210c6e253911c2813d8Timo Sirainen io_loop_set_current(prev_ioloop);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_switch_ioloop(client);
0d5c9a80e91a4073d5fd6820e9ddce2755221f64Stephan Bosch if (client->set.dns_client != NULL)
0d5c9a80e91a4073d5fd6820e9ddce2755221f64Stephan Bosch dns_client_switch_ioloop(client->set.dns_client);
35f3b7e05afecacd0332c210c6e253911c2813d8Timo Sirainen io_loop_set_current(client->ioloop);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch io_loop_destroy(&client->ioloop);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen switch (req->state) {
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen case HTTP_REQUEST_STATE_PAYLOAD_IN:
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen case HTTP_REQUEST_STATE_FINISHED:
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch ret = 1;
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen break;
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen case HTTP_REQUEST_STATE_ABORTED:
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen ret = -1;
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen break;
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen default:
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen ret = 0;
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen break;
a0613a630a412b0649b83c40c83f9fcfe50e1ad7Timo Sirainen }
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch req->payload_wait = FALSE;
b36e026fb1e31bb76524cb345eb40c73e528507bStephan Bosch
b36e026fb1e31bb76524cb345eb40c73e528507bStephan Bosch /* callback may have messed with our pointer,
b36e026fb1e31bb76524cb345eb40c73e528507bStephan Bosch so unref using local variable */
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen if (!http_client_request_unref(&req))
b36e026fb1e31bb76524cb345eb40c73e528507bStephan Bosch *_req = NULL;
b36e026fb1e31bb76524cb345eb40c73e528507bStephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (conn != NULL)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_connection_unref(&conn);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch /* Return status */
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch return ret;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch}
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainenint http_client_request_send_payload(struct http_client_request **_req,
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen const unsigned char *data, size_t size)
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen{
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen struct http_client_request *req = *_req;
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen int ret;
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen i_assert(data != NULL);
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen ret = http_client_request_continue_payload(&req, data, size);
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen if (ret < 0)
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen *_req = NULL;
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen else {
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen i_assert(ret == 0);
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen i_assert(req != NULL);
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen }
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen return ret;
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen}
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainenint http_client_request_finish_payload(struct http_client_request **_req)
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen{
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen struct http_client_request *req = *_req;
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen int ret;
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen *_req = NULL;
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen ret = http_client_request_continue_payload(&req, NULL, 0);
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen i_assert(ret != 0);
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen return ret < 0 ? -1 : 0;
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen}
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Boschstatic void http_client_request_payload_input(struct http_client_request *req)
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch{
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch struct http_client_connection *conn = req->conn;
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch if (conn->io_req_payload != NULL)
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch io_remove(&conn->io_req_payload);
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch (void)http_client_connection_output(conn);
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch}
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainenint http_client_request_send_more(struct http_client_request *req,
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch bool pipelined, const char **error_r)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_connection *conn = req->conn;
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen struct ostream *output = req->payload_output;
d04f3e064ceb2ba1d734182937a7115739ebadbeTimo Sirainen int ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen i_assert(req->payload_input != NULL);
667de5cf294d833b3d47dd455bacff4fd68dd146Timo Sirainen i_assert(req->payload_output != NULL);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch if (conn->io_req_payload != NULL)
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch io_remove(&conn->io_req_payload);
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch
fb025942616dfec7770455a7092d01f2e516314dTimo Sirainen /* chunked ostream needs to write to the parent stream's buffer */
fb025942616dfec7770455a7092d01f2e516314dTimo Sirainen o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen ret = o_stream_send_istream(output, req->payload_input);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch o_stream_set_max_buffer_size(output, (size_t)-1);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen if (req->payload_input->stream_errno != 0) {
50d1446e71cfbdc5b6d7bafcf91b7bff453989d3Stephan Bosch /* we're in the middle of sending a request, so the connection
50d1446e71cfbdc5b6d7bafcf91b7bff453989d3Stephan Bosch will also have to be aborted */
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen *error_r = t_strdup_printf("read(%s) failed: %s",
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen i_stream_get_name(req->payload_input),
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen i_stream_get_error(req->payload_input));
43c49be6f1ca42b9284833b2297e72ea0393fc9cStephan Bosch
43c49be6f1ca42b9284833b2297e72ea0393fc9cStephan Bosch /* the payload stream assigned to this request is broken,
43c49be6f1ca42b9284833b2297e72ea0393fc9cStephan Bosch fail this the request immediately */
43c49be6f1ca42b9284833b2297e72ea0393fc9cStephan Bosch http_client_request_error(&req,
43c49be6f1ca42b9284833b2297e72ea0393fc9cStephan Bosch HTTP_CLIENT_REQUEST_ERROR_BROKEN_PAYLOAD,
43c49be6f1ca42b9284833b2297e72ea0393fc9cStephan Bosch "Broken payload stream");
ea2c9ff03053b7d255984d6bbcb3a48c052d1e4dTimo Sirainen return -1;
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen } else if (output->stream_errno != 0) {
50d1446e71cfbdc5b6d7bafcf91b7bff453989d3Stephan Bosch /* failed to send request */
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen *error_r = t_strdup_printf("write(%s) failed: %s",
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen o_stream_get_name(output),
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen o_stream_get_error(output));
ea2c9ff03053b7d255984d6bbcb3a48c052d1e4dTimo Sirainen return -1;
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen }
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen
d04f3e064ceb2ba1d734182937a7115739ebadbeTimo Sirainen if (ret > 0) {
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch /* finished sending */
ea2c9ff03053b7d255984d6bbcb3a48c052d1e4dTimo Sirainen if (!req->payload_chunked &&
5777eef991bdb9dc487e9b8e8da8a4579fc67f6cTimo Sirainen req->payload_input->v_offset - req->payload_offset != req->payload_size) {
b7540564b9d7b69ce8f6e5a80011ccd5f8b86005Timo Sirainen *error_r = t_strdup_printf("BUG: stream '%s' input size changed: "
b7540564b9d7b69ce8f6e5a80011ccd5f8b86005Timo Sirainen "%"PRIuUOFF_T"-%"PRIuUOFF_T" != %"PRIuUOFF_T,
b7540564b9d7b69ce8f6e5a80011ccd5f8b86005Timo Sirainen i_stream_get_name(req->payload_input),
b7540564b9d7b69ce8f6e5a80011ccd5f8b86005Timo Sirainen req->payload_input->v_offset, req->payload_offset, req->payload_size);
b7540564b9d7b69ce8f6e5a80011ccd5f8b86005Timo Sirainen i_error("%s", *error_r); //FIXME: remove?
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->payload_wait) {
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch /* this chunk of input is finished
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch (client needs to act; disable timeout) */
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch i_assert(!pipelined);
fb025942616dfec7770455a7092d01f2e516314dTimo Sirainen conn->output_locked = TRUE;
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch http_client_connection_stop_request_timeout(conn);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->client->ioloop != NULL)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch io_loop_stop(req->client->ioloop);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch } else {
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch /* finished sending payload */
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen http_client_request_finish_payload_out(req);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch }
43f651585cf5663bf176340b26eadd94b4060a9aTimo Sirainen } else if (i_stream_have_bytes_left(req->payload_input)) {
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch /* output is blocking (server needs to act; enable timeout) */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch conn->output_locked = TRUE;
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch if (!pipelined)
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch http_client_connection_start_request_timeout(conn);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch o_stream_set_flush_pending(output, TRUE);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_debug(req, "Partially sent payload");
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch } else {
3d1edb8e3a07d91860cc6b4b3cec8282caa70891Stephan Bosch /* input is blocking (client needs to act; disable timeout) */
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch conn->output_locked = TRUE;
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch if (!pipelined)
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch http_client_connection_stop_request_timeout(conn);
37703e8d00a3a486aafba6a276fef35b38eab948Timo Sirainen conn->io_req_payload = io_add_istream(req->payload_input,
37703e8d00a3a486aafba6a276fef35b38eab948Timo Sirainen http_client_request_payload_input, req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
ea2c9ff03053b7d255984d6bbcb3a48c052d1e4dTimo Sirainen return 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainenstatic int http_client_request_send_real(struct http_client_request *req,
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch bool pipelined, const char **error_r)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch const struct http_client_settings *set = &req->client->set;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_connection *conn = req->conn;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct ostream *output = conn->conn.output;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch string_t *rtext = t_str_new(256);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct const_iovec iov[3];
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch int ret = 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_assert(!req->conn->output_locked);
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch i_assert(req->payload_output == NULL);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* create request line */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch str_append(rtext, req->method);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch str_append(rtext, " ");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch str_append(rtext, req->target);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, " HTTP/1.1\r\n");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* create special headers implicitly if not set explicitly using
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch http_client_request_add_header() */
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (!req->have_hdr_host) {
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, "Host: ");
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch str_append(rtext, req->authority);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, "\r\n");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (!req->have_hdr_date) {
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, "Date: ");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, http_date_create(req->date));
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, "\r\n");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch }
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch if (!req->have_hdr_authorization &&
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->username != NULL && req->password != NULL) {
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch struct http_auth_credentials auth_creds;
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch http_auth_basic_credentials_init(&auth_creds,
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch req->username, req->password);
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch str_append(rtext, "Authorization: ");
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch http_auth_create_credentials(rtext, &auth_creds);
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch str_append(rtext, "\r\n");
30f35cf5d1e1374d7fab4231e86144fc106a8e79Stephan Bosch }
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch if (http_client_request_to_proxy(req) &&
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch set->proxy_username != NULL && set->proxy_password != NULL) {
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch struct http_auth_credentials auth_creds;
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch http_auth_basic_credentials_init(&auth_creds,
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch set->proxy_username, set->proxy_password);
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch str_append(rtext, "Proxy-Authorization: ");
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch http_auth_create_credentials(rtext, &auth_creds);
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch str_append(rtext, "\r\n");
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch }
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen if (!req->have_hdr_user_agent && req->client->set.user_agent != NULL) {
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen str_printfa(rtext, "User-Agent: %s\r\n",
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen req->client->set.user_agent);
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen }
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch if (!req->have_hdr_expect && req->payload_sync) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch str_append(rtext, "Expect: 100-continue\r\n");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen if (req->payload_input != NULL) {
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen if (req->payload_chunked) {
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen // FIXME: can't do this for a HTTP/1.0 server
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen if (!req->have_hdr_body_spec)
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen str_append(rtext, "Transfer-Encoding: chunked\r\n");
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen req->payload_output =
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen http_transfer_chunked_ostream_create(output);
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen } else {
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen /* send Content-Length if we have specified a payload,
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen even if it's 0 bytes. */
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen if (!req->have_hdr_body_spec) {
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n",
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen req->payload_size);
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen }
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen req->payload_output = output;
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen o_stream_ref(output);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
91a4eaad6cae9b59820a1fa3ad42ef7aea7d1e67Stephan Bosch if (!req->have_hdr_connection &&
91a4eaad6cae9b59820a1fa3ad42ef7aea7d1e67Stephan Bosch !http_client_request_to_proxy(req)) {
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch /* https://tools.ietf.org/html/rfc2068
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch Section 19.7.1:
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch A client MUST NOT send the Keep-Alive connection token to a proxy
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch server as HTTP/1.0 proxy servers do not obey the rules of HTTP/1.1
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch for parsing the Connection header field.
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch */
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch str_append(rtext, "Connection: Keep-Alive\r\n");
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* request line + implicit headers */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch iov[0].iov_base = str_data(rtext);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch iov[0].iov_len = str_len(rtext);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* explicit headers */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch if (req->headers != NULL) {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch iov[1].iov_base = str_data(req->headers);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch iov[1].iov_len = str_len(req->headers);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch } else {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch iov[1].iov_base = "";
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch iov[1].iov_len = 0;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch }
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* end of header */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch iov[2].iov_base = "\r\n";
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch iov[2].iov_len = 2;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_PAYLOAD_OUT;
31fa529029f35f65451fb1d119ed1d5435b62e46Timo Sirainen req->sent_time = ioloop_timeval;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch o_stream_cork(output);
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen if (o_stream_sendv(output, iov, N_ELEMENTS(iov)) < 0) {
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen *error_r = t_strdup_printf("write(%s) failed: %s",
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen o_stream_get_name(output),
dde71564d306d07cba63bdf0f40996ffb90ca47aTimo Sirainen o_stream_get_error(output));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch ret = -1;
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch } else {
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch http_client_request_debug(req, "Sent header");
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch if (req->payload_output != NULL) {
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch if (!req->payload_sync) {
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch if (http_client_request_send_more
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch (req, pipelined, error_r) < 0)
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch ret = -1;
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch } else {
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch http_client_request_debug(req, "Waiting for 100-continue");
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch conn->output_locked = TRUE;
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch } else {
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch req->state = HTTP_REQUEST_STATE_WAITING;
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch if (!pipelined)
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch http_client_connection_start_request_timeout(req->conn);
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch conn->output_locked = FALSE;
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch }
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch if (ret >= 0 && o_stream_flush(output) < 0) {
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch *error_r = t_strdup_printf("flush(%s) failed: %s",
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch o_stream_get_name(output),
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch o_stream_get_error(output));
22215c2d7538f4367c93e2d8b6ec4722463ac757Stephan Bosch ret = -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch o_stream_uncork(output);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainenint http_client_request_send(struct http_client_request *req,
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch bool pipelined, const char **error_r)
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen{
2ff548b46061f984def8d36736745333b8405a31Timo Sirainen char *errstr = NULL;
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen int ret;
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen T_BEGIN {
173d53863744e8ed87e8fa4c32dfcf3759e2ceb0Stephan Bosch ret = http_client_request_send_real(req, pipelined, error_r);
2ff548b46061f984def8d36736745333b8405a31Timo Sirainen if (ret < 0)
2ff548b46061f984def8d36736745333b8405a31Timo Sirainen errstr = i_strdup(*error_r);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen } T_END;
2ff548b46061f984def8d36736745333b8405a31Timo Sirainen *error_r = t_strdup(errstr);
2ff548b46061f984def8d36736745333b8405a31Timo Sirainen i_free(errstr);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen return ret;
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen}
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainenbool http_client_request_callback(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_response *response)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_callback_t *callback = req->callback;
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen unsigned int orig_attempts = req->attempts;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_GOT_RESPONSE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->callback = NULL;
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen if (callback != NULL) {
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen struct http_response response_copy = *response;
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen if (req->attempts > 0 && !req->preserve_exact_reason) {
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen unsigned int total_msecs =
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen timeval_diff_msecs(&ioloop_timeval, &req->submit_time);
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen response_copy.reason = t_strdup_printf(
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen "%s (%u attempts in %u.%03u secs)",
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen response_copy.reason, req->attempts,
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen total_msecs/1000, total_msecs%1000);
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen }
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen
93c9909f68f7d057e38cca3b4612ec8d0bf42999Timo Sirainen callback(&response_copy, req->context);
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen if (req->attempts != orig_attempts) {
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen /* retrying */
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen req->callback = callback;
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen http_client_request_resubmit(req);
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen return FALSE;
6c6915f4d75c352c63156df202fa51cd97524babStephan Bosch } else {
6c6915f4d75c352c63156df202fa51cd97524babStephan Bosch /* release payload early (prevents server/client deadlock in proxy) */
6c6915f4d75c352c63156df202fa51cd97524babStephan Bosch if (req->payload_input != NULL)
6c6915f4d75c352c63156df202fa51cd97524babStephan Bosch i_stream_unref(&req->payload_input);
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen }
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen }
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen return TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Boschstatic void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschhttp_client_request_send_error(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int status, const char *error)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_callback_t *callback;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch bool sending = (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_ABORTED;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch callback = req->callback;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->callback = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (callback != NULL) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_response response;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch http_response_init(&response, status, error);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch (void)callback(&response, req->context);
6c6915f4d75c352c63156df202fa51cd97524babStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* release payload early (prevents server/client deadlock in proxy) */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (!sending && req->payload_input != NULL)
6c6915f4d75c352c63156df202fa51cd97524babStephan Bosch i_stream_unref(&req->payload_input);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
cb44fd2f888be7da34b5d3db2f4d3e88b989f0fbTimo Sirainen if (req->payload_wait && req->client->ioloop != NULL)
47ff1eaf3bc13a702c8491d248d8d34d08796937Timo Sirainen io_loop_stop(req->client->ioloop);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
129596c93692b21d6c6b1313b389774af24c2983Stephan Boschvoid http_client_request_error_delayed(struct http_client_request **_req)
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen{
129596c93692b21d6c6b1313b389774af24c2983Stephan Bosch struct http_client_request *req = *_req;
c6494255de7b934281dd052960fd8ab5aa48e79eTimo Sirainen
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_ABORTED);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen *_req = NULL;
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen
129596c93692b21d6c6b1313b389774af24c2983Stephan Bosch i_assert(req->delayed_error != NULL && req->delayed_error_status != 0);
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen http_client_request_send_error(req, req->delayed_error_status,
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen req->delayed_error);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->queue != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_drop_request(req->queue, req);
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen http_client_request_destroy(&req);
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen}
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainenvoid http_client_request_error(struct http_client_request **_req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int status, const char *error)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen struct http_client_request *req = *_req;
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen i_assert(req->state < HTTP_REQUEST_STATE_FINISHED);
9145c8b5eda526d05bd4a7ced20f6f6f2ff8df03Stephan Bosch req->state = HTTP_REQUEST_STATE_ABORTED;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
840abb812d2e8edc42b5e2a4e3838b8d5e759e6aStephan Bosch if (req->queue != NULL)
840abb812d2e8edc42b5e2a4e3838b8d5e759e6aStephan Bosch http_client_queue_drop_request(req->queue, req);
840abb812d2e8edc42b5e2a4e3838b8d5e759e6aStephan Bosch
5e4cdaaf560cfa94bfc014ce8e1a52e4d0a85b48Stephan Bosch if (!req->submitted ||
5e4cdaaf560cfa94bfc014ce8e1a52e4d0a85b48Stephan Bosch req->state == HTTP_REQUEST_STATE_GOT_RESPONSE) {
5e4cdaaf560cfa94bfc014ce8e1a52e4d0a85b48Stephan Bosch /* we're still in http_client_request_submit() or in the callback
5e4cdaaf560cfa94bfc014ce8e1a52e4d0a85b48Stephan Bosch during a retry attempt. delay reporting the error, so the caller
5e4cdaaf560cfa94bfc014ce8e1a52e4d0a85b48Stephan Bosch doesn't have to handle immediate or nested callbacks. */
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen i_assert(req->delayed_error == NULL);
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen req->delayed_error = p_strdup(req->pool, error);
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen req->delayed_error_status = status;
fca68889b287d8eed4babe72a231bd6079da012dStephan Bosch http_client_delay_request_error(req->client, req);
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen } else {
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen http_client_request_send_error(req, status, error);
79f8a20424633e806447bc9375a5ab403aabc758Stephan Bosch http_client_request_destroy(&req);
6bc9fb43cc1ac24693d030a6cbfa43bc7cbc82cbTimo Sirainen }
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen *_req = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_abort(struct http_client_request **_req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_client_request *req = *_req;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch bool sending = (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen *_req = NULL;
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (req->state >= HTTP_REQUEST_STATE_FINISHED)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->callback = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_ABORTED;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* release payload early (prevents server/client deadlock in proxy) */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (!sending && req->payload_input != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_stream_unref(&req->payload_input);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (req->queue != NULL)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_queue_drop_request(req->queue, req);
cb44fd2f888be7da34b5d3db2f4d3e88b989f0fbTimo Sirainen if (req->payload_wait && req->client->ioloop != NULL)
47ff1eaf3bc13a702c8491d248d8d34d08796937Timo Sirainen io_loop_stop(req->client->ioloop);
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen http_client_request_destroy(&req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainenvoid http_client_request_finish(struct http_client_request *req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (req->state >= HTTP_REQUEST_STATE_FINISHED)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
3e9055cee8e331a84522dd1e65d0d0e09a4e8803Stephan Bosch i_assert(req->refcount > 0);
3e9055cee8e331a84522dd1e65d0d0e09a4e8803Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_debug(req, "Finished");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->callback = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_FINISHED;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->queue != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_drop_request(req->queue, req);
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (req->payload_wait && req->client->ioloop != NULL)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch io_loop_stop(req->client->ioloop);
d1f964d3f1dd9c5868b134c4f44dd63f3722eef7Timo Sirainen http_client_request_unref(&req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_redirect(struct http_client_request *req,
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch unsigned int status, const char *location)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct http_url *url;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch const char *error, *target, *origin_url;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen i_assert(!req->payload_wait);
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* parse URL */
d45ab3fff7c47f1719b9cd310228c0dac2bdd1b2Timo Sirainen if (http_url_parse(location, NULL, 0,
d45ab3fff7c47f1719b9cd310228c0dac2bdd1b2Timo Sirainen pool_datastack_create(), &url, &error) < 0) {
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req, HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch t_strdup_printf("Invalid redirect location: %s", error));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (++req->redirects > req->client->set.max_redirects) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (req->client->set.max_redirects > 0) {
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch t_strdup_printf("Redirected more than %d times",
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->client->set.max_redirects));
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch } else {
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch HTTP_CLIENT_REQUEST_ERROR_INVALID_REDIRECT,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "Redirect refused");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen /* rewind payload stream */
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_input != NULL && req->payload_size > 0 && status != 303) {
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_input->v_offset != req->payload_offset &&
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen !req->payload_input->seekable) {
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req,
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_ABORTED,
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen "Redirect failed: Cannot resend payload; stream is not seekable");
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen return;
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen } else {
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen i_stream_seek(req->payload_input, req->payload_offset);
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch }
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch }
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch /* drop payload output stream from previous attempt */
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch if (req->payload_output != NULL)
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch o_stream_unref(&req->payload_output);
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch
069def4dc35022852d569b7ab75a3b19d2cb0f1cTimo Sirainen target = http_url_create_target(url);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch http_url_copy(req->pool, &req->origin_url, url);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->target = p_strdup(req->pool, target);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->host = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->conn = NULL;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch origin_url = http_url_create(&req->origin_url);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch http_client_request_debug(req, "Redirecting to %s%s",
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch origin_url, target);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->label = p_strdup_printf(req->pool, "[%s %s%s]",
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch req->method, origin_url, req->target);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7231, Section 6.4.4:
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen -> A 303 `See Other' redirect status response is handled a bit differently.
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen Basically, the response content is located elsewhere, but the original
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen (POST) request is handled already.
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen */
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (status == 303 && strcasecmp(req->method, "HEAD") != 0 &&
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen strcasecmp(req->method, "GET") != 0) {
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen // FIXME: should we provide the means to skip this step? The original
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen // request was already handled at this point.
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->method = p_strdup(req->pool, "GET");
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen /* drop payload */
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_input != NULL)
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen i_stream_unref(&req->payload_input);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->payload_size = 0;
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen req->payload_offset = 0;
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch }
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* resubmit */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_NEW;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch http_client_request_do_submit(req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_resubmit(struct http_client_request *req)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen i_assert(!req->payload_wait);
35df1d3e03ffb05ee21077018f5154a4b1e47e37Timo Sirainen
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch http_client_request_debug(req, "Resubmitting request");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
50a6d26bd9041f44b4cad0c0357c0c604c132cc8Stephan Bosch /* rewind payload stream */
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_input != NULL && req->payload_size > 0) {
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen if (req->payload_input->v_offset != req->payload_offset &&
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen !req->payload_input->seekable) {
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req,
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen HTTP_CLIENT_REQUEST_ERROR_ABORTED,
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen "Resubmission failed: Cannot resend payload; stream is not seekable");
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen return;
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen } else {
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen i_stream_seek(req->payload_input, req->payload_offset);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen }
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen }
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch /* drop payload output stream from previous attempt */
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch if (req->payload_output != NULL)
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch o_stream_unref(&req->payload_output);
27421074812b84d144b68388e597f4700f4f1c1bStephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->conn = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->peer = NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch req->state = HTTP_REQUEST_STATE_QUEUED;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch http_client_host_submit_request(req->host, req);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid http_client_request_retry(struct http_client_request *req,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int status, const char *error)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen if (!http_client_request_try_retry(req))
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req, status, error);
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainenbool http_client_request_try_retry(struct http_client_request *req)
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen{
d3d941cc89a8ef5fe0de16bd89e50030e5d22f5bStephan Bosch /* don't ever retry if we're sending data in small blocks via
d3d941cc89a8ef5fe0de16bd89e50030e5d22f5bStephan Bosch http_client_request_send_payload() and we're not waiting for a
d3d941cc89a8ef5fe0de16bd89e50030e5d22f5bStephan Bosch 100 continue (there's no way to rewind the payload for a retry)
d3d941cc89a8ef5fe0de16bd89e50030e5d22f5bStephan Bosch */
d3d941cc89a8ef5fe0de16bd89e50030e5d22f5bStephan Bosch if (req->payload_wait &&
e1d8d185fa74752ba6807e415a9c82ebfdb2082cStephan Bosch (!req->payload_sync || req->payload_sync_continue))
d3d941cc89a8ef5fe0de16bd89e50030e5d22f5bStephan Bosch return FALSE;
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen /* limit the number of attempts for each request */
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen if (req->attempts+1 >= req->client->set.max_attempts)
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen return FALSE;
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen req->attempts++;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen http_client_request_debug(req, "Retrying (attempts=%d)", req->attempts);
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen if (req->callback != NULL)
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen http_client_request_resubmit(req);
6c768e0e1ca2da178e79f7435c32ced01f6bcb24Timo Sirainen return TRUE;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainenvoid http_client_request_set_destroy_callback(struct http_client_request *req,
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen void (*callback)(void *),
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen void *context)
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen{
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen req->destroy_callback = callback;
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen req->destroy_context = context;
4124bebe6daab2cd05acb0416096fc47cb9abd92Timo Sirainen}
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschvoid http_client_request_start_tunnel(struct http_client_request *req,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch struct http_client_tunnel *tunnel)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch{
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch i_assert(req->state == HTTP_REQUEST_STATE_GOT_RESPONSE);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch http_client_connection_start_tunnel(&req->conn, tunnel);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch}