summaryrefslogtreecommitdiff
path: root/plugins/http/tests
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/http/tests')
-rw-r--r--plugins/http/tests/configs/.rr-http.yaml4
-rw-r--r--plugins/http/tests/handler_test.go67
-rw-r--r--plugins/http/tests/http_test.go120
-rw-r--r--plugins/http/tests/parse_test.go54
-rw-r--r--plugins/http/tests/plugin1.go1
-rw-r--r--plugins/http/tests/uploads_test.go431
-rw-r--r--plugins/http/tests/yaml_configs.go39
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
-`