v2 / vlib / net / http / util.v
78 lines · 68 sloc · 2.53 KB · fe02feffa68b9cce558cae5cf57b3e7b5af32689
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
7
8const vschannel_connect_failed_msg = 'Failed to connect to host'
9
10const vschannel_sec_e_internal_error = -2146893052
11
12// A fast version that avoids allocations in s.split()
13// returns the locations of the 2 spaces
14// "GET / HTTP/1.1" => ["GET" "/" "HTTP/1.1"]
15fn fast_request_words(line string) (int, int) {
16 space1 := line.index(' ') or { return 0, 0 }
17 space2 := line.index_after(' ', space1 + 1) or { return 0, 0 }
18 return space1, space2
19}
20
21fn vschannel_error_message(err_code int) string {
22 $if windows {
23 if err_code >= int(net.WsaError.wsaeintr)
24 && err_code <= int(net.WsaError.wsa_ipsec_name_policy_error) {
25 return '(${err_code}) ${net.wsa_error(err_code)}'
26 }
27 }
28 if err_code < 0 {
29 return '0x${u32(err_code):08x}'
30 }
31 return '${err_code}'
32}
33
34fn vschannel_connect_error(err_code int) IError {
35 if err_code == 0 {
36 return error(vschannel_connect_failed_msg)
37 }
38 return error_with_code(vschannel_connect_failed_msg, err_code)
39}
40
41fn vschannel_should_report_connect_failure(err_code int) bool {
42 if err_code == vschannel_sec_e_internal_error {
43 return true
44 }
45 $if windows {
46 return err_code in [int(net.WsaError.wsaenotconn), int(net.WsaError.wsaenetdown),
47 int(net.WsaError.wsaenetunreach), int(net.WsaError.wsaetimedout),
48 int(net.WsaError.wsaeconnrefused), int(net.WsaError.wsaehostdown),
49 int(net.WsaError.wsaehostunreach), int(net.WsaError.wsahost_not_found),
50 int(net.WsaError.wsatry_again), int(net.WsaError.wsano_recovery),
51 int(net.WsaError.wsano_data)]
52 }
53 return false
54}
55
56fn vschannel_looks_like_connect_failure_response(response_text string) bool {
57 trimmed := response_text.trim_space()
58 return trimmed.starts_with('Error ') && (trimmed.contains('sending data to server')
59 || trimmed.contains('Error performing handshake'))
60}
61
62fn vschannel_request_error(err_code int) IError {
63 if vschannel_should_report_connect_failure(err_code) {
64 return vschannel_connect_error(err_code)
65 }
66 return error_with_code('http: vschannel request failed: ${vschannel_error_message(err_code)}',
67 err_code)
68}
69
70fn vschannel_parse_response(response_text string, err_code int) !Response {
71 if response_text.len < 5 || response_text[..5].to_lower() != 'http/' {
72 if vschannel_should_report_connect_failure(err_code)
73 || vschannel_looks_like_connect_failure_response(response_text) {
74 return vschannel_connect_error(err_code)
75 }
76 }
77 return parse_response(response_text)
78}
79