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