v2 / vlib / net / http / backend.c.v
73 lines · 68 sloc · 2.41 KB · 2cc4d27d6292f4dddeb277b24ec3d176ce1eb716
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module http
5
6import net.ssl
7import strings
8
9fn (req &Request) ssl_do(port int, method Method, host_name string, path string, data string, header Header) !Response {
10 $if windows && !no_vschannel ? {
11 return vschannel_ssl_do(req, port, method, host_name, path, data, header)
12 }
13 return net_ssl_do(req, port, method, host_name, path, data, header)
14}
15
16fn net_ssl_do(req &Request, port int, method Method, host_name string, path string, data string, header Header) !Response {
17 mut retries := 0
18 req_headers := req.build_request_headers_with(method, host_name, port, path, data, header)
19 $if trace_http_request ? {
20 eprint('> ')
21 eprint(req_headers)
22 eprintln('')
23 }
24 for {
25 mut ssl_conn := ssl.new_ssl_conn(
26 verify: req.verify
27 cert: req.cert
28 cert_key: req.cert_key
29 validate: req.validate
30 in_memory_verification: req.in_memory_verification
31 )!
32 ssl_conn.dial(host_name, port) or {
33 retries++
34 if is_no_need_retry_error(err.code()) || retries >= req.max_retries {
35 return err
36 }
37 continue
38 }
39 // Propagate the request's read timeout into the SSL backend.
40 // Without this, mbedtls keeps its init-time default and openssl falls back to no
41 // timeout at all on a stalled socket — see issue surfaced by macOS arm64 + tcc CI hangs.
42 if req.read_timeout > 0 {
43 ssl_conn.set_read_timeout(req.read_timeout)
44 }
45 return req.do_request(req_headers, mut ssl_conn)!
46 }
47 return error('http.net_ssl_do: exhausted retries')
48}
49
50fn read_from_ssl_connection_cb(con voidptr, buf &u8, bufsize int) !int {
51 mut ssl_conn := unsafe { &ssl.SSLConn(con) }
52 return ssl_conn.socket_read_into_ptr(buf, bufsize)
53}
54
55fn (req &Request) do_request(req_headers string, mut ssl_conn ssl.SSLConn) !Response {
56 defer {
57 ssl_conn.shutdown() or {}
58 }
59 ssl_conn.write_string(req_headers) or { return err }
60 mut content := strings.new_builder(4096)
61 response_info := req.receive_all_data_from_cb_in_builder(mut content, voidptr(ssl_conn),
62 read_from_ssl_connection_cb)!
63 response_text := content.str()
64 $if trace_http_response ? {
65 eprint('< ')
66 eprint(response_text)
67 eprintln('')
68 }
69 if req.on_finish != unsafe { nil } {
70 req.on_finish(req, u64(response_text.len))!
71 }
72 return parse_received_response(response_text, response_info)
73}
74