Example #1
0
// save gets request fingerprint, extracts request body, status code and headers, then saves it to cache
func (hf *Hoverfly) save(req *http.Request, reqBody []byte, resp *http.Response, respBody []byte) {

	if resp == nil {
		resp = emptyResp
	} else {
		responseObj := models.ResponseDetails{
			Status:  resp.StatusCode,
			Body:    string(respBody),
			Headers: resp.Header,
		}

		requestObj := models.RequestDetails{
			Path:        req.URL.Path,
			Method:      req.Method,
			Destination: req.Host,
			Scheme:      req.URL.Scheme,
			Query:       req.URL.RawQuery,
			Body:        string(reqBody),
			Headers:     req.Header,
		}

		pair := models.RequestResponsePair{
			Response: responseObj,
			Request:  requestObj,
		}

		err := hf.RequestMatcher.SaveRequestResponsePair(&pair)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to save payload")
		}

		pairBytes, err := pair.Encode()
		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to serialize payload")
		} else {
			// hook
			var en Entry
			en.ActionType = ActionTypeRequestCaptured
			en.Message = "captured"
			en.Time = time.Now()
			en.Data = pairBytes

			if err := hf.Hooks.Fire(ActionTypeRequestCaptured, &en); err != nil {
				log.WithFields(log.Fields{
					"error":      err.Error(),
					"message":    en.Message,
					"actionType": ActionTypeRequestCaptured,
				}).Error("failed to fire hook")
			}
		}

	}
}
Example #2
0
func TestRequestResponsePairEncodeEmpty(t *testing.T) {
	RegisterTestingT(t)

	pair := models.RequestResponsePair{}

	pairBytes, err := pair.Encode()
	Expect(err).To(BeNil())

	_, err = models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
}
Example #3
0
func Test_rebuildHashes_whenDataIsHashedForAProxy_andStillAProxy_keysAreNotChanged(t *testing.T) {
	RegisterTestingT(t)
	webserver := false

	db := cache.NewInMemoryCache()

	pair := models.RequestResponsePair{
		Request: models.RequestDetails{
			Path:        "/hello",
			Destination: "a-host.com",
		},
		Response: models.ResponseDetails{
			Body: "a body",
		},
	}

	pairBytes, _ := pair.Encode()

	db.Set([]byte(pair.Id()), pairBytes)

	rebuildHashes(db, webserver)

	result, err := db.Get([]byte(pair.Id()))

	Expect(err).To(BeNil())
	Expect(result).To(Equal(pairBytes))
}
Example #4
0
func TestRequestResponsePairEncodeDecode(t *testing.T) {
	RegisterTestingT(t)

	resp := models.ResponseDetails{
		Status: 200,
		Body:   "body here",
	}

	pair := models.RequestResponsePair{Response: resp}

	pairBytes, err := pair.Encode()
	Expect(err).To(BeNil())

	pairFromBytes, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(pairFromBytes.Response.Body).To(Equal(resp.Body))
	Expect(pairFromBytes.Response.Status).To(Equal(resp.Status))
}
Example #5
0
func ExecuteMiddlewareRemotely(middleware string, pair models.RequestResponsePair) (models.RequestResponsePair, error) {
	pairViewBytes, err := json.Marshal(pair.ConvertToRequestResponsePairView())

	req, err := http.NewRequest("POST", middleware, bytes.NewBuffer(pairViewBytes))
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Error when building request to remote middleware")
		return pair, err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Error when communicating with remote middleware")
		return pair, err
	}

	if resp.StatusCode != 200 {
		log.Error("Remote middleware did not process payload")
		return pair, errors.New("Error when communicating with remote middleware")
	}

	returnedPairViewBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Error when process response from remote middleware")
		return pair, err
	}

	var newPairView views.RequestResponsePairView

	err = json.Unmarshal(returnedPairViewBytes, &newPairView)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Error when trying to serialize response from remote middleware")
		return pair, err
	}
	return models.NewRequestResponsePairFromRequestResponsePairView(newPairView), nil
}
func TestHoverflyGetSimulationReturnsMultipleRequestResponsePairs(t *testing.T) {
	RegisterTestingT(t)

	server, unit := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	recording := models.RequestResponsePair{
		Request: models.RequestDetails{
			Destination: "testhost.com",
			Path:        "/test",
		},
		Response: models.ResponseDetails{
			Status: 200,
			Body:   "test",
		},
	}

	recordingBytes, err := recording.Encode()
	Expect(err).To(BeNil())

	unit.RequestCache.Set([]byte("key"), recordingBytes)
	unit.RequestCache.Set([]byte("key2"), recordingBytes)

	simulation, err := unit.GetSimulation()
	Expect(err).To(BeNil())

	Expect(simulation.DataView.RequestResponsePairs).To(HaveLen(2))

	Expect(*simulation.DataView.RequestResponsePairs[0].Request.Destination).To(Equal("testhost.com"))
	Expect(*simulation.DataView.RequestResponsePairs[0].Request.Path).To(Equal("/test"))
	Expect(*simulation.DataView.RequestResponsePairs[0].Request.RequestType).To(Equal("recording"))

	Expect(simulation.DataView.RequestResponsePairs[0].Response.Status).To(Equal(200))
	Expect(simulation.DataView.RequestResponsePairs[0].Response.Body).To(Equal("test"))

	Expect(*simulation.DataView.RequestResponsePairs[1].Request.Destination).To(Equal("testhost.com"))
	Expect(*simulation.DataView.RequestResponsePairs[1].Request.Path).To(Equal("/test"))
	Expect(*simulation.DataView.RequestResponsePairs[1].Request.RequestType).To(Equal("recording"))

	Expect(simulation.DataView.RequestResponsePairs[1].Response.Status).To(Equal(200))
	Expect(simulation.DataView.RequestResponsePairs[1].Response.Body).To(Equal("test"))
}
Example #7
0
func (this *RequestMatcher) SaveRequestResponsePair(pair *models.RequestResponsePair) error {
	var key string

	if *this.Webserver {
		key = pair.IdWithoutHost()
	} else {
		key = pair.Id()
	}

	log.WithFields(log.Fields{
		"path":          pair.Request.Path,
		"rawQuery":      pair.Request.Query,
		"requestMethod": pair.Request.Method,
		"bodyLen":       len(pair.Request.Body),
		"destination":   pair.Request.Destination,
		"hashKey":       key,
	}).Debug("Capturing")

	pairBytes, err := pair.Encode()

	if err != nil {
		return err
	}

	return this.RequestCache.Set([]byte(key), pairBytes)
}
Example #8
0
// ExecuteMiddleware - takes command (middleware string) and payload, which is passed to middleware
func ExecuteMiddlewareLocally(middlewares string, pair models.RequestResponsePair) (models.RequestResponsePair, error) {

	mws := strings.Split(middlewares, "|")
	var cmdList []*exec.Cmd

	for _, v := range mws {
		commands := strings.Split(strings.TrimSpace(v), " ")

		cmd := exec.Command(commands[0], commands[1:]...)
		cmdList = append(cmdList, cmd)
	}

	// getting payload
	pairViewBytes, err := json.Marshal(pair.ConvertToRequestResponsePairView())

	if log.GetLevel() == log.DebugLevel {
		log.WithFields(log.Fields{
			"middlewares": mws,
			"count":       len(mws),
			"payload":     string(pairViewBytes),
		}).Debug("preparing to modify payload")
	}

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to marshal json")
		return pair, err
	}

	//
	cmdList[0].Stdin = bytes.NewReader(pairViewBytes)

	// Run the pipeline
	mwOutput, stderr, err := Pipeline(cmdList...)

	// middleware failed to execute
	if err != nil {
		if len(stderr) > 0 {
			log.WithFields(log.Fields{
				"sdtderr": string(stderr),
				"error":   err.Error(),
			}).Error("Middleware error")
		} else {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Middleware error")
		}
		return pair, err
	}

	// log stderr, middleware executed successfully
	if len(stderr) > 0 {
		log.WithFields(log.Fields{
			"sdtderr": string(stderr),
		}).Info("Information from middleware")
	}

	if len(mwOutput) > 0 {
		var newPairView views.RequestResponsePairView

		err = json.Unmarshal(mwOutput, &newPairView)

		if err != nil {
			log.WithFields(log.Fields{
				"mwOutput": string(mwOutput),
				"error":    err.Error(),
			}).Error("Failed to unmarshal JSON from middleware")
		} else {
			if log.GetLevel() == log.DebugLevel {
				log.WithFields(log.Fields{
					"middlewares": middlewares,
					"count":       len(middlewares),
					"payload":     string(mwOutput),
				}).Debug("payload after modifications")
			}
			// payload unmarshalled into RequestResponsePair struct, returning it
			return models.NewRequestResponsePairFromRequestResponsePairView(newPairView), nil
		}
	} else {

		log.WithFields(log.Fields{
			"mwOutput": string(mwOutput),
		}).Warn("No response from middleware.")
	}

	return pair, nil

}
Example #9
0
// 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

}
Example #10
0
// ManualAddHandler - manually add new request/responses, using a form
func (d *Hoverfly) ManualAddHandler(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
	err := req.ParseForm()

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Got error while parsing form")
	}

	// request details
	destination := req.PostFormValue("inputDestination")
	method := req.PostFormValue("inputMethod")
	path := req.PostFormValue("inputPath")
	query := req.PostFormValue("inputQuery")
	reqBody := req.PostFormValue("inputRequestBody")

	preq := models.RequestDetails{
		Destination: destination,
		Method:      method,
		Path:        path,
		Query:       query,
		Body:        reqBody}

	// response
	respStatusCode := req.PostFormValue("inputResponseStatusCode")
	respBody := req.PostFormValue("inputResponseBody")
	contentType := req.PostFormValue("inputContentType")

	headers := make(map[string][]string)

	// getting content type
	if contentType == "xml" {
		headers["Content-Type"] = []string{"application/xml"}
	} else if contentType == "json" {
		headers["Content-Type"] = []string{"application/json"}
	} else {
		headers["Content-Type"] = []string{"text/html"}
	}

	sc, _ := strconv.Atoi(respStatusCode)

	presp := models.ResponseDetails{
		Status:  sc,
		Headers: headers,
		Body:    respBody,
	}

	log.WithFields(log.Fields{
		"respBody":    respBody,
		"contentType": contentType,
	}).Info("manually adding request/response")

	p := models.RequestResponsePair{Request: preq, Response: presp}

	var pairViews []views.RequestResponsePairView

	pairViews = append(pairViews, *p.ConvertToRequestResponsePairView())

	err = d.ImportRequestResponsePairViews(pairViews)

	w.Header().Set("Content-Type", "application/json")
	var response messageResponse

	if err != nil {
		response.Message = fmt.Sprintf("Got error: %s", err.Error())
		w.WriteHeader(400)

	} else {
		// redirecting to home
		response.Message = "Record added successfuly"
		w.WriteHeader(201)
	}
	b, err := response.Encode()
	if err != nil {
		// failed to read response body
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Could not encode response body!")
		http.Error(w, "Failed to encode response", 500)
		return
	}
	w.Write(b)

}
Example #11
0
// ExecuteMiddleware - takes command (middleware string) and payload, which is passed to middleware
func (this Middleware) executeMiddlewareLocally(pair models.RequestResponsePair) (models.RequestResponsePair, error) {
	var commandAndArgs []string
	if this.Binary == "" {
		commandAndArgs = strings.Split(strings.TrimSpace(this.FullCommand), " ")
	} else {
		commandAndArgs = []string{this.Binary, this.Script.Name()}
	}

	middlewareCommand := exec.Command(commandAndArgs[0], commandAndArgs[1:]...)

	// getting payload
	pairViewBytes, err := json.Marshal(pair.ConvertToRequestResponsePairView())

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to marshal json")
		return pair, err
	}

	if log.GetLevel() == log.DebugLevel {
		log.WithFields(log.Fields{
			"middleware": this.FullCommand,
			"stdin":      string(pairViewBytes),
		}).Debug("preparing to modify payload")
	}

	var stdout bytes.Buffer
	var stderr bytes.Buffer

	// Redirect standard streams
	middlewareCommand.Stdin = bytes.NewReader(pairViewBytes)
	middlewareCommand.Stdout = &stdout
	middlewareCommand.Stderr = &stderr

	if err := middlewareCommand.Start(); err != nil {
		log.WithFields(log.Fields{
			"sdtdout": string(stdout.Bytes()),
			"sdtderr": string(stderr.Bytes()),
			"error":   err.Error(),
		}).Error("Middleware failed to start")
		return pair, err
	}

	if err := middlewareCommand.Wait(); err != nil {
		log.WithFields(log.Fields{
			"sdtdout": string(stdout.Bytes()),
			"sdtderr": string(stderr.Bytes()),
			"error":   err.Error(),
		}).Error("Middleware failed to stop successfully")
		return pair, err
	}

	// log stderr, middleware executed successfully
	if len(stderr.Bytes()) > 0 {
		log.WithFields(log.Fields{
			"sdtderr": string(stderr.Bytes()),
		}).Info("Information from middleware")
	}

	if len(stdout.Bytes()) > 0 {
		var newPairView v2.RequestResponsePairView

		err = json.Unmarshal(stdout.Bytes(), &newPairView)

		if err != nil {
			log.WithFields(log.Fields{
				"stdout": string(stdout.Bytes()),
				"error":  err.Error(),
			}).Error("Failed to unmarshal JSON from middleware")
		} else {
			if log.GetLevel() == log.DebugLevel {
				log.WithFields(log.Fields{
					"middleware": this.FullCommand,
					"payload":    string(stdout.Bytes()),
				}).Debug("payload after modifications")
			}
			// payload unmarshalled into RequestResponsePair struct, returning it
			return models.NewRequestResponsePairFromRequestResponsePairView(newPairView), nil
		}
	} else {
		log.WithFields(log.Fields{
			"stdout": string(stdout.Bytes()),
		}).Warn("No response from middleware.")
	}

	return pair, nil

}