@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 114 lines 2.98 KB
Raw
1 package network
2
3 import (
4 "context"
5 "net/http"
6 "net/http/httptest"
7 "testing"
8
9 "go.uber.org/zap"
10
11 "github.com/caddyserver/caddy/v2"
12 )
13
14 // TestProxyFromURLPlaceholderHostValidation checks that a network_proxy URL
15 // which resolves to a value without a host is rejected after placeholders are
16 // applied. url.Parse accepts both "http://:80" and "/some/path" without
17 // returning an error, so ProxyFunc has to reject them itself.
18 func TestProxyFromURLPlaceholderHostValidation(t *testing.T) {
19 for i, tc := range []struct {
20 name string
21 url string
22 hostRepl string
23 wantHost string
24 wantErr bool
25 }{
26 {
27 name: "port only, no host",
28 url: "http://{proxy.host}:80",
29 hostRepl: "",
30 wantErr: true,
31 },
32 {
33 name: "no scheme or host, path only",
34 url: "{proxy.host}/some/path",
35 hostRepl: "",
36 wantErr: true,
37 },
38 {
39 // url.Parse puts the userinfo elsewhere, so Host is still just
40 // ":8080" here. The comment above the check doesn't name this
41 // form, but it is equally host-less and equally unusable.
42 name: "userinfo but no host",
43 url: "http://user:pass@{proxy.host}:8080",
44 hostRepl: "",
45 wantErr: true,
46 },
47 {
48 name: "host and port",
49 url: "http://{proxy.host}:8080",
50 hostRepl: "proxy.example.com",
51 wantHost: "proxy.example.com",
52 wantErr: false,
53 },
54 {
55 name: "host without port",
56 url: "http://{proxy.host}",
57 hostRepl: "proxy.example.com",
58 wantHost: "proxy.example.com",
59 wantErr: false,
60 },
61 {
62 // Guards against a repair that splits Host on ":" instead of
63 // using Hostname(): an IPv6 literal is full of colons and must
64 // not be mistaken for a missing host.
65 name: "IPv6 literal with port",
66 url: "http://[{proxy.host}]:8080",
67 hostRepl: "::1",
68 wantHost: "::1",
69 wantErr: false,
70 },
71 {
72 name: "IPv6 literal without port",
73 url: "http://[{proxy.host}]",
74 hostRepl: "2001:db8::1",
75 wantHost: "2001:db8::1",
76 wantErr: false,
77 },
78 } {
79 p := ProxyFromURL{URL: tc.url, logger: zap.NewNop()}
80
81 repl := caddy.NewReplacer()
82 repl.Set("proxy.host", tc.hostRepl)
83
84 req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
85 req = req.WithContext(context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl))
86
87 proxyURL, err := p.ProxyFunc()(req)
88
89 if tc.wantErr {
90 if err == nil {
91 t.Errorf("Test %d (%s): expected an error for %q but got none (proxy URL: %v)",
92 i, tc.name, tc.url, proxyURL)
93 }
94 if proxyURL != nil {
95 t.Errorf("Test %d (%s): expected a nil proxy URL for %q, got %v",
96 i, tc.name, tc.url, proxyURL)
97 }
98 continue
99 }
100
101 if err != nil {
102 t.Errorf("Test %d (%s): unexpected error for %q: %v", i, tc.name, tc.url, err)
103 continue
104 }
105 if proxyURL == nil {
106 t.Errorf("Test %d (%s): expected a proxy URL for %q, got nil", i, tc.name, tc.url)
107 continue
108 }
109 if proxyURL.Hostname() != tc.wantHost {
110 t.Errorf("Test %d (%s): expected host %q, got %q",
111 i, tc.name, tc.wantHost, proxyURL.Hostname())
112 }
113 }
114 }