From ac887eedbc17a0d78b11ff467858c76a5127d1f4 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Fri, 31 Jan 2014 08:10:07 +0100
Subject: [PATCH] CURLOPT_PROXYHEADER: set headers for proxy-only

Includes docs and new test cases: 1525, 1526 and 1527

Co-written-by: Vijay Panghal
---
 docs/libcurl/curl_easy_setopt.3  | 27 +++++++++++
 docs/libcurl/symbols-in-versions |  1 +
 include/curl/curl.h              |  9 +++-
 lib/http.c                       | 84 +++++++++++++++++++++++-----------
 lib/http.h                       |  9 +++-
 lib/http_proxy.c                 |  8 ++--
 lib/rtsp.c                       | 26 +++++------
 lib/url.c                        | 14 ++++++
 lib/urldata.h                    |  1 +
 tests/data/Makefile.am           |  2 +
 tests/data/test1525              | 76 ++++++++++++++++++++++++++++++
 tests/data/test1526              | 76 ++++++++++++++++++++++++++++++
 tests/data/test1527              | 76 ++++++++++++++++++++++++++++++
 tests/libtest/Makefile.inc       | 16 ++++++-
 tests/libtest/lib1525.c          | 96 ++++++++++++++++++++++++++++++++++++++
 tests/libtest/lib1526.c          | 99 ++++++++++++++++++++++++++++++++++++++++
 tests/libtest/lib1527.c          | 95 ++++++++++++++++++++++++++++++++++++++
 17 files changed, 667 insertions(+), 48 deletions(-)
 create mode 100644 tests/data/test1525
 create mode 100644 tests/data/test1526
 create mode 100644 tests/data/test1527
 create mode 100644 tests/libtest/lib1525.c
 create mode 100644 tests/libtest/lib1526.c
 create mode 100644 tests/libtest/lib1527.c

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 16:33:59.355489601 +0200
+++ curl-7.19.7/docs/libcurl/curl_easy_setopt.3	2015-05-04 16:46:43.389905154 +0200
@@ -945,6 +945,33 @@ 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!
+.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 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
+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 16:33:59.303488818 +0200
+++ curl-7.19.7/docs/libcurl/symbols-in-versions	2015-05-04 16:46:43.389905154 +0200
@@ -300,6 +300,7 @@ CURLOPT_PROGRESSMODE            7.1
 CURLOPT_PROTOCOLS               7.19.4
 CURLOPT_PROXY                   7.1
 CURLOPT_PROXYAUTH               7.10.7
+CURLOPT_PROXYHEADER             7.36.0
 CURLOPT_PROXYPASSWORD           7.19.1
 CURLOPT_PROXYPORT               7.1
 CURLOPT_PROXYTYPE               7.10
Index: curl-7.19.7/include/curl/curl.h
===================================================================
--- curl-7.19.7.orig/include/curl/curl.h	2015-05-04 16:33:59.356489616 +0200
+++ curl-7.19.7/include/curl/curl.h	2015-05-04 16:46:43.389905154 +0200
@@ -747,7 +747,8 @@ typedef enum {
   /* Set cookie in request: */
   CINIT(COOKIE, OBJECTPOINT, 22),
 
-  /* This points to a linked list of headers, struct curl_slist kind */
+  /* This points to a linked list of headers, struct curl_slist kind. This
+     list is also used for RTSP (in spite of its name) */
   CINIT(HTTPHEADER, OBJECTPOINT, 23),
 
   /* This points to a linked list of post entries, struct curl_httppost */
@@ -1290,6 +1291,10 @@ typedef enum {
   /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
   CINIT(SSL_OPTIONS, LONG, 216),
 
+  /* This points to a linked list of headers used for proxy requests only,
+     struct curl_slist kind */
+  CINIT(PROXYHEADER, OBJECTPOINT, 228),
+
   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 16:33:59.515492012 +0200
+++ curl-7.19.7/lib/http.c	2015-05-04 16:47:38.016720533 +0200
@@ -186,6 +186,32 @@ static char *checkheaders(struct Session
 }
 
 /*
+ * checkProxyHeaders() checks the linked list of custom proxy headers
+ * if proxy headers are not available, then it will lookup into http header
+ * link list
+ *
+ * It takes a connectdata struct as input instead of the SessionHandle simply
+ * to know if this is a proxy request or not, as it then might check a
+ * different header list.
+ *
+ */
+char *Curl_checkProxyheaders(const struct connectdata *conn,
+                             const char *thisheader)
+{
+  struct curl_slist *head;
+  size_t thislen = strlen(thisheader);
+  struct SessionHandle *data = conn->data;
+
+  for(head = (conn->bits.proxy && data->set.proxyheaders)?
+        data->set.proxyheaders:data->set.headers;
+      head; head=head->next) {
+     if(Curl_raw_nequal(head->data, thisheader, thislen))
+       return head->data;
+  }
+  return NULL;
+}
+
+/*
  * Strip off leading and trailing whitespace from the value in the
  * given HTTP header line and return a strdupped copy. Returns NULL in
  * case of allocation failure. Returns an empty string if the header value
@@ -565,7 +591,7 @@ output_auth_headers(struct connectdata *
   if(authstatus->picked == CURLAUTH_BASIC) {
     /* Basic */
     if((proxy && conn->bits.proxy_user_passwd &&
-       !checkheaders(data, "Proxy-authorization:")) ||
+       !Curl_checkProxyheaders(conn, "Proxy-authorization:")) ||
        (!proxy && conn->bits.user_passwd &&
        !checkheaders(data, "Authorization:"))) {
       auth="Basic";
@@ -976,6 +1002,7 @@ struct send_buffer {
 typedef struct send_buffer send_buffer;
 
 static CURLcode add_custom_headers(struct connectdata *conn,
+                                   bool is_proxy,
                                    send_buffer *req_buffer);
 static CURLcode
  add_buffer(send_buffer *in, const void *inptr, size_t size);
@@ -1357,7 +1384,7 @@ CURLcode Curl_proxyCONNECT(struct connec
         const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
           "1.0" : "1.1";
 
-        if(!checkheaders(data, "Host:")) {
+        if(!Curl_checkProxyheaders(conn, "Host:")) {
           host = aprintf("Host: %s\r\n", host_port);
           if(!host) {
             free(req_buffer);
@@ -1365,10 +1392,10 @@ CURLcode Curl_proxyCONNECT(struct connec
             return CURLE_OUT_OF_MEMORY;
           }
         }
-        if(!checkheaders(data, "Proxy-Connection:"))
+        if(!Curl_checkProxyheaders(conn, "Proxy-Connection:"))
           proxyconn = "Proxy-Connection: Keep-Alive\r\n";
 
-        if(!checkheaders(data, "User-Agent:") &&
+        if(!Curl_checkProxyheaders(conn, "User-Agent:") &&
            data->set.str[STRING_USERAGENT])
           useragent = conn->allocptr.uagent;
 
@@ -1392,7 +1419,7 @@ CURLcode Curl_proxyCONNECT(struct connec
           free(host);
 
         if(CURLE_OK == result)
-          result = add_custom_headers(conn, req_buffer);
+          result = add_custom_headers(conn, TRUE, req_buffer);
 
         if(CURLE_OK == result)
           /* CRLF terminate the request */
@@ -2011,10 +2038,13 @@ static CURLcode expect100(struct Session
 }
 
 static CURLcode add_custom_headers(struct connectdata *conn,
+                                   bool is_proxy,
                                    send_buffer *req_buffer)
 {
   char *ptr;
-  struct curl_slist *headers=conn->data->set.headers;
+  struct curl_slist *headers=
+    (is_proxy && conn->data->set.proxyheaders)?
+    conn->data->set.proxyheaders:conn->data->set.headers;
 
   while(headers) {
     ptr = strchr(headers->data, ':');
@@ -2656,7 +2686,7 @@ CURLcode Curl_http(struct connectdata *c
       return result;
   }
 
-  result = add_custom_headers(conn, req_buffer);
+  result = add_custom_headers(conn, FALSE, req_buffer);
   if(result)
     return result;
 
Index: curl-7.19.7/lib/url.c
===================================================================
--- curl-7.19.7.orig/lib/url.c	2015-05-04 16:33:59.507491892 +0200
+++ curl-7.19.7/lib/url.c	2015-05-04 16:46:43.389905154 +0200
@@ -1242,6 +1242,20 @@ CURLcode Curl_setopt(struct SessionHandl
     data->set.headers = va_arg(param, struct curl_slist *);
     break;
 
+  case CURLOPT_PROXYHEADER:
+    /*
+     * Set a list with proxy headers to use (or replace internals with)
+     *
+     * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
+     * long time we remain doing it this way until CURLOPT_PROXYHEADER is
+     * used. As soon as this option has been used, if set to anything but
+     * NULL, custom headers for proxies are only picked from this list.
+     *
+     * Set this option to NULL to restore the previous behavior.
+     */
+    data->set.proxyheaders = va_arg(param, struct curl_slist *);
+    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 16:33:59.483491530 +0200
+++ curl-7.19.7/lib/urldata.h	2015-05-04 16:46:43.389905154 +0200
@@ -1483,6 +1483,7 @@ struct UserDefined {
   curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */
   curl_off_t set_resume_from;  /* continue [ftp] transfer from here */
   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 cookiesession;   /* new cookie session? */
   bool crlf;            /* convert crlf on ftp upload(?) */
Index: curl-7.19.7/tests/data/test1525
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ curl-7.19.7/tests/data/test1525	2015-05-04 16:46:43.389905154 +0200
@@ -0,0 +1,76 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP CONNECT
+HTTP proxy
+proxytunnel
+CURLOPT_PROXYHEADER
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 200 OK
+Content-Length: 17
+
+</connect>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</data>
+<datacheck>
+HTTP/1.1 200 OK
+Content-Length: 17
+
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</datacheck>
+
+</reply>
+# Client-side
+<client>
+<server>
+http
+http-proxy
+</server>
+<tool>
+lib1525
+</tool>
+ <name>
+CURLOPT_PROXYHEADER: same headers for host and proxy
+ </name>
+ <command>
+ http://the.old.moo.1525:%HTTPPORT/1525 %HOSTIP:%PROXYPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<proxy>
+CONNECT the.old.moo.1525:%HTTPPORT HTTP/1.1
+Host: the.old.moo.1525:%HTTPPORT
+Proxy-Connection: Keep-Alive
+User-Agent: Http Agent
+
+</proxy>
+<protocol>
+PUT /1525 HTTP/1.1
+Host: the.old.moo.1525:%HTTPPORT
+Accept: */*
+User-Agent: Http Agent
+Content-Length: 13
+Expect: 100-continue
+
+Hello Cloud!
+</protocol>
+</verify>
+</testcase>
Index: curl-7.19.7/tests/data/test1526
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ curl-7.19.7/tests/data/test1526	2015-05-04 16:33:59.527492193 +0200
@@ -0,0 +1,76 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP CONNECT
+HTTP proxy
+proxytunnel
+CURLOPT_PROXYHEADER
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 200 OK
+Server: present
+
+</connect>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</data>
+<datacheck>
+HTTP/1.1 200 OK
+Server: present
+
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+http-proxy
+</server>
+<tool>
+lib1526
+</tool>
+ <name>
+CURLOPT_PROXYHEADER: separate host/proxy headers
+ </name>
+ <command>
+ http://the.old.moo.1526:%HTTPPORT/1526 %HOSTIP:%PROXYPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<proxy>
+CONNECT the.old.moo.1526:%HTTPPORT HTTP/1.1
+Host: the.old.moo.1526:%HTTPPORT
+Proxy-Connection: Keep-Alive
+User-Agent: Proxy Agent
+
+</proxy>
+<protocol>
+PUT /1526 HTTP/1.1
+Host: the.old.moo.1526:%HTTPPORT
+Accept: */*
+User-Agent: Http Agent
+Content-Length: 13
+Expect: 100-continue
+
+Hello Cloud!
+</protocol>
+</verify>
+</testcase>
Index: curl-7.19.7/tests/data/test1527
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ curl-7.19.7/tests/data/test1527	2015-05-04 16:33:59.528492208 +0200
@@ -0,0 +1,76 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP CONNECT
+HTTP proxy
+proxytunnel
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 200 OK
+We-are: good
+
+</connect>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</data>
+<datacheck>
+HTTP/1.1 200 OK
+We-are: good
+
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</datacheck>
+
+</reply>
+# Client-side
+<client>
+<server>
+http
+http-proxy
+</server>
+<tool>
+lib1527
+</tool>
+ <name>
+Check same headers are generated without CURLOPT_PROXYHEADER
+ </name>
+ <command>
+ http://the.old.moo.1527:%HTTPPORT/1527 %HOSTIP:%PROXYPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<proxy>
+CONNECT the.old.moo.1527:%HTTPPORT HTTP/1.1
+Host: the.old.moo.1527:%HTTPPORT
+Proxy-Connection: Keep-Alive
+User-Agent: Http Agent
+Expect: 100-continue
+
+</proxy>
+<protocol>
+PUT /1527 HTTP/1.1
+Host: the.old.moo.1527:%HTTPPORT
+Accept: */*
+User-Agent: Http Agent
+Expect: 100-continue
+Content-Length: 13
+
+Hello Cloud!
+</protocol>
+</verify>
+</testcase>
Index: curl-7.19.7/tests/libtest/lib1525.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ curl-7.19.7/tests/libtest/lib1525.c	2015-05-04 16:46:43.389905154 +0200
@@ -0,0 +1,96 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2014, Vijay Panghal, <vpanghal@maginatics.com>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This unit test PUT http data over proxy. Proxy header will be different
+ * from server http header
+ */
+
+#include "test.h"
+
+#include "memdebug.h"
+
+static char data [] = "Hello Cloud!\n";
+
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  size_t  amount = nmemb * size; /* Total bytes curl wants */
+  if (amount < strlen(data)) {
+    return strlen(data);
+  }
+  (void)stream;
+  memcpy(ptr, data, strlen(data));
+  return strlen(data);
+}
+
+
+int test(char *URL)
+{
+  CURL *curl = NULL;
+  CURLcode res = CURLE_FAILED_INIT;
+  /* http and proxy header list*/
+  struct curl_slist *hhl = NULL;
+
+  if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+    fprintf(stderr, "curl_global_init() failed\n");
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  if((curl = curl_easy_init()) == NULL) {
+    fprintf(stderr, "curl_easy_init() failed\n");
+    curl_global_cleanup();
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  hhl = curl_slist_append(hhl, "User-Agent: Http Agent");
+
+  if (!hhl) {
+    goto test_cleanup;
+  }
+
+  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_POST, 0L);
+  test_setopt(curl, CURLOPT_UPLOAD, 1L);
+  test_setopt(curl, CURLOPT_VERBOSE, 1L);
+  test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+  test_setopt(curl, CURLOPT_HEADER, 1L);
+  test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+  test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+  test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
+  test_setopt(curl, CURLOPT_INFILESIZE, strlen(data));
+
+  res = curl_easy_perform(curl);
+
+test_cleanup:
+
+  curl_easy_cleanup(curl);
+
+  curl_slist_free_all(hhl);
+
+  curl_global_cleanup();
+
+  return (int)res;
+}
Index: curl-7.19.7/tests/libtest/lib1526.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ curl-7.19.7/tests/libtest/lib1526.c	2015-05-04 16:46:43.389905154 +0200
@@ -0,0 +1,99 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Vijay Panghal, <vpanghal@maginatics.com>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This unit test PUT http data over proxy. Proxy header will be different
+ * from server http header
+ */
+
+#include "test.h"
+
+#include "memdebug.h"
+
+static char data [] = "Hello Cloud!\n";
+
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  size_t  amount = nmemb * size; /* Total bytes curl wants */
+  if (amount < strlen(data)) {
+    return strlen(data);
+  }
+  (void)stream;
+  memcpy(ptr, data, strlen(data));
+  return strlen(data);
+}
+
+int test(char *URL)
+{
+  CURL *curl = NULL;
+  CURLcode res = CURLE_FAILED_INIT;
+  /* http and proxy header list*/
+  struct curl_slist *hhl = NULL, *phl = NULL;
+
+  if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+    fprintf(stderr, "curl_global_init() failed\n");
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  if((curl = curl_easy_init()) == NULL) {
+    fprintf(stderr, "curl_easy_init() failed\n");
+    curl_global_cleanup();
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  hhl = curl_slist_append(hhl, "User-Agent: Http Agent");
+  phl = curl_slist_append(phl, "User-Agent: Proxy Agent");
+  phl = curl_slist_append(phl, "Expect:");
+
+  if (!hhl || !phl) {
+    goto test_cleanup;
+  }
+
+  test_setopt(curl, CURLOPT_URL, URL);
+  test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
+  test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
+  test_setopt(curl, CURLOPT_PROXYHEADER, phl);
+  test_setopt(curl, CURLOPT_POST, 0L);
+  test_setopt(curl, CURLOPT_UPLOAD, 1L);
+  test_setopt(curl, CURLOPT_VERBOSE, 1L);
+  test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+  test_setopt(curl, CURLOPT_HEADER, 1L);
+  test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+  test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+  test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
+  test_setopt(curl, CURLOPT_INFILESIZE, strlen(data));
+
+  res = curl_easy_perform(curl);
+
+test_cleanup:
+
+  curl_easy_cleanup(curl);
+
+  curl_slist_free_all(hhl);
+
+  curl_slist_free_all(phl);
+
+  curl_global_cleanup();
+
+  return (int)res;
+}
+
Index: curl-7.19.7/tests/libtest/lib1527.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ curl-7.19.7/tests/libtest/lib1527.c	2015-05-04 16:33:59.528492208 +0200
@@ -0,0 +1,95 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Vijay Panghal, <vpanghal@maginatics.com>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This unit test PUT http data over proxy. Same  http header will be generated
+ * for server and proxy
+ */
+
+#include "test.h"
+
+#include "memdebug.h"
+
+static char data [] = "Hello Cloud!\n";
+
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  size_t  amount = nmemb * size; /* Total bytes curl wants */
+  if (amount < strlen(data)) {
+    return strlen(data);
+  }
+  (void)stream;
+  memcpy(ptr, data, strlen(data));
+  return strlen(data);
+}
+
+
+int test(char *URL)
+{
+  CURL *curl = NULL;
+  CURLcode res = CURLE_FAILED_INIT;
+  /* http header list*/
+  struct curl_slist *hhl = NULL;
+
+  if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+    fprintf(stderr, "curl_global_init() failed\n");
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  if((curl = curl_easy_init()) == NULL) {
+    fprintf(stderr, "curl_easy_init() failed\n");
+    curl_global_cleanup();
+    return TEST_ERR_MAJOR_BAD;
+  }
+
+  hhl = curl_slist_append(hhl, "User-Agent: Http Agent");
+  hhl = curl_slist_append(hhl, "Expect: 100-continue");
+
+  if (!hhl) {
+    goto test_cleanup;
+  }
+
+  test_setopt(curl, CURLOPT_URL, URL);
+  test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
+  test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
+  test_setopt(curl, CURLOPT_POST, 0L);
+  test_setopt(curl, CURLOPT_UPLOAD, 1L);
+  test_setopt(curl, CURLOPT_VERBOSE, 1L);
+  test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+  test_setopt(curl, CURLOPT_HEADER, 1L);
+  test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+  test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+  test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
+  test_setopt(curl, CURLOPT_INFILESIZE, strlen(data));
+
+  res = curl_easy_perform(curl);
+
+test_cleanup:
+
+  curl_easy_cleanup(curl);
+
+  curl_slist_free_all(hhl);
+
+  curl_global_cleanup();
+
+  return (int)res;
+}
