github.com/v2fly/v2ray-core/v4@v4.45.2/app/browserforwarder/forwarder.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package browserforwarder 5 6 import ( 7 "bytes" 8 "context" 9 "io" 10 "net/http" 11 "strings" 12 "time" 13 14 "github.com/v2fly/BrowserBridge/handler" 15 16 "github.com/v2fly/v2ray-core/v4/common" 17 "github.com/v2fly/v2ray-core/v4/common/net" 18 "github.com/v2fly/v2ray-core/v4/common/platform/securedload" 19 "github.com/v2fly/v2ray-core/v4/features/extension" 20 "github.com/v2fly/v2ray-core/v4/transport/internet" 21 ) 22 23 //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen 24 25 type Forwarder struct { 26 ctx context.Context 27 28 forwarder *handler.HTTPHandle 29 httpserver *http.Server 30 31 config *Config 32 } 33 34 func (f *Forwarder) ServeHTTP(writer http.ResponseWriter, request *http.Request) { 35 requestPath := request.URL.Path[1:] 36 37 switch requestPath { 38 case "": 39 fallthrough 40 case "index.js": 41 BridgeResource(writer, request, requestPath) 42 case "link": 43 f.forwarder.ServeBridge(writer, request) 44 } 45 } 46 47 func (f *Forwarder) DialWebsocket(url string, header http.Header) (io.ReadWriteCloser, error) { 48 protocolHeader := false 49 protocolHeaderValue := "" 50 unsupportedHeader := false 51 for k, v := range header { 52 if k == "Sec-Websocket-Protocol" { 53 protocolHeader = true 54 protocolHeaderValue = v[0] 55 } else { 56 unsupportedHeader = true 57 } 58 } 59 if unsupportedHeader { 60 return nil, newError("unsupported header used, only Sec-Websocket-Protocol is supported for forwarder") 61 } 62 if !protocolHeader { 63 return f.forwarder.Dial(url) 64 } 65 return f.forwarder.Dial2(url, protocolHeaderValue) 66 } 67 68 func (f *Forwarder) Type() interface{} { 69 return extension.BrowserForwarderType() 70 } 71 72 func (f *Forwarder) Start() error { 73 if f.config.ListenAddr != "" { 74 f.forwarder = handler.NewHttpHandle() 75 f.httpserver = &http.Server{Handler: f} 76 77 var listener net.Listener 78 var err error 79 address := net.ParseAddress(f.config.ListenAddr) 80 81 switch { 82 case address.Family().IsIP(): 83 listener, err = internet.ListenSystem(f.ctx, &net.TCPAddr{IP: address.IP(), Port: int(f.config.ListenPort)}, nil) 84 case strings.EqualFold(address.Domain(), "localhost"): 85 listener, err = internet.ListenSystem(f.ctx, &net.TCPAddr{IP: net.IP{127, 0, 0, 1}, Port: int(f.config.ListenPort)}, nil) 86 default: 87 return newError("forwarder cannot listen on the address: ", address) 88 } 89 if err != nil { 90 return newError("forwarder cannot listen on the port ", f.config.ListenPort).Base(err) 91 } 92 93 go func() { 94 if err := f.httpserver.Serve(listener); err != nil { 95 newError("cannot serve http forward server").Base(err).WriteToLog() 96 } 97 }() 98 } 99 return nil 100 } 101 102 func (f *Forwarder) Close() error { 103 if f.httpserver != nil { 104 return f.httpserver.Close() 105 } 106 return nil 107 } 108 109 func BridgeResource(rw http.ResponseWriter, r *http.Request, path string) { 110 content := path 111 if content == "" { 112 content = "index.html" 113 } 114 data, err := securedload.GetAssetSecured("browserforwarder/" + content) 115 if err != nil { 116 err = newError("cannot load necessary resources").Base(err) 117 http.Error(rw, err.Error(), http.StatusForbidden) 118 return 119 } 120 121 http.ServeContent(rw, r, path, time.Now(), bytes.NewReader(data)) 122 } 123 124 func NewForwarder(ctx context.Context, cfg *Config) *Forwarder { 125 return &Forwarder{config: cfg, ctx: ctx} 126 } 127 128 func init() { 129 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) { 130 return NewForwarder(ctx, cfg.(*Config)), nil 131 })) 132 }