TUN-2880: Return metadata about source of the response from cloudflared

This commit is contained in:
Areg Harutyunyan 2020-04-09 21:59:15 +01:00
parent a37da2b165
commit 322f909edb
4 changed files with 36 additions and 6 deletions

View File

@ -2,6 +2,7 @@ package h2mux
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
@ -20,6 +21,10 @@ var headerEncoding = base64.RawStdEncoding
const ( const (
RequestUserHeadersField = "cf-cloudflared-request-headers" RequestUserHeadersField = "cf-cloudflared-request-headers"
ResponseUserHeadersField = "cf-cloudflared-response-headers" ResponseUserHeadersField = "cf-cloudflared-response-headers"
ResponseMetaHeaderField = "cf-cloudflared-response-meta"
ResponseSourceCloudflared = "cloudflared"
ResponseSourceOrigin = "origin"
) )
// H2RequestHeadersToH1Request converts the HTTP/2 headers coming from origintunneld // H2RequestHeadersToH1Request converts the HTTP/2 headers coming from origintunneld
@ -226,3 +231,19 @@ func CreateSerializedHeaders(headersField string, headers ...http.Header) []Head
strings.Join(serializedHeaderChunks, ";"), strings.Join(serializedHeaderChunks, ";"),
}} }}
} }
type responseMetaHeader struct {
Source string `json:"src"`
}
func CreateResponseMetaHeader(source string) Header {
jsonResponseMetaHeader, err := json.Marshal(responseMetaHeader{Source: source})
if err != nil {
panic(err)
}
return Header{
Name: ResponseMetaHeaderField,
Value: string(jsonResponseMetaHeader),
}
}

View File

@ -688,7 +688,9 @@ func (h *TunnelHandler) serveHTTP(stream *h2mux.MuxedStream, req *http.Request)
} }
defer response.Body.Close() defer response.Body.Close()
err = stream.WriteHeaders(h2mux.H1ResponseToH2ResponseHeaders(response)) headers := h2mux.H1ResponseToH2ResponseHeaders(response)
headers = append(headers, h2mux.CreateResponseMetaHeader(h2mux.ResponseSourceOrigin))
err = stream.WriteHeaders(headers)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Error writing response header") return nil, errors.Wrap(err, "Error writing response header")
} }
@ -725,7 +727,10 @@ func (h *TunnelHandler) isEventStream(response *http.Response) bool {
func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) { func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) {
h.logger.WithError(err).Error("HTTP request error") h.logger.WithError(err).Error("HTTP request error")
stream.WriteHeaders([]h2mux.Header{{Name: ":status", Value: "502"}}) stream.WriteHeaders([]h2mux.Header{
{Name: ":status", Value: "502"},
h2mux.CreateResponseMetaHeader(h2mux.ResponseSourceCloudflared),
})
stream.Write([]byte("502 Bad Gateway")) stream.Write([]byte("502 Bad Gateway"))
h.metrics.incrementResponses(h.connectionID, "502") h.metrics.incrementResponses(h.connectionID, "502")
} }

View File

@ -17,7 +17,6 @@ import (
"github.com/cloudflare/cloudflared/hello" "github.com/cloudflare/cloudflared/hello"
"github.com/cloudflare/cloudflared/log" "github.com/cloudflare/cloudflared/log"
"github.com/cloudflare/cloudflared/websocket" "github.com/cloudflare/cloudflared/websocket"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -47,6 +46,8 @@ func NewHTTPService(transport http.RoundTripper, url *url.URL, chunkedEncoding b
} }
func (hc *HTTPService) Proxy(stream *h2mux.MuxedStream, req *http.Request) (*http.Response, error) { func (hc *HTTPService) Proxy(stream *h2mux.MuxedStream, req *http.Request) (*http.Response, error) {
const responseSourceOrigin = "origin"
// Support for WSGI Servers by switching transfer encoding from chunked to gzip/deflate // Support for WSGI Servers by switching transfer encoding from chunked to gzip/deflate
if !hc.chunkedEncoding { if !hc.chunkedEncoding {
req.TransferEncoding = []string{"gzip", "deflate"} req.TransferEncoding = []string{"gzip", "deflate"}
@ -65,7 +66,9 @@ func (hc *HTTPService) Proxy(stream *h2mux.MuxedStream, req *http.Request) (*htt
} }
defer resp.Body.Close() defer resp.Body.Close()
err = stream.WriteHeaders(h1ResponseToH2Response(resp)) responseHeaders := h1ResponseToH2Response(resp)
responseHeaders = append(responseHeaders, h2mux.CreateResponseMetaHeader(responseSourceOrigin))
err = stream.WriteHeaders(responseHeaders)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error writing response header to HTTP origin") return nil, errors.Wrap(err, "error writing response header to HTTP origin")
} }

View File

@ -180,11 +180,12 @@ func (s *StreamHandler) requestLogger(req *http.Request, tunnelHostname h2mux.Tu
} }
func (s *StreamHandler) writeErrorStatus(stream *h2mux.MuxedStream, status *httpErrorStatus) { func (s *StreamHandler) writeErrorStatus(stream *h2mux.MuxedStream, status *httpErrorStatus) {
stream.WriteHeaders([]h2mux.Header{ _ = stream.WriteHeaders([]h2mux.Header{
{ {
Name: statusPseudoHeader, Name: statusPseudoHeader,
Value: status.status, Value: status.status,
}, },
h2mux.CreateResponseMetaHeader(h2mux.ResponseSourceCloudflared),
}) })
stream.Write(status.text) _, _ = stream.Write(status.text)
} }