mirror of
https://github.com/fatedier/frp.git
synced 2025-05-08 15:38:27 +00:00
config: add VhostEnableH2C flag to support HTTP/2 cleartext upgrade
This commit is contained in:
parent
8593eff752
commit
0a70a6a2d9
@ -230,6 +230,7 @@ func RegisterServerConfigFlags(cmd *cobra.Command, c *v1.ServerConfig, opts ...R
|
||||
cmd.PersistentFlags().IntVarP(&c.QUICBindPort, "quic_bind_port", "", 0, "quic bind udp port")
|
||||
cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
|
||||
cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
|
||||
cmd.PersistentFlags().BoolVarP(&c.VhostEnableH2C, "vhost_enable_h2c", "", false, "vhost enable h2c")
|
||||
cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port")
|
||||
cmd.PersistentFlags().Int64VarP(&c.VhostHTTPTimeout, "vhost_http_timeout", "", 60, "vhost http response header timeout")
|
||||
cmd.PersistentFlags().StringVarP(&c.WebServer.Addr, "dashboard_addr", "", "0.0.0.0", "dashboard address")
|
||||
|
@ -110,6 +110,7 @@ func Convert_ServerCommonConf_To_v1(conf *ServerCommonConf) *v1.ServerConfig {
|
||||
|
||||
out.ProxyBindAddr = conf.ProxyBindAddr
|
||||
out.VhostHTTPPort = conf.VhostHTTPPort
|
||||
out.VhostEnableH2C = conf.VhostEnableH2C
|
||||
out.VhostHTTPSPort = conf.VhostHTTPSPort
|
||||
out.TCPMuxHTTPConnectPort = conf.TCPMuxHTTPConnectPort
|
||||
out.TCPMuxPassthrough = conf.TCPMuxPassthrough
|
||||
|
@ -61,6 +61,11 @@ type ServerCommonConf struct {
|
||||
// requests. If this value is 0, the server will not listen for HTTP
|
||||
// requests. By default, this value is 0.
|
||||
VhostHTTPPort int `ini:"vhost_http_port" json:"vhost_http_port"`
|
||||
// VhostEnableH2c specifies whether to enable HTTP/2 cleartext upgrade.
|
||||
// By default, this value is false. If enabled, the server will be compatible
|
||||
// with http2 on cleartext, accordingly, the vhost server will use http2
|
||||
// transport to proxy the request.
|
||||
VhostEnableH2C bool `json:"vhostEnableH2C,omitempty"`
|
||||
// VhostHTTPSPort specifies the port that the server listens for HTTPS
|
||||
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
||||
// requests. By default, this value is 0.
|
||||
|
@ -47,6 +47,11 @@ type ServerConfig struct {
|
||||
// VhostHTTPTimeout specifies the response header timeout for the Vhost
|
||||
// HTTP server, in seconds. By default, this value is 60.
|
||||
VhostHTTPTimeout int64 `json:"vhostHTTPTimeout,omitempty"`
|
||||
// VhostEnableH2c specifies whether to enable HTTP/2 cleartext upgrade.
|
||||
// By default, this value is false. If enabled, the server will be compatible
|
||||
// with http2 on cleartext, accordingly, the vhost server will use http2
|
||||
// transport to proxy the request.
|
||||
VhostEnableH2C bool `json:"vhostEnableH2C,omitempty"`
|
||||
// VhostHTTPSPort specifies the port that the server listens for HTTPS
|
||||
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
||||
// requests.
|
||||
|
@ -16,6 +16,7 @@ package vhost
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -29,6 +30,8 @@ import (
|
||||
|
||||
libio "github.com/fatedier/golib/io"
|
||||
"github.com/fatedier/golib/pool"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
|
||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
@ -38,10 +41,11 @@ var ErrNoRouteFound = errors.New("no route found")
|
||||
|
||||
type HTTPReverseProxyOptions struct {
|
||||
ResponseHeaderTimeoutS int64
|
||||
EnableH2C bool
|
||||
}
|
||||
|
||||
type HTTPReverseProxy struct {
|
||||
proxy *httputil.ReverseProxy
|
||||
proxy http.Handler
|
||||
vhostRouter *Routers
|
||||
|
||||
responseHeaderTimeout time.Duration
|
||||
@ -55,6 +59,40 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,
|
||||
vhostRouter: vhostRouter,
|
||||
}
|
||||
|
||||
var transport http.RoundTripper
|
||||
// Create a connection to one proxy routed by route policy.
|
||||
transport = &http.Transport{
|
||||
ResponseHeaderTimeout: rp.responseHeaderTimeout,
|
||||
IdleConnTimeout: 60 * time.Second,
|
||||
MaxIdleConnsPerHost: 5,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return rp.CreateConnection(ctx.Value(RouteInfoKey).(*RequestRouteInfo), true)
|
||||
},
|
||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||
// Use proxy mode if there is host in HTTP first request line.
|
||||
// GET http://example.com/ HTTP/1.1
|
||||
// Host: example.com
|
||||
//
|
||||
// Normal:
|
||||
// GET / HTTP/1.1
|
||||
// Host: example.com
|
||||
urlHost := req.Context().Value(RouteInfoKey).(*RequestRouteInfo).URLHost
|
||||
if urlHost != "" {
|
||||
return req.URL, nil
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
if option.EnableH2C {
|
||||
transport = &http2.Transport{
|
||||
AllowHTTP: true,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
|
||||
return rp.CreateConnection(ctx.Value(RouteInfoKey).(*RequestRouteInfo), true)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
proxy := &httputil.ReverseProxy{
|
||||
// Modify incoming requests by route policies.
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
@ -101,29 +139,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// Create a connection to one proxy routed by route policy.
|
||||
Transport: &http.Transport{
|
||||
ResponseHeaderTimeout: rp.responseHeaderTimeout,
|
||||
IdleConnTimeout: 60 * time.Second,
|
||||
MaxIdleConnsPerHost: 5,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return rp.CreateConnection(ctx.Value(RouteInfoKey).(*RequestRouteInfo), true)
|
||||
},
|
||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||
// Use proxy mode if there is host in HTTP first request line.
|
||||
// GET http://example.com/ HTTP/1.1
|
||||
// Host: example.com
|
||||
//
|
||||
// Normal:
|
||||
// GET / HTTP/1.1
|
||||
// Host: example.com
|
||||
urlHost := req.Context().Value(RouteInfoKey).(*RequestRouteInfo).URLHost
|
||||
if urlHost != "" {
|
||||
return req.URL, nil
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
Transport: transport,
|
||||
BufferPool: pool.NewBuffer(32 * 1024),
|
||||
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||
@ -138,7 +154,11 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
_, _ = rw.Write(getNotFoundPageContent())
|
||||
},
|
||||
}
|
||||
rp.proxy = proxy
|
||||
if option.EnableH2C {
|
||||
rp.proxy = h2c.NewHandler(proxy, &http2.Server{})
|
||||
} else {
|
||||
rp.proxy = proxy
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ type serverInfoResp struct {
|
||||
Version string `json:"version"`
|
||||
BindPort int `json:"bindPort"`
|
||||
VhostHTTPPort int `json:"vhostHTTPPort"`
|
||||
VhostEnableH2C bool `json:"vhostEnableH2C"`
|
||||
VhostHTTPSPort int `json:"vhostHTTPSPort"`
|
||||
TCPMuxHTTPConnectPort int `json:"tcpmuxHTTPConnectPort"`
|
||||
KCPBindPort int `json:"kcpBindPort"`
|
||||
@ -111,6 +112,7 @@ func (svr *Service) apiServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||
BindPort: svr.cfg.BindPort,
|
||||
VhostHTTPPort: svr.cfg.VhostHTTPPort,
|
||||
VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
|
||||
VhostEnableH2C: svr.cfg.VhostEnableH2C,
|
||||
TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
|
||||
KCPBindPort: svr.cfg.KCPBindPort,
|
||||
QUICBindPort: svr.cfg.QUICBindPort,
|
||||
|
@ -281,6 +281,7 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
||||
if cfg.VhostHTTPPort > 0 {
|
||||
rp := vhost.NewHTTPReverseProxy(vhost.HTTPReverseProxyOptions{
|
||||
ResponseHeaderTimeoutS: cfg.VhostHTTPTimeout,
|
||||
EnableH2C: cfg.VhostEnableH2C,
|
||||
}, svr.httpVhostRouter)
|
||||
svr.rc.HTTPReverseProxy = rp
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user