From: Stephan Bosch Date: Mon, 16 Sep 2013 23:40:17 +0000 (+0300) Subject: lib-http: http-client: Allow overriding all implicitly generated special headers. X-Git-Tag: 2.2.6~66 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=87c121a4c05b9cee46f1f757ec6999d441519abf;p=thirdparty%2Fdovecot%2Fcore.git lib-http: http-client: Allow overriding all implicitly generated special headers. Which are: Connection, Content-Length, Date, Expect, Host, and Transfer-Encoding. --- diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index af08416f52..93f9346d51 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -69,6 +69,12 @@ struct http_client_request { enum http_request_state state; + unsigned int have_hdr_connection:1; + unsigned int have_hdr_date:1; + unsigned int have_hdr_expect:1; + unsigned int have_hdr_host:1; + unsigned int have_hdr_body_spec:1; + unsigned int payload_sync:1; unsigned int payload_chunked:1; unsigned int payload_wait:1; diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index f67c793180..9d0eb141da 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -151,10 +151,31 @@ void http_client_request_add_header(struct http_client_request *req, const char *key, const char *value) { i_assert(req->state == HTTP_REQUEST_STATE_NEW); - /* don't allow setting Date or Connection header directly; - this is ignored for now for backwards compatibility */ - if (strcasecmp(key, "Date") == 0 || strcasecmp(key, "Connection") == 0) - return; + /* mark presence of special headers */ + switch (key[0]) { + case 'c': case 'C': + if (strcasecmp(key, "Connection") == 0) + req->have_hdr_connection = TRUE; + else if (strcasecmp(key, "Content-Length") == 0) + req->have_hdr_body_spec = TRUE; + break; + case 'd': case 'D': + if (strcasecmp(key, "Date") == 0) + req->have_hdr_date = TRUE; + break; + case 'e': case 'E': + if (strcasecmp(key, "Expect") == 0) + req->have_hdr_expect = TRUE; + break; + case 'h': case 'H': + if (strcasecmp(key, "Host") == 0) + req->have_hdr_host = TRUE; + break; + case 't': case 'T': + if (strcasecmp(key, "Transfer-Encoding") == 0) + req->have_hdr_body_spec = TRUE; + break; + } str_printfa(req->headers, "%s: %s\r\n", key, value); } @@ -407,40 +428,57 @@ static int http_client_request_send_real(struct http_client_request *req, i_assert(!req->conn->output_locked); i_assert(req->payload_output == NULL); + /* create request line */ str_append(rtext, req->method); str_append(rtext, " "); str_append(rtext, req->target); - str_append(rtext, " HTTP/1.1\r\nHost: "); - 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, " HTTP/1.1\r\n"); + + /* create special headers implicitly if not set explicitly using + 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, "\r\n"); } - str_append(rtext, "\r\nDate: "); - str_append(rtext, http_date_create(req->date)); - str_append(rtext, "\r\n"); - if (req->payload_sync) { + if (!req->have_hdr_date) { + str_append(rtext, "Date: "); + str_append(rtext, http_date_create(req->date)); + str_append(rtext, "\r\n"); + } + if (!req->have_hdr_expect && req->payload_sync) { str_append(rtext, "Expect: 100-continue\r\n"); } if (req->payload_chunked) { // FIXME: can't do this for a HTTP/1.0 server - str_append(rtext, "Transfer-Encoding: chunked\r\n"); + if (!req->have_hdr_body_spec) + str_append(rtext, "Transfer-Encoding: chunked\r\n"); req->payload_output = http_transfer_chunked_ostream_create(output); } else if (req->payload_input != NULL) { /* send Content-Length if we have specified a payload, even if it's 0 bytes. */ - str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n", - req->payload_size); + if (!req->have_hdr_body_spec) { + str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n", + req->payload_size); + } req->payload_output = output; o_stream_ref(output); } - str_append(rtext, "Connection: Keep-Alive\r\n"); + if (!req->have_hdr_connection) + str_append(rtext, "Connection: Keep-Alive\r\n"); + /* request line + implicit headers */ iov[0].iov_base = str_data(rtext); - iov[0].iov_len = str_len(rtext); + iov[0].iov_len = str_len(rtext); + /* explicit headers */ iov[1].iov_base = str_data(req->headers); iov[1].iov_len = str_len(req->headers); + /* end of header */ iov[2].iov_base = "\r\n"; iov[2].iov_len = 2;