mirror of
https://github.com/cloudflare/cloudflared.git
synced 2026-08-07 23:31:56 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 87203bbe25 | |||
| 11acb50cf7 | |||
| 23f2a04ed7 | |||
| 1805261263 | |||
| 53de779a0a | |||
| b7e91466f5 | |||
| 4c1b89576c | |||
| a1a554a29d | |||
| fdb1f961b3 |
+1
-1
@@ -1,7 +1,7 @@
|
||||
# use a builder image for building cloudflare
|
||||
ARG TARGET_GOOS
|
||||
ARG TARGET_GOARCH
|
||||
FROM golang:1.15.3 as builder
|
||||
FROM golang:1.15.5 as builder
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0 \
|
||||
TARGET_GOOS=${TARGET_GOOS} \
|
||||
|
||||
@@ -89,7 +89,7 @@ define publish_package
|
||||
for HOST in $(CF_PKG_HOSTS); do \
|
||||
ssh-keyscan -t rsa $$HOST >> ~/.ssh/known_hosts; \
|
||||
scp -4 cloudflared*.$(1) cfsync@$$HOST:/state/cf-pkg/staging/$(2)/$(TARGET_PUBLIC_REPO)/cloudflared/; \
|
||||
ssh cfsync@$$HOST 'chgrp cf /state/cf-pkg/staging/$(2)/$(TARGET_PUBLIC_REPO)/cloudflared/*.$(1) && chmod g+w /state/cf-pkg/staging/$(2)/$(TARGET_PUBLIC_REPO)/cloudflared/*.$(1)'; \
|
||||
ssh cfsync@$$HOST 'chmod g+w /state/cf-pkg/staging/$(2)/$(TARGET_PUBLIC_REPO)/cloudflared/*.$(1)'; \
|
||||
done
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
2020.11.10
|
||||
- 2020-11-20 TUN-3562: Fix panic when using bastion mode ingress rule
|
||||
- 2020-11-20 EDGEPLAT-2958 build cloudflared for Bullseye
|
||||
|
||||
2020.11.9
|
||||
- 2020-11-18 TUN-3557: Detect SSE if content-type starts with text/event-stream
|
||||
- 2020-11-18 TUN-3559: Share response meta header with other packages
|
||||
- 2020-11-18 DEVTOOLS-7936: Remove redundant chgrp from publish
|
||||
- 2020-11-18 TUN-3558: cloudflared allows empty config files
|
||||
- 2020-11-18 TUN-3544: Upgrade to Go 1.15.5
|
||||
|
||||
2020.11.8
|
||||
- 2020-11-17 TUN-3555: Single origin service should default to localhost:8080
|
||||
|
||||
|
||||
+7
-9
@@ -1,6 +1,6 @@
|
||||
pinned_go: &pinned_go go=1.15.3-1
|
||||
pinned_go: &pinned_go go=1.15.5-1
|
||||
build_dir: &build_dir /cfsetup_build
|
||||
default-flavor: stretch
|
||||
default-flavor: buster
|
||||
stretch: &stretch
|
||||
build:
|
||||
build_dir: *build_dir
|
||||
@@ -239,10 +239,8 @@ stretch: &stretch
|
||||
- export GOARCH=amd64
|
||||
- make publish-cloudflared-junos
|
||||
|
||||
jessie: *stretch
|
||||
|
||||
buster: *stretch
|
||||
|
||||
bullseye: *stretch
|
||||
centos-7:
|
||||
publish-rpm:
|
||||
build_dir: *build_dir
|
||||
@@ -250,8 +248,8 @@ centos-7:
|
||||
- https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
pre-cache:
|
||||
- yum install -y fakeroot
|
||||
- wget https://golang.org/dl/go1.15.3.linux-amd64.tar.gz -P /tmp/
|
||||
- tar -C /usr/local -xzf /tmp/go1.15.3.linux-amd64.tar.gz
|
||||
- wget https://golang.org/dl/go1.15.5.linux-amd64.tar.gz -P /tmp/
|
||||
- tar -C /usr/local -xzf /tmp/go1.15.5.linux-amd64.tar.gz
|
||||
post-cache:
|
||||
- export PATH=$PATH:/usr/local/go/bin
|
||||
- export GOOS=linux
|
||||
@@ -262,8 +260,8 @@ centos-7:
|
||||
builddeps: *el7_builddeps
|
||||
pre-cache:
|
||||
- yum install -y fakeroot
|
||||
- wget https://golang.org/dl/go1.15.3.linux-amd64.tar.gz -P /tmp/
|
||||
- tar -C /usr/local -xzf /tmp/go1.15.3.linux-amd64.tar.gz
|
||||
- wget https://golang.org/dl/go1.15.5.linux-amd64.tar.gz -P /tmp/
|
||||
- tar -C /usr/local -xzf /tmp/go1.15.5.linux-amd64.tar.gz
|
||||
post-cache:
|
||||
- export PATH=$PATH:/usr/local/go/bin
|
||||
- export GOOS=linux
|
||||
|
||||
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -392,6 +393,10 @@ func ReadConfigFile(c *cli.Context, log logger.Service) (*configFileSettings, er
|
||||
}
|
||||
defer file.Close()
|
||||
if err := yaml.NewDecoder(file).Decode(&configuration); err != nil {
|
||||
if err == io.EOF {
|
||||
log.Errorf("Configuration file %s was empty", configFile)
|
||||
return &configuration, nil
|
||||
}
|
||||
return nil, errors.Wrap(err, "error parsing YAML in config file at "+configFile)
|
||||
}
|
||||
configuration.sourceFile = configFile
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
@@ -27,7 +28,7 @@ type FileManager struct {
|
||||
notifier Notifier
|
||||
configPath string
|
||||
logger logger.Service
|
||||
ReadConfig func(string) (Root, error)
|
||||
ReadConfig func(string, logger.Service) (Root, error)
|
||||
}
|
||||
|
||||
// NewFileManager creates a config manager
|
||||
@@ -59,7 +60,7 @@ func (m *FileManager) Start(notifier Notifier) error {
|
||||
|
||||
// GetConfig reads the yaml file from the disk
|
||||
func (m *FileManager) GetConfig() (Root, error) {
|
||||
return m.ReadConfig(m.configPath)
|
||||
return m.ReadConfig(m.configPath, m.logger)
|
||||
}
|
||||
|
||||
// Shutdown stops the watcher
|
||||
@@ -67,7 +68,7 @@ func (m *FileManager) Shutdown() {
|
||||
m.watcher.Shutdown()
|
||||
}
|
||||
|
||||
func readConfigFromPath(configPath string) (Root, error) {
|
||||
func readConfigFromPath(configPath string, log logger.Service) (Root, error) {
|
||||
if configPath == "" {
|
||||
return Root{}, errors.New("unable to find config file")
|
||||
}
|
||||
@@ -80,6 +81,10 @@ func readConfigFromPath(configPath string) (Root, error) {
|
||||
|
||||
var config Root
|
||||
if err := yaml.NewDecoder(file).Decode(&config); err != nil {
|
||||
if err == io.EOF {
|
||||
log.Errorf("Configuration file %s was empty", configPath)
|
||||
return Root{}, nil
|
||||
}
|
||||
return Root{}, errors.Wrap(err, "error parsing YAML in config file at "+configPath)
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestConfigChanged(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
configRead := func(configPath string) (Root, error) {
|
||||
configRead := func(configPath string, log logger.Service) (Root, error) {
|
||||
return *c, nil
|
||||
}
|
||||
wait := make(chan struct{})
|
||||
|
||||
@@ -53,10 +53,13 @@ type ConnectedFuse interface {
|
||||
IsConnected() bool
|
||||
}
|
||||
|
||||
func IsServerSentEvent(headers http.Header) bool {
|
||||
if contentType := headers.Get("content-type"); contentType != "" {
|
||||
return strings.HasPrefix(strings.ToLower(contentType), "text/event-stream")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func uint8ToString(input uint8) string {
|
||||
return strconv.FormatUint(uint64(input), 10)
|
||||
}
|
||||
|
||||
func isServerSentEvent(headers http.Header) bool {
|
||||
return strings.ToLower(headers.Get("content-type")) == "text/event-stream"
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/ui"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,3 +113,40 @@ func (mcf mockConnectedFuse) Connected() {}
|
||||
func (mcf mockConnectedFuse) IsConnected() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestIsEventStream(t *testing.T) {
|
||||
tests := []struct {
|
||||
headers http.Header
|
||||
isEventStream bool
|
||||
}{
|
||||
{
|
||||
headers: newHeader("Content-Type", "text/event-stream"),
|
||||
isEventStream: true,
|
||||
},
|
||||
{
|
||||
headers: newHeader("content-type", "text/event-stream"),
|
||||
isEventStream: true,
|
||||
},
|
||||
{
|
||||
headers: newHeader("Content-Type", "text/event-stream; charset=utf-8"),
|
||||
isEventStream: true,
|
||||
},
|
||||
{
|
||||
headers: newHeader("Content-Type", "application/json"),
|
||||
isEventStream: false,
|
||||
},
|
||||
{
|
||||
headers: http.Header{},
|
||||
isEventStream: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
assert.Equal(t, test.isEventStream, IsServerSentEvent(test.headers))
|
||||
}
|
||||
}
|
||||
|
||||
func newHeader(key, value string) http.Header {
|
||||
header := http.Header{}
|
||||
header.Add(key, value)
|
||||
return header
|
||||
}
|
||||
|
||||
+2
-2
@@ -207,14 +207,14 @@ type h2muxRespWriter struct {
|
||||
|
||||
func (rp *h2muxRespWriter) WriteRespHeaders(resp *http.Response) error {
|
||||
headers := h2mux.H1ResponseToH2ResponseHeaders(resp)
|
||||
headers = append(headers, h2mux.Header{Name: responseMetaHeaderField, Value: responseMetaHeaderOrigin})
|
||||
headers = append(headers, h2mux.Header{Name: ResponseMetaHeaderField, Value: responseMetaHeaderOrigin})
|
||||
return rp.WriteHeaders(headers)
|
||||
}
|
||||
|
||||
func (rp *h2muxRespWriter) WriteErrorResponse() {
|
||||
rp.WriteHeaders([]h2mux.Header{
|
||||
{Name: ":status", Value: "502"},
|
||||
{Name: responseMetaHeaderField, Value: responseMetaHeaderCfd},
|
||||
{Name: ResponseMetaHeaderField, Value: responseMetaHeaderCfd},
|
||||
})
|
||||
rp.Write([]byte("502 Bad Gateway"))
|
||||
}
|
||||
|
||||
@@ -105,9 +105,9 @@ func TestServeStreamHTTP(t *testing.T) {
|
||||
require.True(t, hasHeader(stream, ":status", strconv.Itoa(test.expectedStatus)))
|
||||
|
||||
if test.isProxyError {
|
||||
assert.True(t, hasHeader(stream, responseMetaHeaderField, responseMetaHeaderCfd))
|
||||
assert.True(t, hasHeader(stream, ResponseMetaHeaderField, responseMetaHeaderCfd))
|
||||
} else {
|
||||
assert.True(t, hasHeader(stream, responseMetaHeaderField, responseMetaHeaderOrigin))
|
||||
assert.True(t, hasHeader(stream, ResponseMetaHeaderField, responseMetaHeaderOrigin))
|
||||
body := make([]byte, len(test.expectedBody))
|
||||
_, err = stream.Read(body)
|
||||
require.NoError(t, err)
|
||||
@@ -154,7 +154,7 @@ func TestServeStreamWS(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, hasHeader(stream, ":status", strconv.Itoa(http.StatusSwitchingProtocols)))
|
||||
assert.True(t, hasHeader(stream, responseMetaHeaderField, responseMetaHeaderOrigin))
|
||||
assert.True(t, hasHeader(stream, ResponseMetaHeaderField, responseMetaHeaderOrigin))
|
||||
|
||||
data := []byte("test websocket")
|
||||
err = wsutil.WriteClientText(writePipe, data)
|
||||
@@ -209,7 +209,7 @@ func benchmarkServeStreamHTTPSimple(b *testing.B, test testRequest) {
|
||||
b.StopTimer()
|
||||
|
||||
require.NoError(b, openstreamErr)
|
||||
assert.True(b, hasHeader(stream, responseMetaHeaderField, responseMetaHeaderOrigin))
|
||||
assert.True(b, hasHeader(stream, ResponseMetaHeaderField, responseMetaHeaderOrigin))
|
||||
require.True(b, hasHeader(stream, ":status", strconv.Itoa(http.StatusOK)))
|
||||
require.NoError(b, readBodyErr)
|
||||
require.Equal(b, test.expectedBody, body)
|
||||
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
responseMetaHeaderField = "cf-cloudflared-response-meta"
|
||||
ResponseMetaHeaderField = "cf-cloudflared-response-meta"
|
||||
)
|
||||
|
||||
var (
|
||||
canonicalResponseUserHeadersField = http.CanonicalHeaderKey(h2mux.ResponseUserHeadersField)
|
||||
canonicalResponseMetaHeaderField = http.CanonicalHeaderKey(responseMetaHeaderField)
|
||||
canonicalResponseMetaHeaderField = http.CanonicalHeaderKey(ResponseMetaHeaderField)
|
||||
responseMetaHeaderCfd = mustInitRespMetaHeader("cloudflared")
|
||||
responseMetaHeaderOrigin = mustInitRespMetaHeader("origin")
|
||||
)
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ func (rp *http2RespWriter) WriteRespHeaders(resp *http.Response) error {
|
||||
status = http.StatusOK
|
||||
}
|
||||
rp.w.WriteHeader(status)
|
||||
if isServerSentEvent(resp.Header) {
|
||||
if IsServerSentEvent(resp.Header) {
|
||||
rp.shouldFlush = true
|
||||
}
|
||||
if rp.shouldFlush {
|
||||
|
||||
@@ -100,9 +100,9 @@ func TestServeHTTP(t *testing.T) {
|
||||
require.Equal(t, test.expectedBody, respBody)
|
||||
}
|
||||
if test.isProxyError {
|
||||
require.Equal(t, responseMetaHeaderCfd, resp.Header.Get(responseMetaHeaderField))
|
||||
require.Equal(t, responseMetaHeaderCfd, resp.Header.Get(ResponseMetaHeaderField))
|
||||
} else {
|
||||
require.Equal(t, responseMetaHeaderOrigin, resp.Header.Get(responseMetaHeaderField))
|
||||
require.Equal(t, responseMetaHeaderOrigin, resp.Header.Get(ResponseMetaHeaderField))
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
@@ -202,7 +202,7 @@ func TestServeWS(t *testing.T) {
|
||||
resp := respWriter.Result()
|
||||
// http2RespWriter should rewrite status 101 to 200
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
require.Equal(t, responseMetaHeaderOrigin, resp.Header.Get(responseMetaHeaderField))
|
||||
require.Equal(t, responseMetaHeaderOrigin, resp.Header.Get(ResponseMetaHeaderField))
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.15.3 as builder
|
||||
FROM golang:1.15.5 as builder
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0
|
||||
WORKDIR /go/src/github.com/cloudflare/cloudflared/
|
||||
|
||||
+1
-1
@@ -189,7 +189,7 @@ func websocketHandler(logger logger.Service, upgrader websocket.Upgrader) http.H
|
||||
|
||||
func sseHandler(logger logger.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
@@ -84,10 +84,6 @@ func (o *localService) Dial(reqURL *url.URL, headers http.Header) (*gws.Conn, *h
|
||||
return d.Dial(reqURL.String(), headers)
|
||||
}
|
||||
|
||||
func (o *localService) address() string {
|
||||
return o.URL.String()
|
||||
}
|
||||
|
||||
func (o *localService) start(wg *sync.WaitGroup, log logger.Service, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
|
||||
transport, err := newHTTPTransport(o, cfg, log)
|
||||
if err != nil {
|
||||
@@ -151,7 +147,14 @@ func (o *localService) startProxy(staticHost string, wg *sync.WaitGroup, log log
|
||||
}
|
||||
|
||||
func (o *localService) String() string {
|
||||
return o.address()
|
||||
if o.isBastion() {
|
||||
return "Bastion"
|
||||
}
|
||||
return o.URL.String()
|
||||
}
|
||||
|
||||
func (o *localService) isBastion() bool {
|
||||
return o.URL == nil
|
||||
}
|
||||
|
||||
func (o *localService) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
@@ -163,6 +166,10 @@ func (o *localService) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
|
||||
func (o *localService) staticHost() string {
|
||||
|
||||
if o.URL == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
addPortIfMissing := func(uri *url.URL, port int) string {
|
||||
if uri.Port() != "" {
|
||||
return uri.Host
|
||||
|
||||
+1
-12
@@ -96,7 +96,7 @@ func (c *client) proxyHTTP(w connection.ResponseWriter, req *http.Request, rule
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error writing response header")
|
||||
}
|
||||
if isEventStream(resp) {
|
||||
if connection.IsServerSentEvent(resp.Header) {
|
||||
c.logger.Debug("Detected Server-Side Events from Origin")
|
||||
c.writeEventStream(w, resp.Body)
|
||||
} else {
|
||||
@@ -222,14 +222,3 @@ func findCfRayHeader(req *http.Request) string {
|
||||
func isLBProbeRequest(req *http.Request) bool {
|
||||
return strings.HasPrefix(req.UserAgent(), lbProbeUserAgentPrefix)
|
||||
}
|
||||
|
||||
func uint8ToString(input uint8) string {
|
||||
return strconv.FormatUint(uint64(input), 10)
|
||||
}
|
||||
|
||||
func isEventStream(response *http.Response) bool {
|
||||
if response.Header.Get("content-type") == "text/event-stream" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user