diff options
Diffstat (limited to 'service/http')
-rw-r--r-- | service/http/attributes/attributes_test.go | 3 | ||||
-rw-r--r-- | service/http/config.go | 19 | ||||
-rw-r--r-- | service/http/config_test.go | 13 | ||||
-rw-r--r-- | service/http/fcgi_test.go | 9 | ||||
-rw-r--r-- | service/http/handler.go | 32 | ||||
-rw-r--r-- | service/http/handler_test.go | 46 | ||||
-rw-r--r-- | service/http/request.go | 6 | ||||
-rw-r--r-- | service/http/response.go | 7 | ||||
-rw-r--r-- | service/http/rpc_test.go | 13 | ||||
-rw-r--r-- | service/http/service.go | 7 | ||||
-rw-r--r-- | service/http/service_test.go | 18 | ||||
-rw-r--r-- | service/http/ssl_test.go | 10 | ||||
-rw-r--r-- | service/http/uploads.go | 7 | ||||
-rw-r--r-- | service/http/uploads_config_test.go | 3 | ||||
-rw-r--r-- | service/http/uploads_test.go | 9 |
15 files changed, 138 insertions, 64 deletions
diff --git a/service/http/attributes/attributes_test.go b/service/http/attributes/attributes_test.go index 2360fd12..d914f6fa 100644 --- a/service/http/attributes/attributes_test.go +++ b/service/http/attributes/attributes_test.go @@ -1,9 +1,10 @@ package attributes import ( - "github.com/stretchr/testify/assert" "net/http" "testing" + + "github.com/stretchr/testify/assert" ) func TestAllAttributes(t *testing.T) { diff --git a/service/http/config.go b/service/http/config.go index 00f61652..34733e44 100644 --- a/service/http/config.go +++ b/service/http/config.go @@ -3,15 +3,21 @@ package http import ( "errors" "fmt" - "github.com/spiral/roadrunner" - "github.com/spiral/roadrunner/service" "net" + "net/http" "os" "strings" + + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" ) // Config configures RoadRunner HTTP server. type Config struct { + // AppErrorCode is error code for the application errors (default 500) + AppErrorCode uint64 + // Error code for the RR pool or worker errors + InternalErrorCode uint64 // Port and port to handle as http server. Address string @@ -60,7 +66,6 @@ type HTTP2Config struct { func (cfg *HTTP2Config) InitDefaults() error { cfg.Enabled = true cfg.MaxConcurrentStreams = 128 - return nil } @@ -109,6 +114,14 @@ func (c *Config) EnableFCGI() bool { // Hydrate must populate Config values using given Config source. Must return error if Config is not valid. func (c *Config) Hydrate(cfg service.Config) error { + if c.AppErrorCode == 0 { + // set default behaviour - 500 error code + c.AppErrorCode = http.StatusInternalServerError + } + if c.InternalErrorCode == 0 { + // set default behaviour - 500 error code + c.InternalErrorCode = http.StatusInternalServerError + } if c.Workers == nil { c.Workers = &roadrunner.ServerConfig{} } diff --git a/service/http/config_test.go b/service/http/config_test.go index d95e0995..18b8f5a3 100644 --- a/service/http/config_test.go +++ b/service/http/config_test.go @@ -1,21 +1,20 @@ package http import ( - json "github.com/json-iterator/go" - "github.com/spiral/roadrunner" - "github.com/spiral/roadrunner/service" - "github.com/stretchr/testify/assert" "os" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" + "github.com/stretchr/testify/assert" ) type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { - j := json.ConfigCompatibleWithStandardLibrary - return j.Unmarshal([]byte(cfg.cfg), out) + return json.Unmarshal([]byte(cfg.cfg), out) } func Test_Config_Hydrate_Error1(t *testing.T) { diff --git a/service/http/fcgi_test.go b/service/http/fcgi_test.go index e68b2e7f..cf67a68b 100644 --- a/service/http/fcgi_test.go +++ b/service/http/fcgi_test.go @@ -1,15 +1,16 @@ package http import ( + "io/ioutil" + "net/http/httptest" + "testing" + "time" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" "github.com/yookoala/gofast" - "io/ioutil" - "net/http/httptest" - "testing" - "time" ) func Test_FCGI_Service_Echo(t *testing.T) { diff --git a/service/http/handler.go b/service/http/handler.go index eca05483..43f894d7 100644 --- a/service/http/handler.go +++ b/service/http/handler.go @@ -61,11 +61,13 @@ func (e *ResponseEvent) Elapsed() time.Duration { // Handler serves http connections to underlying PHP application using PSR-7 protocol. Context will include request headers, // parsed files and query, payload will include parsed form dataTree (if any). type Handler struct { - cfg *Config - log *logrus.Logger - rr *roadrunner.Server - mul sync.Mutex - lsn func(event int, ctx interface{}) + cfg *Config + log *logrus.Logger + rr *roadrunner.Server + mul sync.Mutex + lsn func(event int, ctx interface{}) + internalErrorCode uint64 + appErrorCode uint64 } // Listen attaches handler event controller. @@ -131,6 +133,10 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // handleError sends error. +/* +handleError distinct RR errors and App errors +You can set return distinct error codes for the App and for the RR +*/ func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error, start time.Time) { // if pipe is broken, there is no sense to write the header // in this case we just report about error @@ -138,8 +144,20 @@ func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error, h.throw(EventError, &ErrorEvent{Request: r, Error: err, start: start, elapsed: time.Since(start)}) return } - // ResponseWriter is ok, write the error code - w.WriteHeader(500) + if errors.Is(err, roadrunner.ErrNoAssociatedPool) || + errors.Is(err, roadrunner.ErrAllocateWorker) || + errors.Is(err, roadrunner.ErrWorkerNotReady) || + errors.Is(err, roadrunner.ErrEmptyPayload) || + errors.Is(err, roadrunner.ErrPoolStopped) || + errors.Is(err, roadrunner.ErrWorkerAllocateTimeout) || + errors.Is(err, roadrunner.ErrAllWorkersAreDead) { + // for the RR errors, write custom error code + w.WriteHeader(int(h.internalErrorCode)) + } else { + // ResponseWriter is ok, write the error code + w.WriteHeader(int(h.appErrorCode)) + } + _, err2 := w.Write([]byte(err.Error())) // error during the writing to the ResponseWriter if err2 != nil { diff --git a/service/http/handler_test.go b/service/http/handler_test.go index 951bcbfd..7a50bf97 100644 --- a/service/http/handler_test.go +++ b/service/http/handler_test.go @@ -3,8 +3,6 @@ package http import ( "bytes" "context" - "github.com/spiral/roadrunner" - "github.com/stretchr/testify/assert" "io/ioutil" "mime/multipart" "net/http" @@ -15,6 +13,9 @@ import ( "strings" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/stretchr/testify/assert" ) // get request and return body @@ -110,6 +111,7 @@ func TestHandler_Echo(t *testing.T) { func Test_HandlerErrors(t *testing.T) { h := &Handler{ + internalErrorCode: 500, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -135,8 +137,38 @@ func Test_HandlerErrors(t *testing.T) { assert.Equal(t, 500, wr.Code) } +func Test_HandlerErrorsPoolErrorCode(t *testing.T) { + h := &Handler{ + internalErrorCode: 777, + cfg: &Config{ + MaxRequestSize: 1024, + Uploads: &UploadsConfig{ + Dir: os.TempDir(), + Forbid: []string{}, + }, + }, + rr: roadrunner.NewServer(&roadrunner.ServerConfig{ + Command: "php ../../tests/http/client.php echo pipes", + Relay: "pipes", + Pool: &roadrunner.Config{ + NumWorkers: 1, + AllocateTimeout: 10000000, + DestroyTimeout: 10000000, + }, + }), + } + + wr := httptest.NewRecorder() + rq := httptest.NewRequest("POST", "/", bytes.NewBuffer([]byte("data"))) + + h.ServeHTTP(wr, rq) + assert.Equal(t, 777, wr.Code) +} + func Test_Handler_JSON_error(t *testing.T) { h := &Handler{ + appErrorCode: 500, + internalErrorCode: 500, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1329,6 +1361,8 @@ func TestHandler_Multipart_PATCH(t *testing.T) { func TestHandler_Error(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1373,6 +1407,8 @@ func TestHandler_Error(t *testing.T) { func TestHandler_Error2(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1417,6 +1453,8 @@ func TestHandler_Error2(t *testing.T) { func TestHandler_Error3(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1, Uploads: &UploadsConfig{ @@ -1478,6 +1516,8 @@ func TestHandler_Error3(t *testing.T) { func TestHandler_ResponseDuration(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1596,6 +1636,7 @@ func TestHandler_ResponseDurationDelayed(t *testing.T) { func TestHandler_ErrorDuration(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1654,6 +1695,7 @@ func TestHandler_ErrorDuration(t *testing.T) { func TestHandler_IP(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ diff --git a/service/http/request.go b/service/http/request.go index 8da5440f..f3fff198 100644 --- a/service/http/request.go +++ b/service/http/request.go @@ -8,7 +8,6 @@ import ( "net/url" "strings" - json "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/spiral/roadrunner" "github.com/spiral/roadrunner/service/http/attributes" @@ -136,13 +135,12 @@ func (r *Request) Close(log *logrus.Logger) { func (r *Request) Payload() (p *roadrunner.Payload, err error) { p = &roadrunner.Payload{} - j := json.ConfigCompatibleWithStandardLibrary - if p.Context, err = j.Marshal(r); err != nil { + if p.Context, err = json.Marshal(r); err != nil { return nil, err } if r.Parsed { - if p.Body, err = j.Marshal(r.body); err != nil { + if p.Body, err = json.Marshal(r.body); err != nil { return nil, err } } else if r.body != nil { diff --git a/service/http/response.go b/service/http/response.go index f34754be..a2540edf 100644 --- a/service/http/response.go +++ b/service/http/response.go @@ -5,11 +5,12 @@ import ( "net/http" "strings" - json "github.com/json-iterator/go" + j "github.com/json-iterator/go" "github.com/spiral/roadrunner" ) +var json = j.ConfigCompatibleWithStandardLibrary // Response handles PSR7 response logic. type Response struct { @@ -26,8 +27,8 @@ type Response struct { // NewResponse creates new response based on given rr payload. func NewResponse(p *roadrunner.Payload) (*Response, error) { r := &Response{body: p.Body} - j := json.ConfigCompatibleWithStandardLibrary - if err := j.Unmarshal(p.Context, r); err != nil { + + if err := json.Unmarshal(p.Context, r); err != nil { return nil, err } diff --git a/service/http/rpc_test.go b/service/http/rpc_test.go index e57a8699..62f27ede 100644 --- a/service/http/rpc_test.go +++ b/service/http/rpc_test.go @@ -1,16 +1,16 @@ package http import ( - json "github.com/json-iterator/go" + "os" + "strconv" + "testing" + "time" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/rpc" "github.com/stretchr/testify/assert" - "os" - "strconv" - "testing" - "time" ) func Test_RPC(t *testing.T) { @@ -88,8 +88,7 @@ func Test_RPC_Unix(t *testing.T) { c.Register(ID, &Service{}) sock := `unix://` + os.TempDir() + `/rpc.unix` - j := json.ConfigCompatibleWithStandardLibrary - data, _ := j.Marshal(sock) + data, _ := json.Marshal(sock) assert.NoError(t, c.Init(&testCfg{ rpcCfg: `{"enable":true, "listen":` + string(data) + `}`, diff --git a/service/http/service.go b/service/http/service.go index 25a10064..7a175dcb 100644 --- a/service/http/service.go +++ b/service/http/service.go @@ -118,7 +118,12 @@ func (s *Service) Serve() error { s.rr.Attach(s.controller) } - s.handler = &Handler{cfg: s.cfg, rr: s.rr} + s.handler = &Handler{ + cfg: s.cfg, + rr: s.rr, + internalErrorCode: s.cfg.InternalErrorCode, + appErrorCode: s.cfg.AppErrorCode, + } s.handler.Listen(s.throw) if s.cfg.EnableHTTP() { diff --git a/service/http/service_test.go b/service/http/service_test.go index f7ee33cc..960bc513 100644 --- a/service/http/service_test.go +++ b/service/http/service_test.go @@ -1,8 +1,13 @@ package http import ( + "io/ioutil" + "net/http" + "os" + "testing" + "time" + "github.com/cenkalti/backoff/v4" - json "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner" @@ -10,11 +15,6 @@ import ( "github.com/spiral/roadrunner/service/env" "github.com/spiral/roadrunner/service/rpc" "github.com/stretchr/testify/assert" - "io/ioutil" - "net/http" - "os" - "testing" - "time" ) type testCfg struct { @@ -44,8 +44,7 @@ func (cfg *testCfg) Get(name string) service.Config { return nil } func (cfg *testCfg) Unmarshal(out interface{}) error { - j := json.ConfigCompatibleWithStandardLibrary - return j.Unmarshal([]byte(cfg.target), out) + return json.Unmarshal([]byte(cfg.target), out) } func Test_Service_NoConfig(t *testing.T) { @@ -752,8 +751,7 @@ func Test_Service_Error4(t *testing.T) { func tmpDir() string { p := os.TempDir() - j := json.ConfigCompatibleWithStandardLibrary - r, _ := j.Marshal(p) + r, _ := json.Marshal(p) return string(r) } diff --git a/service/http/ssl_test.go b/service/http/ssl_test.go index cf147be9..8078a3a7 100644 --- a/service/http/ssl_test.go +++ b/service/http/ssl_test.go @@ -2,14 +2,15 @@ package http 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" + + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/spiral/roadrunner/service" + "github.com/stretchr/testify/assert" ) var sslClient = &http.Client{ @@ -245,7 +246,6 @@ func Test_SSL_Service_Push(t *testing.T) { 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) diff --git a/service/http/uploads.go b/service/http/uploads.go index 39a9eaf2..e369fab2 100644 --- a/service/http/uploads.go +++ b/service/http/uploads.go @@ -2,13 +2,13 @@ package http import ( "fmt" - json "github.com/json-iterator/go" - "github.com/sirupsen/logrus" "io" "io/ioutil" "mime/multipart" "os" "sync" + + "github.com/sirupsen/logrus" ) const ( @@ -42,8 +42,7 @@ type Uploads struct { // MarshalJSON marshal tree tree into JSON. func (u *Uploads) MarshalJSON() ([]byte, error) { - j := json.ConfigCompatibleWithStandardLibrary - return j.Marshal(u.tree) + return json.Marshal(u.tree) } // Open moves all uploaded files to temp directory, return error in case of issue with temp directory. File errors diff --git a/service/http/uploads_config_test.go b/service/http/uploads_config_test.go index 2b6ceebc..ac8bfa1d 100644 --- a/service/http/uploads_config_test.go +++ b/service/http/uploads_config_test.go @@ -1,9 +1,10 @@ package http import ( - "github.com/stretchr/testify/assert" "os" "testing" + + "github.com/stretchr/testify/assert" ) func TestFsConfig_Forbids(t *testing.T) { diff --git a/service/http/uploads_test.go b/service/http/uploads_test.go index 08177c72..bab20d49 100644 --- a/service/http/uploads_test.go +++ b/service/http/uploads_test.go @@ -6,9 +6,6 @@ import ( "crypto/md5" "encoding/hex" "fmt" - json "github.com/json-iterator/go" - "github.com/spiral/roadrunner" - "github.com/stretchr/testify/assert" "io" "io/ioutil" "mime/multipart" @@ -16,6 +13,9 @@ import ( "os" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/stretchr/testify/assert" ) func TestHandler_Upload_File(t *testing.T) { @@ -424,8 +424,7 @@ func fileString(f string, errNo int, mime string) string { v.Size = 0 } - j := json.ConfigCompatibleWithStandardLibrary - r, err := j.Marshal(v) + r, err := json.Marshal(v) if err != nil { fmt.Println(fmt.Errorf("error marshalling fInfo, error: %v", err)) } |