mirror of
https://github.com/fatedier/frp.git
synced 2025-05-25 17:28: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().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().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().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().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().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")
|
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.ProxyBindAddr = conf.ProxyBindAddr
|
||||||
out.VhostHTTPPort = conf.VhostHTTPPort
|
out.VhostHTTPPort = conf.VhostHTTPPort
|
||||||
|
out.VhostEnableH2C = conf.VhostEnableH2C
|
||||||
out.VhostHTTPSPort = conf.VhostHTTPSPort
|
out.VhostHTTPSPort = conf.VhostHTTPSPort
|
||||||
out.TCPMuxHTTPConnectPort = conf.TCPMuxHTTPConnectPort
|
out.TCPMuxHTTPConnectPort = conf.TCPMuxHTTPConnectPort
|
||||||
out.TCPMuxPassthrough = conf.TCPMuxPassthrough
|
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. If this value is 0, the server will not listen for HTTP
|
||||||
// requests. By default, this value is 0.
|
// requests. By default, this value is 0.
|
||||||
VhostHTTPPort int `ini:"vhost_http_port" json:"vhost_http_port"`
|
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
|
// VhostHTTPSPort specifies the port that the server listens for HTTPS
|
||||||
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
||||||
// requests. By default, this value is 0.
|
// requests. By default, this value is 0.
|
||||||
|
@ -47,6 +47,11 @@ type ServerConfig struct {
|
|||||||
// VhostHTTPTimeout specifies the response header timeout for the Vhost
|
// VhostHTTPTimeout specifies the response header timeout for the Vhost
|
||||||
// HTTP server, in seconds. By default, this value is 60.
|
// HTTP server, in seconds. By default, this value is 60.
|
||||||
VhostHTTPTimeout int64 `json:"vhostHTTPTimeout,omitempty"`
|
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
|
// VhostHTTPSPort specifies the port that the server listens for HTTPS
|
||||||
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
||||||
// requests.
|
// requests.
|
||||||
|
@ -16,6 +16,7 @@ package vhost
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -29,6 +30,8 @@ import (
|
|||||||
|
|
||||||
libio "github.com/fatedier/golib/io"
|
libio "github.com/fatedier/golib/io"
|
||||||
"github.com/fatedier/golib/pool"
|
"github.com/fatedier/golib/pool"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
"golang.org/x/net/http2/h2c"
|
||||||
|
|
||||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||||
"github.com/fatedier/frp/pkg/util/log"
|
"github.com/fatedier/frp/pkg/util/log"
|
||||||
@ -38,10 +41,11 @@ var ErrNoRouteFound = errors.New("no route found")
|
|||||||
|
|
||||||
type HTTPReverseProxyOptions struct {
|
type HTTPReverseProxyOptions struct {
|
||||||
ResponseHeaderTimeoutS int64
|
ResponseHeaderTimeoutS int64
|
||||||
|
EnableH2C bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPReverseProxy struct {
|
type HTTPReverseProxy struct {
|
||||||
proxy *httputil.ReverseProxy
|
proxy http.Handler
|
||||||
vhostRouter *Routers
|
vhostRouter *Routers
|
||||||
|
|
||||||
responseHeaderTimeout time.Duration
|
responseHeaderTimeout time.Duration
|
||||||
@ -55,6 +59,40 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
|||||||
responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,
|
responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,
|
||||||
vhostRouter: vhostRouter,
|
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{
|
proxy := &httputil.ReverseProxy{
|
||||||
// Modify incoming requests by route policies.
|
// Modify incoming requests by route policies.
|
||||||
Rewrite: func(r *httputil.ProxyRequest) {
|
Rewrite: func(r *httputil.ProxyRequest) {
|
||||||
@ -101,29 +139,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
// Create a connection to one proxy routed by route policy.
|
Transport: transport,
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
BufferPool: pool.NewBuffer(32 * 1024),
|
BufferPool: pool.NewBuffer(32 * 1024),
|
||||||
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||||
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||||
@ -138,7 +154,11 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
|||||||
_, _ = rw.Write(getNotFoundPageContent())
|
_, _ = rw.Write(getNotFoundPageContent())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
rp.proxy = proxy
|
if option.EnableH2C {
|
||||||
|
rp.proxy = h2c.NewHandler(proxy, &http2.Server{})
|
||||||
|
} else {
|
||||||
|
rp.proxy = proxy
|
||||||
|
}
|
||||||
return rp
|
return rp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ type serverInfoResp struct {
|
|||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
BindPort int `json:"bindPort"`
|
BindPort int `json:"bindPort"`
|
||||||
VhostHTTPPort int `json:"vhostHTTPPort"`
|
VhostHTTPPort int `json:"vhostHTTPPort"`
|
||||||
|
VhostEnableH2C bool `json:"vhostEnableH2C"`
|
||||||
VhostHTTPSPort int `json:"vhostHTTPSPort"`
|
VhostHTTPSPort int `json:"vhostHTTPSPort"`
|
||||||
TCPMuxHTTPConnectPort int `json:"tcpmuxHTTPConnectPort"`
|
TCPMuxHTTPConnectPort int `json:"tcpmuxHTTPConnectPort"`
|
||||||
KCPBindPort int `json:"kcpBindPort"`
|
KCPBindPort int `json:"kcpBindPort"`
|
||||||
@ -111,6 +112,7 @@ func (svr *Service) apiServerInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
BindPort: svr.cfg.BindPort,
|
BindPort: svr.cfg.BindPort,
|
||||||
VhostHTTPPort: svr.cfg.VhostHTTPPort,
|
VhostHTTPPort: svr.cfg.VhostHTTPPort,
|
||||||
VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
|
VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
|
||||||
|
VhostEnableH2C: svr.cfg.VhostEnableH2C,
|
||||||
TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
|
TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
|
||||||
KCPBindPort: svr.cfg.KCPBindPort,
|
KCPBindPort: svr.cfg.KCPBindPort,
|
||||||
QUICBindPort: svr.cfg.QUICBindPort,
|
QUICBindPort: svr.cfg.QUICBindPort,
|
||||||
|
@ -281,6 +281,7 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
|||||||
if cfg.VhostHTTPPort > 0 {
|
if cfg.VhostHTTPPort > 0 {
|
||||||
rp := vhost.NewHTTPReverseProxy(vhost.HTTPReverseProxyOptions{
|
rp := vhost.NewHTTPReverseProxy(vhost.HTTPReverseProxyOptions{
|
||||||
ResponseHeaderTimeoutS: cfg.VhostHTTPTimeout,
|
ResponseHeaderTimeoutS: cfg.VhostHTTPTimeout,
|
||||||
|
EnableH2C: cfg.VhostEnableH2C,
|
||||||
}, svr.httpVhostRouter)
|
}, svr.httpVhostRouter)
|
||||||
svr.rc.HTTPReverseProxy = rp
|
svr.rc.HTTPReverseProxy = rp
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user