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  }