Commit 5d9fc28f authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Modified the default HTTP headers used by libcurl:

A) Normal non-proxy HTTP:

 - no more "Pragma: no-cache" (this only makes sense to proxies)

B) Non-CONNECT HTTP request over proxy:

 - "Pragma: no-cache" is used (like before)
 - "Proxy-Connection: Keep-alive" (for older style 1.0-proxies)

C) CONNECT HTTP request over proxy:

 - "Host: [name]:[port]"
 - "Proxy-Connection: Keep-alive"
parent e5ec5c28
Loading
Loading
Loading
Loading
+143 −66
Original line number Diff line number Diff line
@@ -811,6 +811,8 @@ struct send_buffer {
};
typedef struct send_buffer send_buffer;

static CURLcode add_custom_headers(struct connectdata *conn,
                                   send_buffer *req_buffer);
static CURLcode
 add_buffer(send_buffer *in, const void *inptr, size_t size);

@@ -885,10 +887,11 @@ CURLcode add_buffer_send(send_buffer *in,

    *bytes_written += amount;

    if(http) {
      if((size_t)amount != size) {
      /* The whole request could not be sent in one system call. We must queue
         it up and send it later when we get the chance. We must not loop here
         and wait until it might work again. */
        /* The whole request could not be sent in one system call. We must
           queue it up and send it later when we get the chance. We must not
           loop here and wait until it might work again. */

        size -= amount;

@@ -914,6 +917,18 @@ CURLcode add_buffer_send(send_buffer *in,
      http->sending = HTTPSEND_BODY;
      /* the full buffer was sent, clean up and return */
    }
    else {
      if((size_t)amount != size)
        /* We have no continue-send mechanism now, fail. This can only happen
           when this function is used from the CONNECT sending function. We
           currently (stupidly) assume that the whole request is always sent
           away in the first single chunk.

           This needs FIXing.
        */
        return CURLE_SEND_ERROR;
    }
  }
  if(in->buffer)
    free(in->buffer);
  free(in);
@@ -1038,9 +1053,15 @@ Curl_compareheader(char *headerline, /* line to check */
}

/*
 * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
 * function will issue the necessary commands to get a seamless tunnel through
 * this proxy. After that, the socket can be used just as a normal socket.
 * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP
 * proxy. This function will issue the necessary commands to get a seamless
 * tunnel through this proxy. After that, the socket can be used just as a
 * normal socket.
 *
 * This badly needs to be rewritten. CONNECT should be sent and dealt with
 * like any ordinary HTTP request, and not specially crafted like this. This
 * function only remains here like this for now since the rewrite is a bit too
 * much work to do at the moment.
 */

CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
@@ -1063,6 +1084,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
  char *line_start;
  char *host_port;
  curl_socket_t tunnelsocket = conn->sock[sockindex];
  send_buffer *req_buffer;

#define SELECT_OK      0
#define SELECT_ERROR   1
@@ -1080,26 +1102,66 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
      conn->newurl = NULL;
    }

    /* initialize a dynamic send-buffer */
    req_buffer = add_buffer_init();

    if(!req_buffer)
      return CURLE_OUT_OF_MEMORY;

    host_port = aprintf("%s:%d", hostname, remote_port);
    if(!host_port)
      return CURLE_OUT_OF_MEMORY;

    /* Setup the proxy-authorization header, if any */
    result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);

    if(CURLE_OK == result) {
      char *host=(char *)"";
      const char *proxyconn="";
      char *ptr;

      ptr = checkheaders(data, "Host:");
      if(!ptr) {
        host = aprintf("Host: %s\r\n", host_port);
        if(!host)
          result = CURLE_OUT_OF_MEMORY;
      }
      ptr = checkheaders(data, "Proxy-Connection:");
      if(!ptr)
        proxyconn = "Proxy-Connection: Keep-Alive\r\n";

      /* OK, now send the connect request to the proxy */
      if(CURLE_OK == result) {
        /* Send the connect request to the proxy */
        /* BLOCKING */
        result =
        Curl_sendf(tunnelsocket, conn,
                   "CONNECT %s:%d HTTP/1.0\015\012"
                   "%s"
                   "%s"
                   "\r\n",
          add_bufferf(req_buffer,
                      "CONNECT %s:%d HTTP/1.0\r\n"
                      "%s"  /* Host: */
                      "%s"  /* Proxy-Authorization */
                      "%s"  /* User-Agent */
                      "%s", /* Proxy-Connection */
                      hostname, remote_port,
                      host,
                      conn->allocptr.proxyuserpwd?
                      conn->allocptr.proxyuserpwd:"",
                   data->set.useragent?conn->allocptr.uagent:""
                   );
                      data->set.useragent?conn->allocptr.uagent:"",
                      proxyconn);

        if(CURLE_OK == result)
          result = add_custom_headers(conn, req_buffer);

        if(host && *host)
          free(host);

        if(CURLE_OK == result)
          /* CRLF terminate the request */
          result = add_bufferf(req_buffer, "\r\n");

        if(CURLE_OK == result)
          /* Now send off the request */
          result = add_buffer_send(req_buffer, conn,
                                   &data->info.request_size);
      }
      if(result)
        failf(data, "Failed sending CONNECT to proxy");
    }
@@ -1367,7 +1429,42 @@ static CURLcode expect100(struct SessionHandle *data,
  return result;
}

static CURLcode add_custom_headers(struct connectdata *conn,
                                   send_buffer *req_buffer)
{
  CURLcode result = CURLE_OK;
  char *ptr;
  struct curl_slist *headers=conn->data->set.headers;

  while(headers) {
    ptr = strchr(headers->data, ':');
    if(ptr) {
      /* we require a colon for this to be a true header */

      ptr++; /* pass the colon */
      while(*ptr && isspace((int)*ptr))
        ptr++;

      if(*ptr) {
        /* only send this if the contents was non-blank */

        if(conn->allocptr.host &&
           /* a Host: header was sent already, don't pass on any custom Host:
              header as that will produce *two* in the same request! */
           curl_strnequal("Host:", headers->data, 5))
          ;
        else {

          result = add_bufferf(req_buffer, "%s\r\n", headers->data);
          if(result)
            return result;
        }
      }
    }
    headers = headers->next;
  }
  return result;
}

/*
 * Curl_http() gets called from the generic Curl_do() function when a HTTP
@@ -1620,8 +1717,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
  }


  if(!checkheaders(data, "Pragma:"))
    http->p_pragma = "Pragma: no-cache\r\n";
  http->p_pragma =
    (!checkheaders(data, "Pragma:") &&
     (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )?
    "Pragma: no-cache\r\n":NULL;

  if(!checkheaders(data, "Accept:"))
    http->p_accept = "Accept: */*\r\n";
@@ -1727,7 +1826,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
      data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";

    send_buffer *req_buffer;
    struct curl_slist *headers=data->set.headers;
    curl_off_t postsize; /* off_t type to be able to hold a large file size */

    /* initialize a dynamic send-buffer */
@@ -1750,6 +1848,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                  "%s" /* accept */
                  "%s" /* accept-encoding */
                  "%s" /* referer */
                  "%s" /* Proxy-Connection */
                  "%s",/* transfer-encoding */

                request,
@@ -1768,6 +1867,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
                conn->allocptr.accept_encoding:"",
                (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> */,
                (conn->bits.httpproxy && !conn->bits.tunnel_proxy)?
                  "Proxy-Connection: Keep-Alive\r\n":"",
                te
                );

@@ -1874,33 +1975,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
        return result;
    }

    while(headers) {
      ptr = strchr(headers->data, ':');
      if(ptr) {
        /* we require a colon for this to be a true header */

        ptr++; /* pass the colon */
        while(*ptr && isspace((int)*ptr))
          ptr++;

        if(*ptr) {
          /* only send this if the contents was non-blank */

          if(conn->allocptr.host &&
            /* a Host: header was sent already, don't pass on any custom Host:
               header as that will produce *two* in the same request! */
             curl_strnequal("Host:", headers->data, 5))
            ;
          else {

            result = add_bufferf(req_buffer, "%s\r\n", headers->data);
    result = add_custom_headers(conn, req_buffer);
    if(result)
      return result;
          }
        }
      }
      headers = headers->next;
    }

    http->postdata = NULL;  /* nothing to post at this point */
    Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
+0 −1
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ http://%HOSTIP:%HTTPPORT/1
<protocol>
GET /1 HTTP/1.1
Host: 127.0.0.1:%HTTPPORT
Pragma: no-cache
Accept: */*

</protocol>
+0 −1
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ the
<protocol>
PUT /we/want/10 HTTP/1.1
Host: 127.0.0.1:%HTTPPORT
Pragma: no-cache
Accept: */*
Content-Length: 78
Expect: 100-continue
+0 −2
Original line number Diff line number Diff line
@@ -62,12 +62,10 @@ http://%HOSTIP:%HTTPPORT/want/11 -L
<protocol>
GET /want/11 HTTP/1.1
Host: 127.0.0.1:%HTTPPORT
Pragma: no-cache
Accept: */*

GET /want/data/110002.txt?coolsite=yes HTTP/1.1
Host: 127.0.0.1:%HTTPPORT
Pragma: no-cache
Accept: */*

</protocol>
+0 −1
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ http://%HOSTIP:%HTTPPORT/want/12 -r 100-200
GET /want/12 HTTP/1.1
Range: bytes=100-200
Host: 127.0.0.1:%HTTPPORT
Pragma: no-cache
Accept: */*

</protocol>
Loading