Index: http.c
===================================================================
--- http.c	(revision 1211)
+++ http.c	(working copy)
@@ -347,6 +347,75 @@
   return picked;
 }
 
+static bool complete_request_in_current_connection(struct connectdata *conn, curl_off_t remaining_bytes)
+{
+  struct SessionHandle *data = conn->data;
+  struct HTTP *http = data->req.protop;
+  bool have_ntlm_or_negotiate = FALSE;
+  bool auth_started = FALSE;
+  bool proxy_connect_auth = (0 == http->writebytecount) && (!conn->bits.protoconnstart);
+
+  /* don't reset connection when we're in NTLM or Negotiate authentication;
+   * those authenticate the connection - creating a new connection breaks the
+   * authentication.
+   */
+
+  /* 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);
+  }
+
+  /* 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);
+  }
+
+  if (have_ntlm_or_negotiate)
+  {
+    if (remaining_bytes < 2000 || proxy_connect_auth || auth_started)
+    {
+      /* NTLM/Negotiation has started *OR* there is just a little (<2K)
+       * data left to send, keep on sending.
+       * when we're authenticating a CONNECT there shouldn't be any data to send
+       */
+
+      /* 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 send, close instead of sending %"
+          CURL_FORMAT_CURL_OFF_T " bytes\n",
+          remaining_bytes);
+  }
+
+  return FALSE;
+}
+
 /*
  * Curl_http_perhapsrewind()
  *
@@ -420,34 +489,13 @@
   conn->bits.rewindaftersend = FALSE; /* default */
 
   if((expectsend == -1) || (expectsend > bytessent)) {
-    /* 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. */
+    if(conn->bits.close)
+      /* this is already marked to get closed */
+      return CURLE_OK;
 
-        /* rewind data when completely done sending! */
-        if(!conn->bits.authneg) {
-          conn->bits.rewindaftersend = TRUE;
-          infof(data, "Rewind stream after send\n");
-        }
-
+    if (complete_request_in_current_connection(conn, (curl_off_t)(expectsend - bytessent)))
         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));
-    }
-
     /* This is not NTLM or many bytes left to send: close
      */
     connclose(conn, "Mid-auth HTTP and much data left to send");
@@ -2274,6 +2322,35 @@
   Curl_safefree (conn->allocptr.userpwd);
   conn->allocptr.userpwd = NULL;
 
+  /* CURL bugs:
+   * 1. large parts of the state are not kept in the connection; they live in the
+   *    easy handle instead. If the handle is not reused (or the connection gets moved
+   *    into another handley), the state is lost.
+   *    With proxy authentication this will almost always "destroy" Digest auth, requiring
+   *    another round trip to get the request through.
+   * 2. Negotiate/NTLM authentication is per connection and must not be resend after
+   *    successful authentication.
+   *
+   * So for the proxy authentication header:
+   * - Basic can be reused, so don't free the header and it will keep working even if
+   *   the state from the easy handle gets lost.
+   * - Digest reuse probably doesn't work when the state from the easy handle gets lost -
+   *   on the other hand there is no harm keeping it.
+   *   (the next request needs the state to authenticate with an increased counter)
+   * - free Negotiate and NTLM - not needed anymore, the connection itself
+   *   is authenticated; sending it again actually breaks connections (i.e. sometimes the
+   *   proxy closes them).
+   */
+  switch (data->state.authproxy.picked)
+  {
+  case CURLAUTH_NEGOTIATE:
+  case CURLAUTH_NTLM:
+  case CURLAUTH_NTLM_WB:
+    Curl_safefree(conn->allocptr.proxyuserpwd);
+    conn->allocptr.proxyuserpwd = NULL;
+    break;
+  }
+
   if(result)
     return result;
 
