summaryrefslogtreecommitdiff
path: root/service/http
diff options
context:
space:
mode:
Diffstat (limited to 'service/http')
-rw-r--r--service/http/attributes/attributes_test.go3
-rw-r--r--service/http/config.go19
-rw-r--r--service/http/config_test.go13
-rw-r--r--service/http/fcgi_test.go9
-rw-r--r--service/http/handler.go32
-rw-r--r--service/http/handler_test.go46
-rw-r--r--service/http/request.go6
-rw-r--r--service/http/response.go7
-rw-r--r--service/http/rpc_test.go13
-rw-r--r--service/http/service.go7
-rw-r--r--service/http/service_test.go18
-rw-r--r--service/http/ssl_test.go10
-rw-r--r--service/http/uploads.go7
-rw-r--r--service/http/uploads_config_test.go3
-rw-r--r--service/http/uploads_test.go9
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))
}