From: Daniel Stenberg Date: Sun, 6 Feb 2022 17:10:59 +0000 (+0100) Subject: quiche: use Curl_pseudo_headers X-Git-Tag: curl-7_82_0~117 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3fa405bb58ba3e722bfec1de14fc77a5924ebb0a;p=thirdparty%2Fcurl.git quiche: use Curl_pseudo_headers --- diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c index d2ef9169ce..7104af3842 100644 --- a/lib/vquic/quiche.c +++ b/lib/vquic/quiche.c @@ -37,6 +37,7 @@ #include "strerror.h" #include "vquic.h" #include "transfer.h" +#include "h2h3.h" #include "vtls/openssl.h" #include "vtls/keylog.h" @@ -543,7 +544,7 @@ static int cb_each_header(uint8_t *name, size_t name_len, struct h3h1header *headers = (struct h3h1header *)argp; size_t olen = 0; - if((name_len == 7) && !strncmp(H3_PSEUDO_STATUS, (char *)name, 7)) { + if((name_len == 7) && !strncmp(H2H3_PSEUDO_STATUS, (char *)name, 7)) { msnprintf(headers->dest, headers->destlen, "HTTP/3 %.*s\n", (int) value_len, value); @@ -713,180 +714,31 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem, struct connectdata *conn = data->conn; struct HTTP *stream = data->req.p.http; size_t nheader; - size_t i; - size_t authority_idx; - char *hdbuf = (char *)mem; - char *end, *line_end; int64_t stream3_id; quiche_h3_header *nva = NULL; struct quicsocket *qs = conn->quic; CURLcode result = CURLE_OK; - char *vptr; + struct h2h3req *hreq = NULL; stream->h3req = TRUE; /* senf off! */ - /* Calculate number of headers contained in [mem, mem + len). Assumes a - correctly generated HTTP header field block. */ - nheader = 0; - for(i = 1; i < len; ++i) { - if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { - ++nheader; - ++i; - } - } - if(nheader < 2) + result = Curl_pseudo_headers(data, mem, len, &hreq); + if(result) goto fail; + nheader = hreq->entries; - /* We counted additional 2 \r\n in the first and last line. We need 3 - new headers: :method, :path and :scheme. Therefore we need one - more space. */ - nheader += 1; nva = malloc(sizeof(quiche_h3_header) * nheader); if(!nva) { result = CURLE_OUT_OF_MEMORY; goto fail; } - - /* Extract :method, :path from request line - We do line endings with CRLF so checking for CR is enough */ - line_end = memchr(hdbuf, '\r', len); - if(!line_end) { - result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */ - goto fail; - } - - /* Method does not contain spaces */ - end = memchr(hdbuf, ' ', line_end - hdbuf); - if(!end || end == hdbuf) - goto fail; - nva[0].name = (unsigned char *)H3_PSEUDO_METHOD; - nva[0].name_len = sizeof(H3_PSEUDO_METHOD) - 1; - nva[0].value = (unsigned char *)hdbuf; - nva[0].value_len = (size_t)(end - hdbuf); - - hdbuf = end + 1; - - /* Path may contain spaces so scan backwards */ - end = NULL; - for(i = (size_t)(line_end - hdbuf); i; --i) { - if(hdbuf[i - 1] == ' ') { - end = &hdbuf[i - 1]; - break; - } - } - if(!end || end == hdbuf) - goto fail; - nva[1].name = (unsigned char *)H3_PSEUDO_PATH; - nva[1].name_len = sizeof(H3_PSEUDO_PATH) - 1; - nva[1].value = (unsigned char *)hdbuf; - nva[1].value_len = (size_t)(end - hdbuf); - - nva[2].name = (unsigned char *)H3_PSEUDO_SCHEME; - nva[2].name_len = sizeof(H3_PSEUDO_SCHEME) - 1; - vptr = Curl_checkheaders(data, H3_PSEUDO_SCHEME); - if(vptr) { - vptr += sizeof(H3_PSEUDO_SCHEME); - while(*vptr && ISSPACE(*vptr)) - vptr++; - nva[2].value = (unsigned char *)vptr; - infof(data, "set pseduo header %s to %s", H3_PSEUDO_SCHEME, vptr); - } else { - if(conn->handler->flags & PROTOPT_SSL) - nva[2].value = (unsigned char *)"https"; - else - nva[2].value = (unsigned char *)"http"; - } - nva[2].value_len = strlen((char *)nva[2].value); - - authority_idx = 0; - i = 3; - while(i < nheader) { - size_t hlen; - - hdbuf = line_end + 2; - - /* check for next CR, but only within the piece of data left in the given - buffer */ - line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem)); - if(!line_end || (line_end == hdbuf)) - goto fail; - - /* header continuation lines are not supported */ - if(*hdbuf == ' ' || *hdbuf == '\t') - goto fail; - - for(end = hdbuf; end < line_end && *end != ':'; ++end) - ; - if(end == hdbuf || end == line_end) - goto fail; - hlen = end - hdbuf; - - if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { - authority_idx = i; - nva[i].name = (unsigned char *)H3_PSEUDO_AUTHORITY; - nva[i].name_len = sizeof(H3_PSEUDO_AUTHORITY) - 1; - } - else { - nva[i].name_len = (size_t)(end - hdbuf); - /* Lower case the header name for HTTP/3 */ - Curl_strntolower((char *)hdbuf, hdbuf, nva[i].name_len); - nva[i].name = (unsigned char *)hdbuf; - } - hdbuf = end + 1; - while(*hdbuf == ' ' || *hdbuf == '\t') - ++hdbuf; - end = line_end; - -#if 0 /* This should probably go in more or less like this */ - switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, - end - hdbuf)) { - case HEADERINST_IGNORE: - /* skip header fields prohibited by HTTP/2 specification. */ - --nheader; - continue; - case HEADERINST_TE_TRAILERS: - nva[i].value = (uint8_t*)"trailers"; - nva[i].value_len = sizeof("trailers") - 1; - break; - default: - nva[i].value = (unsigned char *)hdbuf; - nva[i].value_len = (size_t)(end - hdbuf); - } -#endif - nva[i].value = (unsigned char *)hdbuf; - nva[i].value_len = (size_t)(end - hdbuf); - - ++i; - } - - /* :authority must come before non-pseudo header fields */ - if(authority_idx && authority_idx != AUTHORITY_DST_IDX) { - quiche_h3_header authority = nva[authority_idx]; - for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { - nva[i] = nva[i - 1]; - } - nva[i] = authority; - } - - /* Warn stream may be rejected if cumulative length of headers is too - large. */ -#define MAX_ACC 60000 /* <64KB to account for some overhead */ - { - size_t acc = 0; - - for(i = 0; i < nheader; ++i) { - acc += nva[i].name_len + nva[i].value_len; - - H3BUGF(infof(data, "h3 [%.*s: %.*s]", - nva[i].name_len, nva[i].name, - nva[i].value_len, nva[i].value)); - } - - if(acc > MAX_ACC) { - infof(data, "http_request: Warning: The cumulative length of all " - "headers exceeds %d bytes and that could cause the " - "stream to be rejected.", MAX_ACC); + unsigned int i; + for(i = 0; i < nheader; i++) { + nva[i].name = (unsigned char *)hreq->header[i].name; + nva[i].name_len = hreq->header[i].namelen; + nva[i].value = (unsigned char *)hreq->header[i].value; + nva[i].value_len = hreq->header[i].valuelen; } } @@ -933,10 +785,12 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem, stream3_id, (void *)data); stream->stream3_id = stream3_id; + Curl_pseudo_free(hreq); return CURLE_OK; fail: free(nva); + Curl_pseudo_free(hreq); return result; }