@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 144 lines 3.65 KB
Raw
1 package network
2
3 import (
4 "errors"
5 "net/http"
6 "net/url"
7 "strings"
8
9 "go.uber.org/zap"
10
11 "github.com/caddyserver/caddy/v2"
12 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
13 )
14
15 func init() {
16 caddy.RegisterModule(ProxyFromURL{})
17 caddy.RegisterModule(ProxyFromNone{})
18 }
19
20 // The "url" proxy source uses the defined URL as the proxy
21 type ProxyFromURL struct {
22 URL string `json:"url"`
23
24 ctx caddy.Context
25 logger *zap.Logger
26 }
27
28 // CaddyModule implements Module.
29 func (p ProxyFromURL) CaddyModule() caddy.ModuleInfo {
30 return caddy.ModuleInfo{
31 ID: "caddy.network_proxy.url",
32 New: func() caddy.Module {
33 return &ProxyFromURL{}
34 },
35 }
36 }
37
38 func (p *ProxyFromURL) Provision(ctx caddy.Context) error {
39 p.ctx = ctx
40 p.logger = ctx.Logger()
41 return nil
42 }
43
44 // Validate implements Validator.
45 func (p ProxyFromURL) Validate() error {
46 if _, err := url.Parse(p.URL); err != nil {
47 return err
48 }
49 return nil
50 }
51
52 // ProxyFunc implements ProxyFuncProducer.
53 func (p ProxyFromURL) ProxyFunc() func(*http.Request) (*url.URL, error) {
54 if strings.Contains(p.URL, "{") && strings.Contains(p.URL, "}") {
55 // courtesy of @ImpostorKeanu: https://github.com/caddyserver/caddy/pull/6397
56 return func(r *http.Request) (*url.URL, error) {
57 // retrieve the replacer from context.
58 repl, ok := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
59 if !ok {
60 err := errors.New("failed to obtain replacer from request")
61 p.logger.Error(err.Error())
62 return nil, err
63 }
64
65 // apply placeholders to the value
66 // note: h.ForwardProxyURL should never be empty at this point
67 s := repl.ReplaceAll(p.URL, "")
68 if s == "" {
69 p.logger.Error("network_proxy URL was empty after applying placeholders",
70 zap.String("initial_value", p.URL),
71 zap.String("final_value", s),
72 zap.String("hint", "check for invalid placeholders"))
73 return nil, errors.New("empty value for network_proxy URL")
74 }
75
76 // parse the url
77 pUrl, err := url.Parse(s)
78 if err != nil {
79 p.logger.Warn("failed to derive transport proxy from network_proxy URL")
80 pUrl = nil
81 } else if pUrl.Hostname() == "" {
82 // url.Parse does not return an error on these values:
83 //
84 // - http://:80
85 // - pUrl.Host == ":80"
86 // - /some/path
87 // - pUrl.Host == ""
88 //
89 // Super edge cases, but humans are human.
90 err = errors.New("supplied network_proxy URL is missing a host value")
91 pUrl = nil
92 } else {
93 p.logger.Debug("setting transport proxy url", zap.String("url", s))
94 }
95
96 return pUrl, err
97 }
98 }
99 return func(r *http.Request) (*url.URL, error) {
100 return url.Parse(p.URL)
101 }
102 }
103
104 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
105 func (p *ProxyFromURL) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
106 d.Next()
107 d.Next()
108 p.URL = d.Val()
109 return nil
110 }
111
112 // The "none" proxy source module disables the use of network proxy.
113 type ProxyFromNone struct{}
114
115 func (p ProxyFromNone) CaddyModule() caddy.ModuleInfo {
116 return caddy.ModuleInfo{
117 ID: "caddy.network_proxy.none",
118 New: func() caddy.Module {
119 return &ProxyFromNone{}
120 },
121 }
122 }
123
124 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
125 func (p ProxyFromNone) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
126 return nil
127 }
128
129 // ProxyFunc implements ProxyFuncProducer.
130 func (p ProxyFromNone) ProxyFunc() func(*http.Request) (*url.URL, error) {
131 return nil
132 }
133
134 var (
135 _ caddy.Module = ProxyFromURL{}
136 _ caddy.Provisioner = (*ProxyFromURL)(nil)
137 _ caddy.Validator = ProxyFromURL{}
138 _ caddy.ProxyFuncProducer = ProxyFromURL{}
139 _ caddyfile.Unmarshaler = (*ProxyFromURL)(nil)
140
141 _ caddy.Module = ProxyFromNone{}
142 _ caddy.ProxyFuncProducer = ProxyFromNone{}
143 _ caddyfile.Unmarshaler = ProxyFromNone{}
144 )