diff options
Diffstat (limited to 'service')
-rw-r--r-- | service/http/response.go | 58 | ||||
-rw-r--r-- | service/http/response_test.go | 46 |
2 files changed, 93 insertions, 11 deletions
diff --git a/service/http/response.go b/service/http/response.go index 8bd770ec..8dda87c7 100644 --- a/service/http/response.go +++ b/service/http/response.go @@ -2,9 +2,11 @@ package http import ( "encoding/json" - "github.com/spiral/roadrunner" "io" "net/http" + "regexp" + + "github.com/spiral/roadrunner" ) // Response handles PSR7 response logic. @@ -31,16 +33,16 @@ func NewResponse(p *roadrunner.Payload) (*Response, error) { // Write writes response headers, status and body into ResponseWriter. func (r *Response) Write(w http.ResponseWriter) error { + p, h := handlePushHeaders(r.Headers) + if pusher, ok := w.(http.Pusher); ok { + for _, v := range p { + pusher.Push(v, nil) + } + } + + h = handleTrailers(h) for n, h := range r.Headers { for _, v := range h { - if n == "http2-push" { - if pusher, ok := w.(http.Pusher); ok { - pusher.Push(v, nil) - } - - continue - } - w.Header().Add(n, v) } } @@ -59,3 +61,41 @@ func (r *Response) Write(w http.ResponseWriter) error { return nil } + +func handlePushHeaders(h map[string][]string) ([]string, map[string][]string) { + var p []string + pushHeader, ok := h["http2-push"] + if !ok { + return p, h + } + + for _, v := range pushHeader { + p = append(p, v) + } + + delete(h, "http2-push") + + return p, h +} + +func handleTrailers(h map[string][]string) map[string][]string { + trailers, ok := h["trailer"] + if !ok { + return h + } + + zp := regexp.MustCompile(` *, *`) + for _, tr := range trailers { + for _, n := range zp.Split(tr, -1) { + if v, ok := h[n]; ok { + h["Trailer:"+n] = v + + delete(h, n) + } + } + } + + delete(h, "trailer") + + return h +} diff --git a/service/http/response_test.go b/service/http/response_test.go index f885be7f..7ba9d8d4 100644 --- a/service/http/response_test.go +++ b/service/http/response_test.go @@ -3,10 +3,11 @@ package http import ( "bytes" "errors" - "github.com/spiral/roadrunner" - "github.com/stretchr/testify/assert" "net/http" "testing" + + "github.com/spiral/roadrunner" + "github.com/stretchr/testify/assert" ) type testWriter struct { @@ -15,6 +16,8 @@ type testWriter struct { wroteHeader bool code int err error + pushErr error + pushes []string } func (tw *testWriter) Header() http.Header { return tw.h } @@ -34,6 +37,12 @@ func (tw *testWriter) Write(p []byte) (int, error) { func (tw *testWriter) WriteHeader(code int) { tw.wroteHeader = true; tw.code = code } +func (tw *testWriter) Push(target string, opts *http.PushOptions) error { + tw.pushes = append(tw.pushes, target) + + return tw.pushErr +} + func TestNewResponse_Error(t *testing.T) { r, err := NewResponse(&roadrunner.Payload{Context: []byte(`invalid payload`)}) assert.Error(t, err) @@ -90,3 +99,36 @@ func TestNewResponse_StreamError(t *testing.T) { w := &testWriter{h: http.Header(make(map[string][]string)), err: errors.New("error")} assert.Error(t, r.Write(w)) } + +func TestWrite_HandlesPush(t *testing.T) { + r, err := NewResponse(&roadrunner.Payload{ + Context: []byte(`{"headers":{"http2-push":["/test.js"],"content-type":["text/html"]},"status": 200}`), + }) + + assert.NoError(t, err) + assert.NotNil(t, r) + + w := &testWriter{h: http.Header(make(map[string][]string))} + assert.NoError(t, r.Write(w)) + + assert.Nil(t, w.h["http2-push"]) + assert.Equal(t, []string{"/test.js"}, w.pushes) +} + +func TestWrite_HandlesTrailers(t *testing.T) { + r, err := NewResponse(&roadrunner.Payload{ + Context: []byte(`{"headers":{"trailer":["foo, bar", "baz"],"foo":["test"],"bar":["demo"]},"status": 200}`), + }) + + assert.NoError(t, err) + assert.NotNil(t, r) + + w := &testWriter{h: http.Header(make(map[string][]string))} + assert.NoError(t, r.Write(w)) + + assert.Nil(t, w.h["trailer"]) + assert.Nil(t, w.h["foo"]) + assert.Nil(t, w.h["baz"]) + assert.Equal(t, "test", w.h.Get("Trailer:foo")) + assert.Equal(t, "demo", w.h.Get("Trailer:bar")) +} |