diff options
Diffstat (limited to 'plugins/http/tests')
-rw-r--r-- | plugins/http/tests/configs/.rr-http.yaml | 4 | ||||
-rw-r--r-- | plugins/http/tests/handler_test.go | 67 | ||||
-rw-r--r-- | plugins/http/tests/http_test.go | 120 | ||||
-rw-r--r-- | plugins/http/tests/parse_test.go | 54 | ||||
-rw-r--r-- | plugins/http/tests/plugin1.go | 1 | ||||
-rw-r--r-- | plugins/http/tests/uploads_test.go | 431 | ||||
-rw-r--r-- | plugins/http/tests/yaml_configs.go | 39 |
7 files changed, 586 insertions, 130 deletions
diff --git a/plugins/http/tests/configs/.rr-http.yaml b/plugins/http/tests/configs/.rr-http.yaml index 8c6f86d6..a566c794 100644 --- a/plugins/http/tests/configs/.rr-http.yaml +++ b/plugins/http/tests/configs/.rr-http.yaml @@ -9,14 +9,14 @@ server: http: debug: true - address: 0.0.0.0:8080 + address: 127.0.0.1:8080 maxRequestSize: 200 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: 4 + numWorkers: 12 maxJobs: 0 allocateTimeout: 60s destroyTimeout: 60s diff --git a/plugins/http/tests/handler_test.go b/plugins/http/tests/handler_test.go index 81a8449e..38aa4614 100644 --- a/plugins/http/tests/handler_test.go +++ b/plugins/http/tests/handler_test.go @@ -41,22 +41,24 @@ func TestHandler_Echo(t *testing.T) { hs := &http.Server{Addr: ":8177", Handler: h} defer func() { - err = hs.Shutdown(context.Background()) + err := hs.Shutdown(context.Background()) if err != nil { t.Errorf("error during the shutdown: error %v", err) } }() - - go func() { - err = hs.ListenAndServe() + go func(server *http.Server) { + err := server.ListenAndServe() if err != nil && err != http.ErrServerClosed { t.Errorf("error listening the interface: error %v", err) } - }() + }(hs) time.Sleep(time.Millisecond * 10) body, r, err := get("http://localhost:8177/?hello=world") assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() assert.Equal(t, 201, r.StatusCode) assert.Equal(t, "WORLD", body) } @@ -118,7 +120,6 @@ func TestHandler_Headers(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -180,7 +181,6 @@ func TestHandler_Empty_User_Agent(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -241,7 +241,6 @@ func TestHandler_User_Agent(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -302,7 +301,6 @@ func TestHandler_Cookies(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -372,7 +370,6 @@ func TestHandler_JsonPayload_POST(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -493,7 +490,6 @@ func TestHandler_JsonPayload_PATCH(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -565,7 +561,6 @@ func TestHandler_FormData_POST(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -576,7 +571,7 @@ func TestHandler_FormData_POST(t *testing.T) { assert.Equal(t, 200, r.StatusCode) // Sorted - assert.Equal(t, "{\"arr\":{\"c\":{\"z\":\"\",\"p\":\"l\"},\"x\":{\"y\":{\"e\":\"f\",\"z\":\"y\"}}},\"key\":\"value\",\"name\":[\"name1\",\"name2\",\"name3\"]}", string(b)) + assert.Equal(t, "{\"arr\":{\"c\":{\"p\":\"l\",\"z\":\"\"},\"x\":{\"y\":{\"e\":\"f\",\"z\":\"y\"}}},\"key\":\"value\",\"name\":[\"name1\",\"name2\",\"name3\"]}", string(b)) } func TestHandler_FormData_POST_Overwrite(t *testing.T) { @@ -633,7 +628,6 @@ func TestHandler_FormData_POST_Overwrite(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -706,7 +700,6 @@ func TestHandler_FormData_POST_Form_UrlEncoded_Charset(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -779,7 +772,6 @@ func TestHandler_FormData_PUT(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -852,7 +844,6 @@ func TestHandler_FormData_PATCH(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -967,7 +958,6 @@ func TestHandler_Multipart_POST(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -977,7 +967,7 @@ func TestHandler_Multipart_POST(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 200, r.StatusCode) - assert.Equal(t, "{\"arr\":{\"c\":{\"z\":\"\",\"p\":\"l\"},\"x\":{\"y\":{\"e\":\"f\",\"z\":\"y\"}}},\"key\":\"value\",\"name\":[\"name1\",\"name2\",\"name3\"]}", string(b)) + assert.Equal(t, "{\"arr\":{\"c\":{\"p\":\"l\",\"z\":\"\"},\"x\":{\"y\":{\"e\":\"f\",\"z\":\"y\"}}},\"key\":\"value\",\"name\":[\"name1\",\"name2\",\"name3\"]}", string(b)) } func TestHandler_Multipart_PUT(t *testing.T) { @@ -1082,7 +1072,6 @@ func TestHandler_Multipart_PUT(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -1199,7 +1188,6 @@ func TestHandler_Multipart_PATCH(t *testing.T) { err := r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -1252,6 +1240,9 @@ func TestHandler_Error(t *testing.T) { _, r, err := get("http://localhost:8177/?hello=world") assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() assert.Equal(t, 500, r.StatusCode) } @@ -1295,6 +1286,9 @@ func TestHandler_Error2(t *testing.T) { _, r, err := get("http://localhost:8177/?hello=world") assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() assert.Equal(t, 500, r.StatusCode) } @@ -1350,7 +1344,6 @@ func TestHandler_Error3(t *testing.T) { err = r.Body.Close() if err != nil { t.Errorf("error during the closing Body: error %v", err) - } }() @@ -1403,11 +1396,15 @@ func TestHandler_ResponseDuration(t *testing.T) { if t.Elapsed() > 0 { close(gotresp) } + default: } }) body, r, err := get("http://localhost:8177/?hello=world") assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() <-gotresp @@ -1439,14 +1436,14 @@ func TestHandler_ResponseDurationDelayed(t *testing.T) { hs := &http.Server{Addr: ":8177", Handler: h} defer func() { - err = hs.Shutdown(context.Background()) + err := hs.Shutdown(context.Background()) if err != nil { t.Errorf("error during the shutdown: error %v", err) } }() go func() { - err = hs.ListenAndServe() + err := hs.ListenAndServe() if err != nil && err != http.ErrServerClosed { t.Errorf("error listening the interface: error %v", err) } @@ -1460,12 +1457,15 @@ func TestHandler_ResponseDurationDelayed(t *testing.T) { if tp.Elapsed() > time.Second { close(gotresp) } + default: } }) body, r, err := get("http://localhost:8177/?hello=world") assert.NoError(t, err) - + defer func() { + _ = r.Body.Close() + }() <-gotresp assert.Equal(t, 201, r.StatusCode) @@ -1517,11 +1517,15 @@ func TestHandler_ErrorDuration(t *testing.T) { if tp.Elapsed() > 0 { close(goterr) } + default: } }) _, r, err := get("http://localhost:8177/?hello=world") assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() <-goterr @@ -1582,6 +1586,9 @@ func TestHandler_IP(t *testing.T) { body, r, err := get("http://127.0.0.1:8177/") assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() assert.Equal(t, 200, r.StatusCode) assert.Equal(t, "127.0.0.1", body) } @@ -1624,14 +1631,14 @@ func TestHandler_XRealIP(t *testing.T) { hs := &http.Server{Addr: "127.0.0.1:8179", Handler: h} defer func() { - err = hs.Shutdown(context.Background()) + err := hs.Shutdown(context.Background()) if err != nil { t.Errorf("error during the shutdown: error %v", err) } }() go func() { - err = hs.ListenAndServe() + err := hs.ListenAndServe() if err != nil && err != http.ErrServerClosed { t.Errorf("error listening the interface: error %v", err) } @@ -1643,6 +1650,9 @@ func TestHandler_XRealIP(t *testing.T) { }) assert.NoError(t, err) + defer func() { + _ = r.Body.Close() + }() assert.Equal(t, 200, r.StatusCode) assert.Equal(t, "200.0.0.1", body) } @@ -1708,12 +1718,14 @@ func TestHandler_XForwardedFor(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 200, r.StatusCode) assert.Equal(t, "101.0.0.1", body) + _ = r.Body.Close() body, r, err = getHeader("http://127.0.0.1:8177/", map[string]string{ "X-Forwarded-For": "100.0.0.1, 200.0.0.1, 101.0.0.1, invalid", }) assert.NoError(t, err) + _ = r.Body.Close() assert.Equal(t, 200, r.StatusCode) assert.Equal(t, "101.0.0.1", body) } @@ -1769,6 +1781,7 @@ func TestHandler_XForwardedFor_NotTrustedRemoteIp(t *testing.T) { }) assert.NoError(t, err) + _ = r.Body.Close() assert.Equal(t, 200, r.StatusCode) assert.Equal(t, "127.0.0.1", body) } diff --git a/plugins/http/tests/http_test.go b/plugins/http/tests/http_test.go index 2e380a5e..ae9f2bf2 100644 --- a/plugins/http/tests/http_test.go +++ b/plugins/http/tests/http_test.go @@ -25,7 +25,7 @@ func TestHTTPInit(t *testing.T) { assert.NoError(t, err) cfg := &config.Viper{ - Path: ".rr-http.yaml", + Path: "configs/.rr-http.yaml", Prefix: "rr", } @@ -49,7 +49,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 * 5) + tt := time.NewTimer(time.Second * 10) for { select { case e := <-ch: @@ -76,60 +76,60 @@ 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", - } - - 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.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 - } - } - }() + //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", + //} + // + //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.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 + // } + // } + //}() } func get(url string) (string, *http.Response, error) { @@ -141,11 +141,9 @@ func get(url string) (string, *http.Response, error) { if err != nil { return "", nil, err } - - err = r.Body.Close() - if err != nil { - return "", nil, err - } + defer func() { + _ = r.Body.Close() + }() return string(b), r, err } diff --git a/plugins/http/tests/parse_test.go b/plugins/http/tests/parse_test.go new file mode 100644 index 00000000..a93bc059 --- /dev/null +++ b/plugins/http/tests/parse_test.go @@ -0,0 +1,54 @@ +package tests + +import ( + "testing" + + "github.com/spiral/roadrunner/v2/plugins/http" +) + +var samples = []struct { + in string + out []string +}{ + {"key", []string{"key"}}, + {"key[subkey]", []string{"key", "subkey"}}, + {"key[subkey]value", []string{"key", "subkey", "value"}}, + {"key[subkey][value]", []string{"key", "subkey", "value"}}, + {"key[subkey][value][]", []string{"key", "subkey", "value", ""}}, + {"key[subkey] [value][]", []string{"key", "subkey", "value", ""}}, + {"key [ subkey ] [ value ] [ ]", []string{"key", "subkey", "value", ""}}, +} + +func Test_FetchIndexes(t *testing.T) { + for i := 0; i < len(samples); i++ { + r := http.FetchIndexes(samples[i].in) + if !same(r, samples[i].out) { + t.Errorf("got %q, want %q", r, samples[i].out) + } + } +} + +func BenchmarkConfig_FetchIndexes(b *testing.B) { + for _, tt := range samples { + for n := 0; n < b.N; n++ { + r := http.FetchIndexes(tt.in) + if !same(r, tt.out) { + b.Fail() + } + } + } +} + +func same(in, out []string) bool { + if len(in) != len(out) { + return false + } + + for i, v := range in { + if v != out[i] { + return false + } + } + + return true +} diff --git a/plugins/http/tests/plugin1.go b/plugins/http/tests/plugin1.go index 3613ec35..1cbca744 100644 --- a/plugins/http/tests/plugin1.go +++ b/plugins/http/tests/plugin1.go @@ -23,4 +23,3 @@ func (p1 *Plugin1) Stop() error { func (p1 *Plugin1) Name() string { return "http_test.plugin1" } - diff --git a/plugins/http/tests/uploads_test.go b/plugins/http/tests/uploads_test.go new file mode 100644 index 00000000..770e447f --- /dev/null +++ b/plugins/http/tests/uploads_test.go @@ -0,0 +1,431 @@ +package tests + +import ( + "bytes" + "context" + "crypto/sha512" + "encoding/hex" + "fmt" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "os" + "os/exec" + "testing" + "time" + + j "github.com/json-iterator/go" + "github.com/spiral/roadrunner/v2" + httpPlugin "github.com/spiral/roadrunner/v2/plugins/http" + "github.com/stretchr/testify/assert" +) + +var json = j.ConfigCompatibleWithStandardLibrary + +const testFile = "uploads_test.go" + +func TestHandler_Upload_File(t *testing.T) { + pool, err := roadrunner.NewPool(context.Background(), + func() *exec.Cmd { return exec.Command("php", "../../../tests/http/client.php", "upload", "pipes") }, + roadrunner.NewPipeFactory(), + roadrunner.PoolConfig{ + NumWorkers: 1, + AllocateTimeout: time.Second * 1000, + DestroyTimeout: time.Second * 1000, + }) + if err != nil { + t.Fatal(err) + } + + h, err := httpPlugin.NewHandler(1024, httpPlugin.UploadsConfig{ + Dir: os.TempDir(), + Forbid: []string{}, + }, nil, pool) + assert.NoError(t, err) + + hs := &http.Server{Addr: ":8021", Handler: h} + defer func() { + err := hs.Shutdown(context.Background()) + if err != nil { + t.Errorf("error during the shutdown: error %v", err) + } + }() + + go func() { + err := hs.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + t.Errorf("error listening the interface: error %v", err) + } + }() + time.Sleep(time.Millisecond * 10) + + var mb bytes.Buffer + w := multipart.NewWriter(&mb) + + f := mustOpen(testFile) + defer func() { + err := f.Close() + if err != nil { + t.Errorf("failed to close a file: error %v", err) + } + }() + fw, err := w.CreateFormFile("upload", f.Name()) + assert.NotNil(t, fw) + assert.NoError(t, err) + _, err = io.Copy(fw, f) + if err != nil { + t.Errorf("error copying the file: error %v", err) + } + + err = w.Close() + if err != nil { + t.Errorf("error closing the file: error %v", err) + } + + req, err := http.NewRequest("POST", "http://localhost"+hs.Addr, &mb) + assert.NoError(t, err) + + req.Header.Set("Content-Type", w.FormDataContentType()) + + r, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + defer func() { + err := r.Body.Close() + if err != nil { + t.Errorf("error closing the Body: error %v", err) + } + }() + + b, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + assert.NoError(t, err) + assert.Equal(t, 200, r.StatusCode) + + fs := fileString(testFile, 0, "application/octet-stream") + + assert.Equal(t, `{"upload":`+fs+`}`, string(b)) +} + +func TestHandler_Upload_NestedFile(t *testing.T) { + pool, err := roadrunner.NewPool(context.Background(), + func() *exec.Cmd { return exec.Command("php", "../../../tests/http/client.php", "upload", "pipes") }, + roadrunner.NewPipeFactory(), + roadrunner.PoolConfig{ + NumWorkers: 1, + AllocateTimeout: time.Second * 1000, + DestroyTimeout: time.Second * 1000, + }) + if err != nil { + t.Fatal(err) + } + + h, err := httpPlugin.NewHandler(1024, httpPlugin.UploadsConfig{ + Dir: os.TempDir(), + Forbid: []string{}, + }, nil, pool) + assert.NoError(t, err) + + hs := &http.Server{Addr: ":8021", Handler: h} + defer func() { + err := hs.Shutdown(context.Background()) + if err != nil { + t.Errorf("error during the shutdown: error %v", err) + } + }() + + go func() { + err := hs.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + t.Errorf("error listening the interface: error %v", err) + } + }() + time.Sleep(time.Millisecond * 10) + + var mb bytes.Buffer + w := multipart.NewWriter(&mb) + + f := mustOpen(testFile) + defer func() { + err := f.Close() + if err != nil { + t.Errorf("failed to close a file: error %v", err) + } + }() + fw, err := w.CreateFormFile("upload[x][y][z][]", f.Name()) + assert.NotNil(t, fw) + assert.NoError(t, err) + _, err = io.Copy(fw, f) + if err != nil { + t.Errorf("error copying the file: error %v", err) + } + + err = w.Close() + if err != nil { + t.Errorf("error closing the file: error %v", err) + } + + req, err := http.NewRequest("POST", "http://localhost"+hs.Addr, &mb) + assert.NoError(t, err) + + req.Header.Set("Content-Type", w.FormDataContentType()) + + r, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + defer func() { + err := r.Body.Close() + if err != nil { + t.Errorf("error closing the Body: error %v", err) + } + }() + + b, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + assert.NoError(t, err) + assert.Equal(t, 200, r.StatusCode) + + fs := fileString(testFile, 0, "application/octet-stream") + + assert.Equal(t, `{"upload":{"x":{"y":{"z":[`+fs+`]}}}}`, string(b)) +} + +func TestHandler_Upload_File_NoTmpDir(t *testing.T) { + pool, err := roadrunner.NewPool(context.Background(), + func() *exec.Cmd { return exec.Command("php", "../../../tests/http/client.php", "upload", "pipes") }, + roadrunner.NewPipeFactory(), + roadrunner.PoolConfig{ + NumWorkers: 1, + AllocateTimeout: time.Second * 1000, + DestroyTimeout: time.Second * 1000, + }) + if err != nil { + t.Fatal(err) + } + + h, err := httpPlugin.NewHandler(1024, httpPlugin.UploadsConfig{ + Dir: "-------", + Forbid: []string{}, + }, nil, pool) + assert.NoError(t, err) + + hs := &http.Server{Addr: ":8021", Handler: h} + defer func() { + err := hs.Shutdown(context.Background()) + if err != nil { + t.Errorf("error during the shutdown: error %v", err) + } + }() + + go func() { + err := hs.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + t.Errorf("error listening the interface: error %v", err) + } + }() + time.Sleep(time.Millisecond * 10) + + var mb bytes.Buffer + w := multipart.NewWriter(&mb) + + f := mustOpen(testFile) + defer func() { + err := f.Close() + if err != nil { + t.Errorf("failed to close a file: error %v", err) + } + }() + fw, err := w.CreateFormFile("upload", f.Name()) + assert.NotNil(t, fw) + assert.NoError(t, err) + _, err = io.Copy(fw, f) + if err != nil { + t.Errorf("error copying the file: error %v", err) + } + + err = w.Close() + if err != nil { + t.Errorf("error closing the file: error %v", err) + } + + req, err := http.NewRequest("POST", "http://localhost"+hs.Addr, &mb) + assert.NoError(t, err) + + req.Header.Set("Content-Type", w.FormDataContentType()) + + r, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + defer func() { + err := r.Body.Close() + if err != nil { + t.Errorf("error closing the Body: error %v", err) + } + }() + + b, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + assert.NoError(t, err) + assert.Equal(t, 200, r.StatusCode) + + fs := fileString(testFile, 5, "application/octet-stream") + + assert.Equal(t, `{"upload":`+fs+`}`, string(b)) +} + +func TestHandler_Upload_File_Forbids(t *testing.T) { + pool, err := roadrunner.NewPool(context.Background(), + func() *exec.Cmd { return exec.Command("php", "../../../tests/http/client.php", "upload", "pipes") }, + roadrunner.NewPipeFactory(), + roadrunner.PoolConfig{ + NumWorkers: 1, + AllocateTimeout: time.Second * 1000, + DestroyTimeout: time.Second * 1000, + }) + if err != nil { + t.Fatal(err) + } + + h, err := httpPlugin.NewHandler(1024, httpPlugin.UploadsConfig{ + Dir: os.TempDir(), + Forbid: []string{".go"}, + }, nil, pool) + assert.NoError(t, err) + + hs := &http.Server{Addr: ":8021", Handler: h} + defer func() { + err := hs.Shutdown(context.Background()) + if err != nil { + t.Errorf("error during the shutdown: error %v", err) + } + }() + + go func() { + err := hs.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + t.Errorf("error listening the interface: error %v", err) + } + }() + time.Sleep(time.Millisecond * 10) + + var mb bytes.Buffer + w := multipart.NewWriter(&mb) + + f := mustOpen(testFile) + defer func() { + err := f.Close() + if err != nil { + t.Errorf("failed to close a file: error %v", err) + } + }() + fw, err := w.CreateFormFile("upload", f.Name()) + assert.NotNil(t, fw) + assert.NoError(t, err) + _, err = io.Copy(fw, f) + if err != nil { + t.Errorf("error copying the file: error %v", err) + } + + err = w.Close() + if err != nil { + t.Errorf("error closing the file: error %v", err) + } + + req, err := http.NewRequest("POST", "http://localhost"+hs.Addr, &mb) + assert.NoError(t, err) + + req.Header.Set("Content-Type", w.FormDataContentType()) + + r, err := http.DefaultClient.Do(req) + assert.NoError(t, err) + defer func() { + err := r.Body.Close() + if err != nil { + t.Errorf("error closing the Body: error %v", err) + } + }() + + b, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + assert.NoError(t, err) + assert.Equal(t, 200, r.StatusCode) + + fs := fileString(testFile, 7, "application/octet-stream") + + assert.Equal(t, `{"upload":`+fs+`}`, string(b)) +} + +func Test_FileExists(t *testing.T) { + assert.True(t, exists(testFile)) + assert.False(t, exists("uploads_test.")) +} + +func mustOpen(f string) *os.File { + r, err := os.Open(f) + if err != nil { + panic(err) + } + return r +} + +type fInfo struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mime string `json:"mime"` + Error int `json:"error"` + MD5 string `json:"md5,omitempty"` +} + +func fileString(f string, errNo int, mime string) string { + s, err := os.Stat(f) + if err != nil { + fmt.Println(fmt.Errorf("error stat the file, error: %v", err)) + } + + ff, err := os.Open(f) + if err != nil { + fmt.Println(fmt.Errorf("error opening the file, error: %v", err)) + } + + defer func() { + er := ff.Close() + if er != nil { + fmt.Println(fmt.Errorf("error closing the file, error: %v", er)) + } + }() + + h := sha512.New() + _, err = io.Copy(h, ff) + if err != nil { + fmt.Println(fmt.Errorf("error copying the file, error: %v", err)) + } + + v := &fInfo{ + Name: s.Name(), + Size: s.Size(), + Error: errNo, + Mime: mime, + MD5: hex.EncodeToString(h.Sum(nil)), + } + + if errNo != 0 { + v.MD5 = "" + v.Size = 0 + } + + r, err := json.Marshal(v) + if err != nil { + fmt.Println(fmt.Errorf("error marshalling fInfo, error: %v", err)) + } + return string(r) +} + +// exists if file exists. +func exists(path string) bool { + if _, err := os.Stat(path); os.IsNotExist(err) { + return false + } + return true +} diff --git a/plugins/http/tests/yaml_configs.go b/plugins/http/tests/yaml_configs.go deleted file mode 100644 index 9d40edac..00000000 --- a/plugins/http/tests/yaml_configs.go +++ /dev/null @@ -1,39 +0,0 @@ -package tests - -var t1 string = ` -server: - command: "php psr-worker.php" - user: "" - group: "" - env: - "RR_HTTP": "true" - relay: "pipes" - relayTimeout: "20s" - -http: - debug: true - address: 0.0.0.0:8080 - maxRequestSize: 200 - 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: 4 - maxJobs: 0 - allocateTimeout: 60s - destroyTimeout: 60s - - ssl: - port: 8888 - redirect: true - 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 -` |