summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2019-11-25 23:00:12 +0300
committerValery Piashchynski <[email protected]>2019-11-25 23:00:12 +0300
commit20d7536f7b0f16a0265d2d198136b5bd2c115089 (patch)
treebde74ea2e58eb594d79ee465c644227621cf35a3 /service
parentdf3aec38ef1421426084cc51a16a608ac3141715 (diff)
parentec38295a6ff947edee8de1658562476e08cf3184 (diff)
Merge remote-tracking branch 'remotes/upstream/master' into Fix_warning_and_issues
# Conflicts: # service/http/response.go
Diffstat (limited to 'service')
-rw-r--r--service/http/response.go64
-rw-r--r--service/http/response_test.go63
2 files changed, 113 insertions, 14 deletions
diff --git a/service/http/response.go b/service/http/response.go
index 7102f078..aafaed13 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"
+ "strings"
+
+ "github.com/spiral/roadrunner"
)
// Response handles PSR7 response logic.
@@ -31,19 +33,19 @@ func NewResponse(p *roadrunner.Payload) (*Response, error) {
// Write writes response headers, status and body into ResponseWriter.
func (r *Response) Write(w http.ResponseWriter) error {
- for n, h := range r.Headers {
- for _, v := range h {
- if n == "http2-push" {
- if pusher, ok := w.(http.Pusher); ok {
- err := pusher.Push(v, nil)
- if err != nil {
- return err
- }
- }
-
- continue
+ p, h := handlePushHeaders(r.Headers)
+ if pusher, ok := w.(http.Pusher); ok {
+ for _, v := range p {
+ err := pusher.Push(v, nil)
+ if err != nil {
+ return err
}
+ }
+ }
+ h = handleTrailers(h)
+ for n, h := range r.Headers {
+ for _, v := range h {
w.Header().Add(n, v)
}
}
@@ -65,3 +67,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
+ }
+
+ for _, tr := range trailers {
+ for _, n := range strings.Split(tr, ",") {
+ n = strings.Trim(n, "\t ")
+ 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..ad524567 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,53 @@ 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"))
+}
+
+func TestWrite_HandlesHandlesWhitespacesInTrailer(t *testing.T) {
+ r, err := NewResponse(&roadrunner.Payload{
+ Context: []byte(
+ `{"headers":{"trailer":["foo\t,bar , baz"],"foo":["a"],"bar":["b"],"baz":["c"]},"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.Equal(t, "a", w.h.Get("Trailer:foo"))
+ assert.Equal(t, "b", w.h.Get("Trailer:bar"))
+ assert.Equal(t, "c", w.h.Get("Trailer:baz"))
+}