dovecot-2.2: lib-http: http-client: Implemented proxy support.
dovecot at dovecot.org
dovecot at dovecot.org
Sat Oct 12 11:14:58 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/462ae2cb8094
changeset: 16854:462ae2cb8094
user: Stephan Bosch <stephan at rename-it.nl>
date: Sat Oct 12 11:00:15 2013 +0300
description:
lib-http: http-client: Implemented proxy support.
diffstat:
src/lib-http/http-client-host.c | 14 ++-
src/lib-http/http-client-private.h | 34 ++++++++-
src/lib-http/http-client-request.c | 125 ++++++++++++++++++++++++++----------
src/lib-http/http-client.c | 9 ++
src/lib-http/http-client.h | 16 ++++
5 files changed, 151 insertions(+), 47 deletions(-)
diffs (truncated from 394 to 300 lines):
diff -r 9709839d2be7 -r 462ae2cb8094 src/lib-http/http-client-host.c
--- a/src/lib-http/http-client-host.c Sat Oct 12 10:58:04 2013 +0300
+++ b/src/lib-http/http-client-host.c Sat Oct 12 11:00:15 2013 +0300
@@ -454,12 +454,14 @@
struct http_client_request *req)
{
struct http_client_host_port *hport;
- const char *https_name = req->ssl ? req->hostname : NULL;
+ const struct http_url *host_url = req->host_url;
+ const char *https_name = http_client_request_https_name(req);
+ in_port_t port = http_client_request_port(req);
const char *error;
req->host = host;
- if (req->ssl && host->client->ssl_ctx == NULL) {
+ if (host_url->have_ssl && host->client->ssl_ctx == NULL) {
if (http_client_init_ssl_ctx(host->client, &error) < 0) {
http_client_request_error(req,
HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, error);
@@ -468,7 +470,7 @@
}
/* add request to host (grouped by tcp port) */
- hport = http_client_host_port_init(host, req->port, https_name);
+ hport = http_client_host_port_init(host, port, https_name);
if (req->urgent)
array_insert(&hport->request_queue, 0, &req, 1);
else
@@ -542,9 +544,10 @@
struct http_client_request *req)
{
struct http_client_host_port *hport;
- const char *https_name = req->ssl ? req->hostname : NULL;
+ const char *https_name = http_client_request_https_name(req);
+ in_port_t port = http_client_request_port(req);
- hport = http_client_host_port_find(host, req->port, https_name);
+ hport = http_client_host_port_find(host, port, https_name);
if (hport == NULL)
return;
@@ -596,5 +599,4 @@
(*req)->to_delayed_error =
io_loop_move_timeout(&(*req)->to_delayed_error);
}
-
}
diff -r 9709839d2be7 -r 462ae2cb8094 src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h Sat Oct 12 10:58:04 2013 +0300
+++ b/src/lib-http/http-client-private.h Sat Oct 12 11:00:15 2013 +0300
@@ -3,6 +3,7 @@
#include "connection.h"
+#include "http-url.h"
#include "http-client.h"
#define HTTP_DEFAULT_PORT 80
@@ -38,9 +39,13 @@
struct http_client_request {
pool_t pool;
unsigned int refcount;
+ const char *label;
- const char *method, *hostname, *target;
- in_port_t port;
+ const char *method, *target;
+ struct http_url origin_url;
+
+ const struct http_url *host_url;
+ const char *authority;
struct http_client *client;
struct http_client_host *host;
@@ -79,7 +84,6 @@
unsigned int payload_sync:1;
unsigned int payload_chunked:1;
unsigned int payload_wait:1;
- unsigned int ssl:1;
unsigned int urgent:1;
unsigned int submitted:1;
};
@@ -210,8 +214,28 @@
static inline const char *
http_client_request_label(struct http_client_request *req)
{
- return t_strdup_printf("[%s http%s://%s:%d%s]",
- req->method, req->ssl ? "s" : "", req->hostname, req->port, req->target);
+ if (req->label == NULL) {
+ return t_strdup_printf("[%s %s%s]",
+ req->method, http_url_create(&req->origin_url), req->target);
+ }
+ return req->label;
+}
+
+static inline in_port_t
+http_client_request_port(const struct http_client_request *req)
+{
+ const struct http_url *host_url = req->host_url;
+
+ return (host_url->have_port ? host_url->port :
+ (host_url->have_ssl ? HTTPS_DEFAULT_PORT : HTTP_DEFAULT_PORT));
+}
+
+static inline const char *
+http_client_request_https_name(const struct http_client_request *req)
+{
+ const struct http_url *host_url = req->host_url;
+
+ return (host_url->have_ssl ? host_url->host_name : NULL);
}
static inline const char *
diff -r 9709839d2be7 -r 462ae2cb8094 src/lib-http/http-client-request.c
--- a/src/lib-http/http-client-request.c Sat Oct 12 10:58:04 2013 +0300
+++ b/src/lib-http/http-client-request.c Sat Oct 12 11:00:15 2013 +0300
@@ -52,10 +52,8 @@
*/
static void http_client_request_remove_delayed(struct http_client_request *req);
-#undef http_client_request
-struct http_client_request *
-http_client_request(struct http_client *client,
- const char *method, const char *host, const char *target,
+static struct http_client_request *
+http_client_request_new(struct http_client *client, const char *method,
http_client_request_callback_t *callback, void *context)
{
pool_t pool;
@@ -67,18 +65,44 @@
req->refcount = 1;
req->client = client;
req->method = p_strdup(pool, method);
- req->hostname = p_strdup(pool, host);
- req->port = HTTP_DEFAULT_PORT;
- req->target = (target == NULL ? "/" : p_strdup(pool, target));
req->callback = callback;
req->context = context;
- req->headers = str_new(default_pool, 256);
req->date = (time_t)-1;
req->state = HTTP_REQUEST_STATE_NEW;
return req;
}
+#undef http_client_request
+struct http_client_request *
+http_client_request(struct http_client *client,
+ const char *method, const char *host, const char *target,
+ http_client_request_callback_t *callback, void *context)
+{
+ struct http_client_request *req;
+
+ req = http_client_request_new(client, method, callback, context);
+ req->origin_url.host_name = p_strdup(req->pool, host);
+ req->target = (target == NULL ? "/" : p_strdup(req->pool, target));
+ req->headers = str_new(default_pool, 256);
+ return req;
+}
+
+#undef http_client_request_url
+struct http_client_request *
+http_client_request_url(struct http_client *client,
+ const char *method, const struct http_url *target_url,
+ http_client_request_callback_t *callback, void *context)
+{
+ struct http_client_request *req;
+
+ req = http_client_request_new(client, method, callback, context);
+ http_url_copy_authority(req->pool, &req->origin_url, target_url);
+ req->target = p_strdup(req->pool, http_url_create_target(target_url));
+ req->headers = str_new(default_pool, 256);
+ return req;
+}
+
void http_client_request_ref(struct http_client_request *req)
{
req->refcount++;
@@ -124,21 +148,15 @@
in_port_t port)
{
i_assert(req->state == HTTP_REQUEST_STATE_NEW);
- req->port = port;
+ req->origin_url.port = port;
+ req->origin_url.have_port = TRUE;
}
void http_client_request_set_ssl(struct http_client_request *req,
bool ssl)
{
i_assert(req->state == HTTP_REQUEST_STATE_NEW);
- if (ssl) {
- if (!req->ssl && req->port == HTTP_DEFAULT_PORT)
- req->port = HTTPS_DEFAULT_PORT;
- } else {
- if (req->ssl && req->port == HTTPS_DEFAULT_PORT)
- req->port = HTTP_DEFAULT_PORT;
- }
- req->ssl = ssl;
+ req->origin_url.have_ssl = ssl;
}
void http_client_request_set_urgent(struct http_client_request *req)
@@ -180,6 +198,8 @@
req->have_hdr_user_agent = TRUE;
break;
}
+ if (req->headers == NULL)
+ req->headers = str_new(default_pool, 256);
str_printfa(req->headers, "%s: %s\r\n", key, value);
}
@@ -223,15 +243,39 @@
static void http_client_request_do_submit(struct http_client_request *req)
{
+ struct http_client *client = req->client;
struct http_client_host *host;
+ const struct http_url *proxy_url = client->set.proxy_url;
+ const char *target;
i_assert(req->state == HTTP_REQUEST_STATE_NEW);
+ target = t_strconcat
+ (http_url_create_host(&req->origin_url), req->target, NULL);
+
+ /* determine what host to contact to submit this request */
+ if (proxy_url != NULL) {
+ req->host_url = proxy_url; /* proxy server */
+ } else {
+ req->host_url = &req->origin_url; /* origin server */
+ }
+
/* use submission date if no date is set explicitly */
if (req->date == (time_t)-1)
req->date = ioloop_time;
- host = http_client_host_get(req->client, req->hostname);
+ /* prepare value for Host header */
+ req->authority =
+ p_strdup(req->pool, http_url_create_authority(req->host_url));
+
+ /* debug label */
+ req->label = p_strdup_printf(req->pool, "[%s %s]", req->method, target);
+
+ /* request target needs to be made absolute url for proxy requests */
+ if (proxy_url != NULL)
+ req->target = p_strdup(req->pool, target);
+
+ host = http_client_host_get(req->client, req->host_url->host_name);
req->state = HTTP_REQUEST_STATE_QUEUED;
http_client_host_submit_request(host, req);
@@ -239,10 +283,10 @@
void http_client_request_submit(struct http_client_request *req)
{
- http_client_request_debug(req, "Submitted");
req->client->pending_requests++;
http_client_request_do_submit(req);
+ http_client_request_debug(req, "Submitted");
req->submitted = TRUE;
}
@@ -452,11 +496,7 @@
http_client_request_add_header() */
if (!req->have_hdr_host) {
str_append(rtext, "Host: ");
- str_append(rtext, req->hostname);
- if ((!req->ssl &&req->port != HTTP_DEFAULT_PORT) ||
- (req->ssl && req->port != HTTPS_DEFAULT_PORT)) {
- str_printfa(rtext, ":%u", req->port);
- }
+ str_append(rtext, req->authority);
str_append(rtext, "\r\n");
}
if (!req->have_hdr_date) {
@@ -487,8 +527,16 @@
req->payload_output = output;
o_stream_ref(output);
}
- if (!req->have_hdr_connection)
+ if (!req->have_hdr_connection && req->host_url == &req->origin_url) {
+ /* https://tools.ietf.org/html/rfc2068
+ Section 19.7.1:
+
+ A client MUST NOT send the Keep-Alive connection token to a proxy
+ server as HTTP/1.0 proxy servers do not obey the rules of HTTP/1.1
+ for parsing the Connection header field.
+ */
str_append(rtext, "Connection: Keep-Alive\r\n");
+ }
/* request line + implicit headers */
iov[0].iov_base = str_data(rtext);
@@ -665,8 +713,7 @@
unsigned int status, const char *location)
{
More information about the dovecot-cvs
mailing list