func TestRequestBodySentToMiddleware(t *testing.T) { RegisterTestingT(t) // sends a request with fizz=buzz body, server responds with {'message': 'here'} // then, since it's modify mode - middleware is applied again, this time // middleware takes original request body and replaces response body with it. server, dbClient := testTools(200, `{'message': 'here'}`) defer server.Close() requestBody := []byte("fizz=buzz") body := ioutil.NopCloser(bytes.NewBuffer(requestBody)) req, err := http.NewRequest("POST", "http://capture_body.com", body) Expect(err).To(BeNil()) requestDetails, err := models.NewRequestDetailsFromHttpRequest(req) Expect(err).To(BeNil()) dbClient.Cfg.Middleware.FullCommand = "./examples/middleware/reflect_body/reflect_body.py" resp, err := dbClient.modifyRequestResponse(req, requestDetails) // body from the request should be in response body, instead of server's response responseBody, err := ioutil.ReadAll(resp.Body) resp.Body.Close() Expect(err).To(BeNil()) Expect(string(responseBody)).To(Equal(string(requestBody))) }
func TestGetResponseCorruptedRequestResponsePair(t *testing.T) { RegisterTestingT(t) server, dbClient := testTools(200, `{'message': 'here'}`) defer server.Close() requestBody := []byte("fizz=buzz") body := ioutil.NopCloser(bytes.NewBuffer(requestBody)) req, err := http.NewRequest("POST", "http://capture_body.com", body) Expect(err).To(BeNil()) _, err = dbClient.captureRequest(req) Expect(err).To(BeNil()) fp := matching.GetRequestFingerprint(req, requestBody, false) dbClient.RequestCache.Set([]byte(fp), []byte("you shall not decode me!")) // repeating process bodyNew := ioutil.NopCloser(bytes.NewBuffer(requestBody)) reqNew, err := http.NewRequest("POST", "http://capture_body.com", bodyNew) Expect(err).To(BeNil()) requestDetails, err := models.NewRequestDetailsFromHttpRequest(reqNew) Expect(err).To(BeNil()) response, err := dbClient.getResponse(reqNew, requestDetails) Expect(err).ToNot(BeNil()) Expect(response).To(BeNil()) }
func TestMatchOnRequestBody(t *testing.T) { RegisterTestingT(t) server, dbClient := testTools(200, `{'message': 'here'}`) defer server.Close() // preparing and saving requests/responses with unique bodies for i := 0; i < 5; i++ { requestBody := []byte(fmt.Sprintf("fizz=buzz, number=%d", i)) body := ioutil.NopCloser(bytes.NewBuffer(requestBody)) request, err := http.NewRequest("POST", "http://capture_body.com", body) Expect(err).To(BeNil()) resp := models.ResponseDetails{ Status: 200, Body: fmt.Sprintf("body here, number=%d", i), } pair := models.RequestResponsePair{Response: resp} // creating response c := NewConstructor(request, pair) response := c.ReconstructResponse() dbClient.save(request, requestBody, response, []byte(resp.Body)) } // now getting responses for i := 0; i < 5; i++ { requestBody := []byte(fmt.Sprintf("fizz=buzz, number=%d", i)) body := ioutil.NopCloser(bytes.NewBuffer(requestBody)) request, err := http.NewRequest("POST", "http://capture_body.com", body) Expect(err).To(BeNil()) requestDetails, err := models.NewRequestDetailsFromHttpRequest(request) Expect(err).To(BeNil()) response, err := dbClient.getResponse(request, requestDetails) Expect(err).To(BeNil()) responseBody, err := ioutil.ReadAll(response.Body) response.Body.Close() Expect(err).To(BeNil()) Expect(string(responseBody)).To(Equal(fmt.Sprintf("body here, number=%d", i))) } }
func TestModifyRequestNoMiddleware(t *testing.T) { RegisterTestingT(t) server, dbClient := testTools(201, `{'message': 'here'}`) defer server.Close() dbClient.Cfg.Middleware.FullCommand = "" req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil) Expect(err).To(BeNil()) requestDetails, err := models.NewRequestDetailsFromHttpRequest(req) Expect(err).To(BeNil()) _, err = dbClient.modifyRequestResponse(req, requestDetails) Expect(err).ToNot(BeNil()) }
func TestGetNotRecordedRequest(t *testing.T) { RegisterTestingT(t) server, dbClient := testTools(200, `{'message': 'here'}`) defer server.Close() request, err := http.NewRequest("POST", "http://capture_body.com", nil) Expect(err).To(BeNil()) requestDetails, err := models.NewRequestDetailsFromHttpRequest(request) Expect(err).To(BeNil()) response, err := dbClient.getResponse(request, requestDetails) Expect(err).ToNot(BeNil()) Expect(response).To(BeNil()) }
func TestModifyRequest(t *testing.T) { RegisterTestingT(t) server, dbClient := testTools(201, `{'message': 'here'}`) defer server.Close() dbClient.Cfg.Middleware.FullCommand = "./examples/middleware/modify_request/modify_request.py" req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil) Expect(err).To(BeNil()) requestDetails, err := models.NewRequestDetailsFromHttpRequest(req) Expect(err).To(BeNil()) response, err := dbClient.modifyRequestResponse(req, requestDetails) Expect(err).To(BeNil()) // response should be changed to 202 Expect(response.StatusCode).To(Equal(http.StatusAccepted)) }
// doRequest performs original request and returns response that should be returned to client and error (if there is one) func (hf *Hoverfly) doRequest(request *http.Request) (*http.Request, *http.Response, error) { // We can't have this set. And it only contains "/pkg/net/http/" anyway request.RequestURI = "" if hf.Cfg.Middleware.FullCommand != "" { // middleware is provided, modifying request var requestResponsePair models.RequestResponsePair rd, err := models.NewRequestDetailsFromHttpRequest(request) if err != nil { return nil, nil, err } requestResponsePair.Request = rd c := NewConstructor(request, requestResponsePair) err = c.ApplyMiddleware(&hf.Cfg.Middleware) if err != nil { log.WithFields(log.Fields{ "mode": hf.Cfg.Mode, "error": err.Error(), "host": request.Host, "method": request.Method, "path": request.URL.Path, }).Error("could not forward request, middleware failed to modify request.") return nil, nil, err } request, err = c.ReconstructRequest() if err != nil { return nil, nil, err } } requestBody, _ := ioutil.ReadAll(request.Body) request.Body = ioutil.NopCloser(bytes.NewReader(requestBody)) resp, err := hf.HTTP.Do(request) request.Body = ioutil.NopCloser(bytes.NewReader(requestBody)) if err != nil { log.WithFields(log.Fields{ "mode": hf.Cfg.Mode, "error": err.Error(), "host": request.Host, "method": request.Method, "path": request.URL.Path, }).Error("could not forward request, failed to do an HTTP request.") return nil, nil, err } log.WithFields(log.Fields{ "mode": hf.Cfg.Mode, "host": request.Host, "method": request.Method, "path": request.URL.Path, }).Debug("response from external service got successfuly!") resp.Header.Set("hoverfly", "Was-Here") return request, resp, nil }
// processRequest - processes incoming requests and based on proxy state (record/playback) // returns HTTP response. func (hf *Hoverfly) processRequest(req *http.Request) *http.Response { var response *http.Response mode := hf.Cfg.GetMode() requestDetails, err := models.NewRequestDetailsFromHttpRequest(req) if err != nil { return hoverflyError(req, err, "Could not interpret HTTP request", http.StatusServiceUnavailable) } if mode == CaptureMode { var err error response, err = hf.captureRequest(req) if err != nil { return hoverflyError(req, err, "Could not capture request", http.StatusServiceUnavailable) } log.WithFields(log.Fields{ "mode": mode, "middleware": hf.Cfg.Middleware, "path": req.URL.Path, "rawQuery": req.URL.RawQuery, "method": req.Method, "destination": req.Host, }).Info("request and response captured") return response } else if mode == SynthesizeMode { var err error response, err = SynthesizeResponse(req, requestDetails, &hf.Cfg.Middleware) if err != nil { return hoverflyError(req, err, "Could not create synthetic response!", http.StatusServiceUnavailable) } log.WithFields(log.Fields{ "mode": mode, "middleware": hf.Cfg.Middleware, "path": req.URL.Path, "rawQuery": req.URL.RawQuery, "method": req.Method, "destination": req.Host, }).Info("synthetic response created successfuly") } else if mode == ModifyMode { var err error response, err = hf.modifyRequestResponse(req, requestDetails) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "middleware": hf.Cfg.Middleware, }).Error("Got error when performing request modification") return hoverflyError(req, err, fmt.Sprintf("Middleware (%s) failed or something else happened!", hf.Cfg.Middleware), http.StatusServiceUnavailable) } } else { var err *matching.MatchingError response, err = hf.getResponse(req, requestDetails) if err != nil { return hoverflyError(req, err, err.Error(), err.StatusCode) } } respDelay := hf.ResponseDelays.GetDelay(requestDetails) if respDelay != nil { respDelay.Execute() } return response }