* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, 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
#include "curl_base64.h"
#include "cookie.h"
#include "strequal.h"
+#include "vauth/vauth.h"
#include "vtls/vtls.h"
#include "http_digest.h"
-#include "curl_ntlm.h"
+#include "http_ntlm.h"
#include "curl_ntlm_wb.h"
#include "http_negotiate.h"
#include "url.h"
#include "pipeline.h"
#include "http2.h"
#include "connect.h"
-#include "curl_printf.h"
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
ZERO_NULL, /* readwrite */
PORT_HTTPS, /* defport */
CURLPROTO_HTTPS, /* protocol */
- PROTOPT_SSL | PROTOPT_CREDSPERREQUEST /* flags */
+ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
};
#endif
-
CURLcode Curl_http_setup_conn(struct connectdata *conn)
{
- /* allocate the HTTP-specific struct for the SessionHandle, only to survive
+ /* allocate the HTTP-specific struct for the Curl_easy, only to survive
during this request */
struct HTTP *http;
DEBUGASSERT(conn->data->req.protop == NULL);
{
struct curl_slist *head;
size_t thislen = strlen(thisheader);
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
for(head = data->set.headers;head; head=head->next) {
if(Curl_raw_nequal(head->data, thisheader, thislen))
return head->data;
}
+
return NULL;
}
* 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
+ * It takes a connectdata struct as input instead of the Curl_easy 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;
+ struct Curl_easy *data = conn->data;
- for(head = (conn->bits.proxy && data->set.sep_headers)?
- data->set.proxyheaders:data->set.headers;
+ 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))
return head->data;
}
+
return NULL;
}
{
size_t size = 0;
char *authorization = NULL;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
char **userp;
const char *user;
const char *pwd;
free(*userp);
*userp = aprintf("%sAuthorization: Basic %s\r\n",
- proxy?"Proxy-":"",
+ proxy ? "Proxy-" : "",
authorization);
free(authorization);
if(!*userp)
*/
static CURLcode http_perhapsrewind(struct connectdata *conn)
{
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
struct HTTP *http = data->req.protop;
curl_off_t bytessent;
curl_off_t expectsend = -1; /* default is unknown */
#endif
/* This is not NTLM or many bytes left to send: close */
- connclose(conn, "Mid-auth HTTP and much data left to send");
+ streamclose(conn, "Mid-auth HTTP and much data left to send");
data->req.size = 0; /* don't download any more than 0 bytes */
/* There still is data left to send, but this connection is marked for
CURLcode Curl_http_auth_act(struct connectdata *conn)
{
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
bool pickhost = FALSE;
bool pickproxy = FALSE;
CURLcode result = CURLE_OK;
return result;
}
}
-
else if((data->req.httpcode < 300) &&
(!data->state.authhost.done) &&
conn->bits.authneg) {
return result;
}
-
/*
* Output the correct authentication header depending on the auth type
* and whether or not it is to a proxy.
const char *auth = NULL;
CURLcode result = CURLE_OK;
#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO)
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
#endif
#ifdef USE_SPNEGO
struct negotiatedata *negdata = proxy ?
negdata->state = GSS_AUTHNONE;
if((authstatus->picked == CURLAUTH_NEGOTIATE) &&
negdata->context && !GSS_ERROR(negdata->status)) {
- auth="Negotiate";
+ auth = "Negotiate";
result = Curl_output_negotiate(conn, proxy);
if(result)
return result;
#endif
#ifdef USE_NTLM
if(authstatus->picked == CURLAUTH_NTLM) {
- auth="NTLM";
+ auth = "NTLM";
result = Curl_output_ntlm(conn, proxy);
if(result)
return result;
#endif
#ifndef CURL_DISABLE_CRYPTO_AUTH
if(authstatus->picked == CURLAUTH_DIGEST) {
- auth="Digest";
+ auth = "Digest";
result = Curl_output_digest(conn,
proxy,
(const unsigned char *)request,
!Curl_checkProxyheaders(conn, "Proxy-authorization:")) ||
(!proxy && conn->bits.user_passwd &&
!Curl_checkheaders(conn, "Authorization:"))) {
- auth="Basic";
+ auth = "Basic";
result = http_output_basic(conn, proxy);
if(result)
return result;
}
+
/* NOTE: this function should set 'done' TRUE, as the other auth
functions work that way */
authstatus->done = TRUE;
if(auth) {
infof(data, "%s auth using %s with user '%s'\n",
- proxy?"Proxy":"Server", auth,
- proxy?(conn->proxyuser?conn->proxyuser:""):
- (conn->user?conn->user:""));
+ proxy ? "Proxy" : "Server", auth,
+ proxy ? (conn->proxyuser ? conn->proxyuser : "") :
+ (conn->user ? conn->user : ""));
authstatus->multi = (!authstatus->done) ? TRUE : FALSE;
}
else
up the proxy tunnel */
{
CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
struct auth *authhost;
struct auth *authproxy;
return result;
}
-
/*
* Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
* headers. They are dealt with both in the transfer.c main loop and in the
/*
* This resource requires authentication
*/
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
#ifdef USE_SPNEGO
struct negotiatedata *negdata = proxy?
* request is sent, and then it is again set _after_ all response 401/407
* headers have been received but then only to a single preferred method
* (bit).
- *
*/
while(*auth) {
#ifdef USE_SPNEGO
if(checkprefix("Negotiate", auth)) {
- *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) {
- DEBUGASSERT(!data->req.newurl);
- data->req.newurl = strdup(data->change.url);
- if(!data->req.newurl)
- return CURLE_OUT_OF_MEMORY;
- data->state.authproblem = FALSE;
- /* we received a GSS auth token and we dealt with it fine */
- negdata->state = GSS_AUTHRECV;
+ if((authp->avail & CURLAUTH_NEGOTIATE) ||
+ Curl_auth_is_spnego_supported()) {
+ *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) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->change.url);
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authproblem = FALSE;
+ /* we received a GSS auth token and we dealt with it fine */
+ negdata->state = GSS_AUTHRECV;
+ }
+ else
+ data->state.authproblem = TRUE;
}
- else
- data->state.authproblem = TRUE;
}
}
}
#ifdef USE_NTLM
/* NTLM support requires the SSL crypto libs */
if(checkprefix("NTLM", auth)) {
- *availp |= CURLAUTH_NTLM;
- authp->avail |= CURLAUTH_NTLM;
- if(authp->picked == CURLAUTH_NTLM ||
- authp->picked == CURLAUTH_NTLM_WB) {
- /* NTLM authentication is picked and activated */
- CURLcode result = Curl_input_ntlm(conn, proxy, auth);
- if(!result) {
- data->state.authproblem = FALSE;
+ if((authp->avail & CURLAUTH_NTLM) ||
+ (authp->avail & CURLAUTH_NTLM_WB) ||
+ Curl_auth_is_ntlm_supported()) {
+ *availp |= CURLAUTH_NTLM;
+ authp->avail |= CURLAUTH_NTLM;
+
+ if(authp->picked == CURLAUTH_NTLM ||
+ authp->picked == CURLAUTH_NTLM_WB) {
+ /* NTLM authentication is picked and activated */
+ CURLcode result = Curl_input_ntlm(conn, proxy, auth);
+ if(!result) {
+ data->state.authproblem = FALSE;
#ifdef NTLM_WB_ENABLED
- if(authp->picked == CURLAUTH_NTLM_WB) {
- *availp &= ~CURLAUTH_NTLM;
- authp->avail &= ~CURLAUTH_NTLM;
- *availp |= CURLAUTH_NTLM_WB;
- authp->avail |= CURLAUTH_NTLM_WB;
-
- /* Get the challenge-message which will be passed to
- * ntlm_auth for generating the type 3 message later */
- while(*auth && ISSPACE(*auth))
- auth++;
- if(checkprefix("NTLM", auth)) {
- auth += strlen("NTLM");
+ if(authp->picked == CURLAUTH_NTLM_WB) {
+ *availp &= ~CURLAUTH_NTLM;
+ authp->avail &= ~CURLAUTH_NTLM;
+ *availp |= CURLAUTH_NTLM_WB;
+ authp->avail |= CURLAUTH_NTLM_WB;
+
+ /* Get the challenge-message which will be passed to
+ * ntlm_auth for generating the type 3 message later */
while(*auth && ISSPACE(*auth))
auth++;
- if(*auth)
- if((conn->challenge_header = strdup(auth)) == NULL)
- return CURLE_OUT_OF_MEMORY;
+ if(checkprefix("NTLM", auth)) {
+ auth += strlen("NTLM");
+ while(*auth && ISSPACE(*auth))
+ auth++;
+ if(*auth)
+ if((conn->challenge_header = strdup(auth)) == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
- }
#endif
- }
- else {
- infof(data, "Authentication problem. Ignoring this.\n");
- data->state.authproblem = TRUE;
+ }
+ else {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
}
}
}
#endif
#ifndef CURL_DISABLE_CRYPTO_AUTH
if(checkprefix("Digest", auth)) {
- if((authp->avail & CURLAUTH_DIGEST) != 0) {
+ if((authp->avail & CURLAUTH_DIGEST) != 0)
infof(data, "Ignoring duplicate digest auth header.\n");
- }
- else {
+ else if(Curl_auth_is_digest_supported()) {
CURLcode result;
+
*availp |= CURLAUTH_DIGEST;
authp->avail |= CURLAUTH_DIGEST;
/* We call this function on input Digest headers even if Digest
* authentication isn't activated yet, as we need to store the
- * incoming data from this header in case we are gonna use
- * Digest. */
+ * incoming data from this header in case we are going to use
+ * Digest */
result = Curl_input_digest(conn, proxy, auth);
if(result) {
infof(data, "Authentication problem. Ignoring this.\n");
while(*auth && ISSPACE(*auth))
auth++;
}
+
return CURLE_OK;
}
*/
static int http_should_fail(struct connectdata *conn)
{
- struct SessionHandle *data;
+ struct Curl_easy *data;
int httpcode;
DEBUGASSERT(conn);
** Any code >= 400 that's not 401 or 407 is always
** a terminal error
*/
- if((httpcode != 401) &&
- (httpcode != 407))
+ if((httpcode != 401) && (httpcode != 407))
return 1;
/*
struct HTTP *http = conn->data->req.protop;
size_t fullsize = size * nitems;
- if(0 == http->postsize)
+ if(!http->postsize)
/* nothing to return */
return 0;
return result;
}
-
if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) {
/* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
when we speak HTTPS, as if only a fraction of it is sent now, this data
buffer is using this size.
*/
- sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
+ sendsize = (size > CURL_MAX_WRITE_SIZE) ? CURL_MAX_WRITE_SIZE : size;
/* OpenSSL is very picky and we must send the SAME buffer pointer to the
library when we attempt to re-send this buffer. Sending the same data
* only send away a part).
*/
/* how much of the header that was sent */
- size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount;
+ size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
size_t bodylen = amount - headlen;
if(conn->data->set.verbose) {
ptr+headlen, bodylen, conn);
}
}
- if(bodylen)
- /* since we sent a piece of the body here, up the byte counter for it
- accordingly */
- http->writebytecount += bodylen;
/* 'amount' can never be a very large value here so typecasting it so a
signed 31 bit value should not cause problems even if ssize_t is
*bytes_written += (long)amount;
if(http) {
+ /* if we sent a piece of the body here, up the byte counter for it
+ accordingly */
+ http->writebytecount += bodylen;
+
if((size_t)amount != size) {
/* The whole request could not be sent in one system call. We must
queue it up and send it later when we get the chance. We must not
buffer size that doubles the required size. If this new size
would wrap size_t, then just use the largest possible one */
- if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) ||
- (~(size*2) < (in->size_used*2)))
+ if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) ||
+ (~(size * 2) < (in->size_used * 2)))
new_size = (size_t)-1;
else
- new_size = (in->size_used+size)*2;
+ new_size = (in->size_used+size) * 2;
if(in->buffer)
/* we have a buffer, enlarge the existing one */
return GETSOCK_READSOCK(0);
}
}
+
return CURLE_OK;
}
#else
#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */
/*
- * Curl_http_done() gets called from Curl_done() after a single HTTP request
- * has been performed.
+ * Curl_http_done() gets called after a single HTTP request has been
+ * performed.
*/
CURLcode Curl_http_done(struct connectdata *conn,
CURLcode status, bool premature)
{
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
struct HTTP *http = data->req.protop;
-#ifdef USE_NGHTTP2
- struct http_conn *httpc = &conn->proto.httpc;
-#endif
+
+ infof(data, "Curl_http_done: called premature == %d\n", premature);
Curl_unencode_cleanup(conn);
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");
+ * with current code.
+ * Do not close CONNECT_ONLY connections. */
+ if((data->req.httpcode != 401) && (data->req.httpcode != 407) &&
+ !data->set.connect_only)
+ streamclose(conn, "Negotiate transfer completed");
Curl_cleanup_negotiate(data);
}
#endif
conn->seek_func = data->set.seek_func; /* restore */
conn->seek_client = data->set.seek_client; /* restore */
- if(http == NULL)
+ if(!http)
return CURLE_OK;
if(http->send_buffer) {
http->send_buffer = NULL; /* clear the pointer */
}
-#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 */
- Curl_add_buffer_free(http->trailer_recvbuf);
- http->trailer_recvbuf = NULL; /* clear the pointer */
- if(http->push_headers) {
- /* if they weren't used and then freed before */
- 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;
- }
-#endif
+ Curl_http2_done(conn, premature);
if(HTTPREQ_POST_FORM == data->set.httpreq) {
data->req.bytecount = http->readbytecount + http->writebytecount;
entire operation is complete */
!conn->bits.retry &&
!data->set.connect_only &&
- ((http->readbytecount +
- data->req.headerbytecount -
- data->req.deductheadercount)) <= 0) {
+ (http->readbytecount +
+ data->req.headerbytecount -
+ data->req.deductheadercount) <= 0) {
/* If this connection isn't simply closed to be retried, AND nothing was
read from the HTTP server (that counts), this can't be right so we
return an error here */
return CURLE_OK;
}
-
/*
* Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons
* to avoid it include:
* - if any server previously contacted to handle this request only supports
* 1.0.
*/
-static bool use_http_1_1plus(const struct SessionHandle *data,
+static bool use_http_1_1plus(const struct Curl_easy *data,
const struct connectdata *conn)
{
if((data->state.httpversion == 10) || (conn->httpversion == 10))
}
/* check and possibly add an Expect: header */
-static CURLcode expect100(struct SessionHandle *data,
+static CURLcode expect100(struct Curl_easy *data,
struct connectdata *conn,
Curl_send_buffer *req_buffer)
{
data->state.expect100header = TRUE;
}
}
+
return result;
}
struct curl_slist *h[2];
struct curl_slist *headers;
int numlists=1; /* by default */
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
int i;
enum proxy_use proxy;
headers = headers->next;
}
}
+
return CURLE_OK;
}
-CURLcode Curl_add_timecondition(struct SessionHandle *data,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
Curl_send_buffer *req_buffer)
{
const struct tm *tm;
}
/*
- * Curl_http() gets called from the generic Curl_do() function when a HTTP
+ * Curl_http() gets called from the generic multi_do() function when a HTTP
* request is to be performed. This creates and sends a properly constructed
* HTTP request.
*/
CURLcode Curl_http(struct connectdata *conn, bool *done)
{
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
struct HTTP *http;
const char *ppath = data->state.path;
switch(conn->negnpn) {
case CURL_HTTP_VERSION_2:
conn->httpversion = 20; /* we know we're on HTTP/2 now */
- result = Curl_http2_init(conn);
- if(result)
- return result;
-
- result = Curl_http2_setup(conn);
- if(result)
- return result;
result = Curl_http2_switched(conn, NULL, 0);
if(result)
/* continue with HTTP/1.1 when explicitly requested */
break;
default:
- /* and as fallback */
+ /* Check if user wants to use HTTP/2 with clear TCP*/
+#ifdef USE_NGHTTP2
+ if(conn->data->set.httpversion ==
+ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+ DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
+ conn->httpversion = 20;
+
+ result = Curl_http2_switched(conn, NULL, 0);
+ if(result)
+ return result;
+ }
+#endif
break;
}
}
data->state.first_host = strdup(conn->host.name);
if(!data->state.first_host)
return CURLE_OUT_OF_MEMORY;
+
+ data->state.first_remote_port = conn->remote_port;
}
http->writebytecount = http->readbytecount = 0;
if(!conn->allocptr.accept_encoding)
return CURLE_OUT_OF_MEMORY;
}
+ else {
+ Curl_safefree(conn->allocptr.accept_encoding);
+ conn->allocptr.accept_encoding = NULL;
+ }
#ifdef HAVE_LIBZ
/* we only consider transfer-encoding magic if libz support is built-in */
* file size before we continue this venture in the dark lands of HTTP.
*********************************************************************/
- if(data->state.resume_from < 0 ) {
+ if(data->state.resume_from < 0) {
/*
* This is meant to get the size of the present remote-file by itself.
* We don't support this now. Bail out!
"%s" /* TE: */
"%s" /* accept-encoding */
"%s" /* referer */
+ "%s" /* Proxy-Connection */
"%s",/* transfer-encoding */
ftp_typecode,
conn->allocptr.accept_encoding:"",
(data->change.referer && conn->allocptr.ref)?
conn->allocptr.ref:"" /* Referer: <data> */,
+ (conn->bits.httpproxy &&
+ !conn->bits.tunnel_proxy &&
+ !Curl_checkProxyheaders(conn, "Proxy-Connection:"))?
+ "Proxy-Connection: Keep-Alive\r\n":"",
te
);
* Returns TRUE if member of the list matches prefix of string
*/
static bool
-checkhttpprefix(struct SessionHandle *data,
+checkhttpprefix(struct Curl_easy *data,
const char *s)
{
struct curl_slist *head = data->set.http200aliases;
#ifndef CURL_DISABLE_RTSP
static bool
-checkrtspprefix(struct SessionHandle *data,
+checkrtspprefix(struct Curl_easy *data,
const char *s)
{
#endif /* CURL_DISABLE_RTSP */
static bool
-checkprotoprefix(struct SessionHandle *data, struct connectdata *conn,
+checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
const char *s)
{
#ifndef CURL_DISABLE_RTSP
* header. We make sure that the full string fit in the allocated header
* buffer, or else we enlarge it.
*/
-static CURLcode header_append(struct SessionHandle *data,
+static CURLcode header_append(struct Curl_easy *data,
struct SingleRequest *k,
size_t length)
{
return CURLE_OK;
}
-static void print_http_error(struct SessionHandle *data)
+static void print_http_error(struct Curl_easy *data)
{
struct SingleRequest *k = &data->req;
char *beg = k->p;
/*
* Read any HTTP header lines from the server and pass them to the client app.
*/
-CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
ssize_t *nread,
bool *stop_reading)
#endif /* CURL_DOES_CONVERSIONS */
if(100 <= k->httpcode && 199 >= k->httpcode) {
- /*
- * We have made a HTTP PUT or POST and this is 1.1-lingo
- * that tells us that the server is OK with this and ready
- * to receive the data.
- * However, we'll get more headers now so we must get
- * back into the header-parsing state!
- */
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
-
/* "A user agent MAY ignore unexpected 1xx status responses." */
switch(k->httpcode) {
case 100:
+ /*
+ * We have made a HTTP PUT or POST and this is 1.1-lingo
+ * that tells us that the server is OK with this and ready
+ * to receive the data.
+ * However, we'll get more headers now so we must get
+ * back into the header-parsing state!
+ */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
/* if we did wait for this do enable write now! */
- if(k->exp100) {
+ if(k->exp100 > EXP100_SEND_DATA) {
k->exp100 = EXP100_SEND_DATA;
k->keepon |= KEEP_SEND;
}
case 101:
/* Switching Protocols */
if(k->upgr101 == UPGR101_REQUESTED) {
+ /* Switching to HTTP/2 */
infof(data, "Received 101\n");
k->upgr101 = UPGR101_RECEIVED;
+ /* we'll get more headers (HTTP/2 response) */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
/* switch to http2 now. The bytes after response headers
are also processed here, otherwise they are lost. */
result = Curl_http2_switched(conn, k->str, *nread);
return result;
*nread = 0;
}
+ else {
+ /* Switching to another protocol (e.g. WebSocket) */
+ k->header = FALSE; /* no more header to parse! */
+ }
break;
default:
+ /* the status code 1xx indicates a provisional response, so
+ we'll get another set of headers */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
break;
}
}
signal the end of the document. */
infof(data, "no chunk, no close, no size. Assume close to "
"signal end\n");
- connclose(conn, "HTTP: No end-of-message indicator");
+ streamclose(conn, "HTTP: No end-of-message indicator");
}
}
data->req.deductheadercount =
(100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
- if(!*stop_reading) {
- /* Curl_http_auth_act() checks what authentication methods
- * that are available and decides which one (if any) to
- * use. It will set 'newurl' if an auth method was picked. */
- result = Curl_http_auth_act(conn);
+ /* Curl_http_auth_act() checks what authentication methods
+ * that are available and decides which one (if any) to
+ * use. It will set 'newurl' if an auth method was picked. */
+ result = Curl_http_auth_act(conn);
- if(result)
- return result;
+ if(result)
+ return result;
- if(k->httpcode >= 300) {
- if((!conn->bits.authneg) && !conn->bits.close &&
- !conn->bits.rewindaftersend) {
- /*
- * General treatment of errors when about to send data. Including :
- * "417 Expectation Failed", while waiting for 100-continue.
- *
- * The check for close above is done simply because of something
- * else has already deemed the connection to get closed then
- * something else should've considered the big picture and we
- * avoid this check.
- *
- * rewindaftersend indicates that something has told libcurl to
- * continue sending even if it gets discarded
+ if(k->httpcode >= 300) {
+ if((!conn->bits.authneg) && !conn->bits.close &&
+ !conn->bits.rewindaftersend) {
+ /*
+ * General treatment of errors when about to send data. Including :
+ * "417 Expectation Failed", while waiting for 100-continue.
+ *
+ * The check for close above is done simply because of something
+ * else has already deemed the connection to get closed then
+ * something else should've considered the big picture and we
+ * avoid this check.
+ *
+ * rewindaftersend indicates that something has told libcurl to
+ * continue sending even if it gets discarded
+ */
+
+ switch(data->set.httpreq) {
+ case HTTPREQ_PUT:
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ /* We got an error response. If this happened before the whole
+ * request body has been sent we stop sending and mark the
+ * connection for closure after we've read the entire response.
*/
-
- switch(data->set.httpreq) {
- case HTTPREQ_PUT:
- case HTTPREQ_POST:
- case HTTPREQ_POST_FORM:
- /* We got an error response. If this happened before the whole
- * request body has been sent we stop sending and mark the
- * connection for closure after we've read the entire response.
- */
- if(!k->upload_done) {
- infof(data, "HTTP error before end of send, stop sending\n");
- connclose(conn, "Stop sending data before everything sent");
- k->upload_done = TRUE;
- k->keepon &= ~KEEP_SEND; /* don't send */
- if(data->state.expect100header)
- k->exp100 = EXP100_FAILED;
- }
- break;
-
- default: /* default label present to avoid compiler warnings */
- break;
+ if(!k->upload_done) {
+ infof(data, "HTTP error before end of send, stop sending\n");
+ streamclose(conn, "Stop sending data before everything sent");
+ k->upload_done = TRUE;
+ k->keepon &= ~KEEP_SEND; /* don't send */
+ if(data->state.expect100header)
+ k->exp100 = EXP100_FAILED;
}
+ break;
+
+ default: /* default label present to avoid compiler warnings */
+ break;
}
}
(k->size <= -1))
/* Respect section 4.4 of rfc2326: If the Content-Length header is
absent, a length 0 must be assumed. It will prevent libcurl from
- hanging on DECRIBE request that got refused for whatever
+ hanging on DESCRIBE request that got refused for whatever
reason */
*stop_reading = TRUE;
#endif
&httpversion_major,
&conn->httpversion,
&k->httpcode);
+
+ if(nc == 1 && httpversion_major == 2 &&
+ 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
+ conn->httpversion = 0;
+ nc = 3;
+ }
+
if(nc==3) {
conn->httpversion += 10 * httpversion_major;
/* Negative Content-Length is really odd, and we know it
happens for example when older Apache servers send large
files */
- connclose(conn, "negative content-length");
+ streamclose(conn, "negative content-length");
infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T
", closing after transfer\n", contentlength);
}
* the connection will close when this request has been
* served.
*/
- connclose(conn, "Connection: close used");
+ streamclose(conn, "Connection: close used");
}
else if(checkprefix("Transfer-Encoding:", k->p)) {
/* One or more encodings. We check for chunked and/or a compression
k->hbufp = data->state.headerbuff;
k->hbuflen = 0;
}
- while(!*stop_reading && *k->str); /* header line within buffer */
+ while(*k->str); /* header line within buffer */
/* We might have reached the end of the header part here, but
there might be a non-header part left in the end of the read