github.com/v2fly/v2ray-core/v4@v4.45.2/transport/internet/http/hub.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package http 5 6 import ( 7 "context" 8 "io" 9 "net/http" 10 "strings" 11 "time" 12 13 "golang.org/x/net/http2" 14 "golang.org/x/net/http2/h2c" 15 16 "github.com/v2fly/v2ray-core/v4/common" 17 "github.com/v2fly/v2ray-core/v4/common/net" 18 http_proto "github.com/v2fly/v2ray-core/v4/common/protocol/http" 19 "github.com/v2fly/v2ray-core/v4/common/serial" 20 "github.com/v2fly/v2ray-core/v4/common/session" 21 "github.com/v2fly/v2ray-core/v4/common/signal/done" 22 "github.com/v2fly/v2ray-core/v4/transport/internet" 23 "github.com/v2fly/v2ray-core/v4/transport/internet/tls" 24 ) 25 26 type Listener struct { 27 server *http.Server 28 handler internet.ConnHandler 29 local net.Addr 30 config *Config 31 locker *internet.FileLocker // for unix domain socket 32 } 33 34 func (l *Listener) Addr() net.Addr { 35 return l.local 36 } 37 38 func (l *Listener) Close() error { 39 if l.locker != nil { 40 l.locker.Release() 41 } 42 return l.server.Close() 43 } 44 45 type flushWriter struct { 46 w io.Writer 47 d *done.Instance 48 } 49 50 func (fw flushWriter) Write(p []byte) (n int, err error) { 51 if fw.d.Done() { 52 return 0, io.ErrClosedPipe 53 } 54 55 n, err = fw.w.Write(p) 56 if f, ok := fw.w.(http.Flusher); ok { 57 f.Flush() 58 } 59 return 60 } 61 62 func (l *Listener) ServeHTTP(writer http.ResponseWriter, request *http.Request) { 63 host := request.Host 64 if !l.config.isValidHost(host) { 65 writer.WriteHeader(404) 66 return 67 } 68 path := l.config.getNormalizedPath() 69 if !strings.HasPrefix(request.URL.Path, path) { 70 writer.WriteHeader(404) 71 return 72 } 73 74 writer.Header().Set("Cache-Control", "no-store") 75 76 for _, httpHeader := range l.config.Header { 77 for _, httpHeaderValue := range httpHeader.Value { 78 writer.Header().Set(httpHeader.Name, httpHeaderValue) 79 } 80 } 81 82 writer.WriteHeader(200) 83 if f, ok := writer.(http.Flusher); ok { 84 f.Flush() 85 } 86 87 remoteAddr := l.Addr() 88 dest, err := net.ParseDestination(request.RemoteAddr) 89 if err != nil { 90 newError("failed to parse request remote addr: ", request.RemoteAddr).Base(err).WriteToLog() 91 } else { 92 remoteAddr = &net.TCPAddr{ 93 IP: dest.Address.IP(), 94 Port: int(dest.Port), 95 } 96 } 97 98 forwardedAddress := http_proto.ParseXForwardedFor(request.Header) 99 if len(forwardedAddress) > 0 && forwardedAddress[0].Family().IsIP() { 100 remoteAddr = &net.TCPAddr{ 101 IP: forwardedAddress[0].IP(), 102 Port: 0, 103 } 104 } 105 106 done := done.New() 107 conn := net.NewConnection( 108 net.ConnectionOutput(request.Body), 109 net.ConnectionInput(flushWriter{w: writer, d: done}), 110 net.ConnectionOnClose(common.ChainedClosable{done, request.Body}), 111 net.ConnectionLocalAddr(l.Addr()), 112 net.ConnectionRemoteAddr(remoteAddr), 113 ) 114 l.handler(conn) 115 <-done.Wait() 116 } 117 118 func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) { 119 httpSettings := streamSettings.ProtocolSettings.(*Config) 120 var listener *Listener 121 if port == net.Port(0) { // unix 122 listener = &Listener{ 123 handler: handler, 124 local: &net.UnixAddr{ 125 Name: address.Domain(), 126 Net: "unix", 127 }, 128 config: httpSettings, 129 } 130 } else { // tcp 131 listener = &Listener{ 132 handler: handler, 133 local: &net.TCPAddr{ 134 IP: address.IP(), 135 Port: int(port), 136 }, 137 config: httpSettings, 138 } 139 } 140 141 var server *http.Server 142 config := tls.ConfigFromStreamSettings(streamSettings) 143 if config == nil { 144 h2s := &http2.Server{} 145 146 server = &http.Server{ 147 Addr: serial.Concat(address, ":", port), 148 Handler: h2c.NewHandler(listener, h2s), 149 ReadHeaderTimeout: time.Second * 4, 150 } 151 } else { 152 server = &http.Server{ 153 Addr: serial.Concat(address, ":", port), 154 TLSConfig: config.GetTLSConfig(tls.WithNextProto("h2")), 155 Handler: listener, 156 ReadHeaderTimeout: time.Second * 4, 157 } 158 } 159 160 if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { 161 newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx)) 162 } 163 164 listener.server = server 165 go func() { 166 var streamListener net.Listener 167 var err error 168 if port == net.Port(0) { // unix 169 streamListener, err = internet.ListenSystem(ctx, &net.UnixAddr{ 170 Name: address.Domain(), 171 Net: "unix", 172 }, streamSettings.SocketSettings) 173 if err != nil { 174 newError("failed to listen on ", address).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx)) 175 return 176 } 177 locker := ctx.Value(address.Domain()) 178 if locker != nil { 179 listener.locker = locker.(*internet.FileLocker) 180 } 181 } else { // tcp 182 streamListener, err = internet.ListenSystem(ctx, &net.TCPAddr{ 183 IP: address.IP(), 184 Port: int(port), 185 }, streamSettings.SocketSettings) 186 if err != nil { 187 newError("failed to listen on ", address, ":", port).Base(err).AtError().WriteToLog(session.ExportIDToError(ctx)) 188 return 189 } 190 } 191 192 if config == nil { 193 err = server.Serve(streamListener) 194 if err != nil { 195 newError("stopping serving H2C").Base(err).WriteToLog(session.ExportIDToError(ctx)) 196 } 197 } else { 198 err = server.ServeTLS(streamListener, "", "") 199 if err != nil { 200 newError("stopping serving TLS").Base(err).WriteToLog(session.ExportIDToError(ctx)) 201 } 202 } 203 }() 204 205 return listener, nil 206 } 207 208 func init() { 209 common.Must(internet.RegisterTransportListener(protocolName, Listen)) 210 }