예제 #1
0
파일: request.go 프로젝트: armada-io/h2
// Unmarshal the raw bytes payload of this request (into a protobuf)
func (self *Request) Unmarshal(into proto.Message) (err error) {
	switch self.delivery.ContentType {
	case "application/json":
		err = json.Unmarshal(self.delivery.Body, into)
	case "application/octetstream":
		err = proto.Unmarshal(self.delivery.Body, into)
	default:
		err = fmt.Errorf("Unknown content type: %s", self.delivery.ContentType)
	}

	return
}
예제 #2
0
// Caller returns something that implements `Caller` - allowing us to use this as our
// gateway to service calls - the returned `Caller` is thread safe
func (m *Mock) Caller() Caller {
	return func(req *client.Request, rsp proto.Message) errors.Error {
		m.Lock()
		defer m.Unlock()
		for _, s := range m.stubs {
			if s.matches(req) {
				if s.Responder != nil {
					numMatched := len(s.matched)
					responderRsp, err := s.Responder(numMatched, s.matched[numMatched-1])
					if err != nil {
						return err
					}
					// put the responderRsp INTO the rsp
					b, _ := proto.Marshal(responderRsp)
					proto.Unmarshal(b, rsp)

					return nil
				}

				if s.Error != nil {
					return s.Error
				}

				// put the response INTO the rsp
				b, _ := proto.Marshal(s.Response)
				proto.Unmarshal(b, rsp)

				return nil
			}
		}
		// no match found - do default action
		if m.proxy != nil {
			return m.proxy(req, rsp)
		}
		// no default - return error
		return errors.NotFound("mock.notfound", "No mocked service registered to handle request.")
	}
}
예제 #3
0
// Unmarshal the raw bytes payload of this request (into a protobuf)
func (r *Request) Unmarshal(into proto.Message) (err error) {
	if r == nil {
		err = fmt.Errorf("[Client] Cannot unmarshal request from nil Request")
		return
	}
	if into == nil {
		err = fmt.Errorf("[Client] Cannot unmarshal request into nil proto")
		return
	}
	switch r.contentType {
	case "application/json":
		err = json.Unmarshal(r.payload, into)
	case "application/octetstream":
		err = proto.Unmarshal(r.payload, into)
	default:
		err = fmt.Errorf("Unknown content type: %s", r.contentType)
	}

	return
}
예제 #4
0
// Unmarshal the raw bytes payload of this request (into a protobuf)
func (self *Response) Unmarshal(into proto.Message) (err error) {
	if self == nil {
		err = fmt.Errorf("[Client] Cannot unmarshal response from nil Response")
		return
	}
	if into == nil {
		err = fmt.Errorf("[Client] Cannot unmarshal response into nil proto")
		return
	}
	switch self.delivery.ContentType {
	case "application/json":
		err = json.Unmarshal(self.Body(), into)
	case "application/octetstream":
		err = proto.Unmarshal(self.Body(), into)
	default:
		err = fmt.Errorf("Unknown content type: %s", self.delivery.ContentType)
	}

	return
}
예제 #5
0
// ConfiguredHttpCaller with more explicit configuration options than simple HttpCaller
func ConfiguredHttpCaller(opts Options) Caller {
	tp := &httpclient.Transport{
		ConnectTimeout:        durationOrDefault(opts.ConnectTimeout, 5*time.Second),
		RequestTimeout:        durationOrDefault(opts.RequestTimeout, 5*time.Second),
		ResponseHeaderTimeout: durationOrDefault(opts.ResponseHeaderTimeout, 5*time.Second),
	}
	if opts.TlsSkipVerify {
		tp.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	httpClient := &http.Client{Transport: tp}

	return func(req *client.Request, rsp proto.Message) errors.Error {
		u, err := url.Parse(opts.BaseUrl)

		q := u.Query()
		q.Set("session_id", req.SessionID())
		q.Set("service", req.Service())
		q.Set("endpoint", req.Endpoint())
		u.Path = "/rpc"
		u.RawQuery = q.Encode()

		var httpReq *http.Request

		// send JSON req content-type to thin API as form-encoded data
		// send proto req content-type directly as bytes, with proto content type
		if req.ContentType() == jsonContentType {
			values := make(url.Values)
			values.Set("service", req.Service())
			values.Set("endpoint", req.Endpoint())
			values.Set("request", string(req.Payload()))
			httpReq, _ = http.NewRequest("POST", u.String(), bytes.NewReader([]byte(values.Encode())))
			httpReq.Header.Set("Content-Type", formEncodedContentType)
		} else {
			httpReq, _ = http.NewRequest("POST", u.String(), bytes.NewReader(req.Payload()))
			httpReq.Header.Set("Content-Type", protoContentType)
		}

		log.Tracef("[Multiclient] HTTP caller - calling '%s' : content-type '%s'", u.String(), req.ContentType())

		httpRsp, err := httpClient.Do(httpReq)
		if err != nil {
			log.Warnf("[Multiclient] HTTP caller error calling %s.%s via %s : %s", req.Service(), req.Endpoint(), u.String(), err)
			return errors.InternalServerError("multiclienthttp.postform", fmt.Sprintf("Error calling %s.%s via %s : %s", req.Service(), req.Endpoint(), u.String(), err))
		}

		defer httpRsp.Body.Close()
		rspBody, err := ioutil.ReadAll(httpRsp.Body)
		if err != nil {
			return errors.BadResponse("multiclienthttp.readresponse", fmt.Sprintf("Error reading response bytes: %v", err))
		}

		// what status code?
		if httpRsp.StatusCode != 200 {
			// deal with error
			e := &protoerror.PlatformError{}
			var err error
			if req.ContentType() == jsonContentType {
				jsonErr := &errorBody{}
				err = json.Unmarshal(rspBody, jsonErr)
				e.Code = proto.String(jsonErr.DottedCode)
				e.Context = jsonErr.Context
				e.Description = proto.String(jsonErr.Payload)
				e.HttpCode = proto.Uint32(uint32(httpRsp.StatusCode))
				// this conversion is lossy, since the JSON response for errors, as crafted
				// by the "thin API", does not currently include the error type, so we have
				// to guess from HTTP status code, but there is no distinct code for "BAD_RESPONSE"
				switch httpRsp.StatusCode {
				case 400:
					e.Type = protoerror.PlatformError_BAD_REQUEST.Enum()
				case 403:
					e.Type = protoerror.PlatformError_FORBIDDEN.Enum()
				case 404:
					e.Type = protoerror.PlatformError_NOT_FOUND.Enum()
				case 500:
					e.Type = protoerror.PlatformError_INTERNAL_SERVER_ERROR.Enum()
				case 504:
					e.Type = protoerror.PlatformError_TIMEOUT.Enum()
				}
			} else {
				err = proto.Unmarshal(rspBody, e)
			}
			// some issue understanding error rsp
			if err != nil {
				return errors.BadResponse("multiclienthttp.unmarshalerr", fmt.Sprintf("Error unmarshaling error response '%s': %v", string(rspBody), err))
			}
			return errors.FromProtobuf(e)
		}

		// unmarshal response
		if req.ContentType() == jsonContentType {
			err = json.Unmarshal(rspBody, rsp)
		} else {
			err = proto.Unmarshal(rspBody, rsp)
		}
		if err != nil {
			return errors.BadResponse("multiclienthttp.unmarshal", fmt.Sprintf("Error unmarshaling response: %v", err))
		}

		return nil
	}
}