Skip to content

Commit

Permalink
Merge pull request #27 from spiral/feature/arguments
Browse files Browse the repository at this point in the history
Feature/arguments
  • Loading branch information
wolfy-j authored Jul 8, 2018
2 parents afde365 + 466383c commit ad05629
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 22 deletions.
10 changes: 9 additions & 1 deletion php-src/PSR7Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function acceptRequest()
$bodyStream->write($body);
}

return new Diactoros\ServerRequest(
$request = new Diactoros\ServerRequest(
$_SERVER,
$this->wrapUploads($ctx['uploads']),
$ctx['uri'],
Expand All @@ -76,6 +76,14 @@ public function acceptRequest()
$parsedBody,
$ctx['protocol']
);

if (!empty($ctx['attributes'])) {
foreach ($ctx['attributes'] as $key => $value) {
$request = $request->withAttribute($key, $value);
}
}

return $request;
}

/**
Expand Down
69 changes: 69 additions & 0 deletions service/http/attributes.go
Original file line number Diff line number Diff line change
@@ -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)
}
67 changes: 67 additions & 0 deletions service/http/attributes_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
16 changes: 10 additions & 6 deletions service/http/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,23 @@ 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{}
}

// 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() {
Expand Down
13 changes: 7 additions & 6 deletions service/http/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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{}) {
Expand Down
15 changes: 8 additions & 7 deletions service/http/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() }()
Expand Down
2 changes: 1 addition & 1 deletion service/rpc/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 10 additions & 1 deletion service/static/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, "/") {
Expand Down

0 comments on commit ad05629

Please sign in to comment.