urlapi: same origin tests
No binary (build failed)
—
(log yok)
| @@ -718,8 +718,9 @@ static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf, | |
| return second; | |
| } | |
| - | static int set_transfer_url(struct Curl_easy *data, bool via_ssl_conn, |
| - | struct curl_pushheaders *hp) |
| + | static int set_transfer_url(struct Curl_easy *newhandle, |
| + | struct curl_pushheaders *hp, |
| + | struct Curl_easy *data) |
| { | |
| const char *v; | |
| CURLUcode uc; | |
| @@ -732,14 +733,6 @@ static int set_transfer_url(struct Curl_easy *data, bool via_ssl_conn, | |
| v = curl_pushheader_byname(hp, HTTP_PSEUDO_SCHEME); | |
| if(v) { | |
| - | if(!via_ssl_conn) { |
| - | /* PUSH over an insecure connection, accept only insecure schemes. */ |
| - | const struct Curl_scheme *scheme = Curl_get_scheme(v); |
| - | if(!scheme || (scheme->flags & PROTOPT_SSL)) { |
| - | rc = 1; |
| - | goto fail; |
| - | } |
| - | } |
| uc = curl_url_set(u, CURLUPART_SCHEME, v, 0); | |
| if(uc) { | |
| rc = 1; | |
| @@ -765,6 +758,13 @@ static int set_transfer_url(struct Curl_easy *data, bool via_ssl_conn, | |
| } | |
| } | |
| + | /* We can only allow PUSH of resource from the same origin, e.g. |
| + | * scheme + hostname + port */ |
| + | if(!Curl_url_same_origin(data->state.uh, u)) { |
| + | rc = 1; |
| + | goto fail; |
| + | } |
| + | |
| uc = curl_url_get(u, CURLUPART_URL, &url, 0); | |
| if(uc) | |
| rc = 4; | |
| @@ -773,7 +773,7 @@ fail: | |
| if(rc) | |
| return rc; | |
| - | Curl_bufref_set(&data->state.url, url, 0, curl_free); |
| + | Curl_bufref_set(&newhandle->state.url, url, 0, curl_free); |
| return 0; | |
| } | |
| @@ -819,8 +819,7 @@ static int push_promise(struct Curl_cfilter *cf, | |
| heads.stream = stream; | |
| heads.frame = frame; | |
| - | rv = set_transfer_url(newhandle, |
| - | Curl_conn_is_ssl(cf->conn, cf->sockindex), &heads); |
| + | rv = set_transfer_url(newhandle, &heads, data); |
| if(rv) { | |
| CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE, failed to set URL -> %d", | |
| frame->promised_stream_id, rv); | |
| @@ -63,4 +63,6 @@ CURLUcode Curl_junkscan(const char *url, size_t *urllen, bool allowspace); | |
| #define U_CURLU_URLDECODE (unsigned int)CURLU_URLDECODE | |
| #define U_CURLU_PATH_AS_IS (unsigned int)CURLU_PATH_AS_IS | |
| + | bool Curl_url_same_origin(CURLU *base, CURLU *href); |
| + | |
| #endif /* HEADER_CURL_URLAPI_INT_H */ | |
| @@ -1991,3 +1991,36 @@ nomem: | |
| } | |
| return CURLUE_OK; | |
| } | |
| + | |
| + | bool Curl_url_same_origin(CURLU *base, CURLU *href) |
| + | { |
| + | const struct Curl_scheme *s = NULL; |
| + | |
| + | /* base must be an absolute URL */ |
| + | if(!base->scheme || !base->host) |
| + | return FALSE; |
| + | if(href->scheme && !curl_strequal(base->scheme, href->scheme)) |
| + | return FALSE; |
| + | if(href->host) { |
| + | if(!curl_strequal(base->host, href->host)) |
| + | return FALSE; |
| + | if(!curl_strequal(base->port, href->port)) { |
| + | /* This may still match if only one has an explicit port |
| + | * and it is the default for the scheme. */ |
| + | if(base->port && href->port) |
| + | return FALSE; |
| + | |
| + | s = Curl_get_scheme(base->scheme); |
| + | if(!s) /* Cannot match default port for unknown scheme */ |
| + | return FALSE; |
| + | |
| + | /* The port which is set must be the default one */ |
| + | if((base->port && (base->portnum != s->defport)) || |
| + | (href->port && (href->portnum != s->defport))) |
| + | return FALSE; |
| + | } |
| + | } |
| + | else if(href->port) /* no host in href, then there must be no port */ |
| + | return FALSE; |
| + | return TRUE; |
| + | } |
| @@ -301,5 +301,84 @@ static CURLcode test_unit1675(const char *arg) | |
| abort_if(fails, "parse_file tests failed"); | |
| } | |
| + | /* Test same origin check. For now, we can only do that when |
| + | * schemes are supported by libcurl. */ |
| + | #ifndef CURL_DISABLE_HTTP |
| + | { |
| + | CURLU *base, *href; |
| + | int fails = 0; |
| + | unsigned int i; |
| + | bool match; |
| + | struct origin_test { |
| + | const char *base; |
| + | const char *scheme; |
| + | const char *host; |
| + | const char *port; |
| + | const char *path; |
| + | bool expect_match; |
| + | }; |
| + | const struct origin_test tests[] = { |
| + | {"http://host:123/x", "http", "host", "123", "/y", TRUE}, |
| + | {"http://host:123/x", NULL, "host", "123", "/y", TRUE}, |
| + | {"http://host:123/x", NULL, NULL, NULL, "/y", TRUE}, |
| + | {"http://host:80/x", "http", "host", "123", "/y", FALSE}, |
| + | {"http://host:80/x", "http", "host", NULL, "/y", TRUE}, |
| + | {"http://host/x", "http", "host", "80", "/y", TRUE}, |
| + | #ifdef USE_SSL |
| + | {"http://host:123/x", "https", "host", "123", "/y", FALSE}, |
| + | {"https://host/x", "http", "host", "443", "/y", FALSE}, |
| + | {"https://host/x", "https", "host", "443", "/y", TRUE}, |
| + | #endif |
| + | }; |
| + | |
| + | for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { |
| + | CURLUcode uc; |
| + | base = curl_url(); |
| + | href = curl_url(); |
| + | if(!base || !href) { |
| + | curl_mfprintf(stderr, "%d: failed to allocate memory\n", i); |
| + | fails++; |
| + | goto loop_end; |
| + | } |
| + | uc = curl_url_set(base, CURLUPART_URL, tests[i].base, 0); |
| + | if(uc) { |
| + | curl_mfprintf(stderr, "failed to parse %d base %s -> %d\n", i, |
| + | tests[i].base, uc); |
| + | fails++; |
| + | goto loop_end; |
| + | } |
| + | if(tests[i].scheme) |
| + | uc = curl_url_set(href, CURLUPART_SCHEME, tests[i].scheme, 0); |
| + | if(!uc && tests[i].host) |
| + | uc = curl_url_set(href, CURLUPART_HOST, tests[i].host, 0); |
| + | if(!uc && tests[i].port) |
| + | uc = curl_url_set(href, CURLUPART_PORT, tests[i].port, 0); |
| + | if(!uc && tests[i].path) |
| + | uc = curl_url_set(href, CURLUPART_PATH, tests[i].path, 0); |
| + | if(uc) { |
| + | curl_mfprintf(stderr, "failed to parse %d href %s://%s:%s%s -> %d\n", |
| + | i, tests[i].scheme, tests[i].host, tests[i].port, |
| + | tests[i].path, uc); |
| + | fails++; |
| + | goto loop_end; |
| + | } |
| + | |
| + | match = Curl_url_same_origin(base, href); |
| + | if(match != tests[i].expect_match) { |
| + | curl_mfprintf(stderr, "ERROR: %d base %s and href %s://%s:%s%s %s\n", |
| + | i, tests[i].base, tests[i].scheme, tests[i].host, |
| + | tests[i].port, tests[i].path, |
| + | match ? "matched" : "did not match"); |
| + | fails++; |
| + | } |
| + | |
| + | loop_end: |
| + | curl_url_cleanup(base); |
| + | curl_url_cleanup(href); |
| + | } |
| + | abort_if(fails, "same_origin tests failed"); |
| + | } |
| + | #endif /* !CURL_DISABLE_HTTP */ |
| + | |
| UNITTEST_END_SIMPLE | |
| } | |