forked from jnewmano/grpc-json-proxy
/
proxy.go
126 lines (107 loc) · 2.44 KB
/
proxy.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
package main
import (
"bytes"
"crypto/tls"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"time"
"golang.org/x/net/http2"
)
const (
headerContentLength = "Content-Length"
headerGRPCMessage = "Grpc-Message"
headerGRPCStatusCode = "Grpc-Status"
headerUseInsecure = "Grpc-Insecure"
defaultClientTimeout = time.Second * 60
)
// Transport struct for intercepting grpc+json requests
type Transport struct {
HTTPClient *http.Client
H2Client *http.Client
H2NoTLSClient *http.Client
}
/*
NewProxy returns a configured reverse proxy
to handle grpc+json requests
*/
func NewProxy() *httputil.ReverseProxy {
h2NoTLSClient := &http.Client{
// Skip TLS dial
Transport: &http2.Transport{
AllowHTTP: true,
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
return net.Dial(netw, addr)
},
},
Timeout: defaultClientTimeout,
}
h2Client := &http.Client{
Transport: &http2.Transport{},
Timeout: defaultClientTimeout,
}
client := &http.Client{
Timeout: defaultClientTimeout,
}
t := &Transport{
HTTPClient: client,
H2Client: h2Client,
H2NoTLSClient: h2NoTLSClient,
}
u := url.URL{}
p := httputil.NewSingleHostReverseProxy(&u)
p.Director = t.director
p.Transport = t
return p
}
func (t Transport) director(r *http.Request) {
}
/*
RoundTrip handles processing the incoming request
and outgoing response for grpc+json detection
*/
func (t Transport) RoundTrip(r *http.Request) (*http.Response, error) {
isGRPC := false
if isJSONGRPC(r) {
if r.Method != http.MethodPost {
buff := bytes.NewBufferString("HTTP method must be POST")
resp := &http.Response{
StatusCode: 502,
Body: ioutil.NopCloser(buff),
}
return resp, nil
}
isGRPC = true
r = modifyRequestToJSONgRPC(r)
}
client := t.HTTPClient
if isGRPC {
if r.Header.Get(headerUseInsecure) == "true" {
client = t.H2NoTLSClient
} else {
r.URL.Scheme = "https"
client = t.H2Client
}
}
// clear requestURI, set in call to director
r.RequestURI = ""
log.Printf("proxying request url=[%s] isJSONGRPC=[%t]\n", r.URL.String(), isGRPC)
resp, err := client.Do(r)
if err != nil {
log.Printf("unable to do request err=[%s]", err)
buff := bytes.NewBuffer(nil)
buff.WriteString(err.Error())
resp = &http.Response{
StatusCode: 502,
Body: ioutil.NopCloser(buff),
}
return resp, nil
}
if isGRPC {
return handleGRPCResponse(resp)
}
return resp, err
}