Revert "Imported Upstream version 7.44.0"
[platform/upstream/curl.git] / lib / http.c
index 9817d72..ee0a9a4 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -63,6 +63,7 @@
 #include "share.h"
 #include "hostip.h"
 #include "http.h"
+#include "curl_memory.h"
 #include "select.h"
 #include "parsedate.h" /* for the week day and month names */
 #include "strtoofft.h"
 #include "http_proxy.h"
 #include "warnless.h"
 #include "non-ascii.h"
-#include "conncache.h"
+#include "bundles.h"
 #include "pipeline.h"
 #include "http2.h"
 #include "connect.h"
-#include "curl_printf.h"
 
-/* The last #include files should be: */
-#include "curl_memory.h"
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
 #include "memdebug.h"
 
 /*
@@ -153,18 +155,12 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
 {
   /* allocate the HTTP-specific struct for the SessionHandle, only to survive
      during this request */
-  struct HTTP *http;
   DEBUGASSERT(conn->data->req.protop == NULL);
 
-  http = calloc(1, sizeof(struct HTTP));
-  if(!http)
+  conn->data->req.protop = calloc(1, sizeof(struct HTTP));
+  if(!conn->data->req.protop)
     return CURLE_OUT_OF_MEMORY;
 
-  conn->data->req.protop = http;
-
-  Curl_http2_setup_conn(conn);
-  Curl_http2_setup_req(conn->data);
-
   return CURLE_OK;
 }
 
@@ -307,7 +303,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
   if(!authorization)
     return CURLE_REMOTE_ACCESS_DENIED;
 
-  free(*userp);
+  Curl_safefree(*userp);
   *userp = aprintf("%sAuthorization: Basic %s\r\n",
                    proxy?"Proxy-":"",
                    authorization);
@@ -351,6 +347,82 @@ static bool pickoneauth(struct auth *pick)
   return picked;
 }
 
+/* whether to complete request (for authentication) in current connection */
+static bool complete_request(struct connectdata *conn,
+                             curl_off_t remaining_bytes)
+{
+#if defined(USE_NTLM) || defined(USE_SPNEGO)
+  struct SessionHandle *data = conn->data;
+  bool have_ntlm_or_negotiate = FALSE;
+  bool auth_started = FALSE;
+
+  /* don't reset connection when we're in NTLM or Negotiate authentication;
+   * those authenticate the connection - creating a new connection breaks the
+   * authentication.
+   */
+
+#if defined(USE_NTLM)
+  /* proxy NTLM authentication */
+  if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
+      (data->state.authproxy.picked == CURLAUTH_NTLM_WB)) {
+    have_ntlm_or_negotiate = TRUE;
+    auth_started = auth_started
+                 || (conn->proxyntlm.state != NTLMSTATE_NONE);
+  }
+
+  /* normal NTLM authentication */
+  if((data->state.authhost.picked == CURLAUTH_NTLM) ||
+      (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
+    have_ntlm_or_negotiate = TRUE;
+    auth_started = auth_started
+                 || (conn->ntlm.state != NTLMSTATE_NONE);
+  }
+#endif
+
+#if defined(USE_SPNEGO)
+  /* proxy Negotiate authentication */
+  if(data->state.authproxy.picked == CURLAUTH_NEGOTIATE) {
+    have_ntlm_or_negotiate = TRUE;
+    auth_started = auth_started
+                 || (data->state.proxyneg.state != GSS_AUTHNONE);
+  }
+
+  /* normal Negotiate authentication */
+  if(data->state.authhost.picked == CURLAUTH_NEGOTIATE) {
+    have_ntlm_or_negotiate = TRUE;
+    auth_started = auth_started
+                 || (data->state.negotiate.state != GSS_AUTHNONE);
+  }
+#endif
+
+  if(have_ntlm_or_negotiate) {
+    if(remaining_bytes < 2000 || auth_started) {
+      /* NTLM/Negotiation has started *OR* there is just a little (<2K)
+       * data left to send, keep on sending.
+       */
+
+      /* rewind data when completely done sending! */
+      if(!conn->bits.authneg) {
+        conn->bits.rewindaftersend = TRUE;
+        infof(data, "Rewind stream after send\n");
+      }
+
+      return TRUE;
+    }
+
+    infof(data, "NTLM/Negotiate send, close instead of sending %"
+          CURL_FORMAT_CURL_OFF_T " bytes\n",
+          remaining_bytes);
+  }
+#else
+  /* unused parameters: */
+  (void)conn;
+  (void)remaining_bytes;
+#endif
+
+  return FALSE;
+}
+
 /*
  * Curl_http_perhapsrewind()
  *
@@ -409,8 +481,8 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
     /* figure out how much data we are expected to send */
     switch(data->set.httpreq) {
     case HTTPREQ_POST:
-      if(data->state.infilesize != -1)
-        expectsend = data->state.infilesize;
+      if(data->set.postfieldsize != -1)
+        expectsend = data->set.postfieldsize;
       else if(data->set.postfields)
         expectsend = (curl_off_t)strlen(data->set.postfields);
       break;
@@ -429,36 +501,12 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
   conn->bits.rewindaftersend = FALSE; /* default */
 
   if((expectsend == -1) || (expectsend > bytessent)) {
-#if defined(USE_NTLM)
-    /* There is still data left to send */
-    if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
-       (data->state.authhost.picked == CURLAUTH_NTLM) ||
-       (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
-       (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
-      if(((expectsend - bytessent) < 2000) ||
-         (conn->ntlm.state != NTLMSTATE_NONE) ||
-         (conn->proxyntlm.state != NTLMSTATE_NONE)) {
-        /* The NTLM-negotiation has started *OR* there is just a little (<2K)
-           data left to send, keep on sending. */
-
-        /* rewind data when completely done sending! */
-        if(!conn->bits.authneg) {
-          conn->bits.rewindaftersend = TRUE;
-          infof(data, "Rewind stream after send\n");
-        }
+    if(conn->bits.close)
+      /* this is already marked to get closed */
+      return CURLE_OK;
 
-        return CURLE_OK;
-      }
-
-      if(conn->bits.close)
-        /* this is already marked to get closed */
-        return CURLE_OK;
-
-      infof(data, "NTLM send, close instead of sending %"
-            CURL_FORMAT_CURL_OFF_T " bytes\n",
-            (curl_off_t)(expectsend - bytessent));
-    }
-#endif
+    if(complete_request(conn, (curl_off_t)(expectsend - bytessent)))
+      return CURLE_OK;
 
     /* This is not NTLM or many bytes left to send: close */
     connclose(conn, "Mid-auth HTTP and much data left to send");
@@ -469,7 +517,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
   }
 
   if(bytessent)
-    /* we rewind now at once since if we already sent something */
+    /* we rewind now at once since we already sent something */
     return Curl_readrewind(conn);
 
   return CURLE_OK;
@@ -685,7 +733,7 @@ Curl_http_output_auth(struct connectdata *conn,
 
   if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
      conn->bits.user_passwd)
-    /* continue please */;
+    /* continue please */ ;
   else {
     authhost->done = TRUE;
     authproxy->done = TRUE;
@@ -786,13 +834,14 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
   while(*auth) {
 #ifdef USE_SPNEGO
     if(checkprefix("Negotiate", auth)) {
+      int neg;
       *availp |= CURLAUTH_NEGOTIATE;
       authp->avail |= CURLAUTH_NEGOTIATE;
 
       if(authp->picked == CURLAUTH_NEGOTIATE) {
         if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) {
-          CURLcode result = Curl_input_negotiate(conn, proxy, auth);
-          if(!result) {
+          neg = Curl_input_negotiate(conn, proxy, auth);
+          if(neg == 0) {
             DEBUGASSERT(!data->req.newurl);
             data->req.newurl = strdup(data->change.url);
             if(!data->req.newurl)
@@ -1001,8 +1050,8 @@ static size_t readmoredata(char *buffer,
       /* move backup data into focus and continue on that */
       http->postdata = http->backup.postdata;
       http->postsize = http->backup.postsize;
-      conn->data->set.fread_func = http->backup.fread_func;
-      conn->data->set.in = http->backup.fread_in;
+      conn->fread_func = http->backup.fread_func;
+      conn->fread_in = http->backup.fread_in;
 
       http->sending++; /* move one step up */
 
@@ -1033,16 +1082,6 @@ Curl_send_buffer *Curl_add_buffer_init(void)
 }
 
 /*
- * Curl_add_buffer_free() frees all associated resources.
- */
-void Curl_add_buffer_free(Curl_send_buffer *buff)
-{
-  if(buff) /* deal with NULL input */
-    free(buff->buffer);
-  free(buff);
-}
-
-/*
  * Curl_add_buffer_send() sends a header buffer and frees all associated
  * memory.  Body data may be appended to the header data if desired.
  *
@@ -1088,7 +1127,9 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
   /* Curl_convert_to_network calls failf if unsuccessful */
   if(result) {
     /* conversion failed, free memory and return to the caller */
-    Curl_add_buffer_free(in);
+    if(in->buffer)
+      free(in->buffer);
+    free(in);
     return result;
   }
 
@@ -1157,14 +1198,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
         ptr = in->buffer + amount;
 
         /* backup the currently set pointers */
-        http->backup.fread_func = conn->data->set.fread_func;
-        http->backup.fread_in = conn->data->set.in;
+        http->backup.fread_func = conn->fread_func;
+        http->backup.fread_in = conn->fread_in;
         http->backup.postdata = http->postdata;
         http->backup.postsize = http->postsize;
 
         /* set the new pointers for the request-sending */
-        conn->data->set.fread_func = (curl_read_callback)readmoredata;
-        conn->data->set.in = (void *)conn;
+        conn->fread_func = (curl_read_callback)readmoredata;
+        conn->fread_in = (void *)conn;
         http->postdata = ptr;
         http->postsize = (curl_off_t)size;
 
@@ -1187,10 +1228,12 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
         */
         return CURLE_SEND_ERROR;
       else
-        Curl_pipeline_leave_write(conn);
+        conn->writechannel_inuse = FALSE;
     }
   }
-  Curl_add_buffer_free(in);
+  if(in->buffer)
+    free(in->buffer);
+  free(in);
 
   return result;
 }
@@ -1213,7 +1256,8 @@ CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
     return result;
   }
   /* If we failed, we cleanup the whole buffer and return error */
-  free(in->buffer);
+  if(in->buffer)
+    free(in->buffer);
   free(in);
   return CURLE_OUT_OF_MEMORY;
 }
@@ -1393,7 +1437,7 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
 }
 #endif
 
-#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
+#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
     defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS)
 /* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only.
    It should be made to query the generic SSL layer instead. */
@@ -1432,7 +1476,7 @@ static int https_getsock(struct connectdata *conn,
   return GETSOCK_BLANK;
 }
 #endif /* USE_SSL */
-#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */
+#endif /* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL */
 
 /*
  * Curl_http_done() gets called from Curl_done() after a single HTTP request
@@ -1443,26 +1487,19 @@ CURLcode Curl_http_done(struct connectdata *conn,
                         CURLcode status, bool premature)
 {
   struct SessionHandle *data = conn->data;
-  struct HTTP *http = data->req.protop;
-#ifdef USE_NGHTTP2
-  struct http_conn *httpc = &conn->proto.httpc;
-#endif
+  struct HTTP *http =data->req.protop;
 
   Curl_unencode_cleanup(conn);
 
 #ifdef USE_SPNEGO
   if(data->state.proxyneg.state == GSS_AUTHSENT ||
-     data->state.negotiate.state == GSS_AUTHSENT) {
-    /* add forbid re-use if http-code != 401/407 as a WA only needed for
-     * 401/407 that signal auth failure (empty) otherwise state will be RECV
-     * with current code */
-    if((data->req.httpcode != 401) && (data->req.httpcode != 407))
-      connclose(conn, "Negotiate transfer completed");
+      data->state.negotiate.state == GSS_AUTHSENT)
     Curl_cleanup_negotiate(data);
-  }
 #endif
 
   /* set the proper values (possibly modified on POST) */
+  conn->fread_func = data->set.fread_func; /* restore */
+  conn->fread_in = data->set.in; /* restore */
   conn->seek_func = data->set.seek_func; /* restore */
   conn->seek_client = data->set.seek_client; /* restore */
 
@@ -1470,26 +1507,12 @@ CURLcode Curl_http_done(struct connectdata *conn,
     return CURLE_OK;
 
   if(http->send_buffer) {
-    Curl_add_buffer_free(http->send_buffer);
-    http->send_buffer = NULL; /* clear the pointer */
-  }
+    Curl_send_buffer *buff = http->send_buffer;
 
-#ifdef USE_NGHTTP2
-  if(http->header_recvbuf) {
-    DEBUGF(infof(data, "free header_recvbuf!!\n"));
-    Curl_add_buffer_free(http->header_recvbuf);
-    http->header_recvbuf = NULL; /* clear the pointer */
-    for(; http->push_headers_used > 0; --http->push_headers_used) {
-      free(http->push_headers[http->push_headers_used - 1]);
-    }
-    free(http->push_headers);
-    http->push_headers = NULL;
-  }
-  if(http->stream_id) {
-    nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0);
-    http->stream_id = 0;
+    free(buff->buffer);
+    free(buff);
+    http->send_buffer = NULL; /* clear the pointer */
   }
-#endif
 
   if(HTTPREQ_POST_FORM == data->set.httpreq) {
     data->req.bytecount = http->readbytecount + http->writebytecount;
@@ -1553,11 +1576,10 @@ static CURLcode expect100(struct SessionHandle *data,
   const char *ptr;
   data->state.expect100header = FALSE; /* default to false unless it is set
                                           to TRUE below */
-  if(use_http_1_1plus(data, conn) &&
-     (conn->httpversion != 20)) {
-    /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
-       Expect: 100-continue to the headers which actually speeds up post
-       operations (as there is one packet coming back from the web server) */
+  if(use_http_1_1plus(data, conn)) {
+    /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
+       100-continue to the headers which actually speeds up post operations
+       (as there is one packet coming back from the web server) */
     ptr = Curl_checkheaders(conn, "Expect:");
     if(ptr) {
       data->state.expect100header =
@@ -1776,8 +1798,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   if(conn->httpversion < 20) { /* unless the connection is re-used and already
                                   http2 */
     switch(conn->negnpn) {
-    case CURL_HTTP_VERSION_2_0:
-      conn->httpversion = 20; /* we know we're on HTTP/2 now */
+    case NPN_HTTP2:
       result = Curl_http2_init(conn);
       if(result)
         return result;
@@ -1790,7 +1811,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       if(result)
         return result;
       break;
-    case CURL_HTTP_VERSION_1_1:
+    case NPN_HTTP1_1:
       /* continue with HTTP/1.1 when explicitly requested */
       break;
     default:
@@ -1808,8 +1829,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   http = data->req.protop;
 
   if(!data->state.this_is_a_follow) {
-    /* Free to avoid leaking memory on multiple requests*/
-    free(data->state.first_host);
+    /* this is not a followed location, get the original host name */
+    if(data->state.first_host)
+      /* Free to avoid leaking memory on multiple requests*/
+      free(data->state.first_host);
 
     data->state.first_host = strdup(conn->host.name);
     if(!data->state.first_host)
@@ -1853,7 +1876,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
      it might have been used in the proxy connect, but if we have got a header
      with the user-agent string specified, we erase the previously made string
      here. */
-  if(Curl_checkheaders(conn, "User-Agent:")) {
+  if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
     free(conn->allocptr.uagent);
     conn->allocptr.uagent=NULL;
   }
@@ -1996,14 +2019,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     }
 #endif
 
-    if(strcmp("Host:", ptr)) {
-      conn->allocptr.host = aprintf("%s\r\n", ptr);
-      if(!conn->allocptr.host)
-        return CURLE_OUT_OF_MEMORY;
-    }
-    else
-      /* when clearing the header */
-      conn->allocptr.host = NULL;
+    conn->allocptr.host = NULL;
   }
   else {
     /* When building Host: headers, we must put the host name within
@@ -2198,7 +2214,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
        !Curl_checkheaders(conn, "Range:")) {
       /* if a line like this was already allocated, free the previous one */
-      free(conn->allocptr.rangeline);
+      if(conn->allocptr.rangeline)
+        free(conn->allocptr.rangeline);
       conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
                                          data->state.range);
     }
@@ -2206,7 +2223,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
             !Curl_checkheaders(conn, "Content-Range:")) {
 
       /* if a line like this was already allocated, free the previous one */
-      free(conn->allocptr.rangeline);
+      if(conn->allocptr.rangeline)
+        free(conn->allocptr.rangeline);
 
       if(data->set.set_resume_from < 0) {
         /* Upload resume was asked for, but we don't know the size of the
@@ -2270,11 +2288,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     Curl_add_bufferf(req_buffer,
                      "%s" /* ftp typecode (;type=x) */
                      " HTTP/%s\r\n" /* HTTP version */
-                     "%s" /* host */
                      "%s" /* proxyuserpwd */
                      "%s" /* userpwd */
                      "%s" /* range */
                      "%s" /* user agent */
+                     "%s" /* host */
                      "%s" /* accept */
                      "%s" /* TE: */
                      "%s" /* accept-encoding */
@@ -2284,7 +2302,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
                      ftp_typecode,
                      httpstring,
-                     (conn->allocptr.host?conn->allocptr.host:""),
                      conn->allocptr.proxyuserpwd?
                      conn->allocptr.proxyuserpwd:"",
                      conn->allocptr.userpwd?conn->allocptr.userpwd:"",
@@ -2294,6 +2311,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                       *data->set.str[STRING_USERAGENT] &&
                       conn->allocptr.uagent)?
                      conn->allocptr.uagent:"",
+                     (conn->allocptr.host?conn->allocptr.host:""),
                      http->p_accept?http->p_accept:"",
                      conn->allocptr.te?conn->allocptr.te:"",
                      (data->set.str[STRING_ENCODING] &&
@@ -2309,12 +2327,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                      te
       );
 
-  /* clear userpwd to avoid re-using credentials from re-used connections */
-  Curl_safefree(conn->allocptr.userpwd);
+  /*
+   * Free userpwd for Negotiate/NTLM. Cannot reuse as it is associated with
+   * the connection and shouldn't be repeated over it either.
+   */
+  switch (data->state.authhost.picked) {
+  case CURLAUTH_NEGOTIATE:
+  case CURLAUTH_NTLM:
+  case CURLAUTH_NTLM_WB:
+    Curl_safefree(conn->allocptr.userpwd);
+    break;
+  }
 
   /*
-   * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated
-   * with the connection and shouldn't be repeated over it either.
+   * Same for proxyuserpwd
    */
   switch (data->state.authproxy.picked) {
   case CURLAUTH_NEGOTIATE:
@@ -2434,14 +2460,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
     /* Get the currently set callback function pointer and store that in the
        form struct since we might want the actual user-provided callback later
-       on. The data->set.fread_func pointer itself will be changed for the
+       on. The conn->fread_func pointer itself will be changed for the
        multipart case to the function that returns a multipart formatted
        stream. */
-    http->form.fread_func = data->set.fread_func;
+    http->form.fread_func = conn->fread_func;
 
     /* Set the read function to read from the generated form data */
-    data->set.fread_func = (curl_read_callback)Curl_FormReader;
-    data->set.in = &http->form;
+    conn->fread_func = (curl_read_callback)Curl_FormReader;
+    conn->fread_in = &http->form;
 
     http->sending = HTTPSEND_BODY;
 
@@ -2561,8 +2587,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       postsize = 0;
     else {
       /* figure out the size of the postfields */
-      postsize = (data->state.infilesize != -1)?
-        data->state.infilesize:
+      postsize = (data->set.postfieldsize != -1)?
+        data->set.postfieldsize:
         (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1);
     }
 
@@ -2659,8 +2685,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
         http->sending = HTTPSEND_BODY;
 
-        data->set.fread_func = (curl_read_callback)readmoredata;
-        data->set.in = (void *)conn;
+        conn->fread_func = (curl_read_callback)readmoredata;
+        conn->fread_in = (void *)conn;
 
         /* set the upload size to the progress meter */
         Curl_pgrsSetUploadSize(data, http->postsize);
@@ -2685,7 +2711,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
           return result;
       }
 
-      else if(data->state.infilesize) {
+      else if(data->set.postfieldsize) {
         /* set the upload size to the progress meter */
         Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
 
@@ -3076,19 +3102,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
         }
       }
 
-      /* At this point we have some idea about the fate of the connection.
-         If we are closing the connection it may result auth failure. */
-#if defined(USE_NTLM)
-      if(conn->bits.close &&
-         (((data->req.httpcode == 401) &&
-           (conn->ntlm.state == NTLMSTATE_TYPE2)) ||
-          ((data->req.httpcode == 407) &&
-           (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) {
-        infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
-        data->state.authproblem = TRUE;
-      }
-#endif
-
       /*
        * When all the headers have been parsed, see if we should give
        * up and return an error.
@@ -3366,23 +3379,28 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
         }
         else if(conn->httpversion == 20 ||
                 (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
-          DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
-
-          /* HTTP/2 cannot blacklist multiplexing since it is a core
-             functionality of the protocol */
-          conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+          /* Don't enable pipelining for HTTP/2 or upgraded connection. For
+             HTTP/2, we do not support multiplexing. In general, requests
+             cannot be pipelined in upgraded connection, since it is now
+             different protocol. */
+          DEBUGF(infof(data,
+                       "HTTP 2 or upgraded connection do not support "
+                       "pipelining for now\n"));
         }
         else if(conn->httpversion >= 11 &&
                 !conn->bits.close) {
+          struct connectbundle *cb_ptr;
+
           /* If HTTP version is >= 1.1 and connection is persistent
              server supports pipelining. */
           DEBUGF(infof(data,
                        "HTTP 1.1 or later with persistent connection, "
                        "pipelining supported\n"));
           /* Activate pipelining if needed */
-          if(conn->bundle) {
+          cb_ptr = conn->bundle;
+          if(cb_ptr) {
             if(!Curl_pipeline_site_blacklisted(data, conn))
-              conn->bundle->multiuse = BUNDLE_PIPELINING;
+              cb_ptr->server_supports_pipelining = TRUE;
           }
         }
 
@@ -3461,17 +3479,14 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
       }
     }
     else if(checkprefix("Server:", k->p)) {
-      if(conn->httpversion < 20) {
-        /* only do this for non-h2 servers */
-        char *server_name = Curl_copy_header_value(k->p);
-
-        /* Turn off pipelining if the server version is blacklisted  */
-        if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) {
-          if(Curl_pipeline_server_blacklisted(data, server_name))
-            conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
-        }
-        free(server_name);
+      char *server_name = Curl_copy_header_value(k->p);
+
+      /* Turn off pipelining if the server version is blacklisted */
+      if(conn->bundle && conn->bundle->server_supports_pipelining) {
+        if(Curl_pipeline_server_blacklisted(data, server_name))
+          conn->bundle->server_supports_pipelining = FALSE;
       }
+      Curl_safefree(server_name);
     }
     else if((conn->httpversion == 10) &&
             conn->bits.httpproxy &&
@@ -3568,6 +3583,14 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
           k->auto_decoding = GZIP;
           start += 6;
         }
+        else if(checkprefix("compress", start)) {
+          k->auto_decoding = COMPRESS;
+          start += 8;
+        }
+        else if(checkprefix("x-compress", start)) {
+          k->auto_decoding = COMPRESS;
+          start += 10;
+        }
         else
           /* unknown! */
           break;
@@ -3600,6 +3623,9 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
       else if(checkprefix("gzip", start)
               || checkprefix("x-gzip", start))
         k->auto_decoding = GZIP;
+      else if(checkprefix("compress", start)
+              || checkprefix("x-compress", start))
+        k->auto_decoding = COMPRESS;
     }
     else if(checkprefix("Content-Range:", k->p)) {
       /* Content-Range: bytes [num]-
@@ -3665,7 +3691,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
 
       result = Curl_http_input_auth(conn, proxy, auth);
 
-      free(auth);
+      Curl_safefree(auth);
 
       if(result)
         return result;