diff options
author | Wolfy-J <[email protected]> | 2018-07-07 20:14:04 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2018-07-07 20:14:04 -0700 |
commit | ad0562981de801ad32b5bfd48cea9c92793a8cc0 (patch) | |
tree | 2b8ee2778ddf5399a1fe9260c0947bf9a194bf80 | |
parent | afde365ba6210569b7d48dec0c07434a7f8a1fd8 (diff) | |
parent | 466383c72d921aba728de40b60910741e561c1d1 (diff) |
Merge pull request #27 from spiral/feature/arguments
Feature/arguments
-rw-r--r-- | php-src/PSR7Client.php | 10 | ||||
-rw-r--r-- | service/http/attributes.go | 69 | ||||
-rw-r--r-- | service/http/attributes_test.go | 67 | ||||
-rw-r--r-- | service/http/request.go | 16 | ||||
-rw-r--r-- | service/http/service.go | 13 | ||||
-rw-r--r-- | service/http/service_test.go | 15 | ||||
-rw-r--r-- | service/rpc/service_test.go | 2 | ||||
-rw-r--r-- | service/static/service.go | 11 |
8 files changed, 181 insertions, 22 deletions
diff --git a/php-src/PSR7Client.php b/php-src/PSR7Client.php index f8913a8d..858e8405 100644 --- a/php-src/PSR7Client.php +++ b/php-src/PSR7Client.php @@ -64,7 +64,7 @@ class PSR7Client $bodyStream->write($body); } - return new Diactoros\ServerRequest( + $request = new Diactoros\ServerRequest( $_SERVER, $this->wrapUploads($ctx['uploads']), $ctx['uri'], @@ -76,6 +76,14 @@ class PSR7Client $parsedBody, $ctx['protocol'] ); + + if (!empty($ctx['attributes'])) { + foreach ($ctx['attributes'] as $key => $value) { + $request = $request->withAttribute($key, $value); + } + } + + return $request; } /** diff --git a/service/http/attributes.go b/service/http/attributes.go new file mode 100644 index 00000000..acea38a1 --- /dev/null +++ b/service/http/attributes.go @@ -0,0 +1,69 @@ +package http + +import ( + "context" + "net/http" + "errors" +) + +const contextKey = "psr:attributes" + +type attrs map[string]interface{} + +// InitAttributes returns request with new context and attribute bag. +func InitAttributes(r *http.Request) *http.Request { + return r.WithContext(context.WithValue(r.Context(), contextKey, attrs{})) +} + +// AllAttributes returns all context attributes. +func AllAttributes(r *http.Request) map[string]interface{} { + v := r.Context().Value(contextKey) + if v == nil { + return attrs{} + } + + return v.(attrs) +} + +// Get gets the value from request context. It replaces any existing +// values. +func GetAttribute(r *http.Request, key string) interface{} { + v := r.Context().Value(contextKey) + if v == nil { + return nil + } + + return v.(attrs).Get(key) +} + +// Set sets the key to value. It replaces any existing +// values. Context specific. +func SetAttribute(r *http.Request, key string, value interface{}) error { + v := r.Context().Value(contextKey) + if v == nil { + return errors.New("unable to find psr:attributes context value") + } + + v.(attrs).Set(key, value) + return nil +} + +// Get gets the value associated with the given key. +func (v attrs) Get(key string) interface{} { + if v == nil { + return "" + } + + return v[key] +} + +// Set sets the key to value. It replaces any existing +// values. +func (v attrs) Set(key string, value interface{}) { + v[key] = value +} + +// Del deletes the value associated with key. +func (v attrs) Del(key string) { + delete(v, key) +} diff --git a/service/http/attributes_test.go b/service/http/attributes_test.go new file mode 100644 index 00000000..aeb7fe74 --- /dev/null +++ b/service/http/attributes_test.go @@ -0,0 +1,67 @@ +package http + +import ( + "testing" + "net/http" + "github.com/stretchr/testify/assert" +) + +func TestAllAttributes(t *testing.T) { + r := &http.Request{} + r = InitAttributes(r) + + SetAttribute(r, "key", "value") + + assert.Equal(t, AllAttributes(r), map[string]interface{}{ + "key": "value", + }) +} + +func TestAllAttributesNone(t *testing.T) { + r := &http.Request{} + r = InitAttributes(r) + + assert.Equal(t, AllAttributes(r), map[string]interface{}{}) +} + +func TestAllAttributesNone2(t *testing.T) { + r := &http.Request{} + + assert.Equal(t, AllAttributes(r), map[string]interface{}{}) +} + +func TestGetAttribute(t *testing.T) { + r := &http.Request{} + r = InitAttributes(r) + + SetAttribute(r, "key", "value") + assert.Equal(t, GetAttribute(r, "key"), "value") +} + +func TestGetAttributeNone(t *testing.T) { + r := &http.Request{} + r = InitAttributes(r) + + assert.Equal(t, GetAttribute(r, "key"), nil) +} + +func TestGetAttributeNone2(t *testing.T) { + r := &http.Request{} + + assert.Equal(t, GetAttribute(r, "key"), nil) +} + +func TestSetAttribute(t *testing.T) { + r := &http.Request{} + r = InitAttributes(r) + + SetAttribute(r, "key", "value") + assert.Equal(t, GetAttribute(r, "key"), "value") +} + +func TestSetAttributeNone(t *testing.T) { + r := &http.Request{} + + SetAttribute(r, "key", "value") + assert.Equal(t, GetAttribute(r, "key"), nil) +}
\ No newline at end of file diff --git a/service/http/request.go b/service/http/request.go index 9281a3f5..21566416 100644 --- a/service/http/request.go +++ b/service/http/request.go @@ -44,6 +44,9 @@ type Request struct { // Uploads contains list of uploaded files, their names, sized and associations with temporary files. Uploads *Uploads `json:"uploads"` + // Attributes can be set by chained middleware to safely pass value from Golang to PHP. See: GetAttribute, SetAttribute functions. + Attributes map[string]interface{} `json:"attributes"` + // request body can be parsedData or []byte body interface{} } @@ -51,12 +54,13 @@ type Request struct { // NewRequest creates new PSR7 compatible request using net/http request. func NewRequest(r *http.Request, cfg *UploadsConfig) (req *Request, err error) { req = &Request{ - Protocol: r.Proto, - Method: r.Method, - URI: uri(r), - Headers: r.Header, - Cookies: make(map[string]string), - RawQuery: r.URL.RawQuery, + Protocol: r.Proto, + Method: r.Method, + URI: uri(r), + Headers: r.Header, + Cookies: make(map[string]string), + RawQuery: r.URL.RawQuery, + Attributes: AllAttributes(r), } for _, c := range r.Cookies() { diff --git a/service/http/service.go b/service/http/service.go index cef019b3..710cd60c 100644 --- a/service/http/service.go +++ b/service/http/service.go @@ -13,8 +13,8 @@ import ( // ID contains default svc name. const ID = "http" -// must return true if request/response pair is handled within the middleware. -type middleware func(w http.ResponseWriter, r *http.Request) bool +// http middleware type. +type middleware func(f http.HandlerFunc) http.HandlerFunc // Service manages rr, http servers. type Service struct { @@ -113,13 +113,14 @@ func (s *Service) Stop() { // middleware handles connection using set of mdws and rr PSR-7 server. func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) { + r = InitAttributes(r) + + f := s.srv.ServeHTTP for _, m := range s.mdws { - if m(w, r) { - return - } + f = m(f) } - s.srv.ServeHTTP(w, r) + f(w, r) } func (s *Service) listener(event int, ctx interface{}) { diff --git a/service/http/service_test.go b/service/http/service_test.go index 02d1c3f0..50836b4b 100644 --- a/service/http/service_test.go +++ b/service/http/service_test.go @@ -253,14 +253,15 @@ func Test_Service_Middleware(t *testing.T) { assert.NotNil(t, s) assert.Equal(t, service.StatusConfigured, st) - s.(*Service).AddMiddleware(func(w http.ResponseWriter, r *http.Request) bool { - if r.URL.Path == "/halt" { - w.WriteHeader(500) - w.Write([]byte("halted")) - return true + s.(*Service).AddMiddleware(func(f http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/halt" { + w.WriteHeader(500) + w.Write([]byte("halted")) + } else { + f(w, r) + } } - - return false }) go func() { c.Serve() }() diff --git a/service/rpc/service_test.go b/service/rpc/service_test.go index ce85d52f..d4734bb5 100644 --- a/service/rpc/service_test.go +++ b/service/rpc/service_test.go @@ -84,8 +84,8 @@ func Test_Serve_Client(t *testing.T) { assert.NoError(t, s.Register("test", &testService{})) go func() { assert.NoError(t, s.Serve()) }() - time.Sleep(time.Millisecond) + client, err := s.Client() assert.NotNil(t, client) assert.NoError(t, err) diff --git a/service/static/service.go b/service/static/service.go index 2324dcd1..add242e4 100644 --- a/service/static/service.go +++ b/service/static/service.go @@ -56,7 +56,16 @@ func (s *Service) Serve() error { return nil } func (s *Service) Stop() {} // middleware must return true if request/response pair is handled within the middleware. -func (s *Service) middleware(w http.ResponseWriter, r *http.Request) bool { +func (s *Service) middleware(f http.HandlerFunc) http.HandlerFunc { + // Define the http.HandlerFunc + return func(w http.ResponseWriter, r *http.Request) { + if !s.handleStatic(w, r) { + f(w, r) + } + } +} + +func (s *Service) handleStatic(w http.ResponseWriter, r *http.Request) bool { fPath := r.URL.Path if !strings.HasPrefix(fPath, "/") { |