TUN-2880: Return metadata about source of the response from cloudflared
This commit is contained in:
parent
a37da2b165
commit
322f909edb
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue