-
Notifications
You must be signed in to change notification settings - Fork 129
/
http.go
130 lines (108 loc) · 3.06 KB
/
http.go
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package winrm
import (
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"net/url"
"strings"
"time"
"github.com/masterzen/winrm/soap"
)
var soapXML = "application/soap+xml"
// body func reads the response body and return it as a string
func body(response *http.Response) (string, error) {
// if we received the content we expected
if strings.Contains(response.Header.Get("Content-Type"), "application/soap+xml") {
body, err := io.ReadAll(response.Body)
defer func() {
// defer can modify the returned value before
// it is actually passed to the calling statement
if errClose := response.Body.Close(); errClose != nil && err == nil {
err = errClose
}
}()
if err != nil {
return "", fmt.Errorf("error while reading request body %w", err)
}
return string(body), nil
}
return "", fmt.Errorf("invalid content type")
}
type clientRequest struct {
transport http.RoundTripper
dial func(network, addr string) (net.Conn, error)
proxyfunc func(req *http.Request) (*url.URL, error)
}
func (c *clientRequest) Transport(endpoint *Endpoint) error {
dial := (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial
if c.dial != nil {
dial = c.dial
}
proxyfunc := http.ProxyFromEnvironment
if c.proxyfunc != nil {
proxyfunc = c.proxyfunc
}
//nolint:gosec
transport := &http.Transport{
Proxy: proxyfunc,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: endpoint.Insecure,
ServerName: endpoint.TLSServerName,
},
Dial: dial,
ResponseHeaderTimeout: endpoint.Timeout,
}
if endpoint.CACert != nil && len(endpoint.CACert) > 0 {
certPool, err := readCACerts(endpoint.CACert)
if err != nil {
return err
}
transport.TLSClientConfig.RootCAs = certPool
}
c.transport = transport
return nil
}
// Post make post to the winrm soap service
func (c clientRequest) Post(client *Client, request *soap.SoapMessage) (string, error) {
httpClient := &http.Client{Transport: c.transport}
//nolint:noctx
req, err := http.NewRequest("POST", client.url, strings.NewReader(request.String()))
if err != nil {
return "", fmt.Errorf("impossible to create http request %w", err)
}
req.Header.Set("Content-Type", soapXML+";charset=UTF-8")
req.SetBasicAuth(client.username, client.password)
resp, err := httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("unknown error %w", err)
}
body, err := body(resp)
if err != nil {
return "", fmt.Errorf("http response error: %d - %w", resp.StatusCode, err)
}
// if we have different 200 http status code
// we must replace the error
defer func() {
if resp.StatusCode != 200 {
body, err = "", fmt.Errorf("http error %d: %s", resp.StatusCode, body)
}
}()
return body, err
}
// NewClientWithDial NewClientWithDial
func NewClientWithDial(dial func(network, addr string) (net.Conn, error)) *clientRequest {
return &clientRequest{
dial: dial,
}
}
// NewClientWithProxyFunc NewClientWithProxyFunc
func NewClientWithProxyFunc(proxyfunc func(req *http.Request) (*url.URL, error)) *clientRequest {
return &clientRequest{
proxyfunc: proxyfunc,
}
}