mirror of
https://github.com/rclone/rclone.git
synced 2026-07-11 08:15:24 -04:00
lib/http: Add HTTP/2 cleartext support in server configuration
Enable HTTP/2 cleartext support for non-TLS listeners.
This commit is contained in:
@@ -23,6 +23,8 @@ import (
|
|||||||
"github.com/rclone/rclone/lib/atexit"
|
"github.com/rclone/rclone/lib/atexit"
|
||||||
sdActivation "github.com/rclone/rclone/lib/sdactivation"
|
sdActivation "github.com/rclone/rclone/lib/sdactivation"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Help returns text describing the http server to add to the command
|
// Help returns text describing the http server to add to the command
|
||||||
@@ -61,6 +63,12 @@ identically.
|
|||||||
|
|
||||||
` + "`--{{ .Prefix }}disable-zip`" + ` may be set to disable the zipping download option.
|
` + "`--{{ .Prefix }}disable-zip`" + ` may be set to disable the zipping download option.
|
||||||
|
|
||||||
|
#### Protocol
|
||||||
|
|
||||||
|
The server supports HTTP/1.1 and HTTP/2. HTTP/2 is used automatically
|
||||||
|
for TLS connections. For non-TLS connections, HTTP/2 cleartext (h2c)
|
||||||
|
is supported, allowing HTTP/2 without encryption.
|
||||||
|
|
||||||
#### TLS (SSL)
|
#### TLS (SSL)
|
||||||
|
|
||||||
By default this will serve over http. If you want you can serve over
|
By default this will serve over http. If you want you can serve over
|
||||||
@@ -273,11 +281,18 @@ func newInstance(ctx context.Context, s *Server, listener net.Listener, tlsCfg *
|
|||||||
listener = tls.NewListener(listener, tlsCfg)
|
listener = tls.NewListener(listener, tlsCfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var handler http.Handler = s.mux
|
||||||
|
// Enable h2c (HTTP/2 cleartext) for non-TLS listeners
|
||||||
|
if tlsCfg == nil {
|
||||||
|
h2s := &http2.Server{}
|
||||||
|
handler = h2c.NewHandler(s.mux, h2s)
|
||||||
|
}
|
||||||
|
|
||||||
return &instance{
|
return &instance{
|
||||||
url: url,
|
url: url,
|
||||||
listener: listener,
|
listener: listener,
|
||||||
httpServer: &http.Server{
|
httpServer: &http.Server{
|
||||||
Handler: s.mux,
|
Handler: handler,
|
||||||
ReadTimeout: time.Duration(s.cfg.ServerReadTimeout),
|
ReadTimeout: time.Duration(s.cfg.ServerReadTimeout),
|
||||||
WriteTimeout: time.Duration(s.cfg.ServerWriteTimeout),
|
WriteTimeout: time.Duration(s.cfg.ServerWriteTimeout),
|
||||||
MaxHeaderBytes: s.cfg.MaxHeaderBytes,
|
MaxHeaderBytes: s.cfg.MaxHeaderBytes,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testEmptyHandler() http.Handler {
|
func testEmptyHandler() http.Handler {
|
||||||
@@ -550,6 +551,49 @@ func TestNewServerTLS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestH2CServer(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
cfg := DefaultCfg()
|
||||||
|
cfg.ListenAddr = []string{"127.0.0.1:0"}
|
||||||
|
|
||||||
|
s, err := NewServer(ctx, WithConfig(cfg))
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
require.NoError(t, s.Shutdown())
|
||||||
|
}()
|
||||||
|
|
||||||
|
expected := []byte("h2c-test-response")
|
||||||
|
s.Router().Mount("/", testEchoHandler(expected))
|
||||||
|
s.Serve()
|
||||||
|
|
||||||
|
url := testGetServerURL(t, s)
|
||||||
|
require.True(t, strings.HasPrefix(url, "http://"), "url should have http scheme (no TLS)")
|
||||||
|
|
||||||
|
// Create an HTTP/2 cleartext client
|
||||||
|
client := &http.Client{
|
||||||
|
Transport: &http2.Transport{
|
||||||
|
AllowHTTP: true,
|
||||||
|
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
|
||||||
|
return net.Dial(network, addr)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
require.Equal(t, 2, resp.ProtoMajor, "response should be HTTP/2")
|
||||||
|
testExpectRespBody(t, resp, expected)
|
||||||
|
}
|
||||||
|
|
||||||
func TestHelpPrefixServer(t *testing.T) {
|
func TestHelpPrefixServer(t *testing.T) {
|
||||||
// This test assumes template variables are placed correctly.
|
// This test assumes template variables are placed correctly.
|
||||||
const testPrefix = "server-help-test"
|
const testPrefix = "server-help-test"
|
||||||
|
|||||||
Reference in New Issue
Block a user