func()

in pkg/hostmgr/mesos/yarpc/transport/mhttp/outbound.go [150:245]


func (o *outbound) Call(
	ctx context.Context,
	req *transport.Request) (*transport.Response, error) {

	if !o.started.Load() {
		// panic because there's no recovery from this
		panic(errOutboundNotStarted)
	}

	start := time.Now()
	deadline, _ := ctx.Deadline()
	ttl := deadline.Sub(start)

	hostPort := o.detector.HostPort()
	if len(hostPort) == 0 {
		return nil, errNoLeader
	}

	actualURL := o.urlTemplate
	actualURL.Host = hostPort

	request, err := http.NewRequest("POST", actualURL.String(), req.Body)
	if err != nil {
		return nil, err
	}

	request.Header = http.Header{}
	for k, v := range o.defaultHeaders {
		for _, vv := range v {
			request.Header.Set(k, vv)
		}
	}
	for k, v := range req.Headers.Items() {
		request.Header.Set(k, v)
	}
	request.Header.Set(CallerHeader, req.Caller)
	request.Header.Set(ServiceHeader, req.Service)
	request.Header.Set(ProcedureHeader, req.Procedure)
	request.Header.Set(TTLMSHeader, fmt.Sprintf("%d", ttl/time.Millisecond))

	encoding := string(req.Encoding)
	if encoding != "" {
		request.Header.Set(EncodingHeader, encoding)
	}

	response, err := ctxhttp.Do(ctx, o.Client, request)
	if err != nil {
		o.scope.Counter(outboundError).Inc(1)
		if err == context.DeadlineExceeded {
			return nil, yarpcerrors.DeadlineExceededErrorf(
				"Outbound service timeout: service: %s, procedure: %s, timeout: %v",
				req.Service,
				req.Procedure,
				deadline.Sub(start))
		}

		return nil, err
	}

	if response.StatusCode >= 200 && response.StatusCode < 300 {
		return &transport.Response{
			Headers: transport.NewHeaders(),
			Body:    response.Body,
		}, nil
	}

	// TODO Behavior for 300-range status codes is undefined
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	if err := response.Body.Close(); err != nil {
		return nil, err
	}

	// Trim the trailing newline from HTTP error messages
	message := fmt.Sprintf(
		"{\"status_code\": %d, \"contents\": \"%s\"}",
		response.StatusCode,
		strings.TrimSuffix(string(contents), "\n"))

	if response.StatusCode == 401 {
		return nil, yarpcerrors.UnauthenticatedErrorf(message)
	}

	if response.StatusCode >= 400 && response.StatusCode < 500 {
		return nil, yarpcerrors.InternalErrorf(message)
	}

	if response.StatusCode == http.StatusGatewayTimeout {
		return nil, yarpcerrors.DeadlineExceededErrorf(message)
	}

	return nil, yarpcerrors.UnknownErrorf(message)
}