mirror of
https://github.com/curl/curl.git
synced 2026-08-24 15:53:32 +03:00
http2: support HTTP/2 to forward proxies, non-tunneling
- with `--proxy-http2` allow h2 ALPN negotiation to forward proxies - applies to http: requests against a https: proxy only, as https: requests will auto-tunnel - adding a HTTP/1 request parser in http1.c - removed h2h3.c - using new request parser in nghttp2 and all h3 backends - adding test 2603 for request parser - adding h2 proxy test cases to test_10_* scorecard.py: request scoring accidentally always run curl with '-v'. Removed that, expect double numbers. labeller: added http1.* and h2-proxy sources to detection Closes #10967
This commit is contained in:
parent
fb1d62ff07
commit
fc2f1e547a
28 changed files with 1522 additions and 824 deletions
|
|
@ -38,7 +38,7 @@ include_directories(
|
|||
# or else they will fail to link. Some of the tests require the special libcurlu
|
||||
# build, so filter those out until we get libcurlu.
|
||||
list(FILTER UNITPROGS EXCLUDE REGEX
|
||||
"unit1394|unit1395|unit1604|unit1608|unit1621|unit1650|unit1653|unit1655|unit1660|unit2600|unit2601|unit2602")
|
||||
"unit1394|unit1395|unit1604|unit1608|unit1621|unit1650|unit1653|unit1655|unit1660|unit2600|unit2601|unit2602|unit2603")
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
foreach(_testfile ${UNITPROGS})
|
||||
add_executable(${_testfile} EXCLUDE_FROM_ALL ${_testfile}.c ${UNITFILES})
|
||||
|
|
|
|||
|
|
@ -158,4 +158,6 @@ unit2601_SOURCES = unit2601.c $(UNITFILES)
|
|||
|
||||
unit2602_SOURCES = unit2602.c $(UNITFILES)
|
||||
|
||||
unit2603_SOURCES = unit2603.c $(UNITFILES)
|
||||
|
||||
unit3200_SOURCES = unit3200.c $(UNITFILES)
|
||||
|
|
|
|||
|
|
@ -38,5 +38,5 @@ UNITPROGS = unit1300 unit1302 unit1303 unit1304 unit1305 unit1307 \
|
|||
unit1620 unit1621 \
|
||||
unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
|
||||
unit1660 unit1661 \
|
||||
unit2600 unit2601 unit2602 \
|
||||
unit2600 unit2601 unit2602 unit2603 \
|
||||
unit3200
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ UNITTEST_START
|
|||
Curl_dyn_init(&dbuf, 32*1024);
|
||||
fail_if(Curl_dynhds_h1_dprint(&hds, &dbuf), "h1 print failed");
|
||||
if(Curl_dyn_ptr(&dbuf)) {
|
||||
fprintf(stderr, "%s", Curl_dyn_ptr(&dbuf));
|
||||
fail_if(strcmp(Curl_dyn_ptr(&dbuf),
|
||||
"test1: 123\r\ntest1: 123\r\nBla-Bla: thingies\r\n"),
|
||||
"h1 format differs");
|
||||
|
|
@ -121,5 +120,29 @@ UNITTEST_START
|
|||
}
|
||||
|
||||
Curl_dynhds_free(&hds);
|
||||
Curl_dynhds_init(&hds, 128, 4*1024);
|
||||
/* continuation without previous header fails */
|
||||
result = Curl_dynhds_h1_cadd_line(&hds, " indented value");
|
||||
fail_unless(result, "add should have failed");
|
||||
|
||||
/* continuation with previous header must succeed */
|
||||
fail_if(Curl_dynhds_h1_cadd_line(&hds, "ti1: val1"), "add");
|
||||
fail_if(Curl_dynhds_h1_cadd_line(&hds, " val2"), "add indent");
|
||||
fail_if(Curl_dynhds_h1_cadd_line(&hds, "ti2: val1"), "add");
|
||||
fail_if(Curl_dynhds_h1_cadd_line(&hds, "\tval2"), "add indent");
|
||||
fail_if(Curl_dynhds_h1_cadd_line(&hds, "ti3: val1"), "add");
|
||||
fail_if(Curl_dynhds_h1_cadd_line(&hds, " val2"), "add indent");
|
||||
|
||||
Curl_dyn_init(&dbuf, 32*1024);
|
||||
fail_if(Curl_dynhds_h1_dprint(&hds, &dbuf), "h1 print failed");
|
||||
if(Curl_dyn_ptr(&dbuf)) {
|
||||
fprintf(stderr, "indent concat: %s\n", Curl_dyn_ptr(&dbuf));
|
||||
fail_if(strcmp(Curl_dyn_ptr(&dbuf),
|
||||
"ti1: val1 val2\r\nti2: val1 val2\r\nti3: val1 val2\r\n"),
|
||||
"wrong format");
|
||||
}
|
||||
Curl_dyn_free(&dbuf);
|
||||
|
||||
Curl_dynhds_free(&hds);
|
||||
|
||||
UNITTEST_STOP
|
||||
|
|
|
|||
190
tests/unit/unit2603.c
Normal file
190
tests/unit/unit2603.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curlcheck.h"
|
||||
|
||||
#include "urldata.h"
|
||||
#include "http.h"
|
||||
#include "http1.h"
|
||||
#include "curl_log.h"
|
||||
|
||||
static CURLcode unit_setup(void)
|
||||
{
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void unit_stop(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct tcase {
|
||||
const char **input;
|
||||
const char *default_scheme;
|
||||
const char *method;
|
||||
const char *scheme;
|
||||
const char *authority;
|
||||
const char *path;
|
||||
size_t header_count;
|
||||
size_t input_remain;
|
||||
};
|
||||
|
||||
static void check_eq(const char *s, const char *exp_s, const char *name)
|
||||
{
|
||||
if(s && exp_s) {
|
||||
if(strcmp(s, exp_s)) {
|
||||
fprintf(stderr, "expected %s: '%s' but got '%s'\n", name, exp_s, s);
|
||||
fail("unexpected req component");
|
||||
}
|
||||
}
|
||||
else if(!s && exp_s) {
|
||||
fprintf(stderr, "expected %s: '%s' but got NULL\n", name, exp_s);
|
||||
fail("unexpected req component");
|
||||
}
|
||||
else if(s && !exp_s) {
|
||||
fprintf(stderr, "expected %s: NULL but got '%s'\n", name, s);
|
||||
fail("unexpected req component");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_success(struct tcase *t)
|
||||
{
|
||||
struct h1_req_parser p;
|
||||
const char *buf;
|
||||
size_t buflen, i, in_len, in_consumed;
|
||||
CURLcode err;
|
||||
ssize_t nread;
|
||||
|
||||
Curl_h1_req_parse_init(&p, 1024);
|
||||
in_len = in_consumed = 0;
|
||||
for(i = 0; t->input[i]; ++i) {
|
||||
buf = t->input[i];
|
||||
buflen = strlen(buf);
|
||||
in_len += buflen;
|
||||
nread = Curl_h1_req_parse_read(&p, buf, buflen, t->default_scheme,
|
||||
0, &err);
|
||||
if(nread < 0) {
|
||||
fprintf(stderr, "got err %d parsing: '%s'\n", err, buf);
|
||||
fail("error consuming");
|
||||
}
|
||||
in_consumed += (size_t)nread;
|
||||
if((size_t)nread != buflen) {
|
||||
if(!p.done) {
|
||||
fprintf(stderr, "only %zd/%zu consumed for: '%s'\n",
|
||||
nread, buflen, buf);
|
||||
fail("not all consumed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail_if(!p.done, "end not detected");
|
||||
fail_if(!p.req, "not request created");
|
||||
if(t->input_remain != (in_len - in_consumed)) {
|
||||
fprintf(stderr, "expected %zu input bytes to remain, but got %zu\n",
|
||||
t->input_remain, in_len - in_consumed);
|
||||
fail("unexpected input consumption");
|
||||
}
|
||||
if(p.req) {
|
||||
check_eq(p.req->method, t->method, "method");
|
||||
check_eq(p.req->scheme, t->scheme, "scheme");
|
||||
check_eq(p.req->authority, t->authority, "authority");
|
||||
check_eq(p.req->path, t->path, "path");
|
||||
if(Curl_dynhds_count(&p.req->headers) != t->header_count) {
|
||||
fprintf(stderr, "expected %zu headers but got %zu\n", t->header_count,
|
||||
Curl_dynhds_count(&p.req->headers));
|
||||
fail("unexpected req header count");
|
||||
}
|
||||
}
|
||||
|
||||
Curl_h1_req_parse_free(&p);
|
||||
}
|
||||
|
||||
static const char *T1_INPUT[] = {
|
||||
"GET /path HTTP/1.1\r\nHost: test.curl.se\r\n\r\n",
|
||||
NULL,
|
||||
};
|
||||
static struct tcase TEST1a = {
|
||||
T1_INPUT, NULL, "GET", NULL, NULL, "/path", 1, 0
|
||||
};
|
||||
static struct tcase TEST1b = {
|
||||
T1_INPUT, "https", "GET", "https", NULL, "/path", 1, 0
|
||||
};
|
||||
|
||||
static const char *T2_INPUT[] = {
|
||||
"GET /path HTT",
|
||||
"P/1.1\r\nHost: te",
|
||||
"st.curl.se\r\n\r",
|
||||
"\n12345678",
|
||||
NULL,
|
||||
};
|
||||
static struct tcase TEST2 = {
|
||||
T2_INPUT, NULL, "GET", NULL, NULL, "/path", 1, 8
|
||||
};
|
||||
|
||||
static const char *T3_INPUT[] = {
|
||||
"GET ftp://ftp.curl.se/xxx?a=2 HTTP/1.1\r\nContent-Length: 0\r",
|
||||
"\nUser-Agent: xxx\r\n\r\n",
|
||||
NULL,
|
||||
};
|
||||
static struct tcase TEST3a = {
|
||||
T3_INPUT, NULL, "GET", "ftp", "ftp.curl.se", "/xxx?a=2", 2, 0
|
||||
};
|
||||
|
||||
static const char *T4_INPUT[] = {
|
||||
"CONNECT ftp.curl.se:123 HTTP/1.1\r\nContent-Length: 0\r\n",
|
||||
"User-Agent: xxx\r\n",
|
||||
"nothing: \r\n\r\n\n\n",
|
||||
NULL,
|
||||
};
|
||||
static struct tcase TEST4a = {
|
||||
T4_INPUT, NULL, "CONNECT", NULL, "ftp.curl.se:123", NULL, 3, 2
|
||||
};
|
||||
|
||||
static const char *T5_INPUT[] = {
|
||||
"OPTIONS * HTTP/1.1\r\nContent-Length: 0\r\nBlabla: xxx.yyy\r",
|
||||
"\n\tzzzzzz\r\n\r\n",
|
||||
"123",
|
||||
NULL,
|
||||
};
|
||||
static struct tcase TEST5a = {
|
||||
T5_INPUT, NULL, "OPTIONS", NULL, NULL, "*", 2, 3
|
||||
};
|
||||
|
||||
static const char *T6_INPUT[] = {
|
||||
"PUT /path HTTP/1.1\nHost: test.curl.se\n\n123",
|
||||
NULL,
|
||||
};
|
||||
static struct tcase TEST6a = {
|
||||
T6_INPUT, NULL, "PUT", NULL, NULL, "/path", 1, 3
|
||||
};
|
||||
|
||||
UNITTEST_START
|
||||
|
||||
parse_success(&TEST1a);
|
||||
parse_success(&TEST1b);
|
||||
parse_success(&TEST2);
|
||||
parse_success(&TEST3a);
|
||||
parse_success(&TEST4a);
|
||||
parse_success(&TEST5a);
|
||||
parse_success(&TEST6a);
|
||||
|
||||
UNITTEST_STOP
|
||||
Loading…
Add table
Add a link
Reference in a new issue