// DumpResponse is like DumpRequest but dumps a response. func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) { var b bytes.Buffer save := resp.Body savecl := resp.ContentLength if !body { // For content length of zero. Make sure the body is an empty // reader, instead of returning error through failureToReadBody{}. if resp.ContentLength == 0 { resp.Body = emptyBody } else { resp.Body = failureToReadBody{} } } else if resp.Body == nil { resp.Body = emptyBody } else { save, resp.Body, err = drainBody(resp.Body) if err != nil { return nil, err } } err = resp.Write(&b) if err == errNoBody { err = nil } resp.Body = save resp.ContentLength = savecl if err != nil { return nil, err } return b.Bytes(), nil }
func (srv *Server) handlerExecutePipeline(request *Request, keepAlive bool) *http.Response { var res *http.Response // execute the pipeline if res = srv.Pipeline.execute(request); res == nil { res = StringResponse(request.HttpRequest, 404, nil, "Not Found") } // The res.Write omits Content-length on 0 length bodies, and by spec, // it SHOULD. While this is not MUST, it's kinda broken. See sec 4.4 // of rfc2616 and a 200 with a zero length does not satisfy any of the // 5 conditions if Connection: keep-alive is set :( // I'm forcing chunked which seems to work because I couldn't get the // content length to write if it was 0. // Specifically, the android http client waits forever if there's no // content-length instead of assuming zero at the end of headers. der. if res.Body == nil { if request.HttpRequest.Method != "HEAD" { res.ContentLength = 0 } res.TransferEncoding = []string{"identity"} res.Body = ioutil.NopCloser(bytes.NewBuffer([]byte{})) } else if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) { // the following is copied from net/http/transfer.go // in the std lib, this is only applied to a request. we need it on a response // Test to see if it's actually zero or just unset. var buf [1]byte n, _ := io.ReadFull(res.Body, buf[:]) if n == 1 { // Oh, guess there is data in this Body Reader after all. // The ContentLength field just wasn't set. // Stich the Body back together again, re-attaching our // consumed byte. res.ContentLength = -1 res.Body = &lengthFixReadCloser{io.MultiReader(bytes.NewBuffer(buf[:]), res.Body), res.Body} } else { res.TransferEncoding = []string{"identity"} } } if res.ContentLength < 0 && request.HttpRequest.Method != "HEAD" { res.TransferEncoding = []string{"chunked"} } // For HTTP/1.0 and Keep-Alive, sending the Connection: Keep-Alive response header is required // because close is default (opposite of 1.1) if keepAlive && !request.HttpRequest.ProtoAtLeast(1, 1) { res.Header.Set("Connection", "Keep-Alive") } // cleanup request.HttpRequest.Body.Close() return res }
func (c *imageTransformer) transformResponse(r *http.Response) { var images []APIImages if err := json.NewDecoder(r.Body).Decode(&images); err != nil { return } for _, im := range images { if im.Labels == nil { im.Labels = make(map[string]string) } im.Labels["hola"] = "world" } var b bytes.Buffer w := bufio.NewWriter(&b) // Now take the struct and encode it if err := json.NewEncoder(w).Encode(&images); err != nil { return } // Restore the io.ReadCloser to its original state r.Body = ioutil.NopCloser(bytes.NewBuffer(b.Bytes())) // Set size of modified body r.ContentLength = int64(binary.Size(b)) }
// DumpResponse is like DumpRequest but dumps a response. func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) { // dump出响应内容 var b bytes.Buffer save := resp.Body savecl := resp.ContentLength if !body { resp.Body = failureToReadBody{} } else if resp.Body == nil { resp.Body = emptyBody } else { save, resp.Body, err = drainBody(resp.Body) if err != nil { return } } err = resp.Write(&b) if err == errNoBody { err = nil } resp.Body = save resp.ContentLength = savecl if err != nil { return nil, err } return b.Bytes(), nil }
func (c *Client) logResponse(resp *http.Response) error { if c.logHTTP { var err error save := resp.Body savecl := resp.ContentLength body := true if !body { resp.Body = failureToReadBody{} } else if resp.Body == nil { resp.Body = emptyBody } else { save, resp.Body, err = drainBody(resp.Body) if err != nil { return err } } fmt.Println("----------- response start -----------") err = resp.Write(os.Stderr) if err == errNoBody { err = nil } resp.Body = save resp.ContentLength = savecl if err != nil { return err } fmt.Println("----------- response end -----------") } return nil }
func maybeUngzipResponse(resp *http.Response) { if resp.Header.Get("Content-Encoding") == "gzip" { resp.Header.Del("Content-Encoding") resp.Header.Del("Content-Length") resp.ContentLength = -1 resp.Body = &gzipReader{body: resp.Body} } }
func TestHandleHttpResponseReturnsErrOnZeroContentLength(t *testing.T) { var response http.Response response.StatusCode = 200 response.ContentLength = 0 _, err := handleHTTPResponse(&response, nil) assertEqual(t, "No content was returned", err.Error(), "The returned error was not the expected error") }
func (c *URLCache) Restore(res *http.Response) { res.Status = c.CachedResponse.Status res.StatusCode = c.CachedResponse.StatusCode res.Header = c.CachedResponse.Header res.ContentLength = c.CachedResponse.ContentLength res.TransferEncoding = c.CachedResponse.TransferEncoding res.Body = &ClosableBuffer{bytes.NewReader(c.CachedBody)} res.Header.Set(CachedHeader, CachedHeaderVal) res.Header.Set(CachedMD5Header, c.MD5) }
func TestGobResponseSniff1(t *testing.T) { var e request e.embedMime = new(embedMime) ctx := context.Background() response := new(http.Response) response.StatusCode = 200 b := []byte{0x37, 0xff, 0x81, 0x03, 0x01, 0x01, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x01, 0xff, 0x82, 0x00, 0x01, 0x04, 0x01, 0x03, 0x53, 0x74, 0x72, 0x01, 0x0c, 0x00, 0x01, 0x03, 0x4e, 0x75, 0x6d, 0x01, 0x08, 0x00, 0x01, 0x04, 0x42, 0x6f, 0x6f, 0x6c, 0x01, 0x02, 0x00, 0x01, 0x04, 0x4e, 0x75, 0x6c, 0x6c, 0x01, 0x10, 0x00, 0x00, 0x00, 0x0e, 0xff, 0x82, 0x01, 0x03, 0x62, 0x61, 0x72, 0x01, 0xfe, 0x24, 0x40, 0x01, 0x01, 0x00} buf := bytes.NewBuffer(b) response.Body = ioutil.NopCloser(buf) response.ContentLength = int64(buf.Len()) def := encoding.Default() e1, err := def.DecodeResponse(&e)(ctx, response) if err != nil { t.Logf("Decode Request Failed: %s\n", err) t.Fail() } if e1 != &e { t.Logf("Returned Result is NOT the same value: %#v\n", e1) t.Fail() } if e.Str != "bar" { t.Logf("e.Str != \"bar\": \"%s\"\n", e.Str) t.Fail() } if e.Num != 10.0 { t.Logf("e.Num != 10.0: %f\n", e.Num) t.Fail() } if !e.Bool { t.Logf("!e.Bool: %f\n", e.Bool) t.Fail() } if e.Null != nil { t.Logf("e.Null != nil: %f\n", e.Null) t.Fail() } }
func (t *minionTransport) ProcessResponse(req *http.Request, resp *http.Response) (*http.Response, error) { body, err := ioutil.ReadAll(resp.Body) if err != nil { // copying the response body did not work return nil, err } bodyNode := &html.Node{ Type: html.ElementNode, Data: "body", DataAtom: atom.Body, } nodes, err := html.ParseFragment(bytes.NewBuffer(body), bodyNode) if err != nil { glog.Errorf("Failed to found <body> node: %v", err) return resp, err } // Define the method to traverse the doc tree and update href node to // point to correct minion var updateHRef func(*html.Node) updateHRef = func(n *html.Node) { if n.Type == html.ElementNode && n.Data == "a" { for i, attr := range n.Attr { if attr.Key == "href" { Url := &url.URL{ Path: "/proxy/minion/" + req.URL.Host + req.URL.Path + attr.Val, } n.Attr[i].Val = Url.String() break } } } for c := n.FirstChild; c != nil; c = c.NextSibling { updateHRef(c) } } newContent := &bytes.Buffer{} for _, n := range nodes { updateHRef(n) err = html.Render(newContent, n) if err != nil { glog.Errorf("Failed to render: %v", err) } } resp.Body = ioutil.NopCloser(newContent) // Update header node with new content-length // TODO: Remove any hash/signature headers here? resp.Header.Del("Content-Length") resp.ContentLength = int64(newContent.Len()) return resp, err }
func RedirectResponse(req *http.Request, url string) *http.Response { res := new(http.Response) res.StatusCode = 302 res.ProtoMajor = 1 res.ProtoMinor = 1 res.ContentLength = 0 res.Request = req res.Header = make(map[string][]string) res.Header.Set("Location", url) return res }
func marshalResponseBody(r *http.Response, body interface{}) error { newBody, err := json.Marshal(body) if err != nil { return err } r.Body = ioutil.NopCloser(bytes.NewReader(newBody)) r.ContentLength = int64(len(newBody)) // Stop it being chunked, because that hangs r.TransferEncoding = nil return nil }
// ResponseHeader returns a new set of headers from a request. func ResponseHeader(res *http.Response) *Header { return &Header{ h: res.Header, host: func() string { return "" }, cl: func() int64 { return res.ContentLength }, te: func() []string { return res.TransferEncoding }, setHost: func(string) {}, setCL: func(cl int64) { res.ContentLength = cl }, setTE: func(te []string) { res.TransferEncoding = te }, } }
func (f *EtagFilter) FilterResponse(request *falcore.Request, res *http.Response) { request.CurrentStage.Status = 1 // Skipped (default) if if_none_match := request.HttpRequest.Header.Get("If-None-Match"); if_none_match != "" { if res.StatusCode == 200 && res.Header.Get("Etag") == if_none_match { res.StatusCode = 304 res.Status = "304 Not Modified" res.Body.Close() res.Body = nil res.ContentLength = 0 request.CurrentStage.Status = 0 // Success } } }
func TestHandleHttpResponseReturnsErrOnContentLengthTooLarge(t *testing.T) { var response http.Response response.StatusCode = 200 response.ContentLength = MaxFeedSize + 1 _, err := handleHTTPResponse(&response, nil) assertStartsWith(t, err.Error(), "Feed exceeds maximum size of", "The returned error was not the expected error") }
// DumpResponse is like DumpRequest but dumps a response. func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) { var b bytes.Buffer save := resp.Body savecl := resp.ContentLength if !body || resp.Body == nil { resp.Body = nil resp.ContentLength = 0 } else { save, resp.Body, err = drainBody(resp.Body) if err != nil { return } } err = resp.Write(&b) resp.Body = save resp.ContentLength = savecl if err != nil { return } dump = b.Bytes() return }
// ModifyResponse sets the Content-Type header and overrides the response body. func (m *Modifier) ModifyResponse(res *http.Response) error { // Replace the existing body, close it first. res.Body.Close() res.Header.Set("Content-Type", m.contentType) // Reset the Content-Encoding since we know that the new body isn't encoded. res.Header.Del("Content-Encoding") res.ContentLength = int64(len(m.body)) res.Body = ioutil.NopCloser(bytes.NewReader(m.body)) return nil }
func (rt ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *SessionState) error { _, versionPaths, _, _ := rt.Spec.GetVersionData(req) found, meta := rt.Spec.CheckSpecMatchesStatus(req.URL.Path, req.Method, versionPaths, TransformedResponse) if found { thisMeta := meta.(*TransformSpec) // Read the body: defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) // Put into an interface: var bodyData interface{} switch thisMeta.TemplateMeta.TemplateData.Input { case tykcommon.RequestXML: mxj.XmlCharsetReader = WrappedCharsetReader bodyData, err = mxj.NewMapXml(body) // unmarshal if err != nil { log.WithFields(logrus.Fields{ "prefix": "outbound-transform", "server_name": rt.Spec.APIDefinition.Proxy.TargetURL, "api_id": rt.Spec.APIDefinition.APIID, "path": req.URL.Path, }).Error("Error unmarshalling XML: ", err) } case tykcommon.RequestJSON: json.Unmarshal(body, &bodyData) default: json.Unmarshal(body, &bodyData) } // Apply to template var bodyBuffer bytes.Buffer err = thisMeta.Template.Execute(&bodyBuffer, bodyData) if err != nil { log.WithFields(logrus.Fields{ "prefix": "outbound-transform", "server_name": rt.Spec.APIDefinition.Proxy.TargetURL, "api_id": rt.Spec.APIDefinition.APIID, "path": req.URL.Path, }).Error("Failed to apply template to request: ", err) } res.ContentLength = int64(bodyBuffer.Len()) res.Header.Set("Content-Length", strconv.Itoa(bodyBuffer.Len())) res.Body = ioutil.NopCloser(&bodyBuffer) } return nil }
func TestXMLResponseSniff1(t *testing.T) { var e request e.embedMime = new(embedMime) ctx := context.Background() response := new(http.Response) response.StatusCode = 200 str := "<request><str>bar</str><num>10.0</num><bool>true</bool><null>null</null></request>" t.Logf("Data: %s\n", str) buf := bytes.NewBuffer([]byte(str)) response.Body = ioutil.NopCloser(buf) response.ContentLength = int64(buf.Len()) def := encoding.Default() e1, err := def.DecodeResponse(&e)(ctx, response) if err != nil { t.Logf("Decode Request Failed: %s\n", err) t.Fail() } if e1 != &e { t.Logf("Returned Result is NOT the same value: %#v\n", e1) t.Fail() } if e.Str != "bar" { t.Logf("e.Str != \"bar\": \"%s\"\n", e.Str) t.Fail() } if e.Num != 10.0 { t.Logf("e.Num != 10.0: %f\n", e.Num) t.Fail() } if !e.Bool { t.Logf("!e.Bool: %f\n", e.Bool) t.Fail() } if e.Null != nil { t.Logf("e.Null != nil: %f\n", e.Null) t.Fail() } }
func SimpleResponse(req *http.Request, status int, headers http.Header, body string) *http.Response { res := new(http.Response) body_rdr := (*fixedResBody)(strings.NewReader(body)) res.StatusCode = status res.ProtoMajor = 1 res.ProtoMinor = 1 res.ContentLength = int64((*strings.Reader)(body_rdr).Len()) res.Request = req res.Header = make(map[string][]string) res.Body = body_rdr if headers != nil { res.Header = headers } return res }
func (res *HTTPResponseEvent) ToResponse() *http.Response { raw := new(http.Response) raw.Proto = "HTTP" raw.ProtoMajor = 1 raw.ProtoMinor = 1 //raw.Close = true raw.ContentLength = int64(res.Content.Len()) raw.Header = make(http.Header) raw.StatusCode = int(res.Status) res.SetHeader("Content-Length", strconv.Itoa(res.Content.Len())) for i := 0; i < len(res.Headers); i++ { header := res.Headers[i] if strings.EqualFold(header.Name, "Set-Cookie") || strings.EqualFold(header.Name, "Set-Cookie2") { tmp := strings.Split(header.Value, ",") if len(tmp) > 1 { var vlist list.List for _, v := range tmp { if (!strings.Contains(v, "=") || strings.Index(v, "=") > strings.Index(v, ";")) && vlist.Len() > 0 { v = vlist.Back().Value.(string) + "," + v vlist.Remove(vlist.Back()) vlist.PushBack(v) //headerValues.add(headerValues.removeLast() + "," + v); } else { vlist.PushBack(v) } } e := vlist.Front() for { if e == nil { break } raw.Header.Add(header.Name, e.Value.(string)) e = e.Next() } } else { raw.Header.Add(header.Name, header.Value) } } else { raw.Header.Add(header.Name, header.Value) } } if raw.ContentLength > 0 { raw.Body = ioutil.NopCloser(&res.Content) } return raw }
// fixLinks modifies links in an HTML file such that they will be redirected through the proxy if needed. func (t *proxyTransport) fixLinks(req *http.Request, resp *http.Response) (*http.Response, error) { origBody := resp.Body defer origBody.Close() newContent := &bytes.Buffer{} var reader io.Reader = origBody var writer io.Writer = newContent encoding := resp.Header.Get("Content-Encoding") switch encoding { case "gzip": var err error reader, err = gzip.NewReader(reader) if err != nil { return nil, fmt.Errorf("errorf making gzip reader: %v", err) } gzw := gzip.NewWriter(writer) defer gzw.Close() writer = gzw // TODO: support flate, other encodings. case "": // This is fine default: // Some encoding we don't understand-- don't try to parse this glog.Errorf("Proxy encountered encoding %v for text/html; can't understand this so not fixing links.", encoding) return resp, nil } doc, err := html.Parse(reader) if err != nil { glog.Errorf("Parse failed: %v", err) return resp, err } t.scan(doc, func(n *html.Node) { t.updateURLs(n, req.URL) }) if err := html.Render(writer, doc); err != nil { glog.Errorf("Failed to render: %v", err) } resp.Body = ioutil.NopCloser(newContent) // Update header node with new content-length // TODO: Remove any hash/signature headers here? resp.Header.Del("Content-Length") resp.ContentLength = int64(newContent.Len()) return resp, err }
func (rt ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *SessionState) error { // New request checker, more targetted, less likely to fail var stat RequestStatus var meta interface{} var found bool _, versionPaths, _, _ := rt.Spec.GetVersionData(req) found, meta = rt.Spec.CheckSpecMatchesStatus(req.URL.Path, req.Method, versionPaths, TransformedResponse) if found { stat = StatusTransformResponse } if stat == StatusTransformResponse { thisMeta := meta.(*TransformSpec) // Read the body: defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) // Put into an interface: var bodyData interface{} switch thisMeta.TemplateMeta.TemplateData.Input { case tykcommon.RequestXML: log.Warning("XML Input is not supprted") case tykcommon.RequestJSON: json.Unmarshal(body, &bodyData) default: json.Unmarshal(body, &bodyData) } // Apply to template var bodyBuffer bytes.Buffer log.Warning("RUNNING TRANSFORM") err = thisMeta.Template.Execute(&bodyBuffer, bodyData) if err != nil { log.Error("Failed to apply template to request: ", err) } res.ContentLength = int64(bodyBuffer.Len()) res.Header.Set("Content-Length", strconv.Itoa(bodyBuffer.Len())) res.Body = ioutil.NopCloser(&bodyBuffer) } return nil }
// NewNotification returns a notification response with a specific body content. func NewNotification(body *bytes.Buffer) *http.Response { resp := new(http.Response) resp.Status = "200 OK" resp.StatusCode = http.StatusOK resp.ProtoMajor = 1 resp.ProtoMinor = 0 resp.Body = ioutil.NopCloser(body) resp.ContentLength = int64(body.Len()) resp.Header = map[string][]string{} resp.Header.Set("Content-Type", HTTPContentTypeHAPJson) // Will be ignored unfortunately and won't be fixed https://github.com/golang/go/issues/9304 // Make sure to call FixProtocolSpecifier() instead resp.Proto = "EVENT/1.0" return resp }
// Create an http Response from scratch, there must be a better way that this but I // don't know what it is func concoctResponse(req *http.Request, message string, code int) *http.Response { r := http.Response{ Status: "Bad Gateway", //strconv.Itoa(code), StatusCode: code, Proto: req.Proto, ProtoMajor: req.ProtoMajor, ProtoMinor: req.ProtoMinor, Header: make(map[string][]string), Request: req, } body := bytes.NewReader([]byte(message)) r.Body = ioutil.NopCloser(body) r.ContentLength = int64(body.Len()) r.Header.Add("content-type", "text/plain") r.Header.Add("date", time.Now().Format(time.RFC1123)) r.Header.Add("server", "wstunnel") return &r }
// Generate an http.Response using the basic fields func SimpleResponse(req *http.Request, status int, headers http.Header, contentLength int64, body io.Reader) *http.Response { res := new(http.Response) res.StatusCode = status res.ProtoMajor = 1 res.ProtoMinor = 1 res.ContentLength = contentLength res.Request = req res.Header = make(map[string][]string) if body_rdr, ok := body.(io.ReadCloser); ok { res.Body = body_rdr } else if body != nil { res.Body = ioutil.NopCloser(body) } if headers != nil { res.Header = headers } return res }
func extractBody(resp *http.Response) (extract []byte, err error) { save := resp.Body savecl := resp.ContentLength save, resp.Body, err = copyBody(resp.Body) if err != nil { return } defer resp.Body.Close() extract, err = ioutil.ReadAll(resp.Body) resp.Body = save resp.ContentLength = savecl if err != nil { return nil, err } return extract, nil }
func (r *response) Response() *http.Response { if r.Data == nil { r.Data = new(bytes.Buffer) } out := new(http.Response) out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode)) out.StatusCode = r.StatusCode out.Proto = "HTTP/1.1" out.ProtoMajor = 1 out.ProtoMinor = 1 out.Header = r.Header out.Body = &readCloser{r.Data} out.ContentLength = int64(r.Data.Len()) out.TransferEncoding = nil out.Close = true out.Trailer = make(http.Header) out.Request = r.Request return out }
func proxyHandler(r *http.Response, ctx *goproxy.ProxyCtx) *http.Response { if reAdminUrl.FindString(r.Request.URL.Path) == "" { return r } buf := NewBuffer() _, err := buf.B.ReadFrom(r.Body) if err != nil { log.Print(err) return r } b := reWlsStatus.ReplaceAll(buf.B.Bytes(), activeWls) buf.B.Reset() buf.B.Write(b) r.Body = buf r.ContentLength = int64(buf.B.Len()) return r }
func (r *Response) Response() *http.Response { out := new(http.Response) r.headerM.Lock() out.Status = fmt.Sprintf("%d %s", r.StatusCode, http.StatusText(r.StatusCode)) out.StatusCode = r.StatusCode out.Header = r.Header r.headerM.Unlock() out.Proto = "HTTP/1.1" out.ProtoMajor = 1 out.ProtoMinor = 1 r.dataM.Lock() if r.data == nil { out.Body = &ReadCloser{new(bytes.Buffer)} } else if unrequestedGzip(r) { // User-agents MUST support gzip compression. // Regardless of the Accept-Encoding sent by the user-agent, the server may // always send content encoded with gzip or deflate encoding. r.data.Prep() out.Header.Del("Content-Encoding") out.Header.Del("Content-Length") out.ContentLength = -1 out.Body = &gzipReader{body: r.data} } else { r.data.Prep() out.Body = r.data out.ContentLength = r.data.written } r.dataM.Unlock() out.TransferEncoding = nil out.Close = true out.Trailer = make(http.Header) out.Request = r.Request return out }