diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ca7e21d..3343b929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -## 5.7.1 (unreleased) +## 5.8.0 (unreleased) + +### New features +- [PR #716](https://github.com/rqlite/rqlite/pull/716): Support HTTP/2 protocol over TLS. Fixes [issue #516](https://github.com/rqlite/rqlite/issues/516). + ### Implementation changes and bug fixes - [PR #711](https://github.com/rqlite/rqlite/pull/711), [PR# 712](https://github.com/rqlite/rqlite/pull/712): Ignore join addresses if node already part of cluster. Fixes [issue #710](https://github.com/rqlite/rqlite/issues/710). - [PR #715](https://github.com/rqlite/rqlite/pull/715): Compress SQLite database in Raft snapshot. diff --git a/go.mod b/go.mod index 08b05384..f0e0698a 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/mkideal/cli v0.2.3 github.com/mkideal/pkg v0.1.2 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad + golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/sys v0.0.0-20201223074533-0d417f636930 // indirect golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect google.golang.org/protobuf v1.25.0 diff --git a/go.sum b/go.sum index e75ba0b1..16028595 100644 --- a/go.sum +++ b/go.sum @@ -233,6 +233,7 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -274,6 +275,7 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/http/service.go b/http/service.go index f8dbcc22..20eedaa8 100644 --- a/http/service.go +++ b/http/service.go @@ -221,7 +221,7 @@ func (s *Service) Start() error { s.logger.Println("HTTP service Serve() returned:", err.Error()) } }() - s.logger.Println("service listening on", s.addr) + s.logger.Println("service listening on", s.Addr()) return nil } @@ -900,7 +900,9 @@ func requestQueries(r *http.Request) ([]*command.Statement, error) { // createTLSConfig returns a TLS config from the given cert and key. func createTLSConfig(certFile, keyFile, caCertFile string) (*tls.Config, error) { var err error - config := &tls.Config{} + config := &tls.Config{ + NextProtos: []string{"h2", "http/1.1"}, + } config.Certificates = make([]tls.Certificate, 1) config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) if err != nil { diff --git a/http/service_test.go b/http/service_test.go index 07a3866f..5acbeef4 100644 --- a/http/service_test.go +++ b/http/service_test.go @@ -1,14 +1,19 @@ package http import ( + "crypto/tls" "fmt" "io" + "io/ioutil" "net/http" "testing" "github.com/rqlite/rqlite/command" sql "github.com/rqlite/rqlite/db" "github.com/rqlite/rqlite/store" + "github.com/rqlite/rqlite/testdata/x509" + + "golang.org/x/net/http2" ) func Test_NormalizeAddr(t *testing.T) { @@ -604,6 +609,54 @@ func Test_FormRedirectHTTPS(t *testing.T) { } } +func Test_TLSServce(t *testing.T) { + m := &MockStore{} + var s *Service + tempDir := mustTempDir() + + s = New("127.0.0.1:0", m, nil) + s.CertFile = x509.CertFile(tempDir) + s.KeyFile = x509.KeyFile(tempDir) + s.BuildInfo = map[string]interface{}{ + "version": "the version", + } + if err := s.Start(); err != nil { + t.Fatalf("failed to start service") + } + defer s.Close() + + url := fmt.Sprintf("https://%s", s.Addr().String()) + + // Test connecting with a HTTP client. + tn := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{Transport: tn} + resp, err := client.Get(url) + if err != nil { + t.Fatalf("failed to make HTTP request: %s", err) + } + + if v := resp.Header.Get("X-RQLITE-VERSION"); v != "the version" { + t.Fatalf("incorrect build version present in HTTP response header, got: %s", v) + } + + // Test connecting with a HTTP/2 client. + client = &http.Client{ + Transport: &http2.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } + resp, err = client.Get(url) + if err != nil { + t.Fatalf("failed to make HTTP/2 request: %s", err) + } + + if v := resp.Header.Get("X-RQLITE-VERSION"); v != "the version" { + t.Fatalf("incorrect build version present in HTTP/2 response header, got: %s", v) + } +} + type MockStore struct { executeFn func(queries []string, tx bool) ([]*sql.Result, error) queryFn func(queries []string, tx, leader, verify bool) ([]*sql.Rows, error) @@ -692,3 +745,12 @@ func mustNewHTTPRequest(url string) *http.Request { } return req } + +func mustTempDir() string { + var err error + path, err := ioutil.TempDir("", "rqlilte-system-test-") + if err != nil { + panic("failed to create temp dir") + } + return path +}