Merge branch 'master' into getcertificate

This commit is contained in:
Matthew Holt 2016-01-25 13:47:13 -07:00
commit 178c4d11d9
19 changed files with 899 additions and 754 deletions

View File

@ -25,6 +25,7 @@ func saveRSAPrivateKey(key *rsa.PrivateKey, file string) error {
if err != nil { if err != nil {
return err return err
} }
keyOut.Chmod(0600)
defer keyOut.Close() defer keyOut.Close()
return pem.Encode(keyOut, &pemKey) return pem.Encode(keyOut, &pemKey)
} }

View File

@ -6,6 +6,7 @@ import (
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"os" "os"
"runtime"
"testing" "testing"
) )
@ -28,13 +29,26 @@ func TestSaveAndLoadRSAPrivateKey(t *testing.T) {
t.Fatal("error saving private key:", err) t.Fatal("error saving private key:", err)
} }
// it doesn't make sense to test file permission on windows
if runtime.GOOS != "windows" {
// get info of the key file
info, err := os.Stat(keyFile)
if err != nil {
t.Fatal("error stating private key:", err)
}
// verify permission of key file is correct
if info.Mode().Perm() != 0600 {
t.Error("Expected key file to have permission 0600, but it wasn't")
}
}
// test load // test load
loadedKey, err := loadRSAPrivateKey(keyFile) loadedKey, err := loadRSAPrivateKey(keyFile)
if err != nil { if err != nil {
t.Error("error loading private key:", err) t.Error("error loading private key:", err)
} }
// very loaded key is correct // verify loaded key is correct
if !rsaPrivateKeysSame(privateKey, loadedKey) { if !rsaPrivateKeysSame(privateKey, loadedKey) {
t.Error("Expected key bytes to be the same, but they weren't") t.Error("Expected key bytes to be the same, but they weren't")
} }

View File

@ -322,7 +322,7 @@ func newClientPort(leEmail, port string) (*acme.Client, error) {
client.SetHTTPAddress(":" + port) client.SetHTTPAddress(":" + port)
client.SetTLSAddress(":" + port) client.SetTLSAddress(":" + port)
} }
client.ExcludeChallenges([]string{"tls-sni-01", "dns-01"}) // We can only guarantee http-01 at this time, but tls-01 should work if port is not custom! client.ExcludeChallenges([]acme.Challenge{acme.TLSSNI01, acme.DNS01}) // We can only guarantee http-01 at this time, but tls-01 should work if port is not custom!
// If not registered, the user must register an account with the CA // If not registered, the user must register an account with the CA
// and agree to terms // and agree to terms

View File

@ -32,6 +32,8 @@ func init() {
// work if executing with `go run`, since the binary is cleaned up // work if executing with `go run`, since the binary is cleaned up
// when `go run` sees the initial parent process exit. // when `go run` sees the initial parent process exit.
func Restart(newCaddyfile Input) error { func Restart(newCaddyfile Input) error {
log.Println("[INFO] Restarting")
if newCaddyfile == nil { if newCaddyfile == nil {
caddyfileMu.Lock() caddyfileMu.Lock()
newCaddyfile = caddyfile newCaddyfile = caddyfile

View File

@ -1,8 +1,12 @@
package caddy package caddy
import "log"
// Restart restarts Caddy forcefully using newCaddyfile, // Restart restarts Caddy forcefully using newCaddyfile,
// or, if nil, the current/existing Caddyfile is reused. // or, if nil, the current/existing Caddyfile is reused.
func Restart(newCaddyfile Input) error { func Restart(newCaddyfile Input) error {
log.Println("[INFO] Restarting")
if newCaddyfile == nil { if newCaddyfile == nil {
caddyfileMu.Lock() caddyfileMu.Lock()
newCaddyfile = caddyfile newCaddyfile = caddyfile

View File

@ -214,6 +214,7 @@ td .name {
margin-left: 1.75em; margin-left: 1.75em;
word-break: break-all; word-break: break-all;
overflow-wrap: break-word; overflow-wrap: break-word;
white-space: pre-wrap;
} }
footer { footer {

View File

@ -47,7 +47,7 @@ func gzipParse(c *Controller) ([]gzip.Config, error) {
return configs, c.ArgErr() return configs, c.ArgErr()
} }
for _, e := range exts { for _, e := range exts {
if !strings.HasPrefix(e, ".") && e != gzip.ExtWildCard { if !strings.HasPrefix(e, ".") && e != gzip.ExtWildCard && e != "" {
return configs, fmt.Errorf(`gzip: invalid extension "%v" (must start with dot)`, e) return configs, fmt.Errorf(`gzip: invalid extension "%v" (must start with dot)`, e)
} }
extFilter.Exts.Add(e) extFilter.Exts.Add(e)

View File

@ -50,6 +50,9 @@ func TestGzip(t *testing.T) {
level 1 level 1
} }
gzip`, false}, gzip`, false},
{`gzip {
ext ""
}`, false},
{`gzip { not /file {`gzip { not /file
ext .html ext .html
level 1 level 1

342
dist/CHANGES.txt vendored
View File

@ -1,171 +1,171 @@
CHANGES CHANGES
<master> 0.8.1 (January 12, 2016)
- Improved OCSP stapling - Improved OCSP stapling
- Can reload config with new hosts that need certs from Let's Encrypt - Better graceful reload when new hosts need certificates from Let's Encrypt
- If pidfile is created, it is deleted when Caddy exits - Current pidfile is now deleted when Caddy exits
- browse: New default template - browse: New default template
- gzip: Added min_length setting - gzip: Added min_length setting
- import: Support for glob patterns (*) to import multiple files - import: Support for glob patterns (*) to import multiple files
- rewrite: New complex rules with conditions, regex captures, and status code - rewrite: New complex rules with conditions, regex captures, and status code
- tls: Removed DES ciphers from default cipher suite list - tls: Removed DES ciphers from default cipher suite list
- tls: All supported certificates are OCSP-stapled - tls: All supported certificates are OCSP-stapled
- tls: Allow custom configuration without specifying certificate and key - tls: Allow custom configuration without specifying certificate and key
- tls: No longer allow HTTPS over port 80 - tls: No longer allow HTTPS over port 80
- Dozens of bug fixes, improvements, and more tests across the board - Dozens of bug fixes, improvements, and more tests across the board
0.8.0 (December 4, 2015) 0.8.0 (December 4, 2015)
- HTTPS by default via Let's Encrypt (certs & keys are fully managed) - HTTPS by default via Let's Encrypt (certs & keys are fully managed)
- Graceful restarts (on POSIX-compliant systems) - Graceful restarts (on POSIX-compliant systems)
- Major internal refactoring to allow use of Caddy as library - Major internal refactoring to allow use of Caddy as library
- New directive 'mime' to customize Content-Type based on file extension - New directive 'mime' to customize Content-Type based on file extension
- New -accept flag to accept Let's Encrypt SA without prompt - New -accept flag to accept Let's Encrypt SA without prompt
- New -email flag to customize default email used for ACME transactions - New -email flag to customize default email used for ACME transactions
- New -ca flag to customize ACME CA server URL - New -ca flag to customize ACME CA server URL
- New -revoke flag to revoke a certificate - New -revoke flag to revoke a certificate
- New -log flag to enable process log - New -log flag to enable process log
- New -pidfile flag to enable writing pidfile - New -pidfile flag to enable writing pidfile
- New -grace flag to customize the graceful shutdown timeout - New -grace flag to customize the graceful shutdown timeout
- New support for SIGHUP, SIGTERM, and SIGQUIT signals - New support for SIGHUP, SIGTERM, and SIGQUIT signals
- browse: Render filenames with multiple whitespace properly - browse: Render filenames with multiple whitespace properly
- core: Use environment variables in Caddyfile - core: Use environment variables in Caddyfile
- markdown: Include Last-Modified header in response - markdown: Include Last-Modified header in response
- markdown: Render tables, strikethrough, and fenced code blocks - markdown: Render tables, strikethrough, and fenced code blocks
- proxy: Ability to exclude/ignore paths from proxying - proxy: Ability to exclude/ignore paths from proxying
- startup, shutdown: Better Windows support - startup, shutdown: Better Windows support
- templates: Bug fix for .Host when port is absent - templates: Bug fix for .Host when port is absent
- templates: Include Last-Modified header in response - templates: Include Last-Modified header in response
- templates: Support for custom delimiters - templates: Support for custom delimiters
- tls: For non-local hosts, default port is now 443 unless specified - tls: For non-local hosts, default port is now 443 unless specified
- tls: Force-disable HTTPS - tls: Force-disable HTTPS
- tls: Specify Let's Encrypt email address - tls: Specify Let's Encrypt email address
- Many, many more tests and numerous bug fixes and improvements - Many, many more tests and numerous bug fixes and improvements
0.7.6 (September 28, 2015) 0.7.6 (September 28, 2015)
- Pass in simple Caddyfile as command line arguments - Pass in simple Caddyfile as command line arguments
- basicauth: Support for legacy htpasswd files - basicauth: Support for legacy htpasswd files
- browse: JSON response with file listing - browse: JSON response with file listing
- core: Caddyfile as command line argument - core: Caddyfile as command line argument
- errors: Can write full stack trace to HTTP response for debugging - errors: Can write full stack trace to HTTP response for debugging
- errors, log: Roll log files after certain size or age - errors, log: Roll log files after certain size or age
- proxy: Fix for 32-bit architectures - proxy: Fix for 32-bit architectures
- rewrite: Better compatibility with fastcgi and PHP apps - rewrite: Better compatibility with fastcgi and PHP apps
- templates: Added .StripExt and .StripHTML methods - templates: Added .StripExt and .StripHTML methods
- Internal improvements and minor bug fixes - Internal improvements and minor bug fixes
0.7.5 (August 5, 2015) 0.7.5 (August 5, 2015)
- core: All listeners bind to 0.0.0.0 unless 'bind' directive is used - core: All listeners bind to 0.0.0.0 unless 'bind' directive is used
- fastcgi: Set HTTPS env variable if connection is secure - fastcgi: Set HTTPS env variable if connection is secure
- log: Output to system log (except Windows) - log: Output to system log (except Windows)
- markdown: Added dev command to disable caching during development - markdown: Added dev command to disable caching during development
- markdown: Fixed error reporting during initial site generation - markdown: Fixed error reporting during initial site generation
- markdown: Fixed crash if path does not exist when server starts - markdown: Fixed crash if path does not exist when server starts
- markdown: Fixed site generation and link indexing when files change - markdown: Fixed site generation and link indexing when files change
- templates: Added .NowDate for use in date-related functions - templates: Added .NowDate for use in date-related functions
- Several bug fixes related to startup and shutdown functions - Several bug fixes related to startup and shutdown functions
0.7.4 (July 30, 2015) 0.7.4 (July 30, 2015)
- browse: Sorting preference persisted in cookie - browse: Sorting preference persisted in cookie
- browse: Added index.txt and default.txt to list of default files - browse: Added index.txt and default.txt to list of default files
- browse: Template files may now use Caddy template actions - browse: Template files may now use Caddy template actions
- markdown: Template files may now use Caddy template actions - markdown: Template files may now use Caddy template actions
- markdown: Several bug fixes, especially for large and empty Markdown files - markdown: Several bug fixes, especially for large and empty Markdown files
- markdown: Generate index pages to link to markdown pages (sitegen only) - markdown: Generate index pages to link to markdown pages (sitegen only)
- markdown: Flatten structure of front matter, changed template variables - markdown: Flatten structure of front matter, changed template variables
- redir: Can use variables (placeholders) like log formats can - redir: Can use variables (placeholders) like log formats can
- redir: Catch-all redirects no longer preserve path; use {uri} instead - redir: Catch-all redirects no longer preserve path; use {uri} instead
- redir: Syntax supports redirect tables by opening a block - redir: Syntax supports redirect tables by opening a block
- templates: Renamed .Date to .Now and added .Truncate, .Replace actions - templates: Renamed .Date to .Now and added .Truncate, .Replace actions
- Other minor internal improvements and more tests - Other minor internal improvements and more tests
0.7.3 (July 15, 2015) 0.7.3 (July 15, 2015)
- errors: Error log now shows timestamp with each entry - errors: Error log now shows timestamp with each entry
- gzip: Fixed; Default filtering is by extension; removed MIME type filter - gzip: Fixed; Default filtering is by extension; removed MIME type filter
- import: Fixed; works inside and outside server blocks - import: Fixed; works inside and outside server blocks
- redir: Query string preserved on catch-all redirects - redir: Query string preserved on catch-all redirects
- templates: Proper 403 or 404 errors for restricted or missing files - templates: Proper 403 or 404 errors for restricted or missing files
0.7.2 (July 1, 2015) 0.7.2 (July 1, 2015)
- Custom builds through caddyserver.com - extend Caddy by writing addons - Custom builds through caddyserver.com - extend Caddy by writing addons
- browse: Sort by clicking column heading or using query string - browse: Sort by clicking column heading or using query string
- core: Serving hostname that doesn't resolve issues warning then listens on 0.0.0.0 - core: Serving hostname that doesn't resolve issues warning then listens on 0.0.0.0
- errors: Missing error page during parse time is warning, not error - errors: Missing error page during parse time is warning, not error
- ext: Extension only appended if request path does not end in / - ext: Extension only appended if request path does not end in /
- fastcgi: Fix for backend responding without status text - fastcgi: Fix for backend responding without status text
- fastcgi: Fix PATH_TRANSLATED when PATH_INFO is empty (RFC 3875) - fastcgi: Fix PATH_TRANSLATED when PATH_INFO is empty (RFC 3875)
- git: Removed from core (available as add-on) - git: Removed from core (available as add-on)
- gzip: Enable by file path and/or extension - gzip: Enable by file path and/or extension
- gzip: Customize compression level - gzip: Customize compression level
- log: Fix for missing status in log entry when error unhandled - log: Fix for missing status in log entry when error unhandled
- proxy: Strip prefix from path for proxy to path - proxy: Strip prefix from path for proxy to path
- redir: Meta tag redirects - redir: Meta tag redirects
- templates: Support for nested includes - templates: Support for nested includes
- Internal improvements and more tests - Internal improvements and more tests
0.7.1 (June 2, 2015) 0.7.1 (June 2, 2015)
- basicauth: Patched timing vulnerability - basicauth: Patched timing vulnerability
- proxy: Support for WebSocket backends - proxy: Support for WebSocket backends
- tls: Client authentication - tls: Client authentication
0.7.0 (May 25, 2015) 0.7.0 (May 25, 2015)
- New directive 'internal' to protect resources with X-Accel-Redirect - New directive 'internal' to protect resources with X-Accel-Redirect
- New -version flag to show program name and version - New -version flag to show program name and version
- core: Fixed escaped backslash characters inside quoted strings - core: Fixed escaped backslash characters inside quoted strings
- core: Fixed parsing Caddyfile for IPv6 addresses missing ports - core: Fixed parsing Caddyfile for IPv6 addresses missing ports
- core: A notice is shown when non-local address resolves to loopback interface - core: A notice is shown when non-local address resolves to loopback interface
- core: Warns if file descriptor limit is too low for production site (Mac/Linux) - core: Warns if file descriptor limit is too low for production site (Mac/Linux)
- fastcgi: Support for Unix sockets - fastcgi: Support for Unix sockets
- git: Fixed issue that prevented pulling at designated interval - git: Fixed issue that prevented pulling at designated interval
- header: Remove a header field by prefixing field name with "-" - header: Remove a header field by prefixing field name with "-"
- markdown: Simple static site generation - markdown: Simple static site generation
- markdown: Support for metadata ("front matter") at beginning of files - markdown: Support for metadata ("front matter") at beginning of files
- rewrite: Experimental support for regular expressions - rewrite: Experimental support for regular expressions
- tls: Customize cipher suites and protocols - tls: Customize cipher suites and protocols
- tls: Removed RC4 ciphers - tls: Removed RC4 ciphers
- Other internal improvements that are not user-facing (more tests, etc.) - Other internal improvements that are not user-facing (more tests, etc.)
0.6.0 (May 7, 2015) 0.6.0 (May 7, 2015)
- New directive 'git' to automatically pull changes - New directive 'git' to automatically pull changes
- New directive 'bind' to override host server binds to - New directive 'bind' to override host server binds to
- New -root flag to specify root path to default site - New -root flag to specify root path to default site
- Ability to receive config data piped through stdin - Ability to receive config data piped through stdin
- core: Warning if root directory doesn't exist at startup - core: Warning if root directory doesn't exist at startup
- core: Entire process dies if any server fails to start - core: Entire process dies if any server fails to start
- gzip: Fixed Content-Length value when proxying requests - gzip: Fixed Content-Length value when proxying requests
- errors: Error log now includes file and line number of panics - errors: Error log now includes file and line number of panics
- fastcgi: Pass custom environment variables - fastcgi: Pass custom environment variables
- fastcgi: Support for HEAD, OPTIONS, PUT, PATCH, and DELETE methods - fastcgi: Support for HEAD, OPTIONS, PUT, PATCH, and DELETE methods
- fastcgi: Fixed SERVER_SOFTWARE variables - fastcgi: Fixed SERVER_SOFTWARE variables
- markdown: Support for index files when URL points to a directory - markdown: Support for index files when URL points to a directory
- proxy: Load balancing with multiple backends, health checks, failovers, and multiple policies - proxy: Load balancing with multiple backends, health checks, failovers, and multiple policies
- proxy: Add custom headers - proxy: Add custom headers
- startup/shutdown: Run command in background with '&' at end - startup/shutdown: Run command in background with '&' at end
- templates: Added .tpl and .tmpl as default extensions - templates: Added .tpl and .tmpl as default extensions
- templates: Support for index files when URL points to a directory - templates: Support for index files when URL points to a directory
- templates: Changed .RemoteAddr to .IP and stripped out remote port - templates: Changed .RemoteAddr to .IP and stripped out remote port
- tls: TLS disabled (with warning) for servers that are explicitly http:// - tls: TLS disabled (with warning) for servers that are explicitly http://
- websocket: Fixed SERVER_SOFTWARE and GATEWAY_INTERFACE variables - websocket: Fixed SERVER_SOFTWARE and GATEWAY_INTERFACE variables
- Many internal improvements - Many internal improvements
0.5.1 (April 30, 2015) 0.5.1 (April 30, 2015)
- Default host is now 0.0.0.0 (wildcard) - Default host is now 0.0.0.0 (wildcard)
- New -host and -port flags to override default host and port - New -host and -port flags to override default host and port
- core: Support for binding to 0.0.0.0 - core: Support for binding to 0.0.0.0
- core: Graceful error handling during heavy load; proper error responses - core: Graceful error handling during heavy load; proper error responses
- errors: Fixed file path handling - errors: Fixed file path handling
- errors: Fixed panic due to nil log file - errors: Fixed panic due to nil log file
- fastcgi: Support for index files - fastcgi: Support for index files
- fastcgi: Fix for handling errors that come from responder - fastcgi: Fix for handling errors that come from responder
0.5.0 (April 28, 2015) 0.5.0 (April 28, 2015)
- Initial release - Initial release

1078
dist/LICENSES.txt vendored

File diff suppressed because it is too large Load Diff

42
dist/README.txt vendored
View File

@ -1,21 +1,21 @@
CADDY 0.8 CADDY 0.8.1
Website Website
https://caddyserver.com https://caddyserver.com
@caddyserver @caddyserver
Source Code Source Code
https://github.com/mholt/caddy https://github.com/mholt/caddy
For instructions on using Caddy, please see the user guide on the website. For a list of what's new in this version, see CHANGES.txt. For instructions on using Caddy, please see the user guide on the website. For a list of what's new in this version, see CHANGES.txt.
If you have a question, bug report, or would like to contribute, please open an issue or submit a pull request on GitHub. Your contributions do not go unnoticed! If you have a question, bug report, or would like to contribute, please open an issue or submit a pull request on GitHub. Your contributions do not go unnoticed!
For a good time, follow @mholt6 on Twitter. For a good time, follow @mholt6 on Twitter.
And thanks - you're awesome! And thanks - you're awesome!
--- ---
(c) 2015 Matthew Holt (c) 2015 Matthew Holt

View File

@ -27,7 +27,7 @@ var (
const ( const (
appName = "Caddy" appName = "Caddy"
appVersion = "0.8" appVersion = "0.8.1"
) )
func init() { func init() {

View File

@ -196,7 +196,7 @@ func directoryListing(files []os.FileInfo, r *http.Request, canGoUp bool, root s
fileCount++ fileCount++
} }
url := url.URL{Path: name} url := url.URL{Path: "./" + name} // prepend with "./" to fix paths with ':' in the name
fileinfos = append(fileinfos, FileInfo{ fileinfos = append(fileinfos, FileInfo{
IsDir: f.IsDir(), IsDir: f.IsDir(),

View File

@ -147,11 +147,11 @@ func TestBrowseTemplate(t *testing.T) {
<h1>/photos/</h1> <h1>/photos/</h1>
<a href="test.html">test.html</a><br> <a href="./test.html">test.html</a><br>
<a href="test2.html">test2.html</a><br> <a href="./test2.html">test2.html</a><br>
<a href="test3.html">test3.html</a><br> <a href="./test3.html">test3.html</a><br>
</body> </body>
</html> </html>
@ -209,7 +209,7 @@ func TestBrowseJson(t *testing.T) {
name += "/" name += "/"
} }
url := url.URL{Path: name} url := url.URL{Path: "./" + name}
fileinfos = append(fileinfos, FileInfo{ fileinfos = append(fileinfos, FileInfo{
IsDir: f.IsDir(), IsDir: f.IsDir(),

View File

@ -15,7 +15,7 @@ type RequestFilter interface {
} }
// defaultExtensions is the list of default extensions for which to enable gzipping. // defaultExtensions is the list of default extensions for which to enable gzipping.
var defaultExtensions = []string{"", ".txt", ".htm", ".html", ".css", ".php", ".js", ".json", ".md", ".xml"} var defaultExtensions = []string{"", ".txt", ".htm", ".html", ".css", ".php", ".js", ".json", ".md", ".xml", ".svg"}
// DefaultExtFilter creates an ExtFilter with default extensions. // DefaultExtFilter creates an ExtFilter with default extensions.
func DefaultExtFilter() ExtFilter { func DefaultExtFilter() ExtFilter {

View File

@ -57,6 +57,10 @@ func (uh *UpstreamHost) Down() bool {
return uh.CheckDown(uh) return uh.CheckDown(uh)
} }
// tryDuration is how long to try upstream hosts; failures result in
// immediate retries until this duration ends or we get a nil host.
var tryDuration = 60 * time.Second
// ServeHTTP satisfies the middleware.Handler interface. // ServeHTTP satisfies the middleware.Handler interface.
func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
@ -68,7 +72,7 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// Since Select() should give us "up" hosts, keep retrying // Since Select() should give us "up" hosts, keep retrying
// hosts until timeout (or until we get a nil host). // hosts until timeout (or until we get a nil host).
for time.Now().Sub(start) < (60 * time.Second) { for time.Now().Sub(start) < tryDuration {
host := upstream.Select() host := upstream.Select()
if host == nil { if host == nil {
return http.StatusBadGateway, errUnreachable return http.StatusBadGateway, errUnreachable

View File

@ -4,10 +4,13 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"io" "io"
"io/ioutil"
"log"
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"os"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -15,6 +18,70 @@ import (
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
func init() {
tryDuration = 50 * time.Millisecond // prevent tests from hanging
}
func TestReverseProxy(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
var requestReceived bool
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestReceived = true
w.Write([]byte("Hello, client"))
}))
defer backend.Close()
// set up proxy
p := &Proxy{
Upstreams: []Upstream{newFakeUpstream(backend.URL, false)},
}
// create request and response recorder
r, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
w := httptest.NewRecorder()
p.ServeHTTP(w, r)
if !requestReceived {
t.Error("Expected backend to receive request, but it didn't")
}
}
func TestReverseProxyInsecureSkipVerify(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
var requestReceived bool
backend := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestReceived = true
w.Write([]byte("Hello, client"))
}))
defer backend.Close()
// set up proxy
p := &Proxy{
Upstreams: []Upstream{newFakeUpstream(backend.URL, true)},
}
// create request and response recorder
r, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
w := httptest.NewRecorder()
p.ServeHTTP(w, r)
if !requestReceived {
t.Error("Even with insecure HTTPS, expected backend to receive request, but it didn't")
}
}
func TestWebSocketReverseProxyServeHTTPHandler(t *testing.T) { func TestWebSocketReverseProxyServeHTTPHandler(t *testing.T) {
// No-op websocket backend simply allows the WS connection to be // No-op websocket backend simply allows the WS connection to be
// accepted then it will be immediately closed. Perfect for testing. // accepted then it will be immediately closed. Perfect for testing.
@ -93,18 +160,24 @@ func TestWebSocketReverseProxyFromWSClient(t *testing.T) {
} }
} }
// newWebSocketTestProxy returns a test proxy that will func newFakeUpstream(name string, insecure bool) *fakeUpstream {
// redirect to the specified backendAddr. The function uri, _ := url.Parse(name)
// also sets up the rules/environment for testing WebSocket u := &fakeUpstream{
// proxy. name: name,
func newWebSocketTestProxy(backendAddr string) *Proxy { host: &UpstreamHost{
return &Proxy{ Name: name,
Upstreams: []Upstream{&fakeUpstream{name: backendAddr}}, ReverseProxy: NewSingleHostReverseProxy(uri, ""),
},
} }
if insecure {
u.host.ReverseProxy.Transport = InsecureTransport
}
return u
} }
type fakeUpstream struct { type fakeUpstream struct {
name string name string
host *UpstreamHost
} }
func (u *fakeUpstream) From() string { func (u *fakeUpstream) From() string {
@ -112,6 +185,32 @@ func (u *fakeUpstream) From() string {
} }
func (u *fakeUpstream) Select() *UpstreamHost { func (u *fakeUpstream) Select() *UpstreamHost {
return u.host
}
func (u *fakeUpstream) IsAllowedPath(requestPath string) bool {
return true
}
// newWebSocketTestProxy returns a test proxy that will
// redirect to the specified backendAddr. The function
// also sets up the rules/environment for testing WebSocket
// proxy.
func newWebSocketTestProxy(backendAddr string) *Proxy {
return &Proxy{
Upstreams: []Upstream{&fakeWsUpstream{name: backendAddr}},
}
}
type fakeWsUpstream struct {
name string
}
func (u *fakeWsUpstream) From() string {
return "/"
}
func (u *fakeWsUpstream) Select() *UpstreamHost {
uri, _ := url.Parse(u.name) uri, _ := url.Parse(u.name)
return &UpstreamHost{ return &UpstreamHost{
Name: u.name, Name: u.name,
@ -122,7 +221,7 @@ func (u *fakeUpstream) Select() *UpstreamHost {
} }
} }
func (u *fakeUpstream) IsAllowedPath(requestPath string) bool { func (u *fakeWsUpstream) IsAllowedPath(requestPath string) bool {
return true return true
} }

View File

@ -12,6 +12,7 @@
package proxy package proxy
import ( import (
"crypto/tls"
"io" "io"
"net" "net"
"net/http" "net/http"
@ -103,6 +104,16 @@ var hopHeaders = []string{
"Upgrade", "Upgrade",
} }
var InsecureTransport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request, extraHeaders http.Header) error { func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request, extraHeaders http.Header) error {
transport := p.Transport transport := p.Transport
if transport == nil { if transport == nil {

View File

@ -19,10 +19,11 @@ var (
) )
type staticUpstream struct { type staticUpstream struct {
from string from string
proxyHeaders http.Header proxyHeaders http.Header
Hosts HostPool Hosts HostPool
Policy Policy Policy Policy
insecureSkipVerify bool
FailTimeout time.Duration FailTimeout time.Duration
MaxFails int32 MaxFails int32
@ -90,6 +91,9 @@ func NewStaticUpstreams(c parse.Dispenser) ([]Upstream, error) {
} }
if baseURL, err := url.Parse(uh.Name); err == nil { if baseURL, err := url.Parse(uh.Name); err == nil {
uh.ReverseProxy = NewSingleHostReverseProxy(baseURL, uh.WithoutPathPrefix) uh.ReverseProxy = NewSingleHostReverseProxy(baseURL, uh.WithoutPathPrefix)
if upstream.insecureSkipVerify {
uh.ReverseProxy.Transport = InsecureTransport
}
} else { } else {
return upstreams, err return upstreams, err
} }
@ -175,6 +179,8 @@ func parseBlock(c *parse.Dispenser, u *staticUpstream) error {
return c.ArgErr() return c.ArgErr()
} }
u.IgnoredSubPaths = ignoredPaths u.IgnoredSubPaths = ignoredPaths
case "insecure_skip_verify":
u.insecureSkipVerify = true
default: default:
return c.Errf("unknown property '%s'", c.Val()) return c.Errf("unknown property '%s'", c.Val())
} }