http2 support
This commit is contained in:
parent
118546f86a
commit
fc59f801d7
35
handler.go
35
handler.go
|
@ -38,19 +38,30 @@ func (s *ProxyHandler) HandleTunnel(wr http.ResponseWriter, req *http.Request) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
|
||||||
// Upgrade client connection
|
if req.ProtoMajor == 0 || req.ProtoMajor == 1 {
|
||||||
localconn, _, err := hijack(wr)
|
// Upgrade client connection
|
||||||
if err != nil {
|
localconn, _, err := hijack(wr)
|
||||||
s.logger.Error("Can't hijack client connection: %v", err)
|
if err != nil {
|
||||||
http.Error(wr, "Can't hijack client connection", http.StatusInternalServerError)
|
s.logger.Error("Can't hijack client connection: %v", err)
|
||||||
|
http.Error(wr, "Can't hijack client connection", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer localconn.Close()
|
||||||
|
|
||||||
|
// Inform client connection is built
|
||||||
|
fmt.Fprintf(localconn, "HTTP/%d.%d 200 OK\r\n\r\n", req.ProtoMajor, req.ProtoMinor)
|
||||||
|
|
||||||
|
proxy(req.Context(), localconn, conn)
|
||||||
|
} else if req.ProtoMajor == 2 {
|
||||||
|
wr.Header()["Date"] = nil
|
||||||
|
wr.WriteHeader(http.StatusOK)
|
||||||
|
flush(wr)
|
||||||
|
proxyh2(req.Context(), req.Body, wr, conn)
|
||||||
|
} else {
|
||||||
|
s.logger.Error("Unsupported protocol version: %s", req.Proto)
|
||||||
|
http.Error(wr, "Unsupported protocol version.", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer localconn.Close()
|
|
||||||
|
|
||||||
// Inform client connection is built
|
|
||||||
fmt.Fprintf(localconn, "HTTP/%d.%d 200 OK\r\n\r\n", req.ProtoMajor, req.ProtoMinor)
|
|
||||||
|
|
||||||
proxy(req.Context(), localconn, conn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProxyHandler) HandleRequest(wr http.ResponseWriter, req *http.Request) {
|
func (s *ProxyHandler) HandleRequest(wr http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -71,7 +82,7 @@ func (s *ProxyHandler) HandleRequest(wr http.ResponseWriter, req *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProxyHandler) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
func (s *ProxyHandler) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
|
||||||
s.logger.Info("Request: %v %v %v", req.RemoteAddr, req.Method, req.URL)
|
s.logger.Info("Request: %v %v %v %v", req.RemoteAddr, req.Proto, req.Method, req.URL)
|
||||||
if !s.auth.Validate(wr, req) {
|
if !s.auth.Validate(wr, req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
2
main.go
2
main.go
|
@ -7,7 +7,6 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"time"
|
"time"
|
||||||
"net/http"
|
"net/http"
|
||||||
"crypto/tls"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func perror(msg string) {
|
func perror(msg string) {
|
||||||
|
@ -67,7 +66,6 @@ func run() int {
|
||||||
Addr: args.bind_address,
|
Addr: args.bind_address,
|
||||||
Handler: NewProxyHandler(args.timeout, auth, proxyLogger),
|
Handler: NewProxyHandler(args.timeout, auth, proxyLogger),
|
||||||
ErrorLog: log.New(logWriter, "HTTPSRV : ", log.LstdFlags | log.Lshortfile),
|
ErrorLog: log.New(logWriter, "HTTPSRV : ", log.LstdFlags | log.Lshortfile),
|
||||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)), // No HTTP/2
|
|
||||||
ReadTimeout: 0,
|
ReadTimeout: 0,
|
||||||
ReadHeaderTimeout: 0,
|
ReadHeaderTimeout: 0,
|
||||||
WriteTimeout: 0,
|
WriteTimeout: 0,
|
||||||
|
|
30
utils.go
30
utils.go
|
@ -42,6 +42,36 @@ func proxy(ctx context.Context, left, right net.Conn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func proxyh2(ctx context.Context, leftreader io.ReadCloser, leftwriter io.Writer, right net.Conn) {
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
ltr := func (dst net.Conn, src io.Reader) {
|
||||||
|
defer wg.Done()
|
||||||
|
io.Copy(dst, src)
|
||||||
|
dst.Close()
|
||||||
|
}
|
||||||
|
rtl := func (dst io.Writer, src io.Reader) {
|
||||||
|
defer wg.Done()
|
||||||
|
copyBody(dst, src)
|
||||||
|
}
|
||||||
|
wg.Add(2)
|
||||||
|
go ltr(right, leftreader)
|
||||||
|
go rtl(leftwriter, right)
|
||||||
|
groupdone := make(chan struct{}, 1)
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
groupdone <-struct{}{}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
leftreader.Close()
|
||||||
|
right.Close()
|
||||||
|
case <-groupdone:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
<-groupdone
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Hop-by-hop headers. These are removed when sent to the backend.
|
// Hop-by-hop headers. These are removed when sent to the backend.
|
||||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
|
||||||
var hopHeaders = []string{
|
var hopHeaders = []string{
|
||||||
|
|
Loading…
Reference in New Issue