summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2018-07-07 20:14:04 -0700
committerGitHub <[email protected]>2018-07-07 20:14:04 -0700
commitad0562981de801ad32b5bfd48cea9c92793a8cc0 (patch)
tree2b8ee2778ddf5399a1fe9260c0947bf9a194bf80
parentafde365ba6210569b7d48dec0c07434a7f8a1fd8 (diff)
parent466383c72d921aba728de40b60910741e561c1d1 (diff)
Merge pull request #27 from spiral/feature/arguments
Feature/arguments
-rw-r--r--php-src/PSR7Client.php10
-rw-r--r--service/http/attributes.go69
-rw-r--r--service/http/attributes_test.go67
-rw-r--r--service/http/request.go16
-rw-r--r--service/http/service.go13
-rw-r--r--service/http/service_test.go15
-rw-r--r--service/rpc/service_test.go2
-rw-r--r--service/static/service.go11
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, "/") {