Commit 91ff9380 authored by Dan Fandrich's avatar Dan Fandrich
Browse files

Improved the logic the decides whether to use HTTP 1.1 features or not in a

request.

Detect cases where an upload must be sent chunked and the server supports
only HTTP 1.0 and return CURLE_UPLOAD_FAILED.
parent 3acd1146
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -6,6 +6,19 @@

                                  Changelog

Daniel Fandrich (5 Sep 2008)
- Improved the logic the decides whether to use HTTP 1.1 features or not in a
  request.  Setting a specific version with CURLOPT_HTTP_VERSION overrides
  all other checks, but otherwise, a 1.0 request will be made if the server
  is known to support only 1.0 because it previously responded so and the
  connection was kept alive, or a response to a previous request on this handle
  came back as 1.0. The latter could take place in cases like redirection or
  authentication where several requests have to be made before the operation
  is complete.

- Detect cases where an upload must be sent chunked and the server supports
  only HTTP 1.0 and return CURLE_UPLOAD_FAILED.

Daniel Stenberg (5 Sep 2008)
- Martin Drasar provided the CURLOPT_POSTREDIR patch. It renames
  CURLOPT_POST301 (but adds a define for backwards compatibility for you who
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ This release includes the following changes:
 o pkg-config can now show supported_protocols and supported_features
 o Added CURLOPT_CERTINFO and CURLINFO_CERTINFO
 o Added CURLOPT_POSTREDIR
 o Better detect HTTP 1.0 servers and don't do HTTP 1.1 requests on them

This release includes the following bugfixes:

+0 −6
Original line number Diff line number Diff line
@@ -4,12 +4,6 @@ To be addressed before 7.19.1 (planned release: October/November 2008)
162 - Craig Perras' note "http upload: how to stop on error"
      http://curl.haxx.se/mail/archive-2008-08/0138.html

163 - Detecting illegal attempts at chunked transfers on HTTP 1.0
      (tests 1069, 1072, 1073)
      http://curl.haxx.se/mail/archive-2008-08/0435.html

164 - Automatic downgrading to HTTP 1.0 (tests 1071 through 1074)

165 - "Problem with CURLOPT_RESUME_FROM and CURLOPT_APPEND" by Daniele Pinau,
      recipe: http://curl.haxx.se/mail/lib-2008-08/0439.html

+31 −11
Original line number Diff line number Diff line
@@ -1950,15 +1950,30 @@ CURLcode Curl_http_done(struct connectdata *conn,
  return CURLE_OK;
}


/* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it
are if the user specifically requested HTTP 1.0, if the server we are
connected to only supports 1.0, or if any server previously contacted to
handle this request only supports 1.0. */
static bool use_http_1_1(const struct SessionHandle *data,
                         const struct connectdata *conn)
{
  return (data->set.httpversion == CURL_HTTP_VERSION_1_1) ||
         ((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
          ((conn->httpversion == 11) ||
           ((conn->httpversion != 10) &&
            (data->state.httpversion != 10))));
}

/* check and possibly add an Expect: header */
static CURLcode expect100(struct SessionHandle *data,
                          struct connectdata *conn,
                          send_buffer *req_buffer)
{
  CURLcode result = CURLE_OK;
  data->state.expect100header = FALSE; /* default to false unless it is set
                                          to TRUE below */
  if((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
     !checkheaders(data, "Expect:")) {
  if(use_http_1_1(data, conn) && !checkheaders(data, "Expect:")) {
    /* 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
@@ -2139,10 +2154,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
  else {
    if((conn->protocol&PROT_HTTP) &&
        data->set.upload &&
        (data->set.infilesize == -1) &&
        (data->set.httpversion != CURL_HTTP_VERSION_1_0)) {
        (data->set.infilesize == -1)) {
      if (use_http_1_1(data, conn)) {
        /* HTTP, upload, unknown file size and not HTTP 1.0 */
        data->req.upload_chunky = TRUE;
      } else {
        failf(data, "Chunky upload is not supported by HTTP 1.0");
        return CURLE_UPLOAD_FAILED;
      }
    }
    else {
      /* else, no chunky upload */
@@ -2410,8 +2429,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
    }
  }

  /* Use 1.1 unless the use specificly asked for 1.0 */
  httpstring= data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
  /* Use 1.1 unless the user specifically asked for 1.0 or the server only
     supports 1.0 */
  httpstring= use_http_1_1(data, conn)?"1.1":"1.0";

  /* initialize a dynamic send-buffer */
  req_buffer = add_buffer_init();
@@ -2635,7 +2655,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
        return result;
    }

    result = expect100(data, req_buffer);
    result = expect100(data, conn, req_buffer);
    if(result)
      return result;

@@ -2707,7 +2727,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
        return result;
    }

    result = expect100(data, req_buffer);
    result = expect100(data, conn, req_buffer);
    if(result)
      return result;

@@ -2772,7 +2792,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
           sure that the expect100header is always set to the preferred value
           here. */
        if(postsize > TINY_INITIAL_POST_SIZE) {
          result = expect100(data, req_buffer);
          result = expect100(data, conn, req_buffer);
          if(result)
            return result;
        }
+16 −11
Original line number Diff line number Diff line
@@ -832,7 +832,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
	k->header = FALSE; /* no more header to parse! */

	if((k->size == -1) && !k->chunk && !conn->bits.close &&
	   (k->httpversion >= 11) ) {
	   (conn->httpversion >= 11) ) {
	  /* On HTTP 1.1, when connection is not to get closed, but no
	     Content-Length nor Content-Encoding chunked have been
	     received, according to RFC2616 section 4.4 point 5, we
@@ -1006,17 +1006,17 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
      nc = sscanf(HEADER1,
		  " HTTP/%d.%d %3d",
		  &httpversion_major,
		  &k->httpversion,
		  &conn->httpversion,
		  &k->httpcode);
      if(nc==3) {
	k->httpversion += 10 * httpversion_major;
	conn->httpversion += 10 * httpversion_major;
      }
      else {
	/* this is the real world, not a Nirvana
	   NCSA 1.5.x returns this crap when asked for HTTP/1.1
	*/
	nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
	k->httpversion = 10;
	conn->httpversion = 10;

	/* If user has set option HTTP200ALIASES,
	   compare header line against list of aliases
@@ -1025,14 +1025,18 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
	  if(checkhttpprefix(data, k->p)) {
	    nc = 1;
	    k->httpcode = 200;
	    k->httpversion = 10;
	    conn->httpversion = 10;
	  }
	}
      }

      if(nc) {
	data->info.httpcode = k->httpcode;
	data->info.httpversion = k->httpversion;
	data->info.httpversion = conn->httpversion;
        if (!data->state.httpversion ||
            data->state.httpversion > conn->httpversion)
          /* store the lowest server version we encounter */
          data->state.httpversion = conn->httpversion;

	/*
	 * This code executes as part of processing the header.  As a
@@ -1060,14 +1064,14 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
	  }
	}

	if(k->httpversion == 10) {
	if(conn->httpversion == 10) {
	  /* Default action for HTTP/1.0 must be to close, unless
	     we get one of those fancy headers that tell us the
	     server keeps it open for us! */
	  infof(data, "HTTP 1.0, assume close after body\n");
	  conn->bits.close = TRUE;
	}
	else if(k->httpversion >= 11 &&
	else if(conn->httpversion >= 11 &&
		!conn->bits.close) {
	  /* If HTTP version is >= 1.1 and connection is persistent
	     server supports pipelining. */
@@ -1161,7 +1165,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
	data->info.contenttype = contenttype;
      }
    }
    else if((k->httpversion == 10) &&
    else if((conn->httpversion == 10) &&
	    conn->bits.httpproxy &&
	    Curl_compareheader(k->p,
			       "Proxy-Connection:", "keep-alive")) {
@@ -1174,7 +1178,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
      conn->bits.close = FALSE; /* don't close when done */
      infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
    }
    else if((k->httpversion == 11) &&
    else if((conn->httpversion == 11) &&
	    conn->bits.httpproxy &&
	    Curl_compareheader(k->p,
			       "Proxy-Connection:", "close")) {
@@ -1185,7 +1189,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data,
      conn->bits.close = TRUE; /* close when done */
      infof(data, "HTTP/1.1 proxy connection set close!\n");
    }
    else if((k->httpversion == 10) &&
    else if((conn->httpversion == 10) &&
	    Curl_compareheader(k->p, "Connection:", "keep-alive")) {
      /*
       * A HTTP/1.0 reply with the 'Connection: keep-alive' line
@@ -1886,6 +1890,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
  data->set.followlocation=0; /* reset the location-follow counter */
  data->state.this_is_a_follow = FALSE; /* reset this */
  data->state.errorbuf = FALSE; /* no error has occurred */
  data->state.httpversion = 0; /* don't assume any particular server version */

  data->state.authproblem = FALSE;
  data->state.authhost.want = data->set.httpauth;
Loading