mirror of
https://github.com/telanflow/mps.git
synced 2025-09-26 20:41:25 +08:00
116 lines
2.6 KiB
Go
116 lines
2.6 KiB
Go
package mps
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
)
|
|
|
|
// The basic proxy type. Implements http.Handler.
|
|
type HttpProxy struct {
|
|
// Handles Connect requests use the TunnelHandler by default
|
|
HandleConnect http.Handler
|
|
|
|
// HTTP requests use the ForwardHandler by default
|
|
HttpHandler http.Handler
|
|
|
|
// HTTP requests use the ReverseHandler by default
|
|
ReverseHandler http.Handler
|
|
|
|
// Client request Context
|
|
Ctx *Context
|
|
}
|
|
|
|
func NewHttpProxy() *HttpProxy {
|
|
// default Context with Proxy
|
|
ctx := NewContext()
|
|
return &HttpProxy{
|
|
Ctx: ctx,
|
|
// default handles Connect method
|
|
HandleConnect: &TunnelHandler{Ctx: ctx},
|
|
// default handles HTTP request
|
|
HttpHandler: &ForwardHandler{Ctx: ctx},
|
|
// default Reverse proxy
|
|
ReverseHandler: &ReverseHandler{Ctx: ctx},
|
|
}
|
|
}
|
|
|
|
// Standard net/http function.
|
|
func (proxy *HttpProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
if req.Method == http.MethodConnect {
|
|
proxy.HandleConnect.ServeHTTP(rw, req)
|
|
return
|
|
}
|
|
|
|
// reverse proxy http request for example:
|
|
// GET / HTTP/1.1
|
|
// Host: www.example.com
|
|
// Connection: keep-alive
|
|
//
|
|
// forward proxy http request for example :
|
|
// GET http://www.example.com/ HTTP/1.1
|
|
// Host: www.example.com
|
|
// Proxy-Connection: keep-alive
|
|
//
|
|
// Determines whether the path is absolute
|
|
if !req.URL.IsAbs() {
|
|
proxy.ReverseHandler.ServeHTTP(rw, req)
|
|
} else {
|
|
proxy.HttpHandler.ServeHTTP(rw, req)
|
|
}
|
|
}
|
|
|
|
// Use registers an Middleware to proxy
|
|
func (proxy *HttpProxy) Use(middleware ...Middleware) {
|
|
proxy.Ctx.Use(middleware...)
|
|
}
|
|
|
|
// UseFunc registers an MiddlewareFunc to proxy
|
|
func (proxy *HttpProxy) UseFunc(fus ...MiddlewareFunc) {
|
|
proxy.Ctx.UseFunc(fus...)
|
|
}
|
|
|
|
// OnRequest filter requests through Filters
|
|
func (proxy *HttpProxy) OnRequest(filters ...Filter) *ReqFilterGroup {
|
|
return &ReqFilterGroup{ctx: proxy.Ctx, filters: filters}
|
|
}
|
|
|
|
// OnResponse filter response through Filters
|
|
func (proxy *HttpProxy) OnResponse(filters ...Filter) *RespFilterGroup {
|
|
return &RespFilterGroup{ctx: proxy.Ctx, filters: filters}
|
|
}
|
|
|
|
// Transport get http.Transport instance
|
|
func (proxy *HttpProxy) Transport() *http.Transport {
|
|
return proxy.Ctx.Transport
|
|
}
|
|
|
|
// hijacker an HTTP handler to take over the connection.
|
|
func hijacker(rw http.ResponseWriter) (conn net.Conn, err error) {
|
|
hij, ok := rw.(http.Hijacker)
|
|
if !ok {
|
|
err = errors.New("not a hijacker")
|
|
return
|
|
}
|
|
|
|
conn, _, err = hij.Hijack()
|
|
if err != nil {
|
|
err = fmt.Errorf("cannot hijack connection %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
func copyHeaders(dst, src http.Header, keepDestHeaders bool) {
|
|
if !keepDestHeaders {
|
|
for k := range dst {
|
|
dst.Del(k)
|
|
}
|
|
}
|
|
for k, vs := range src {
|
|
for _, v := range vs {
|
|
dst.Add(k, v)
|
|
}
|
|
}
|
|
}
|