From ef6be35bae1fe501fecd9a2a21eb5d03ddff4243 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 4 Feb 2014 23:37:29 +0100
Subject: [PATCH] CURLOPT_HEADEROPT: added

Modified the logic so that CURLOPT_HEADEROPT now controls if PROXYHEADER
is actually used or not.
---
 docs/libcurl/curl_easy_setopt.3  | 60 ++++++++++++++++++++++++----------------
 docs/libcurl/symbols-in-versions |  1 +
 include/curl/curl.h              |  7 +++++
 lib/http.c                       |  4 +--
 lib/url.c                        |  8 ++++++
 lib/urldata.h                    |  1 +
 tests/data/test1525              |  2 +-
 tests/libtest/lib1525.c          |  3 +-
 tests/libtest/lib1526.c          |  1 +
 9 files changed, 59 insertions(+), 28 deletions(-)

Index: curl-7.19.7/docs/libcurl/curl_easy_setopt.3
===================================================================
--- curl-7.19.7.orig/docs/libcurl/curl_easy_setopt.3	2015-05-04 18:07:53.611260517 +0200
+++ curl-7.19.7/docs/libcurl/curl_easy_setopt.3	2015-05-04 18:47:55.515956050 +0200
@@ -921,20 +921,20 @@ set the User-Agent: header in the http r
 can be used to fool servers or scripts. You can also set any custom header
 with \fICURLOPT_HTTPHEADER\fP.
 .IP CURLOPT_HTTPHEADER
-Pass a pointer to a linked list of HTTP headers to pass to the server in your
-HTTP request. The linked list should be a fully valid list of \fBstruct
-curl_slist\fP structs properly filled in. Use \fIcurl_slist_append(3)\fP to
-create the list and \fIcurl_slist_free_all(3)\fP to clean up an entire
-list. If you add a header that is otherwise generated and used by libcurl
-internally, your added one will be used instead. If you add a header with no
-content as in 'Accept:' (no data on the right side of the colon), the
-internally used header will get disabled. Thus, using this option you can add
-new headers, replace internal headers and remove internal headers. To add a
-header with no content, make the content be two quotes: \&"". The headers
-included in the linked list must not be CRLF-terminated, because curl adds
-CRLF after each header item. Failure to comply with this will result in
-strange bugs because the server will most likely ignore part of the headers
-you specified.
+Pass a pointer to a linked list of HTTP headers to pass to the server and/or
+proxy in your HTTP request. The same list is used for both host and proxy
+requests!
+
+The linked list should be a fully valid list of \fBstruct curl_slist\fP
+structs properly filled in. Use \fIcurl_slist_append(3)\fP to create the list
+and \fIcurl_slist_free_all(3)\fP to clean up an entire list. If you add a
+header that is otherwise generated and used by libcurl internally, your added
+one will be used instead. If you add a header with no content as in 'Accept:'
+(no data on the right side of the colon), the internally used header will get
+disabled. With this option you can add new headers, replace internal headers
+and remove internal headers. To add a header with no content (nothing to the
+right side of the colon), use the form 'MyHeader;' (note the ending
+semicolon).
 
 The first line in a request (containing the method, usually a GET or POST) is
 not a header and cannot be replaced using this option. Only the lines
@@ -946,32 +946,39 @@ Pass a NULL to this to reset back to no
 The most commonly replaced headers have "shortcuts" in the options
 \fICURLOPT_COOKIE\fP, \fICURLOPT_USERAGENT\fP and \fICURLOPT_REFERER\fP.
 
-Starting in 7.36.0, libcurl offers an alternative option that sets or replaces
-headers only for requests that are sent to a proxy:
-\fICURLOPT_PROXYHEADER\fP. If \fICURLOPT_PROXYHEADER\fP is not used at all by
-an application, the \fICURLOPT_HTTPHEADER headers\fP will be used for proxy
-requests as well!
+There's an alternative option that sets or replaces headers only for requests
+that are sent with CONNECT to a proxy: \fICURLOPT_PROXYHEADER\fP. Use
+\fICURLOPT_HEADEROPT\fP to control the behavior.
+.IP CURLOPT_HEADEROPT
+Pass a long that is a bitmask of options of how to deal with headers. The
+available options are:
+
+CURLHEADER_UNIFIED - keep working as before. This means CURLOPT_HTTPHEADER
+headers will be used in requests both to servers and in CONNECT requests. With
+this option enabled, \fICURLOPT_PROXYHEADER\fP will not have any effect.
+
+CURLHEADER_SEPARATE - makes \fICURLOPT_HTTPHEADER\fP headers only get sent to
+a host and not to a proxy if CONNECT is being used. It has to be set to make
+\fICURLOPT_PROXYHEADER\fP get used.
+
+This behavior is set per request and an application can alter it between
+different invokes if desired.
+
 .IP CURLOPT_PROXYHEADER
 Pass a pointer to a linked list of HTTP headers to pass in your HTTP request
 sent to a proxy. The rules for this list is identical to the
 \fICURLOPT_HTTPHEADER\fP option's.
 
-The headers set with this option is only ever used in requests sent to a
-proxy.
-
-As a special quirk to stay backwards compatible with the libcurl versions
-released before this option existed, all headers set with
-\fICURLOPT_HTTPHEADER\fP will also be used for proxies unless you set one or
-more headers (or even just NULL) with \fICURLOPT_PROXYHEADER\fP.
+The headers set with this option is only ever used in requests sent to a proxy
+- when there's also a request sent to a host.
 
 The first line in a request (containing the method, usually a GET or POST) is
-not a header and cannot be replaced using this option. Only the lines
+NOT a header and cannot be replaced using this option. Only the lines
 following the request-line are headers. Adding this method line in this list
 of headers will only cause your request to send an invalid header.
 
 Pass a NULL to this to reset back to no custom headers.
 
-This option was added in libcurl 7.36.0.
 .IP CURLOPT_HTTP200ALIASES
 Pass a pointer to a linked list of aliases to be treated as valid HTTP 200
 responses.  Some servers respond with a custom header response line.  For
Index: curl-7.19.7/docs/libcurl/symbols-in-versions
===================================================================
--- curl-7.19.7.orig/docs/libcurl/symbols-in-versions	2015-05-04 18:07:53.611260517 +0200
+++ curl-7.19.7/docs/libcurl/symbols-in-versions	2015-05-04 18:07:53.621260668 +0200
@@ -237,6 +237,7 @@ CURLOPT_FTP_USE_EPSV            7.9.2
 CURLOPT_GSSAPI_DELEGATION       7.21.8
 CURLOPT_HEADER                  7.1
 CURLOPT_HEADERFUNCTION          7.7.2
+CURLOPT_HEADEROPT               7.36.0
 CURLOPT_HTTP200ALIASES          7.10.3
 CURLOPT_HTTPAUTH                7.10.6
 CURLOPT_HTTPGET                 7.8.1
Index: curl-7.19.7/include/curl/curl.h
===================================================================
--- curl-7.19.7.orig/include/curl/curl.h	2015-05-04 18:07:53.611260517 +0200
+++ curl-7.19.7/include/curl/curl.h	2015-05-04 18:07:53.621260668 +0200
@@ -612,6 +612,10 @@ typedef enum {
   CURLFTPMETHOD_LAST       /* not an option, never use */
 } curl_ftpmethod;
 
+/* bitmask defines for CURLOPT_HEADEROPT */
+#define CURLHEADER_UNIFIED  0
+#define CURLHEADER_SEPARATE (1<<0)
+
 /* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
 #define CURLPROTO_HTTP   (1<<0)
 #define CURLPROTO_HTTPS  (1<<1)
@@ -1295,6 +1299,9 @@ typedef enum {
      struct curl_slist kind */
   CINIT(PROXYHEADER, OBJECTPOINT, 228),
 
+  /* Pass in a bitmask of "header options" */
+  CINIT(HEADEROPT, LONG, 229),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
Index: curl-7.19.7/lib/http.c
===================================================================
--- curl-7.19.7.orig/lib/http.c	2015-05-04 18:07:53.612260532 +0200
+++ curl-7.19.7/lib/http.c	2015-05-04 18:47:57.946993454 +0200
@@ -202,7 +202,7 @@ char *Curl_checkProxyheaders(const struc
   size_t thislen = strlen(thisheader);
   struct SessionHandle *data = conn->data;
 
-  for(head = (conn->bits.proxy && data->set.proxyheaders)?
+  for(head = (conn->bits.proxy && data->set.sep_headers)?
         data->set.proxyheaders:data->set.headers;
       head; head=head->next) {
      if(Curl_raw_nequal(head->data, thisheader, thislen))
@@ -2043,7 +2043,7 @@ static CURLcode add_custom_headers(struc
 {
   char *ptr;
   struct curl_slist *headers=
-    (is_proxy && conn->data->set.proxyheaders)?
+    (is_proxy && conn->data->set.sep_headers)?
     conn->data->set.proxyheaders:conn->data->set.headers;
 
   while(headers) {
Index: curl-7.19.7/lib/url.c
===================================================================
--- curl-7.19.7.orig/lib/url.c	2015-05-04 18:07:53.612260532 +0200
+++ curl-7.19.7/lib/url.c	2015-05-04 18:49:04.049010312 +0200
@@ -838,6 +839,7 @@ CURLcode Curl_setopt(struct SessionHandl
                      va_list param)
 {
   char *argptr;
+  long arg;
   CURLcode result = CURLE_OK;
 #ifndef CURL_DISABLE_HTTP
   curl_off_t bigsize;
@@ -1256,6 +1258,14 @@ CURLcode Curl_setopt(struct SessionHandl
     data->set.proxyheaders = va_arg(param, struct curl_slist *);
     break;
 
+  case CURLOPT_HEADEROPT:
+    /*
+     * Set header option.
+     */
+    arg = va_arg(param, long);
+    data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
+    break;
+
   case CURLOPT_HTTP200ALIASES:
     /*
      * Set a list of aliases for HTTP 200 in response header
Index: curl-7.19.7/lib/urldata.h
===================================================================
--- curl-7.19.7.orig/lib/urldata.h	2015-05-04 18:07:53.613260547 +0200
+++ curl-7.19.7/lib/urldata.h	2015-05-04 18:07:53.622260684 +0200
@@ -1485,6 +1485,7 @@ struct UserDefined {
   struct curl_slist *headers; /* linked list of extra headers */
   struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */
   struct curl_httppost *httppost;  /* linked list of POST data */
+  bool sep_headers;     /* handle host and proxy headers separately */
   bool cookiesession;   /* new cookie session? */
   bool crlf;            /* convert crlf on ftp upload(?) */
   struct curl_slist *quote;     /* after connection is established */
Index: curl-7.19.7/tests/data/test1525
===================================================================
--- curl-7.19.7.orig/tests/data/test1525	2015-05-04 18:07:53.613260547 +0200
+++ curl-7.19.7/tests/data/test1525	2015-05-04 18:07:53.623260699 +0200
@@ -46,7 +46,7 @@ http-proxy
 lib1525
 </tool>
  <name>
-CURLOPT_PROXYHEADER: same headers for host and proxy
+CURLOPT_PROXYHEADER is ignored CURLHEADER_UNIFIED
  </name>
  <command>
  http://the.old.moo.1525:%HTTPPORT/1525 %HOSTIP:%PROXYPORT
Index: curl-7.19.7/tests/libtest/lib1525.c
===================================================================
--- curl-7.19.7.orig/tests/libtest/lib1525.c	2015-05-04 18:07:53.613260547 +0200
+++ curl-7.19.7/tests/libtest/lib1525.c	2015-05-04 18:07:53.623260699 +0200
@@ -71,7 +71,8 @@ int test(char *URL)
   test_setopt(curl, CURLOPT_URL, URL);
   test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
   test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
-  test_setopt(curl, CURLOPT_PROXYHEADER, NULL);
+  test_setopt(curl, CURLOPT_PROXYHEADER, hhl);
+  test_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_UNIFIED);
   test_setopt(curl, CURLOPT_POST, 0L);
   test_setopt(curl, CURLOPT_UPLOAD, 1L);
   test_setopt(curl, CURLOPT_VERBOSE, 1L);
Index: curl-7.19.7/tests/libtest/lib1526.c
===================================================================
--- curl-7.19.7.orig/tests/libtest/lib1526.c	2015-05-04 18:07:53.613260547 +0200
+++ curl-7.19.7/tests/libtest/lib1526.c	2015-05-04 18:07:53.623260699 +0200
@@ -72,6 +72,7 @@ int test(char *URL)
   test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
   test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
   test_setopt(curl, CURLOPT_PROXYHEADER, phl);
+  test_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
   test_setopt(curl, CURLOPT_POST, 0L);
   test_setopt(curl, CURLOPT_UPLOAD, 1L);
   test_setopt(curl, CURLOPT_VERBOSE, 1L);
