diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 0c17eeb..9969b59 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -997,7 +997,7 @@ index b4aaba2a2..0d716640c 100644 #else int unused; /* prevent a compiler warning */ diff --git a/lib/http2.c b/lib/http2.c -index e74400a4c..b0e6674f2 100644 +index e74400a4c..aec67c975 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -41,6 +41,7 @@ @@ -1017,7 +1017,39 @@ index e74400a4c..b0e6674f2 100644 #ifdef DEBUG_HTTP2 #define H2BUGF(x) x -@@ -1193,16 +1194,30 @@ static void populate_settings(struct Curl_easy *data, +@@ -75,13 +76,20 @@ static int h2_process_pending_input(struct Curl_easy *data, + struct http_conn *httpc, + CURLcode *err); + ++/* ++ * curl-impersonate: Use Chrome's default HTTP/2 stream weight. ++ */ ++ ++#define CHROME_DEFAULT_STREAM_WEIGHT (256) ++ + /* + * Curl_http2_init_state() is called when the easy handle is created and + * allows for HTTP/2 specific init of state. + */ + void Curl_http2_init_state(struct UrlState *state) + { +- state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; ++ state->stream_weight = CHROME_DEFAULT_STREAM_WEIGHT; ++ state->stream_depends_e = TRUE; + } + + /* +@@ -90,7 +98,8 @@ void Curl_http2_init_state(struct UrlState *state) + */ + void Curl_http2_init_userset(struct UserDefined *set) + { +- set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; ++ set->stream_weight = CHROME_DEFAULT_STREAM_WEIGHT; ++ set->stream_depends_e = TRUE; + } + + static int http2_getsock(struct Curl_easy *data, +@@ -1193,16 +1202,30 @@ static void populate_settings(struct Curl_easy *data, { nghttp2_settings_entry *iv = httpc->local_settings; @@ -1026,21 +1058,21 @@ index e74400a4c..b0e6674f2 100644 + /* curl-impersonate: Align HTTP/2 settings to Chrome's */ + iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[0].value = 0x10000; - -- iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; -- iv[1].value = HTTP2_HUGE_WINDOW_SIZE; ++ + iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; + iv[1].value = Curl_multi_max_concurrent_streams(data->multi); -- iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; -- iv[2].value = data->multi->push_cb != NULL; +- iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; +- iv[1].value = HTTP2_HUGE_WINDOW_SIZE; + iv[2].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[2].value = 0x600000; -- httpc->local_settings_num = 3; +- iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; +- iv[2].value = data->multi->push_cb != NULL; + iv[3].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE; + iv[3].value = 0x40000; -+ + +- httpc->local_settings_num = 3; + // iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + // iv[2].value = data->multi->push_cb != NULL; + @@ -1055,7 +1087,7 @@ index e74400a4c..b0e6674f2 100644 } void Curl_http2_done(struct Curl_easy *data, bool premature) -@@ -1816,10 +1831,6 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex, +@@ -1816,10 +1839,6 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex, return -1; } @@ -1066,7 +1098,7 @@ index e74400a4c..b0e6674f2 100644 /* USHRT_MAX is 65535 == 0xffff */ #define HEADER_OVERFLOW(x) \ (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen) -@@ -1890,6 +1901,53 @@ static header_instruction inspect_header(const char *name, size_t namelen, +@@ -1890,6 +1909,53 @@ static header_instruction inspect_header(const char *name, size_t namelen, } } @@ -1120,7 +1152,7 @@ index e74400a4c..b0e6674f2 100644 static ssize_t http2_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, CURLcode *err) { -@@ -1905,6 +1963,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, +@@ -1905,6 +1971,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, nghttp2_nv *nva = NULL; size_t nheader; size_t i; @@ -1128,7 +1160,7 @@ index e74400a4c..b0e6674f2 100644 size_t authority_idx; char *hdbuf = (char *)mem; char *end, *line_end; -@@ -2010,12 +2069,21 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, +@@ -2010,12 +2077,21 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, end = memchr(hdbuf, ' ', line_end - hdbuf); if(!end || end == hdbuf) goto fail; @@ -1156,7 +1188,7 @@ index e74400a4c..b0e6674f2 100644 failf(data, "Failed sending HTTP request: Header overflow"); goto fail; } -@@ -2032,25 +2100,35 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, +@@ -2032,25 +2108,35 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, } if(!end || end == hdbuf) goto fail; @@ -1205,7 +1237,7 @@ index e74400a4c..b0e6674f2 100644 failf(data, "Failed sending HTTP request: Header overflow"); goto fail; } -@@ -2117,10 +2195,13 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, +@@ -2117,10 +2203,13 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, ++i; } diff --git a/firefox/patches/curl-impersonate.patch b/firefox/patches/curl-impersonate.patch index 7356652..48eef26 100644 --- a/firefox/patches/curl-impersonate.patch +++ b/firefox/patches/curl-impersonate.patch @@ -706,7 +706,7 @@ index f08a343e3..2bbce4b23 100644 if(result) return result; diff --git a/lib/http2.c b/lib/http2.c -index e74400a4c..5df654d04 100644 +index e74400a4c..1dd2593a5 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -56,7 +56,7 @@ @@ -718,7 +718,38 @@ index e74400a4c..5df654d04 100644 #ifdef DEBUG_HTTP2 #define H2BUGF(x) x -@@ -1193,14 +1193,18 @@ static void populate_settings(struct Curl_easy *data, +@@ -75,13 +75,20 @@ static int h2_process_pending_input(struct Curl_easy *data, + struct http_conn *httpc, + CURLcode *err); + ++ ++/* ++ * curl-impersonate: Set the HTTP/2 stream weight to the one used by Firefox ++ * by default to fetch html resources. ++ */ ++#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) ++ + /* + * Curl_http2_init_state() is called when the easy handle is created and + * allows for HTTP/2 specific init of state. + */ + void Curl_http2_init_state(struct UrlState *state) + { +- state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; ++ state->stream_weight = FIREFOX_DEFAULT_STREAM_WEIGHT; + } + + /* +@@ -90,7 +97,7 @@ void Curl_http2_init_state(struct UrlState *state) + */ + void Curl_http2_init_userset(struct UserDefined *set) + { +- set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; ++ set->stream_weight = FIREFOX_DEFAULT_STREAM_WEIGHT; + } + + static int http2_getsock(struct Curl_easy *data, +@@ -1193,14 +1200,18 @@ static void populate_settings(struct Curl_easy *data, { nghttp2_settings_entry *iv = httpc->local_settings; @@ -742,7 +773,27 @@ index e74400a4c..5df654d04 100644 httpc->local_settings_num = 3; } -@@ -1818,7 +1822,8 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex, +@@ -1566,12 +1577,18 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, + * struct. + */ + ++/* ++ * curl-impersonate: By default Firefox uses stream 13 as the "parent" of the ++ * stream that fetches the main html resource of the web page. ++ */ ++#define FIREFOX_DEFAULT_STREAM_DEP (13) ++ + static void h2_pri_spec(struct Curl_easy *data, + nghttp2_priority_spec *pri_spec) + { + struct HTTP *depstream = (data->set.stream_depends_on? + data->set.stream_depends_on->req.p.http:NULL); +- int32_t depstream_id = depstream? depstream->stream_id:0; ++ int32_t depstream_id = depstream? depstream->stream_id:FIREFOX_DEFAULT_STREAM_DEP; + nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, + data->set.stream_depends_e); + data->state.stream_weight = data->set.stream_weight; +@@ -1818,7 +1835,8 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex, /* Index where :authority header field will appear in request header field list. */ @@ -752,6 +803,102 @@ index e74400a4c..5df654d04 100644 /* USHRT_MAX is 65535 == 0xffff */ #define HEADER_OVERFLOW(x) \ +@@ -2276,6 +2294,73 @@ CURLcode Curl_http2_setup(struct Curl_easy *data, + return CURLE_OK; + } + ++/* ++ * curl-impersonate: Start with stream id 15 as Firefox does. ++ */ ++#define FIREFOX_DEFAULT_STREAM_ID (15) ++ ++static CURLcode http2_set_stream_priority(struct Curl_easy *data, ++ int32_t stream_id, ++ int32_t dep_stream_id, ++ int32_t weight) ++{ ++ int rv; ++ nghttp2_priority_spec pri_spec; ++ struct connectdata *conn = data->conn; ++ struct http_conn *httpc = &conn->proto.httpc; ++ ++ nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, 0); ++ rv = nghttp2_submit_priority(httpc->h2, NGHTTP2_FLAG_NONE, ++ stream_id, &pri_spec); ++ if(rv) { ++ failf(data, "nghttp2_submit_priority() failed: %s(%d)", ++ nghttp2_strerror(rv), rv); ++ return CURLE_HTTP2; ++ } ++ ++ return CURLE_OK; ++} ++ ++ ++/* ++ * curl-impersonate: Firefox uses an elaborate scheme of http/2 streams to ++ * split the load for html/js/css/images. It builds a tree of streams with ++ * different weights (priorities) by default and communicates this to the ++ * server. Imitate that behavior. ++ */ ++static CURLcode http2_set_stream_priorities(struct Curl_easy *data) ++{ ++ CURLcode result; ++ struct connectdata *conn = data->conn; ++ struct http_conn *httpc = &conn->proto.httpc; ++ ++ result = http2_set_stream_priority(data, 3, 0, 201); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(data, 5, 0, 101); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(data, 7, 0, 0); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(data, 9, 7, 0); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(data, 11, 3, 0); ++ if(result) ++ return result; ++ ++ result = http2_set_stream_priority(data, 13, 0, 241); ++ if(result) ++ return result; ++ ++ return CURLE_OK; ++} ++ + CURLcode Curl_http2_switched(struct Curl_easy *data, + const char *mem, size_t nread) + { +@@ -2284,6 +2369,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data, + struct http_conn *httpc = &conn->proto.httpc; + int rv; + struct HTTP *stream = data->req.p.http; ++ nghttp2_priority_spec pri_spec; + + result = Curl_http2_setup(data, conn); + if(result) +@@ -2338,6 +2424,13 @@ CURLcode Curl_http2_switched(struct Curl_easy *data, + return CURLE_HTTP2; + } + ++ result = http2_set_stream_priorities(data); ++ if(result) ++ return result; ++ ++ /* Best effort to set the request's stream id to 15, like Firefox does. */ ++ nghttp2_session_set_next_stream_id(httpc->h2, FIREFOX_DEFAULT_STREAM_ID); ++ + /* we are going to copy mem to httpc->inbuf. This is required since + mem is part of buffer pointed by stream->mem, and callbacks + called by nghttp2_session_mem_recv() will write stream specific diff --git a/lib/setopt.c b/lib/setopt.c index 599ed5d99..1baa48e70 100644 --- a/lib/setopt.c