Skip to content

Commit

Permalink
Merge 1ee8283 into 28a9deb
Browse files Browse the repository at this point in the history
  • Loading branch information
kpacha committed Nov 21, 2018
2 parents 28a9deb + 1ee8283 commit f9b11bc
Show file tree
Hide file tree
Showing 10 changed files with 755 additions and 28 deletions.
30 changes: 28 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -21,6 +21,7 @@ deps:
test:
go generate ./...
go test -cover -race ./...
go test -coverprofile=coverage.out -tags integration ./...

benchmark:
@echo "Proxy middleware stack"
Expand Down
20 changes: 18 additions & 2 deletions proxy/http.go
Expand Up @@ -2,6 +2,7 @@ package proxy

import (
"context"
"fmt"
"net/http"
"strings"

Expand Down Expand Up @@ -37,10 +38,11 @@ func NewHTTPProxyWithHTTPExecutor(remote *config.Backend, re client.HTTPRequestE

ef := NewEntityFormatter(remote)
rp := DefaultHTTPResponseParserFactory(HTTPResponseParserConfig{dec, ef})
return NewHTTPProxyDetailed(remote, re, client.DefaultHTTPStatusHandler, rp)
return NewHTTPProxyDetailed(remote, re, client.GetHTTPStatusHandler(remote), rp)
}

// NewHTTPProxyDetailed creates a http proxy with the injected configuration, HTTPRequestExecutor, Decoder and HTTPResponseParser
// NewHTTPProxyDetailed creates a http proxy with the injected configuration, HTTPRequestExecutor,
// Decoder and HTTPResponseParser
func NewHTTPProxyDetailed(remote *config.Backend, re client.HTTPRequestExecutor, ch client.HTTPStatusHandler, rp HTTPResponseParser) Proxy {
return func(ctx context.Context, request *Request) (*Response, error) {
requestToBakend, err := http.NewRequest(strings.ToTitle(request.Method), request.URL.String(), request.Body)
Expand Down Expand Up @@ -69,6 +71,14 @@ func NewHTTPProxyDetailed(remote *config.Backend, re client.HTTPRequestExecutor,

resp, err = ch(ctx, resp)
if err != nil {
if t, ok := err.(responseError); ok {
return &Response{
Data: map[string]interface{}{
fmt.Sprintf("error_%s", t.Name()): t,
},
Metadata: Metadata{StatusCode: t.StatusCode()},
}, nil
}
return nil, err
}

Expand All @@ -91,3 +101,9 @@ func NewRequestBuilderMiddleware(remote *config.Backend) Middleware {
}
}
}

type responseError interface {
Error() string
Name() string
StatusCode() int
}
48 changes: 48 additions & 0 deletions proxy/http_test.go
Expand Up @@ -193,6 +193,54 @@ func TestNewHTTPProxy_badStatusCode(t *testing.T) {
}
}

func TestNewHTTPProxy_badStatusCode_detailed(t *testing.T) {
expectedMethod := "GET"
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "booom", 500)
}))
defer backendServer.Close()

rpURL, _ := url.Parse(backendServer.URL)
backend := config.Backend{
Decoder: encoding.JSONDecoder,
ExtraConfig: config.ExtraConfig{
client.Namespace: map[string]interface{}{
"return_error_details": "some",
},
},
}
request := Request{
Method: expectedMethod,
Path: "/",
URL: rpURL,
Body: newDummyReadCloser(""),
}
mustEnd := time.After(time.Duration(150) * time.Millisecond)

ctx, cancel := context.WithTimeout(context.Background(), time.Duration(10)*time.Millisecond)
defer cancel()
response, err := httpProxy(&backend)(ctx, &request)
if err != nil {
t.Errorf("The proxy propagated the backend error: %s", err.Error())
}
if response == nil {
t.Error("We were expecting a response but we got none")
return
}
if response.Metadata.StatusCode != 500 {
t.Errorf("unexpected error code: %d", response.Metadata.StatusCode)
}
b, _ := json.Marshal(response.Data)
if string(b) != `{"error_some":{"http_status_code":500,"http_body":"booom\n"}}` {
t.Errorf("unexpected response content: %s", string(b))
}
select {
case <-mustEnd:
t.Errorf("Error: expected response")
default:
}
}

func TestNewHTTPProxy_decodingError(t *testing.T) {
expectedMethod := "GET"
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down
34 changes: 21 additions & 13 deletions router/gin/endpoint.go
Expand Up @@ -43,39 +43,42 @@ func CustomErrorEndpointHandler(configuration *config.EndpointConfig, prxy proxy
default:
}

complete := router.HeaderIncompleteResponseValue

if response != nil && len(response.Data) > 0 {
if response.IsComplete {
c.Header(router.CompleteResponseHeaderName, router.HeaderCompleteResponseValue)
complete = router.HeaderCompleteResponseValue
if isCacheEnabled {
c.Header("Cache-Control", cacheControlHeaderValue)
}
} else {
c.Header(router.CompleteResponseHeaderName, router.HeaderIncompleteResponseValue)
}

for k, v := range response.Metadata.Headers {
c.Header(k, v[0])
}
} else {
if err != nil {
abort(c, errF(err))
}

c.Header(router.CompleteResponseHeaderName, complete)

if err != nil {
c.Error(err)

if response == nil {
if t, ok := err.(responseError); ok {
c.Status(t.StatusCode())
} else {
c.Status(errF(err))
}
cancel()
return
}
c.Header(router.CompleteResponseHeaderName, router.HeaderIncompleteResponseValue)
}

render(c, response)
cancel()
}
}

func abort(c *gin.Context, code int) {
c.Status(code)
c.Header(router.CompleteResponseHeaderName, router.HeaderIncompleteResponseValue)
c.Abort()
}

// NewRequest gets a request from the current gin context and the received query string
func NewRequest(headersToSend []string) func(*gin.Context, []string) *proxy.Request {
if len(headersToSend) == 0 {
Expand Down Expand Up @@ -115,3 +118,8 @@ func NewRequest(headersToSend []string) func(*gin.Context, []string) *proxy.Requ
}
}
}

type responseError interface {
Error() string
StatusCode() int
}
27 changes: 16 additions & 11 deletions router/gin/render.go
Expand Up @@ -70,50 +70,55 @@ func negotiatedRender(c *gin.Context, response *proxy.Response) {
}

func stringRender(c *gin.Context, response *proxy.Response) {
status := c.Writer.Status()

if response == nil {
c.String(http.StatusOK, "")
c.String(status, "")
return
}
d, ok := response.Data["content"]
if !ok {
c.String(http.StatusOK, "")
c.String(status, "")
return
}
msg, ok := d.(string)
if !ok {
c.String(http.StatusOK, "")
c.String(status, "")
return
}
c.String(http.StatusOK, msg)
c.String(status, msg)
}

func jsonRender(c *gin.Context, response *proxy.Response) {
status := c.Writer.Status()
if response == nil {
c.JSON(http.StatusOK, emptyResponse)
c.JSON(status, emptyResponse)
return
}
c.JSON(http.StatusOK, response.Data)
c.JSON(status, response.Data)
}

func xmlRender(c *gin.Context, response *proxy.Response) {
status := c.Writer.Status()
if response == nil {
c.XML(http.StatusOK, nil)
c.XML(status, nil)
return
}
d, ok := response.Data["content"]
if !ok {
c.XML(http.StatusOK, nil)
c.XML(status, nil)
return
}
c.XML(http.StatusOK, d)
c.XML(status, d)
}

func yamlRender(c *gin.Context, response *proxy.Response) {
status := c.Writer.Status()
if response == nil {
c.YAML(http.StatusOK, emptyResponse)
c.YAML(status, emptyResponse)
return
}
c.YAML(http.StatusOK, response.Data)
c.YAML(status, response.Data)
}

func noopRender(c *gin.Context, response *proxy.Response) {
Expand Down

0 comments on commit f9b11bc

Please sign in to comment.