errorFromResponse builds a twirp.Error from a non-200 HTTP response. If the response has a valid serialized Twirp error, then it's returned. If not, the response status code is used to generate a similar twirp error. See twirpErrorFromIntermediary for more info on intermediary errors.
(resp *http.Response)
| 746 | // If not, the response status code is used to generate a similar twirp |
| 747 | // error. See twirpErrorFromIntermediary for more info on intermediary errors. |
| 748 | func errorFromResponse(resp *http.Response) twirp.Error { |
| 749 | statusCode := resp.StatusCode |
| 750 | statusText := http.StatusText(statusCode) |
| 751 | |
| 752 | if isHTTPRedirect(statusCode) { |
| 753 | // Unexpected redirect: it must be an error from an intermediary. |
| 754 | // Twirp clients don't follow redirects automatically, Twirp only handles |
| 755 | // POST requests, redirects should only happen on GET and HEAD requests. |
| 756 | location := resp.Header.Get("Location") |
| 757 | msg := fmt.Sprintf("unexpected HTTP status code %d %q received, Location=%q", statusCode, statusText, location) |
| 758 | return twirpErrorFromIntermediary(statusCode, msg, location) |
| 759 | } |
| 760 | |
| 761 | respBodyBytes, err := io.ReadAll(resp.Body) |
| 762 | if err != nil { |
| 763 | return wrapInternal(err, "failed to read server error response body") |
| 764 | } |
| 765 | |
| 766 | var tj twerrJSON |
| 767 | dec := json.NewDecoder(bytes.NewReader(respBodyBytes)) |
| 768 | dec.DisallowUnknownFields() |
| 769 | if err := dec.Decode(&tj); err != nil || tj.Code == "" { |
| 770 | // Invalid JSON response; it must be an error from an intermediary. |
| 771 | msg := fmt.Sprintf("Error from intermediary with HTTP status code %d %q", statusCode, statusText) |
| 772 | return twirpErrorFromIntermediary(statusCode, msg, string(respBodyBytes)) |
| 773 | } |
| 774 | |
| 775 | errorCode := twirp.ErrorCode(tj.Code) |
| 776 | if !twirp.IsValidErrorCode(errorCode) { |
| 777 | msg := "invalid type returned from server error response: " + tj.Code |
| 778 | return twirp.InternalError(msg).WithMeta("body", string(respBodyBytes)) |
| 779 | } |
| 780 | |
| 781 | twerr := twirp.NewError(errorCode, tj.Msg) |
| 782 | for k, v := range tj.Meta { |
| 783 | twerr = twerr.WithMeta(k, v) |
| 784 | } |
| 785 | return twerr |
| 786 | } |
| 787 | |
| 788 | // twirpErrorFromIntermediary maps HTTP errors from non-twirp sources to twirp errors. |
| 789 | // The mapping is similar to gRPC: https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md. |
no test coverage detected