@@ -3,33 +3,12 @@ module http
33// HTTP version negotiation and multi-version request dispatch.
44// Alt-Svc cache integration: do_http2 checks for Alt-Svc headers in responses
55// and negotiate_version consults the cache before defaulting to HTTP/2.
6+ //
7+ // v3 (QUIC) support lives in request_version_d_use_ngtcp2.v and is only
8+ // compiled when `-d use_ngtcp2` is passed. The fallback stubs are in
9+ // request_version_notd_use_ngtcp2.v.
610import net.urllib
711import net.http.v2
8- import net.http.v3
9-
10- // negotiate_version selects the HTTP version for a request.
11- // Checks Alt-Svc cache for h3 entries before defaulting to v2 for HTTPS.
12- fn (req &Request) negotiate_version (url urllib.URL) Version {
13- if req.version != .unknown {
14- return req.version
15- }
16-
17- if url.scheme != 'https' {
18- return .v1_1
19- }
20-
21- if req.alt_svc_cache != unsafe { nil } {
22- origin := normalized_origin (url)
23- mut cache := unsafe { req.alt_svc_cache }
24- if _ := cache.get_h3_endpoint (origin) {
25- return .v3_0
26- }
27- }
28-
29- return .v2_0
30- }
31-
32- // Method is now unified via common.Method — direct cast replaces manual mapping.
3312
3413// build_client_header prepares the request header for v2/v3 clients,
3514// adding user-agent and content-length if not already set.
@@ -61,42 +40,11 @@ fn normalized_origin(url urllib.URL) string {
6140 return '${url.scheme} ://${url.hostname()} :${port} '
6241}
6342
64- fn (req &Request) do_http2 (url urllib.URL) ! Response {
65- host_name := url.hostname ()
66- mut nport := url.port ().int ()
67- if nport == 0 {
68- nport = 443
69- }
70-
71- address := '${host_name} :${nport} '
72-
73- mut client := v2 .new_client (address) or { return error ('HTTP/2 connection failed: ${err} ' ) }
74-
75- defer {
76- client.close ()
77- }
78-
79- v2_req := v2 .Request{
80- method: v2 .Method (req.method)
81- url: build_request_path (url)
82- host: host_name
83- data: req.data
84- header: req.build_client_header ()
85- }
86-
87- v2_resp := client.request (v2_ req) or { return error ('HTTP/2 request failed: ${err} ' ) }
88-
89- actual_resp := if v2 .is_misdirected (v2_ resp) {
90- client.close ()
91- v2 .handle_misdirected (address, v2_ req) or {
92- return error ('HTTP/2 misdirected retry failed: ${err} ' )
93- }
94- } else {
95- v2_ resp
96- }
97-
43+ // maybe_store_alt_svc checks the response for an Alt-Svc header and, if
44+ // present, parses and stores the entries in the Alt-Svc cache.
45+ fn (req &Request) maybe_store_alt_svc (url urllib.URL, resp_header Header) {
9846 if req.alt_svc_cache != unsafe { nil } {
99- if alt_svc_val := actual_resp.header .get_custom ('alt-svc' ) {
47+ if alt_svc_val := resp_header .get_custom ('alt-svc' ) {
10048 entries := parse_alt_svc (alt_svc_val)
10149 if entries.len > 0 {
10250 origin := normalized_origin (url)
@@ -105,15 +53,9 @@ fn (req &Request) do_http2(url urllib.URL) !Response {
10553 }
10654 }
10755 }
108-
109- return Response{
110- body: actual_resp.body
111- status_code: actual_resp.status_code
112- header: actual_resp.header
113- }
11456}
11557
116- fn (req &Request) do_http3 (url urllib.URL) ! Response {
58+ fn (req &Request) do_http2 (url urllib.URL) ! Response {
11759 host_name := url.hostname ()
11860 mut nport := url.port ().int ()
11961 if nport == 0 {
@@ -122,41 +64,38 @@ fn (req &Request) do_http3(url urllib.URL) !Response {
12264
12365 address := '${host_name} :${nport} '
12466
125- mut client := v3 .new_client (address) or { return error ('HTTP/3 connection failed: ${err} ' ) }
67+ mut client := v2 .new_client_with_config (address, v2 .ClientConfig{
68+ verify: req.verify
69+ cert: req.cert
70+ cert_key: req.cert_key
71+ validate: req.validate
72+ in_memory_verification: req.in_memory_verification
73+ }) or { return error ('HTTP/2 connection failed: ${err} ' ) }
12674
12775 defer {
12876 client.close ()
12977 }
13078
131- v3_req := v 3 .Request{
132- method: v 3 .Method (req.method)
79+ v2_req := v 2 .Request{
80+ method: v 2 .Method (req.method)
13381 url: build_request_path (url)
13482 host: host_name
13583 data: req.data
13684 header: req.build_client_header ()
13785 }
13886
139- v3_resp := client.request (v 3_ req ) or { return error ('HTTP/3 request failed: ${err} ' ) }
87+ v2_resp := client.request (v 2_ req ) or { return error ('HTTP/2 request failed: ${err} ' ) }
14088
141- actual_resp := if v 3 .is_misdirected (v 3_ resp ) {
89+ actual_resp := if v 2 .is_misdirected (v 2_ resp ) {
14290 client.close ()
143- v 3 .handle_misdirected (address, v 3_ req ) or {
144- return error ('HTTP/3 misdirected retry failed: ${err} ' )
91+ v 2 .handle_misdirected (address, v 2_ req ) or {
92+ return error ('HTTP/2 misdirected retry failed: ${err} ' )
14593 }
14694 } else {
147- v 3_ resp
95+ v 2_ resp
14896 }
14997
150- if req.alt_svc_cache != unsafe { nil } {
151- if alt_svc_val := actual_resp.header.get_custom ('alt-svc' ) {
152- entries := parse_alt_svc (alt_svc_val)
153- if entries.len > 0 {
154- origin := normalized_origin (url)
155- mut cache := unsafe { req.alt_svc_cache }
156- cache.store (origin, entries)
157- }
158- }
159- }
98+ req.maybe_store_alt_svc (url, actual_resp.header)
16099
161100 return Response{
162101 body: actual_resp.body
0 commit comments