diff options
author | Valery Piashchynski <[email protected]> | 2020-11-19 21:34:22 +0300 |
---|---|---|
committer | Valery Piashchynski <[email protected]> | 2020-11-19 21:34:22 +0300 |
commit | bc0be9c17220220ae9b40b65e874701edaecd8ce (patch) | |
tree | 6ee032eee330f8bc8824e426bab1846c9479333c /plugins/http | |
parent | 729c19af8c410a28b7b46c134fd7fe9608cd73b1 (diff) |
Add SSL tests
Diffstat (limited to 'plugins/http')
17 files changed, 326 insertions, 159 deletions
diff --git a/plugins/http/constants.go b/plugins/http/constants.go index a25f52a4..773d1f46 100644 --- a/plugins/http/constants.go +++ b/plugins/http/constants.go @@ -3,4 +3,4 @@ package http import "net/http" var http2pushHeaderKey = http.CanonicalHeaderKey("http2-push") -var trailerHeaderKey = http.CanonicalHeaderKey("trailer") +var TrailerHeaderKey = http.CanonicalHeaderKey("trailer") diff --git a/plugins/http/plugin.go b/plugins/http/plugin.go index 51142ddd..aae42891 100644 --- a/plugins/http/plugin.go +++ b/plugins/http/plugin.go @@ -108,9 +108,20 @@ func (s *Plugin) Init(cfg config.Configurer, log log.Logger, server factory.Serv } s.pool = p + s.AddListener(s.logCallback) + return nil } +func (s *Plugin) logCallback(event interface{}) { + switch ev := event.(type) { + case ResponseEvent: + s.log.Info("response received", "elapsed", ev.Elapsed().String(), "remote address", ev.Request.RemoteAddr) + default: + fmt.Println(event) + } +} + // Serve serves the svc. func (s *Plugin) Serve() chan error { s.Lock() diff --git a/plugins/http/response.go b/plugins/http/response.go index 6b9fad6c..b0023b59 100644 --- a/plugins/http/response.go +++ b/plugins/http/response.go @@ -16,13 +16,13 @@ type Response struct { // Header contains list of response headers. Headers map[string][]string `json:"headers"` - // associated body payload. - body interface{} + // associated Body payload. + Body interface{} } // NewResponse creates new response based on given pool payload. func NewResponse(p roadrunner.Payload) (*Response, error) { - r := &Response{body: p.Body} + r := &Response{Body: p.Body} if err := json.Unmarshal(p.Context, r); err != nil { return nil, err } @@ -52,14 +52,14 @@ func (r *Response) Write(w http.ResponseWriter) error { w.WriteHeader(r.Status) - if data, ok := r.body.([]byte); ok { + if data, ok := r.Body.([]byte); ok { _, err := w.Write(data) if err != nil { return handleWriteError(err) } } - if rc, ok := r.body.(io.Reader); ok { + if rc, ok := r.Body.(io.Reader); ok { if _, err := io.Copy(w, rc); err != nil { return err } @@ -83,7 +83,7 @@ func handlePushHeaders(h map[string][]string) []string { } func handleTrailers(h map[string][]string) { - trailers, ok := h[trailerHeaderKey] + trailers, ok := h[TrailerHeaderKey] if !ok { return } @@ -99,5 +99,5 @@ func handleTrailers(h map[string][]string) { } } - delete(h, trailerHeaderKey) + delete(h, TrailerHeaderKey) } diff --git a/plugins/http/config_test.go b/plugins/http/tests/config_test.go index 6d23b6ca..068bd66e 100644 --- a/plugins/http/config_test.go +++ b/plugins/http/tests/config_test.go @@ -1,4 +1,4 @@ -package http +package tests //import ( // "os" diff --git a/plugins/http/tests/configs/.rr-fcgi.yaml b/plugins/http/tests/configs/.rr-fcgi.yaml new file mode 100644 index 00000000..cdfdd969 --- /dev/null +++ b/plugins/http/tests/configs/.rr-fcgi.yaml @@ -0,0 +1,35 @@ +server: + command: "php ../../../tests/http/client.php echo pipes" + user: "" + group: "" + env: + "RR_HTTP": "true" + relay: "pipes" + relayTimeout: "20s" + +http: + debug: true + address: :8080 + maxRequestSize: 1024 + middleware: [ "" ] + uploads: + forbid: [ ".php", ".exe", ".bat" ] + trustedSubnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] + pool: + numWorkers: 1 + maxJobs: 0 + allocateTimeout: 60s + destroyTimeout: 60s + + ssl: + port: 8888 + redirect: false + cert: fixtures/server.crt + key: fixtures/server.key + # rootCa: root.crt + fcgi: + address: tcp://0.0.0.0:6920 + http2: + enabled: false + h2c: false + maxConcurrentStreams: 128
\ No newline at end of file diff --git a/plugins/http/tests/configs/.rr-h2c.yaml b/plugins/http/tests/configs/.rr-h2c.yaml new file mode 100644 index 00000000..cdfdd969 --- /dev/null +++ b/plugins/http/tests/configs/.rr-h2c.yaml @@ -0,0 +1,35 @@ +server: + command: "php ../../../tests/http/client.php echo pipes" + user: "" + group: "" + env: + "RR_HTTP": "true" + relay: "pipes" + relayTimeout: "20s" + +http: + debug: true + address: :8080 + maxRequestSize: 1024 + middleware: [ "" ] + uploads: + forbid: [ ".php", ".exe", ".bat" ] + trustedSubnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] + pool: + numWorkers: 1 + maxJobs: 0 + allocateTimeout: 60s + destroyTimeout: 60s + + ssl: + port: 8888 + redirect: false + cert: fixtures/server.crt + key: fixtures/server.key + # rootCa: root.crt + fcgi: + address: tcp://0.0.0.0:6920 + http2: + enabled: false + h2c: false + maxConcurrentStreams: 128
\ No newline at end of file diff --git a/plugins/http/tests/configs/.rr-handler-echo.yaml b/plugins/http/tests/configs/.rr-handler-echo.yaml deleted file mode 100644 index e69de29b..00000000 --- a/plugins/http/tests/configs/.rr-handler-echo.yaml +++ /dev/null diff --git a/plugins/http/tests/configs/.rr-ssl.yaml b/plugins/http/tests/configs/.rr-ssl.yaml new file mode 100644 index 00000000..cdfdd969 --- /dev/null +++ b/plugins/http/tests/configs/.rr-ssl.yaml @@ -0,0 +1,35 @@ +server: + command: "php ../../../tests/http/client.php echo pipes" + user: "" + group: "" + env: + "RR_HTTP": "true" + relay: "pipes" + relayTimeout: "20s" + +http: + debug: true + address: :8080 + maxRequestSize: 1024 + middleware: [ "" ] + uploads: + forbid: [ ".php", ".exe", ".bat" ] + trustedSubnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] + pool: + numWorkers: 1 + maxJobs: 0 + allocateTimeout: 60s + destroyTimeout: 60s + + ssl: + port: 8888 + redirect: false + cert: fixtures/server.crt + key: fixtures/server.key + # rootCa: root.crt + fcgi: + address: tcp://0.0.0.0:6920 + http2: + enabled: false + h2c: false + maxConcurrentStreams: 128
\ No newline at end of file diff --git a/plugins/http/fcgi_test.go b/plugins/http/tests/fcgi_test.go index 82b7d1c4..0a0b2b41 100644 --- a/plugins/http/fcgi_test.go +++ b/plugins/http/tests/fcgi_test.go @@ -1,4 +1,4 @@ -package http +package tests // //import ( diff --git a/plugins/http/h2c_test.go b/plugins/http/tests/h2c_test.go index 936ca8eb..c85ce942 100644 --- a/plugins/http/h2c_test.go +++ b/plugins/http/tests/h2c_test.go @@ -1,4 +1,4 @@ -package http +package tests // //import ( diff --git a/plugins/http/tests/http_test.go b/plugins/http/tests/http_test.go index ae9f2bf2..4f43ca1e 100644 --- a/plugins/http/tests/http_test.go +++ b/plugins/http/tests/http_test.go @@ -2,8 +2,11 @@ package tests import ( "bytes" + "crypto/tls" "io/ioutil" + "net" "net/http" + "net/http/httptest" "os" "os/signal" "syscall" @@ -20,6 +23,14 @@ import ( "github.com/stretchr/testify/assert" ) +var sslClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, +} + func TestHTTPInit(t *testing.T) { cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel), endure.Visualize(endure.StdOut, "")) assert.NoError(t, err) @@ -49,7 +60,7 @@ func TestHTTPInit(t *testing.T) { sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - tt := time.NewTimer(time.Second * 10) + tt := time.NewTimer(time.Second * 1000) for { select { case e := <-ch: @@ -75,61 +86,175 @@ func TestHTTPInit(t *testing.T) { } } -func TestHTTPHandler(t *testing.T) { - //cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel), endure.Visualize(endure.StdOut, "")) - //assert.NoError(t, err) - // - //cfg := &config.Viper{ - // Path: "configs/.rr-handler-echo.yaml", - // Prefix: "rr", - //} +func TestSSL(t *testing.T) { + cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel), endure.Visualize(endure.StdOut, "")) + assert.NoError(t, err) + + cfg := &config.Viper{ + Path: "configs/.rr-ssl.yaml", + Prefix: "rr", + } + + err = cont.RegisterAll( + cfg, + &rpcPlugin.Plugin{}, + &logger.ZapLogger{}, + &server.Plugin{}, + &httpPlugin.Plugin{}, + ) + assert.NoError(t, err) + + err = cont.Init() + if err != nil { + t.Fatal(err) + } + + ch, err := cont.Serve() + assert.NoError(t, err) + + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + + go func() { + tt := time.NewTimer(time.Second * 1000) + for { + select { + case e := <-ch: + assert.Fail(t, "error", e.Error.Error()) + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + case <-sig: + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + return + case <-tt.C: + // timeout + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + return + } + } + }() + + t.Run("SSLEcho", sslEcho) +} + +func sslEcho(t *testing.T) { + req, err := http.NewRequest("GET", "https://localhost:8888?hello=world", nil) + assert.NoError(t, err) + + r, err := sslClient.Do(req) + assert.NoError(t, err) + + b, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + assert.NoError(t, err) + assert.Equal(t, 201, r.StatusCode) + assert.Equal(t, "WORLD", string(b)) + + err2 := r.Body.Close() + if err2 != nil { + t.Errorf("fail to close the Body: error %v", err2) + } +} + +func TestFastCGI(t *testing.T) { + cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.DebugLevel), endure.Visualize(endure.StdOut, "")) + assert.NoError(t, err) + + cfg := &config.Viper{ + Path: "configs/.rr-fcgi.yaml", + Prefix: "rr", + } + + err = cont.RegisterAll( + cfg, + &rpcPlugin.Plugin{}, + &logger.ZapLogger{}, + &server.Plugin{}, + &httpPlugin.Plugin{}, + ) + assert.NoError(t, err) + + err = cont.Init() + if err != nil { + t.Fatal(err) + } + + ch, err := cont.Serve() + assert.NoError(t, err) + + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + + go func() { + tt := time.NewTimer(time.Second * 1000) + for { + select { + case e := <-ch: + assert.Fail(t, "error", e.Error.Error()) + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + case <-sig: + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + return + case <-tt.C: + // timeout + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + return + } + } + }() + + t.Run("FastCGIEcho", fcgiEcho) +} + +func fcgiEcho(t *testing.T) { + conn, err := net.Dial("tcp", "0.0.0.0:6920") + if err != nil { + t.Fatal(err) + } + + _, err = conn.Write([]byte("data")) + if err != nil { + t.Fatal(err) + } + + //fcgiConnFactory := gofast.SimpleConnFactory("tcp", "0.0.0.0:6920") // - //err = cont.RegisterAll( - // cfg, - // &rpcPlugin.Plugin{}, - // &logger.ZapLogger{}, - // &server.Plugin{}, - // &httpPlugin.Plugin{}, + //fcgiHandler := gofast.NewHandler( + // gofast.BasicParamsMap(gofast.BasicSession), + // gofast.SimpleClientFactory(fcgiConnFactory, 0), //) - //assert.NoError(t, err) - // - //err = cont.Init() + + w := httptest.NewRecorder() + //req := httptest.NewRequest("GET", "http://site.local/?hello=world", nil) + //err = fcgi.Serve(, req) //if err != nil { // t.Fatal(err) //} - // - //ch, err := cont.Serve() - //assert.NoError(t, err) - // - //sig := make(chan os.Signal, 1) - //signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - // - //go func() { - // tt := time.NewTimer(time.Minute * 5) - // for { - // select { - // case e := <-ch: - // assert.Fail(t, "error", e.Error.Error()) - // err = cont.Stop() - // if err != nil { - // assert.FailNow(t, "error", err.Error()) - // } - // case <-sig: - // err = cont.Stop() - // if err != nil { - // assert.FailNow(t, "error", err.Error()) - // } - // return - // case <-tt.C: - // // timeout - // err = cont.Stop() - // if err != nil { - // assert.FailNow(t, "error", err.Error()) - // } - // return - // } - // } - //}() + //fcgiHandler.ServeHTTP(w, req) + + body, err := ioutil.ReadAll(w.Result().Body) + + assert.NoError(t, err) + assert.Equal(t, 201, w.Result().StatusCode) + assert.Equal(t, "WORLD", string(body)) } func get(url string) (string, *http.Response, error) { diff --git a/plugins/http/plugin_test.go b/plugins/http/tests/plugin_test.go index 012cea04..852e5545 100644 --- a/plugins/http/plugin_test.go +++ b/plugins/http/tests/plugin_test.go @@ -1,4 +1,4 @@ -package http +package tests //import ( // "github.com/cenkalti/backoff/v4" diff --git a/plugins/http/response_test.go b/plugins/http/tests/response_test.go index b5adbad9..2bfe7d56 100644 --- a/plugins/http/response_test.go +++ b/plugins/http/tests/response_test.go @@ -1,4 +1,4 @@ -package http +package tests import ( "bytes" @@ -7,6 +7,7 @@ import ( "testing" "github.com/spiral/roadrunner/v2" + http2 "github.com/spiral/roadrunner/v2/plugins/http" "github.com/stretchr/testify/assert" ) @@ -44,13 +45,13 @@ func (tw *testWriter) Push(target string, opts *http.PushOptions) error { } func TestNewResponse_Error(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{Context: []byte(`invalid payload`)}) + r, err := http2.NewResponse(roadrunner.Payload{Context: []byte(`invalid payload`)}) assert.Error(t, err) assert.Nil(t, r) } func TestNewResponse_Write(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{ + r, err := http2.NewResponse(roadrunner.Payload{ Context: []byte(`{"headers":{"key":["value"]},"status": 301}`), Body: []byte(`sample body`), }) @@ -67,7 +68,7 @@ func TestNewResponse_Write(t *testing.T) { } func TestNewResponse_Stream(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{ + r, err := http2.NewResponse(roadrunner.Payload{ Context: []byte(`{"headers":{"key":["value"]},"status": 301}`), }) @@ -76,8 +77,8 @@ func TestNewResponse_Stream(t *testing.T) { t.Fatal("response is nil") } - r.body = &bytes.Buffer{} - r.body.(*bytes.Buffer).WriteString("hello world") + r.Body = &bytes.Buffer{} + r.Body.(*bytes.Buffer).WriteString("hello world") assert.NoError(t, err) assert.NotNil(t, r) @@ -91,7 +92,7 @@ func TestNewResponse_Stream(t *testing.T) { } func TestNewResponse_StreamError(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{ + r, err := http2.NewResponse(roadrunner.Payload{ Context: []byte(`{"headers":{"key":["value"]},"status": 301}`), }) @@ -100,8 +101,8 @@ func TestNewResponse_StreamError(t *testing.T) { t.Fatal("response is nil") } - r.body = &bytes.Buffer{} - r.body.(*bytes.Buffer).WriteString("hello world") + r.Body = &bytes.Buffer{} + r.Body.(*bytes.Buffer).WriteString("hello world") assert.NoError(t, err) assert.NotNil(t, r) @@ -111,7 +112,7 @@ func TestNewResponse_StreamError(t *testing.T) { } func TestWrite_HandlesPush(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{ + r, err := http2.NewResponse(roadrunner.Payload{ Context: []byte(`{"headers":{"Http2-Push":["/test.js"],"content-type":["text/html"]},"status": 200}`), }) @@ -126,7 +127,7 @@ func TestWrite_HandlesPush(t *testing.T) { } func TestWrite_HandlesTrailers(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{ + r, err := http2.NewResponse(roadrunner.Payload{ Context: []byte(`{"headers":{"Trailer":["foo, bar", "baz"],"foo":["test"],"bar":["demo"]},"status": 200}`), }) @@ -136,7 +137,7 @@ func TestWrite_HandlesTrailers(t *testing.T) { w := &testWriter{h: http.Header(make(map[string][]string))} assert.NoError(t, r.Write(w)) - assert.Nil(t, w.h[trailerHeaderKey]) + assert.Nil(t, w.h[http2.TrailerHeaderKey]) assert.Nil(t, w.h["foo"]) //nolint:golint,staticcheck assert.Nil(t, w.h["baz"]) //nolint:golint,staticcheck @@ -145,7 +146,7 @@ func TestWrite_HandlesTrailers(t *testing.T) { } func TestWrite_HandlesHandlesWhitespacesInTrailer(t *testing.T) { - r, err := NewResponse(roadrunner.Payload{ + r, err := http2.NewResponse(roadrunner.Payload{ Context: []byte( `{"headers":{"Trailer":["foo\t,bar , baz"],"foo":["a"],"bar":["b"],"baz":["c"]},"status": 200}`), }) diff --git a/plugins/http/rpc_test.go b/plugins/http/tests/rpc_test.go index 86499d46..925aa082 100644 --- a/plugins/http/rpc_test.go +++ b/plugins/http/tests/rpc_test.go @@ -1,4 +1,4 @@ -package http +package tests // //import ( diff --git a/plugins/http/ssl_test.go b/plugins/http/tests/ssl_test.go index df09aef5..ee0e6e98 100644 --- a/plugins/http/ssl_test.go +++ b/plugins/http/tests/ssl_test.go @@ -1,82 +1,5 @@ -package http +package tests -// -//import ( -// "crypto/tls" -// "github.com/sirupsen/logrus" -// "github.com/sirupsen/logrus/hooks/test" -// "github.com/spiral/roadrunner/service" -// "github.com/stretchr/testify/assert" -// "io/ioutil" -// "net/http" -// "testing" -// "time" -//) -// -//var sslClient = &http.Client{ -// Transport: &http.Transport{ -// TLSClientConfig: &tls.Config{ -// InsecureSkipVerify: true, -// }, -// }, -//} -// -//func Test_SSL_Service_Echo(t *testing.T) { -// logger, _ := test.NewNullLogger() -// logger.SetLevel(logrus.DebugLevel) -// -// c := service.NewContainer(logger) -// c.Register(ID, &Service{}) -// -// assert.NoError(t, c.Init(&testCfg{httpCfg: `{ -// "address": ":6029", -// "ssl": { -// "port": 6900, -// "key": "fixtures/server.key", -// "cert": "fixtures/server.crt" -// }, -// "workers":{ -// "command": "php ../../tests/http/client.php echo pipes", -// "pool": {"numWorkers": 1} -// } -// }`})) -// -// s, st := c.Get(ID) -// assert.NotNil(t, s) -// assert.Equal(t, service.StatusOK, st) -// -// // should do nothing -// s.(*Service).Stop() -// -// go func() { -// err := c.Serve() -// if err != nil { -// t.Errorf("error during the Serve: error %v", err) -// } -// }() -// time.Sleep(time.Millisecond * 500) -// -// req, err := http.NewRequest("GET", "https://localhost:6900?hello=world", nil) -// assert.NoError(t, err) -// -// r, err := sslClient.Do(req) -// assert.NoError(t, err) -// -// b, err := ioutil.ReadAll(r.Body) -// assert.NoError(t, err) -// -// assert.NoError(t, err) -// assert.Equal(t, 201, r.StatusCode) -// assert.Equal(t, "WORLD", string(b)) -// -// err2 := r.Body.Close() -// if err2 != nil { -// t.Errorf("fail to close the Body: error %v", err2) -// } -// -// c.Stop() -//} -// //func Test_SSL_Service_NoRedirect(t *testing.T) { // logger, _ := test.NewNullLogger() // logger.SetLevel(logrus.DebugLevel) diff --git a/plugins/http/uploads_config_test.go b/plugins/http/tests/uploads_config_test.go index ac8bfa1d..497cd54f 100644 --- a/plugins/http/uploads_config_test.go +++ b/plugins/http/tests/uploads_config_test.go @@ -1,14 +1,15 @@ -package http +package tests import ( "os" "testing" + "github.com/spiral/roadrunner/v2/plugins/http" "github.com/stretchr/testify/assert" ) func TestFsConfig_Forbids(t *testing.T) { - cfg := UploadsConfig{Forbid: []string{".php"}} + cfg := http.UploadsConfig{Forbid: []string{".php"}} assert.True(t, cfg.Forbids("index.php")) assert.True(t, cfg.Forbids("index.PHP")) @@ -17,9 +18,9 @@ func TestFsConfig_Forbids(t *testing.T) { } func TestFsConfig_TmpFallback(t *testing.T) { - cfg := UploadsConfig{Dir: "test"} + cfg := http.UploadsConfig{Dir: "test"} assert.Equal(t, "test", cfg.TmpDir()) - cfg = UploadsConfig{Dir: ""} + cfg = http.UploadsConfig{Dir: ""} assert.Equal(t, os.TempDir(), cfg.TmpDir()) } diff --git a/plugins/http/uploads_config.go b/plugins/http/uploads_config.go index 3f655064..4c20c8e8 100644 --- a/plugins/http/uploads_config.go +++ b/plugins/http/uploads_config.go @@ -19,6 +19,7 @@ type UploadsConfig struct { // InitDefaults sets missing values to their default values. func (cfg *UploadsConfig) InitDefaults() error { cfg.Forbid = []string{".php", ".exe", ".bat"} + cfg.Dir = os.TempDir() return nil } |