mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 00:19:57 +00:00
TUN-1099: Bring back changes in 2018.10.1
This commit is contained in:
@@ -6,7 +6,9 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/idna"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const defaultScheme = "http"
|
||||
@@ -15,7 +17,7 @@ var supportedProtocol = [2]string{"http", "https"}
|
||||
|
||||
func ValidateHostname(hostname string) (string, error) {
|
||||
if hostname == "" {
|
||||
return "", fmt.Errorf("Hostname should not be empty")
|
||||
return "", nil
|
||||
}
|
||||
// users gives url(contains schema) not just hostname
|
||||
if strings.Contains(hostname, ":") || strings.Contains(hostname, "%3A") {
|
||||
@@ -48,7 +50,7 @@ func ValidateHostname(hostname string) (string, error) {
|
||||
|
||||
func ValidateUrl(originUrl string) (string, error) {
|
||||
if originUrl == "" {
|
||||
return "", fmt.Errorf("Url should not be empty")
|
||||
return "", fmt.Errorf("URL should not be empty")
|
||||
}
|
||||
|
||||
if net.ParseIP(originUrl) != nil {
|
||||
@@ -134,3 +136,44 @@ func validateIP(scheme, host, port string) (string, error) {
|
||||
}
|
||||
return fmt.Sprintf("%s://%s", scheme, host), nil
|
||||
}
|
||||
|
||||
func ValidateHTTPService(originURL string, transport http.RoundTripper) error {
|
||||
parsedURL, err := url.Parse(originURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: transport}
|
||||
|
||||
initialResponse, initialErr := client.Get(parsedURL.String())
|
||||
if initialErr != nil || initialResponse.StatusCode != http.StatusOK {
|
||||
// Attempt the same endpoint via the other protocol (http/https); maybe we have better luck?
|
||||
oldScheme := parsedURL.Scheme
|
||||
parsedURL.Scheme = toggleProtocol(parsedURL.Scheme)
|
||||
|
||||
secondResponse, _ := client.Get(parsedURL.String())
|
||||
|
||||
if secondResponse != nil && secondResponse.StatusCode == http.StatusOK { // Worked this time--advise the user to switch protocols
|
||||
return errors.Errorf(
|
||||
"%s doesn't seem to work over %s, but does seem to work over %s. Consider changing the origin URL to %s",
|
||||
parsedURL.Hostname(),
|
||||
oldScheme,
|
||||
parsedURL.Scheme,
|
||||
parsedURL,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return initialErr
|
||||
}
|
||||
|
||||
func toggleProtocol(httpProtocol string) string {
|
||||
switch httpProtocol {
|
||||
case "http":
|
||||
return "https"
|
||||
case "https":
|
||||
return "http"
|
||||
default:
|
||||
return httpProtocol
|
||||
}
|
||||
}
|
||||
|
@@ -4,13 +4,21 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TestValidateHostname(t *testing.T) {
|
||||
var inputHostname string
|
||||
hostname, err := ValidateHostname(inputHostname)
|
||||
assert.Equal(t, err, fmt.Errorf("Hostname should not be empty"))
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Empty(t, hostname)
|
||||
|
||||
inputHostname = "hello.example.com"
|
||||
@@ -42,7 +50,7 @@ func TestValidateHostname(t *testing.T) {
|
||||
|
||||
func TestValidateUrl(t *testing.T) {
|
||||
validUrl, err := ValidateUrl("")
|
||||
assert.Equal(t, fmt.Errorf("Url should not be empty"), err)
|
||||
assert.Equal(t, fmt.Errorf("URL should not be empty"), err)
|
||||
assert.Empty(t, validUrl)
|
||||
|
||||
validUrl, err = ValidateUrl("https://localhost:8080")
|
||||
@@ -134,3 +142,102 @@ func TestValidateUrl(t *testing.T) {
|
||||
assert.Equal(t, "https://hello.example.com:8080", validUrl)
|
||||
|
||||
}
|
||||
|
||||
func TestToggleProtocol(t *testing.T) {
|
||||
assert.Equal(t, "https", toggleProtocol("http"))
|
||||
assert.Equal(t, "http", toggleProtocol("https"))
|
||||
assert.Equal(t, "random", toggleProtocol("random"))
|
||||
assert.Equal(t, "", toggleProtocol(""))
|
||||
}
|
||||
|
||||
func TestValidateHTTPService_HTTP2HTTP(t *testing.T) {
|
||||
server, client, err := createMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
assert.NoError(t, err)
|
||||
defer server.Close()
|
||||
|
||||
assert.Equal(t, nil, ValidateHTTPService("http://example.com/", client.Transport))
|
||||
}
|
||||
|
||||
func TestValidateHTTPService_ServerNonOKResponse(t *testing.T) {
|
||||
server, client, err := createMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(400)
|
||||
}))
|
||||
assert.NoError(t, err)
|
||||
defer server.Close()
|
||||
|
||||
assert.Equal(t, nil, ValidateHTTPService("http://example.com/", client.Transport))
|
||||
}
|
||||
|
||||
func TestValidateHTTPService_HTTPS2HTTP(t *testing.T) {
|
||||
server, client, err := createMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
assert.NoError(t, err)
|
||||
defer server.Close()
|
||||
|
||||
assert.Equal(t,
|
||||
"example.com doesn't seem to work over https, but does seem to work over http. Consider changing the origin URL to http://example.com:1234/",
|
||||
ValidateHTTPService("https://example.com:1234/", client.Transport).Error())
|
||||
}
|
||||
|
||||
func TestValidateHTTPService_HTTPS2HTTPS(t *testing.T) {
|
||||
server, client, err := createSecureMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
assert.NoError(t, err)
|
||||
defer server.Close()
|
||||
|
||||
assert.Equal(t, nil, ValidateHTTPService("https://example.com/", client.Transport))
|
||||
}
|
||||
|
||||
func TestValidateHTTPService_HTTP2HTTPS(t *testing.T) {
|
||||
server, client, err := createSecureMockServerAndClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
assert.NoError(t, err)
|
||||
defer server.Close()
|
||||
|
||||
assert.Equal(t,
|
||||
"example.com doesn't seem to work over http, but does seem to work over https. Consider changing the origin URL to https://example.com:1234/",
|
||||
ValidateHTTPService("http://example.com:1234/", client.Transport).Error())
|
||||
}
|
||||
|
||||
func createMockServerAndClient(handler http.Handler) (*httptest.Server, *http.Client, error) {
|
||||
client := http.DefaultClient
|
||||
server := httptest.NewServer(handler)
|
||||
|
||||
client.Transport = &http.Transport{
|
||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||
return url.Parse(server.URL)
|
||||
},
|
||||
}
|
||||
|
||||
return server, client, nil
|
||||
}
|
||||
|
||||
func createSecureMockServerAndClient(handler http.Handler) (*httptest.Server, *http.Client, error) {
|
||||
client := http.DefaultClient
|
||||
server := httptest.NewTLSServer(handler)
|
||||
|
||||
cert, err := x509.ParseCertificate(server.TLS.Certificates[0].Certificate[0])
|
||||
if err != nil {
|
||||
server.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
certpool := x509.NewCertPool()
|
||||
certpool.AddCert(cert)
|
||||
|
||||
client.Transport = &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return net.Dial("tcp", server.URL[strings.LastIndex(server.URL, "/")+1:])
|
||||
},
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: certpool,
|
||||
},
|
||||
}
|
||||
|
||||
return server, client, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user