http2 support

This commit is contained in:
Vladislav Yarmak 2020-05-24 15:24:11 +03:00
parent 118546f86a
commit fc59f801d7
3 changed files with 53 additions and 14 deletions

View File

@ -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
} }

View File

@ -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,

View File

@ -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{