diff options
Diffstat (limited to 'Utilities/cmcurl/lib/http.c')
-rw-r--r-- | Utilities/cmcurl/lib/http.c | 175 |
1 files changed, 99 insertions, 76 deletions
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index cb585e7..faa486c 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -88,6 +88,7 @@ #include "hsts.h" #include "ws.h" #include "c-hyper.h" +#include "curl_ctype.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -233,15 +234,12 @@ static CURLcode http_setup_conn(struct Curl_easy *data, Curl_mime_initpart(&http->form); data->req.p.http = http; + connkeep(conn, "HTTP default"); - if((data->state.httpwant == CURL_HTTP_VERSION_3) - || (data->state.httpwant == CURL_HTTP_VERSION_3ONLY)) { + if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) { CURLcode result = Curl_conn_may_http3(data, conn); if(result) return result; - - /* TODO: HTTP lower version eyeballing */ - conn->transport = TRNSPRT_QUIC; } return CURLE_OK; @@ -2342,7 +2340,16 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, return result; } - if(http->postsize) { + /* For really small puts we don't use Expect: headers at all, and for + the somewhat bigger ones we allow the app to disable it. Just make + sure that the expect100header is always set to the preferred value + here. */ + ptr = Curl_checkheaders(data, STRCONST("Expect")); + if(ptr) { + data->state.expect100header = + Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue")); + } + else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) { result = expect100(data, conn, r); if(result) return result; @@ -4155,11 +4162,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(!k->headerline++) { /* This is the first header, it MUST be the error code line or else we consider this to be the body right away! */ - int httpversion_major; - int rtspversion_major; - int nc = 0; -#define HEADER1 headp /* no conversion needed, just use headp */ - + bool fine_statusline = FALSE; if(conn->handler->protocol & PROTO_FAMILY_HTTP) { /* * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 @@ -4168,39 +4171,60 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * says. We allow any three-digit number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ - char separator; - char twoorthree[2]; int httpversion = 0; - char digit4 = 0; - nc = sscanf(HEADER1, - " HTTP/%1d.%1d%c%3d%c", - &httpversion_major, - &httpversion, - &separator, - &k->httpcode, - &digit4); - - if(nc == 1 && httpversion_major >= 2 && - 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) { - conn->httpversion = 0; - nc = 4; - separator = ' '; - } - - /* There can only be a 4th response code digit stored in 'digit4' if - all the other fields were parsed and stored first, so nc is 5 when - digit4 a digit. - - The sscanf() line above will also allow zero-prefixed and negative - numbers, so we check for that too here. - */ - else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) { - failf(data, "Unsupported response code in HTTP response"); - return CURLE_UNSUPPORTED_PROTOCOL; + char *p = headp; + + while(*p && ISBLANK(*p)) + p++; + if(!strncmp(p, "HTTP/", 5)) { + p += 5; + switch(*p) { + case '1': + p++; + if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) { + if(ISBLANK(p[2])) { + httpversion = 10 + (p[1] - '0'); + p += 3; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(ISSPACE(*p)) + fine_statusline = TRUE; + } + } + } + if(!fine_statusline) { + failf(data, "Unsupported HTTP/1 subversion in response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + break; + case '2': + case '3': + if(!ISBLANK(p[1])) + break; + httpversion = (*p - '0') * 10; + p += 2; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(!ISSPACE(*p)) + break; + fine_statusline = TRUE; + } + break; + default: /* unsupported */ + failf(data, "Unsupported HTTP version in response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } } - if((nc >= 4) && (' ' == separator)) { - httpversion += 10 * httpversion_major; + if(fine_statusline) { + if(k->httpcode < 100) { + failf(data, "Unsupported response code in HTTP response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } switch(httpversion) { case 10: case 11: @@ -4227,51 +4251,50 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; } } - else if(!nc) { - /* 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); - conn->httpversion = 10; - + else { /* If user has set option HTTP200ALIASES, compare header line against list of aliases */ - if(!nc) { - statusline check = - checkhttpprefix(data, - Curl_dyn_ptr(&data->state.headerb), - Curl_dyn_len(&data->state.headerb)); - if(check == STATUS_DONE) { - nc = 1; - k->httpcode = 200; - conn->httpversion = 10; - } + statusline check = + checkhttpprefix(data, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(check == STATUS_DONE) { + fine_statusline = TRUE; + k->httpcode = 200; + conn->httpversion = 10; } } - else { - failf(data, "Unsupported HTTP version in response"); - return CURLE_UNSUPPORTED_PROTOCOL; - } } else if(conn->handler->protocol & CURLPROTO_RTSP) { - char separator; - int rtspversion; - nc = sscanf(HEADER1, - " RTSP/%1d.%1d%c%3d", - &rtspversion_major, - &rtspversion, - &separator, - &k->httpcode); - if((nc == 4) && (' ' == separator)) { - conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ - } - else { - nc = 0; + char *p = headp; + while(*p && ISBLANK(*p)) + p++; + if(!strncmp(p, "RTSP/", 5)) { + p += 5; + if(ISDIGIT(*p)) { + p++; + if((p[0] == '.') && ISDIGIT(p[1])) { + if(ISBLANK(p[2])) { + p += 3; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(ISSPACE(*p)) { + fine_statusline = TRUE; + conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */ + } + } + } + } + } + if(!fine_statusline) + return CURLE_WEIRD_SERVER_REPLY; } } - if(nc) { + if(fine_statusline) { result = Curl_http_statusline(data, conn); if(result) return result; |