forked from neex/http2smugl
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp_client.go
More file actions
115 lines (96 loc) · 2.28 KB
/
http_client.go
File metadata and controls
115 lines (96 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"fmt"
"net/url"
"strconv"
"time"
)
type RequestParams struct {
Target *url.URL
Method, ConnectAddr string
Headers Headers
NoAutoHeaders bool
NoUserAgent bool
Body []byte
Timeout time.Duration
AddContentLength bool
}
type HTTPMessage struct {
Headers Headers
Body []byte
}
type ConnDropError struct {
Wrapped error
}
func (r ConnDropError) Error() string {
return fmt.Sprintf("server dropped connection, error=%v", r.Wrapped)
}
type TimeoutError struct {
}
func (t TimeoutError) Error() string {
return "timeout"
}
func (t TimeoutError) Timeout() bool {
return true
}
func (t TimeoutError) Temporary() bool {
return false
}
func DoRequest(params *RequestParams) (*HTTPMessage, error) {
var proto string
switch params.Target.Scheme {
case "https", "https+http2":
proto = "http2"
case "https+h3":
proto = "http3"
default:
return nil, fmt.Errorf(`invalid scheme: %#v`, params.Target.Scheme)
}
var headers Headers
if params.NoAutoHeaders {
headers = params.Headers
} else {
if params.Target.Path == "" {
params.Target.Path = "/"
}
headers = Headers{
{":authority", params.Target.Host},
{":method", params.Method},
{":path", params.Target.Path},
{":scheme", "https"},
}
if !params.NoUserAgent {
headers = append(headers, Header{"user-agent", "Mozilla/5.0"})
}
toSkip := make(map[string]struct{})
for i := range headers {
h := &headers[i]
if v, ok := params.Headers.Get(h.Name); ok {
h.Value = v
toSkip[h.Name] = struct{}{}
}
}
for _, h := range params.Headers {
if _, ok := toSkip[h.Name]; ok {
delete(toSkip, h.Name)
continue
}
headers = append(headers, h)
}
}
if params.AddContentLength {
headers = append(headers, Header{"content-length", strconv.Itoa(len(params.Body))})
}
targetAddr := params.ConnectAddr
if targetAddr == "" {
targetAddr = params.Target.Host
}
switch proto {
case "http2":
return sendHTTP2Request(targetAddr, params.Target.Host, false, &HTTPMessage{headers, params.Body}, params.Timeout)
case "http3":
return sendHTTP3Request(targetAddr, params.Target.Host, false, &HTTPMessage{headers, params.Body}, params.Timeout)
default:
panic(fmt.Errorf("invalid proto: %#v", proto))
}
}