// 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 (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 }
// 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 traceHttpResponse(c *Configuration, res *http.Response) { if res == nil { return } tracerx.Printf("HTTP: %d", res.StatusCode) if c.isTracingHttp == false { return } fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "< %s %s\n", res.Proto, res.Status) for key, _ := range res.Header { fmt.Fprintf(os.Stderr, "< %s: %s\n", key, res.Header.Get(key)) } traceBody := false ctype := strings.ToLower(strings.SplitN(res.Header.Get("Content-Type"), ";", 2)[0]) for _, tracedType := range tracedTypes { if strings.Contains(ctype, tracedType) { traceBody = true } } res.Body = newCountedResponse(res) if traceBody { res.Body = newTracedBody(res.Body) } fmt.Fprintf(os.Stderr, "\n") }
func CopyHttpResponse(r *http.Response) *http.Response { resCopy := new(http.Response) if r == nil { return resCopy } *resCopy = *r if r.Body != nil { defer r.Body.Close() // Buffer body data var bodyBuffer bytes.Buffer bodyBuffer2 := new(bytes.Buffer) io.Copy(&bodyBuffer, r.Body) *bodyBuffer2 = bodyBuffer // Create new ReadClosers so we can split output r.Body = ioutil.NopCloser(&bodyBuffer) resCopy.Body = ioutil.NopCloser(bodyBuffer2) } return resCopy }
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 CopyResponse(dest *http.Response, src *http.Response) { *dest = *src var bodyBytes []byte if src.Body != nil { bodyBytes, _ = ioutil.ReadAll(src.Body) } // Restore the io.ReadCloser to its original state src.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) dest.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) }
// readResponse is like Read, but for HTTP response. Upon return, the body is // replaced wit a buffer and can be read again. func (srv *Server) readResponse(resp *http.Response) ([]byte, error) { p, err := srv.read(resp.Body, resp.ContentLength) resp.Body.Close() switch e := srv.uninstrument(err); { case e == io.EOF || e == io.ErrUnexpectedEOF || len(p) == 0: resp.Body = ioutil.NopCloser(eofReader{}) return nil, io.EOF case err != nil: return nil, err case len(p) != 0: resp.Body = ioutil.NopCloser(bytes.NewReader(p)) } return p, nil }
func TestGetUser(t *testing.T) { g := New("clientID", "secret", "http://myapp.com/") creds := &common.Credentials{Map: objx.MSI()} testTripperFactory := new(test.TestTripperFactory) testTripper := new(test.TestTripper) testTripperFactory.On("NewTripper", mock.Anything, g).Return(testTripper, nil) testResponse := new(http.Response) testResponse.Header = make(http.Header) testResponse.Header.Set("Content-Type", "application/json") testResponse.StatusCode = 200 testResponse.Body = ioutil.NopCloser(strings.NewReader(`{"full_name":"their-name","id":"uniqueid","username":"******","avatar_url":"http://myface.com/","online":true}`)) testTripper.On("RoundTrip", mock.Anything).Return(testResponse, nil) g.tripperFactory = testTripperFactory user, err := g.GetUser(creds) if assert.NoError(t, err) && assert.NotNil(t, user) { assert.Equal(t, user.Name(), "their-name") assert.Equal(t, user.AuthCode(), "") assert.Equal(t, user.Nickname(), "loginname") assert.Equal(t, user.Email(), "") // doesn't come from soundcloud assert.Equal(t, user.AvatarURL(), "http://myface.com/") assert.Equal(t, user.Data()["online"], true) } }
func TestRuntime_OverrideClientOperation(t *testing.T) { client := &http.Client{} rt := NewWithClient("", "/", []string{"https"}, client) var i int rt.clientOnce.Do(func() { i++ }) assert.Equal(t, client, rt.client) assert.Equal(t, 0, i) var seen *http.Client rt.do = func(_ context.Context, cl *http.Client, _ *http.Request) (*http.Response, error) { seen = cl res := new(http.Response) res.StatusCode = 200 res.Body = ioutil.NopCloser(bytes.NewBufferString("OK")) return res, nil } client2 := new(http.Client) client2.Timeout = 3 * time.Second if assert.NotEqual(t, client, client2) { _, err := rt.Submit(&runtime.ClientOperation{ Client: client2, Params: runtime.ClientRequestWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error { return nil }), Reader: runtime.ClientResponseReaderFunc(func(_ runtime.ClientResponse, _ runtime.Consumer) (interface{}, error) { return nil, nil }), }) if assert.NoError(t, err) { assert.Equal(t, client2, seen) } } }
// Do sends an HTTP request with the provided http.Client and returns an HTTP response. // If the client is nil, http.DefaultClient is used. // If the context is canceled or times out, ctx.Err() will be returned. func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { if client == nil { client = http.DefaultClient } // Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go. cancel := canceler(client, req) type responseAndError struct { resp *http.Response err error } result := make(chan responseAndError, 1) // Make local copies of test hooks closed over by goroutines below. // Prevents data races in tests. testHookDoReturned := testHookDoReturned testHookDidBodyClose := testHookDidBodyClose go func() { resp, err := client.Do(req) testHookDoReturned() result <- responseAndError{resp, err} }() var resp *http.Response select { case <-ctx.Done(): testHookContextDoneBeforeHeaders() cancel() // Clean up after the goroutine calling client.Do: go func() { if r := <-result; r.resp != nil { testHookDidBodyClose() r.resp.Body.Close() } }() return nil, ctx.Err() case r := <-result: var err error resp, err = r.resp, r.err if err != nil { return resp, err } } c := make(chan struct{}) go func() { select { case <-ctx.Done(): cancel() case <-c: // The response's Body is closed. } }() resp.Body = ¬ifyingReader{resp.Body, c} return resp, nil }
func (self *Surfer) Download(sp *spider.Spider, cReq *request.Request) *spider.Context { ctx := spider.GetContext(sp, cReq) var resp *http.Response var err error switch cReq.GetDownloaderID() { case SURF_ID: resp, err = self.surf.Download(cReq) case PHANTOM_ID: resp, err = self.phantom.Download(cReq) } if resp.StatusCode >= 400 { err = errors.New("响应状态 " + resp.Status) } if resp.Header.Get("Content-Encoding") == "gzip" { var gzipReader *gzip.Reader gzipReader, err = gzip.NewReader(resp.Body) resp.Body.Close() if err == nil { resp.Body = ioutil.NopCloser(gzipReader) } } ctx.SetResponse(resp).SetError(err) return ctx }
func fockHTTPServer(req *http.Request, support_version bool) (error, *http.Response) { if support_version { contentType := req.Header.Get("Content-Type:") if contentType != "application/octet-stream" { return errors.New("Content-Type: unmatched"), nil } if strings.EqualFold(req.Method, "POST") { return errors.New("method unmatched"), nil } protocol := req.Header.Get("application/X-DNSoverHTTP") if strings.EqualFold(protocol, "UDP") || strings.EqualFold(protocol, "TCP") { return errors.New("protocol isn't UDP or TCP"), nil } return nil, new(http.Response) } else { if strings.EqualFold(req.Method, "POST") { return errors.New("method unmatched"), nil } contentType := req.Header.Get("Content-Type:") if contentType != "application/X-DNSoverHTTP" { return errors.New("Content-Type: unmatched"), nil } protocol := req.Header.Get("X-Proxy-DNS-Transport") if strings.EqualFold(protocol, "UDP") || strings.EqualFold(protocol, "TCP") { return errors.New("protocol isn't UDP or TCP"), nil } res := new(http.Response) res.Body = req.Body return nil, res } }
func buildTestHTTPResponse(body string) *http.Response { rsp := new(http.Response) rsp.Body = noopCloser{bytes.NewBufferString(body)} return rsp }
// Get the robots.txt group for this crawler. func (this *worker) getRobotsTxtGroup(b []byte, res *http.Response) (g *robotstxt.Group) { var data *robotstxt.RobotsData var e error if res != nil { // Get the bytes from the response body b, e = ioutil.ReadAll(res.Body) // Rewind the res.Body (by re-creating it from the bytes) res.Body = ioutil.NopCloser(bytes.NewBuffer(b)) // Error or not, the robots.txt has been fetched, so notify this.extender.FetchedRobots(res) } if e == nil { data, e = robotstxt.FromBytes(b) } // If robots data cannot be parsed, will return nil, which will allow access by default. // Reasonable, since by default no robots.txt means full access, so invalid // robots.txt is similar behavior. if e != nil { this.extender.Error(newCrawlError(e, CekParseRobots, nil)) this.logFunc(LogError, "ERROR parsing robots.txt for host %s: %s", this.host, e.Error()) } else { g = data.FindGroup(this.robotUserAgent) } return }
// save saves the body of a response corresponding to a request. func (c *CachedRoundTrip) save(req *http.Request, resp *http.Response) error { if resp.StatusCode == http.StatusMovedPermanently || resp.StatusCode == http.StatusTemporaryRedirect { u, err := resp.Location() if err != nil { return err } err = c.Cache.Put(req.URL, c.newEntry([]byte("REDIRECT:"+u.String()), resp)) if err != nil { return err } return nil } body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } resp.Body.Close() err = c.Cache.Put(req.URL, c.newEntry(body, resp)) if err != nil { return err } resp.Body = ioutil.NopCloser(bytes.NewReader(body)) return nil }
func TestCheckResponseForErrors(t *testing.T) { var err error var resp http.Response resp.StatusCode = 300 _, err = checkResponseForErrors(&resp) if err == nil { t.Error("should have returned error") } resp.StatusCode = 503 _, err = checkResponseForErrors(&resp) if err == nil { t.Error("should have returned error") } resp.StatusCode = 404 resp.Body = ioutil.NopCloser(strings.NewReader(`{"message":"Record Not Found","errors":[{"resource":"Activity","field":"id","code":"invalid"}]}`)) _, err = checkResponseForErrors(&resp) if err == nil { t.Error("should have returned error") } if se, ok := err.(Error); ok { if len(se.Errors) == 0 { t.Error("Detailed errors not parsed") } } else { t.Error("Should have returned strava error") } }
func (rp *RProxy) delta(r *http.Response, ctx *goproxy.ProxyCtx) *http.Response { if !rp.HasSig() { return r } r.Header.Set("Content-Type", "application/rproxy-patch") defer r.Body.Close() var body bytes.Buffer _, err := io.Copy(&body, r.Body) if err != nil { log.Println("Error recopying body: ", err) return r } var delta bytes.Buffer rdiff := exec.Command("/usr/bin/rdiff", "delta", "sig", "-", "-") rdiff.Stdin = &body rdiff.Stdout = &delta var errBuf bytes.Buffer rdiff.Stderr = &errBuf err = rdiff.Run() if err != nil { log.Println("Error running rdiff delta:", err) log.Println("rdiff error: ", string(errBuf.Bytes())) } r.Body = &bytesCloser{delta} log.Printf("S -> C: %dB", delta.Len()) return r }
// Dump is a convenient method to log the full contents of a request and its response. func Dump(t T, resp *http.Response) { // dump request var buffer bytes.Buffer buffer.WriteString("\n") buffer.WriteString(fmt.Sprintf("%v %v\n", resp.Request.Method, resp.Request.URL)) for k, v := range resp.Request.Header { buffer.WriteString(fmt.Sprintf("%s : %v\n", k, strings.Join(v, ","))) } // dump response buffer.WriteString("\n") if resp == nil { return } for k, v := range resp.Header { buffer.WriteString(fmt.Sprintf("%s : %v\n", k, strings.Join(v, ","))) } if resp.Body != nil { body, err := ioutil.ReadAll(resp.Body) if err != nil { buffer.WriteString(fmt.Sprintf("unable to read body:%v", err)) } else { buffer.WriteString(string(body)) } resp.Body.Close() // put the body back for re-reads resp.Body = ioutil.NopCloser(bytes.NewReader(body)) } buffer.WriteString("\n") t.Logf(buffer.String()) }
func PrintResponseInfo(res *http.Response, err error) { fmt.Println(`==response start===============================================`) format := "%10s : %v\n" if err != nil { fmt.Printf(format, "err", err) } if res != nil { fmt.Printf(format, "status", res.Status) fmt.Printf(format, "req_url", res.Request.URL) fmt.Printf(format, "req_method", res.Request.Method) content_type := res.Header.Get("Content-Type") if content_type[:4] == "text" { buf := bytes.NewBuffer([]byte{}) io.Copy(buf, res.Body) fmt.Printf(format, "body", buf.String()) res.Body = ioutil.NopCloser(buf).(io.ReadCloser) } fmt.Printf("%10s\n", "header") for k, v := range res.Header { fmt.Printf("%2s %30s : %s\n", "", k, v) } } fmt.Println(`==response end===============================================`) fmt.Println() }
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)) }
func NewTestResponse(status float64, data interface{}, errors []map[string]interface{}, context string, changeInfo api.ChangeInfo) *api.Response { httpResponse := new(http.Response) sro := map[string]interface{}{common.ResponseObjectFieldStatusCode: status, common.ResponseObjectFieldData: data, common.ResponseObjectFieldErrors: errors, common.ResponseObjectFieldChangeInfo: changeInfo, common.ResponseObjectFieldContext: context} session := api.NewSession("project", "company", "apiKey") responseBytes, _ := session.Codec().Marshal(sro, nil) httpResponse.Body = ioutil.NopCloser(bytes.NewBuffer(responseBytes)) httpResponse.Header = make(map[string][]string) response, newResponseErr := api.NewResponse(session, httpResponse) if newResponseErr != nil { panic(fmt.Sprintf("NewTestResponse: %s", newResponseErr)) } return response }
// putCache puts the supplied http.Response into the cache. func putCache(c *Context, req *http.Request, resp *http.Response) error { defer resp.Body.Close() filename := cacheEntryFilename(c, req.URL.String()) f, err := os.Create(filename) if err != nil { return err } if err := resp.Write(f); err != nil { f.Close() return err } f.Close() if log.V(1) { log.Infof("wrote %q to response cache", req.URL.String()) } // TODO(spencer): this sucks, but we must re-read the response as // the body is closed during the call to resp.Write(). if readResp, err := readCachedResponse(filename, req); err != nil { log.Errorf("failed reading cached response: %s", err) return err } else { resp.Body = readResp.Body } return nil }
func TestGetUser(t *testing.T) { g := New("clientID", "secret", "http://myapp.com/") creds := &common.Credentials{Map: objx.MSI()} testTripperFactory := new(test.TestTripperFactory) testTripper := new(test.TestTripper) testTripperFactory.On("NewTripper", mock.Anything, g).Return(testTripper, nil) testResponse := new(http.Response) testResponse.Header = make(http.Header) testResponse.Header.Set("Content-Type", "application/json") testResponse.StatusCode = 200 testResponse.Body = ioutil.NopCloser(strings.NewReader(`{"name":"their-name","id":"uniqueid","login":"******","email":"*****@*****.**","picture":"http://myface.com/","blog":"http://blog.com/"}`)) testTripper.On("RoundTrip", mock.Anything).Return(testResponse, nil) g.tripperFactory = testTripperFactory user, err := g.GetUser(creds) if assert.NoError(t, err) && assert.NotNil(t, user) { assert.Equal(t, user.Name(), "their-name") assert.Equal(t, user.AuthCode(), "") // doesn't come from google assert.Equal(t, user.Email(), "*****@*****.**") assert.Equal(t, user.AvatarURL(), "http://myface.com/") assert.Equal(t, user.Data()["blog"], "http://blog.com/") googleCreds := user.ProviderCredentials()[googleName] if assert.NotNil(t, googleCreds) { assert.Equal(t, "uniqueid", googleCreds.Get(common.CredentialsKeyID).Str()) } } }
func TestDealWithItParentTest(t *testing.T) { stub := StubHandler().(*stubHandler) target := ChartHandler(make(chan bool), &Results{}, stub).(*chartHandler) expectedData := []byte("Expected Data") var response http.Response response.Body = nopCloser{bytes.NewBuffer(expectedData)} testTime := time.Now() timer := StubTimer(testTime, testTime.Add(time.Hour)) go func() { <-target.logger }() target.DealWithIt(response, &timer) if stub.dealCalled == 0 { t.Errorf("TestDealWithItParent: Failed to call DealWithIt on the parent") } result, err := ioutil.ReadAll(stub.savedBody) if err != nil { t.Errorf("TestDealWithItParent: Failed to read expected data from parent call, err %v", err) } if !bytes.Equal(result, expectedData) { t.Errorf("TestDealWithItParent: Expected '%v' but got '%v'", expectedData, result) } }
// FileFetcher's Fetch() implementation func (this *fileFetcherExtender) Fetch(u *url.URL, userAgent string, headRequest bool) (*http.Response, error) { var res *http.Response = new(http.Response) var req *http.Request var e error if req, e = http.NewRequest("GET", u.String(), nil); e != nil { panic(e) } // Prepare the pseudo-request req.Header.Add("User-Agent", userAgent) // Open the file specified as path in u, relative to testdata/[host]/ f, e := os.Open(path.Join(FileFetcherBasePath, u.Host, u.Path)) if e != nil { // Treat errors as 404s - file not found res.Status = "404 Not Found" res.StatusCode = 404 } else { res.Status = "200 OK" res.StatusCode = 200 res.Body = f } res.Request = req return res, e }
func TestOAuth2Provider_Non200Response(t *testing.T) { config := &common.Config{ Map: objx.MSI( OAuth2KeyRedirectUrl, OAuth2KeyRedirectUrl, OAuth2KeyScope, OAuth2KeyScope, OAuth2KeyClientID, OAuth2KeyClientID, OAuth2KeySecret, OAuth2KeySecret, OAuth2KeyAuthURL, OAuth2KeyAuthURL, OAuth2KeyTokenURL, OAuth2KeyTokenURL)} testTripperFactory := new(test.TestTripperFactory) testTripper := new(test.TestTripper) testProvider := new(test.TestProvider) testResponse := new(http.Response) testResponse.Header = make(http.Header) testResponse.Header.Set("Content-Type", "text/plain") testResponse.StatusCode = 401 testResponse.Body = ioutil.NopCloser(strings.NewReader("No mate")) testTripperFactory.On("NewTripper", common.EmptyCredentials, mock.Anything).Return(testTripper, nil) testTripper.On("RoundTrip", mock.Anything).Return(testResponse, nil) data := objx.MSI(OAuth2KeyCode, []string{"123"}) _, err := CompleteAuth(testTripperFactory, data, config, testProvider) if assert.Error(t, err) { assert.IsType(t, &common.AuthServerError{}, err) } mock.AssertExpectationsForObjects(t, testTripperFactory.Mock, testTripper.Mock, testProvider.Mock) }
func TestGetUser(t *testing.T) { testProvider := new(test.TestProvider) creds := new(common.Credentials) testTripperFactory := new(test.TestTripperFactory) testTripper := new(test.TestTripper) testTripperFactory.On("NewTripper", creds, testProvider).Return(testTripper, nil) testResponse := new(http.Response) testResponse.Header = make(http.Header) testResponse.Header.Set("Content-Type", "application/json") testResponse.StatusCode = 200 testResponse.Body = ioutil.NopCloser(strings.NewReader(`{"name":"their-name","id":"uniqueid","login":"******","email":"*****@*****.**","avatar_url":"http://myface.com/","blog":"http://blog.com/"}`)) testTripper.On("RoundTrip", mock.Anything).Return(testResponse, nil) client := &http.Client{Transport: testTripper} testProvider.On("GetClient", creds).Return(client, nil) data, err := Get(testProvider, creds, "endpoint") if assert.NoError(t, err) && assert.NotNil(t, data) { assert.Equal(t, data["name"], "their-name") assert.Equal(t, data["id"], "uniqueid") assert.Equal(t, data["login"], "loginname") assert.Equal(t, data["email"], "*****@*****.**") assert.Equal(t, data["avatar_url"], "http://myface.com/") assert.Equal(t, data["blog"], "http://blog.com/") } }
func buildError(r *http.Response) error { if debug { log.Printf("got error (status code %v)", r.StatusCode) data, err := ioutil.ReadAll(r.Body) if err != nil { log.Printf("\tread error: %v", err) } else { log.Printf("\tdata:\n%s\n\n", data) } r.Body = ioutil.NopCloser(bytes.NewBuffer(data)) } err := Error{} // TODO return error if Unmarshal fails? xml.NewDecoder(r.Body).Decode(&err) r.Body.Close() err.StatusCode = r.StatusCode if err.Message == "" { err.Message = r.Status } if debug { log.Printf("err: %#v\n", err) } return &err }
func (lrt *LoggingRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { var err error var res *http.Response log.Printf("Forwarding to: %s\n", request.URL.String()) res, err = lrt.transport.RoundTrip(request) if err != nil { return nil, err } body, err := ioutil.ReadAll(res.Body) if err != nil { log.Fatalln(err.Error()) } log.Println("") log.Printf("Response Headers: %#v\n", res.Header) log.Println("") log.Printf("Response Body: %s\n", string(body)) log.Println("") res.Body = ioutil.NopCloser(bytes.NewBuffer(body)) log.Println("Sending response to GoRouter...") return res, err }