117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"github.com/golang/glog"
|
|
"golang.org/x/net/http2"
|
|
"io"
|
|
//"net"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
)
|
|
|
|
func init() {
|
|
if glog.V(LDEBUG) {
|
|
http2.VerboseLogs = true
|
|
}
|
|
}
|
|
|
|
func handlerHttp2Request(w http.ResponseWriter, req *http.Request) {
|
|
glog.V(LINFO).Infof("[http2] %s - %s", req.RemoteAddr, req.Host)
|
|
if glog.V(LDEBUG) {
|
|
dump, _ := httputil.DumpRequest(req, false)
|
|
glog.Infoln(string(dump))
|
|
}
|
|
|
|
c, err := Connect(req.Host)
|
|
if err != nil {
|
|
glog.V(LWARNING).Infof("[http2] %s -> %s : %s", req.RemoteAddr, req.Host, err)
|
|
w.Header().Set("Proxy-Agent", "gost/"+Version)
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
if fw, ok := w.(http.Flusher); ok {
|
|
fw.Flush()
|
|
}
|
|
return
|
|
}
|
|
defer c.Close()
|
|
|
|
glog.V(LINFO).Infof("[http2] %s <-> %s", req.RemoteAddr, req.Host)
|
|
errc := make(chan error, 2)
|
|
|
|
if req.Method == http.MethodConnect {
|
|
w.Header().Set("Proxy-Agent", "gost/"+Version)
|
|
w.WriteHeader(http.StatusOK)
|
|
if fw, ok := w.(http.Flusher); ok {
|
|
fw.Flush()
|
|
}
|
|
|
|
// compatible with HTTP 1.x
|
|
if hj, ok := w.(http.Hijacker); ok && req.ProtoMajor == 1 {
|
|
// we take over the underly connection
|
|
conn, _, err := hj.Hijack()
|
|
if err != nil {
|
|
glog.V(LWARNING).Infof("[http2] %s -> %s : %s", req.RemoteAddr, req.Host, err)
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
go Pipe(conn, c, errc)
|
|
go Pipe(c, conn, errc)
|
|
} else {
|
|
go Pipe(req.Body, c, errc)
|
|
go Pipe(c, flushWriter{w}, errc)
|
|
}
|
|
|
|
select {
|
|
case <-errc:
|
|
// glog.V(LWARNING).Infoln("exit", err)
|
|
}
|
|
} else {
|
|
req.Header.Set("Connection", "Keep-Alive")
|
|
if err = req.Write(c); err != nil {
|
|
glog.V(LWARNING).Infof("[http2] %s -> %s : %s", req.RemoteAddr, req.Host, err)
|
|
return
|
|
}
|
|
|
|
resp, err := http.ReadResponse(bufio.NewReader(c), req)
|
|
if err != nil {
|
|
glog.V(LWARNING).Infoln(err)
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
for k, v := range resp.Header {
|
|
for _, vv := range v {
|
|
w.Header().Add(k, vv)
|
|
}
|
|
}
|
|
w.WriteHeader(resp.StatusCode)
|
|
|
|
if _, err := io.Copy(flushWriter{w}, resp.Body); err != nil {
|
|
glog.V(LWARNING).Infof("[http2] %s <- %s : %s", req.RemoteAddr, req.Host, err)
|
|
}
|
|
}
|
|
|
|
glog.V(LINFO).Infof("[http2] %s >-< %s", req.RemoteAddr, req.Host)
|
|
}
|
|
|
|
func handleHttp2Transport(w http.ResponseWriter, req *http.Request) {
|
|
glog.V(LINFO).Infof("[http2] %s - %s", req.RemoteAddr, req.Host)
|
|
if glog.V(LDEBUG) {
|
|
dump, _ := httputil.DumpRequest(req, false)
|
|
glog.Infoln(string(dump))
|
|
}
|
|
}
|
|
|
|
type flushWriter struct {
|
|
w io.Writer
|
|
}
|
|
|
|
func (fw flushWriter) Write(p []byte) (n int, err error) {
|
|
n, err = fw.w.Write(p)
|
|
if f, ok := fw.w.(http.Flusher); ok {
|
|
f.Flush()
|
|
}
|
|
return
|
|
}
|