]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: http-client: Allow overriding all implicitly generated special headers.
authorStephan Bosch <stephan@rename-it.nl>
Mon, 16 Sep 2013 23:40:17 +0000 (02:40 +0300)
committerStephan Bosch <stephan@rename-it.nl>
Mon, 16 Sep 2013 23:40:17 +0000 (02:40 +0300)
Which are: Connection, Content-Length, Date, Expect, Host, and Transfer-Encoding.

src/lib-http/http-client-private.h
src/lib-http/http-client-request.c

index af08416f523b0fca7b8c06693028c30a461ab30c..93f9346d51dfc0f818dd3af0860c7c5a508c3551 100644 (file)
@@ -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;
index f67c7931804fecc4c49389cd0137bea5f720eb83..9d0eb141da9e58ea2370613c6fcf17f22b015f10 100644 (file)
@@ -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;