summaryrefslogtreecommitdiff
path: root/plugins/http/response.go
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2020-12-26 00:47:21 +0300
committerGitHub <[email protected]>2020-12-26 00:47:21 +0300
commit566d7f4c95eb5dedcb2da5afcda4bbea8eba077f (patch)
tree0007a6b8c8ac9e7d31b8a5f3f7f27669c860d261 /plugins/http/response.go
parent1bc3db2ea9b95edd0101676d7bfd75df3782c3bd (diff)
parent7a0dee1a416705c621edbf50e1f43fb39845348f (diff)
Merge pull request #463 from spiral/experiment/core_pluginsv2.0.0-beta1
[RR2] Plugins
Diffstat (limited to 'plugins/http/response.go')
-rw-r--r--plugins/http/response.go105
1 files changed, 105 insertions, 0 deletions
diff --git a/plugins/http/response.go b/plugins/http/response.go
new file mode 100644
index 00000000..17049ce1
--- /dev/null
+++ b/plugins/http/response.go
@@ -0,0 +1,105 @@
+package http
+
+import (
+ "io"
+ "net/http"
+ "strings"
+ "sync"
+
+ "github.com/spiral/roadrunner/v2/pkg/payload"
+)
+
+// Response handles PSR7 response logic.
+type Response struct {
+ // Status contains response status.
+ Status int `json:"status"`
+
+ // Header contains list of response headers.
+ Headers map[string][]string `json:"headers"`
+
+ // associated Body payload.
+ Body interface{}
+ sync.Mutex
+}
+
+// NewResponse creates new response based on given pool payload.
+func NewResponse(p payload.Payload) (*Response, error) {
+ r := &Response{Body: p.Body}
+ if err := json.Unmarshal(p.Context, r); err != nil {
+ return nil, err
+ }
+
+ return r, nil
+}
+
+// Write writes response headers, status and body into ResponseWriter.
+func (r *Response) Write(w http.ResponseWriter) error {
+ // INFO map is the reference type in golang
+ p := handlePushHeaders(r.Headers)
+ if pusher, ok := w.(http.Pusher); ok {
+ for _, v := range p {
+ err := pusher.Push(v, nil)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ handleTrailers(r.Headers)
+ for n, h := range r.Headers {
+ for _, v := range h {
+ w.Header().Add(n, v)
+ }
+ }
+
+ w.WriteHeader(r.Status)
+
+ if data, ok := r.Body.([]byte); ok {
+ _, err := w.Write(data)
+ if err != nil {
+ return handleWriteError(err)
+ }
+ }
+
+ if rc, ok := r.Body.(io.Reader); ok {
+ if _, err := io.Copy(w, rc); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func handlePushHeaders(h map[string][]string) []string {
+ var p []string
+ pushHeader, ok := h[http2pushHeaderKey]
+ if !ok {
+ return p
+ }
+
+ p = append(p, pushHeader...)
+
+ delete(h, http2pushHeaderKey)
+
+ return p
+}
+
+func handleTrailers(h map[string][]string) {
+ trailers, ok := h[TrailerHeaderKey]
+ if !ok {
+ return
+ }
+
+ 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, TrailerHeaderKey)
+}