mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-27 02:33:48 +08:00
commit
a881838836
10
app/app.go
10
app/app.go
|
@ -16,10 +16,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// Program name
|
||||
// Name is the program name
|
||||
Name = "Caddy"
|
||||
|
||||
// Program version
|
||||
// Version is the program version
|
||||
Version = "0.6.0"
|
||||
)
|
||||
|
||||
|
@ -27,13 +27,13 @@ var (
|
|||
// Servers is a list of all the currently-listening servers
|
||||
Servers []*server.Server
|
||||
|
||||
// This mutex protects the Servers slice during changes
|
||||
// ServersMutex protects the Servers slice during changes
|
||||
ServersMutex sync.Mutex
|
||||
|
||||
// Waiting on Wg will block until all listeners have shut down.
|
||||
// Wg is used to wait for all servers to shut down
|
||||
Wg sync.WaitGroup
|
||||
|
||||
// Whether HTTP2 is enabled or not
|
||||
// Http2 indicates whether HTTP2 is enabled or not
|
||||
Http2 bool // TODO: temporary flag until http2 is standard
|
||||
|
||||
// Quiet mode hides non-error initialization output
|
||||
|
|
|
@ -19,7 +19,8 @@ const (
|
|||
DefaultPort = "2015"
|
||||
DefaultRoot = "."
|
||||
|
||||
// The default configuration file to load if none is specified
|
||||
// DefaultConfigFile is the name of the configuration file that is loaded
|
||||
// by default if no other file is specified.
|
||||
DefaultConfigFile = "Caddyfile"
|
||||
)
|
||||
|
||||
|
|
|
@ -58,9 +58,8 @@ func (l *lexer) next() bool {
|
|||
}
|
||||
if err == io.EOF {
|
||||
return false
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if quoted {
|
||||
|
|
|
@ -57,7 +57,7 @@ func gitParse(c *Controller) (*git.Repo, error) {
|
|||
repo.Path = filepath.Clean(c.Root + string(filepath.Separator) + args[1])
|
||||
fallthrough
|
||||
case 1:
|
||||
repo.Url = args[0]
|
||||
repo.URL = args[0]
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
|
@ -66,7 +66,7 @@ func gitParse(c *Controller) (*git.Repo, error) {
|
|||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
repo.Url = c.Val()
|
||||
repo.URL = c.Val()
|
||||
case "path":
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
|
@ -103,19 +103,19 @@ func gitParse(c *Controller) (*git.Repo, error) {
|
|||
}
|
||||
|
||||
// if repo is not specified, return error
|
||||
if repo.Url == "" {
|
||||
if repo.URL == "" {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
||||
// if private key is not specified, convert repository url to https
|
||||
// if private key is not specified, convert repository URL to https
|
||||
// to avoid ssh authentication
|
||||
// else validate git url
|
||||
// else validate git URL
|
||||
// Note: private key support not yet available on Windows
|
||||
var err error
|
||||
if repo.KeyPath == "" {
|
||||
repo.Url, repo.Host, err = sanitizeHttp(repo.Url)
|
||||
repo.URL, repo.Host, err = sanitizeHTTP(repo.URL)
|
||||
} else {
|
||||
repo.Url, repo.Host, err = sanitizeGit(repo.Url)
|
||||
repo.URL, repo.Host, err = sanitizeGit(repo.URL)
|
||||
// TODO add Windows support for private repos
|
||||
if runtime.GOOS == "windows" {
|
||||
return nil, fmt.Errorf("Private repository not yet supported on Windows")
|
||||
|
@ -134,12 +134,12 @@ func gitParse(c *Controller) (*git.Repo, error) {
|
|||
return repo, repo.Prepare()
|
||||
}
|
||||
|
||||
// sanitizeHttp cleans up repository url and converts to https format
|
||||
// sanitizeHTTP cleans up repository URL and converts to https format
|
||||
// if currently in ssh format.
|
||||
// Returns sanitized url, hostName (e.g. github.com, bitbucket.com)
|
||||
// and possible error
|
||||
func sanitizeHttp(repoUrl string) (string, string, error) {
|
||||
url, err := url.Parse(repoUrl)
|
||||
func sanitizeHTTP(repoURL string) (string, string, error) {
|
||||
url, err := url.Parse(repoURL)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
@ -148,46 +148,46 @@ func sanitizeHttp(repoUrl string) (string, string, error) {
|
|||
url.Path = url.Path[len("git@"):]
|
||||
i := strings.Index(url.Path, ":")
|
||||
if i < 0 {
|
||||
return "", "", fmt.Errorf("Invalid git url %s", repoUrl)
|
||||
return "", "", fmt.Errorf("Invalid git url %s", repoURL)
|
||||
}
|
||||
url.Host = url.Path[:i]
|
||||
url.Path = "/" + url.Path[i+1:]
|
||||
}
|
||||
|
||||
repoUrl = "https://" + url.Host + url.Path
|
||||
repoURL = "https://" + url.Host + url.Path
|
||||
|
||||
// add .git suffix if missing
|
||||
if !strings.HasSuffix(repoUrl, ".git") {
|
||||
repoUrl += ".git"
|
||||
if !strings.HasSuffix(repoURL, ".git") {
|
||||
repoURL += ".git"
|
||||
}
|
||||
|
||||
return repoUrl, url.Host, nil
|
||||
return repoURL, url.Host, nil
|
||||
}
|
||||
|
||||
// sanitizeGit cleans up repository url and converts to ssh format for private
|
||||
// repositories if required.
|
||||
// Returns sanitized url, hostName (e.g. github.com, bitbucket.com)
|
||||
// and possible error
|
||||
func sanitizeGit(repoUrl string) (string, string, error) {
|
||||
repoUrl = strings.TrimSpace(repoUrl)
|
||||
func sanitizeGit(repoURL string) (string, string, error) {
|
||||
repoURL = strings.TrimSpace(repoURL)
|
||||
|
||||
// check if valid ssh format
|
||||
if !strings.HasPrefix(repoUrl, "git@") || strings.Index(repoUrl, ":") < len("git@a:") {
|
||||
if !strings.HasPrefix(repoURL, "git@") || strings.Index(repoURL, ":") < len("git@a:") {
|
||||
// check if valid http format and convert to ssh
|
||||
if url, err := url.Parse(repoUrl); err == nil && strings.HasPrefix(url.Scheme, "http") {
|
||||
repoUrl = fmt.Sprintf("git@%v:%v", url.Host, url.Path[1:])
|
||||
if url, err := url.Parse(repoURL); err == nil && strings.HasPrefix(url.Scheme, "http") {
|
||||
repoURL = fmt.Sprintf("git@%v:%v", url.Host, url.Path[1:])
|
||||
} else {
|
||||
return "", "", fmt.Errorf("Invalid git url %s", repoUrl)
|
||||
return "", "", fmt.Errorf("Invalid git url %s", repoURL)
|
||||
}
|
||||
}
|
||||
hostUrl := repoUrl[len("git@"):]
|
||||
i := strings.Index(hostUrl, ":")
|
||||
host := hostUrl[:i]
|
||||
hostURL := repoURL[len("git@"):]
|
||||
i := strings.Index(hostURL, ":")
|
||||
host := hostURL[:i]
|
||||
|
||||
// add .git suffix if missing
|
||||
if !strings.HasSuffix(repoUrl, ".git") {
|
||||
repoUrl += ".git"
|
||||
if !strings.HasSuffix(repoURL, ".git") {
|
||||
repoURL += ".git"
|
||||
}
|
||||
|
||||
return repoUrl, host, nil
|
||||
return repoURL, host, nil
|
||||
}
|
||||
|
|
|
@ -32,29 +32,29 @@ func TestGitParse(t *testing.T) {
|
|||
expected *git.Repo
|
||||
}{
|
||||
{`git git@github.com:user/repo`, false, &git.Repo{
|
||||
Url: "https://github.com/user/repo.git",
|
||||
URL: "https://github.com/user/repo.git",
|
||||
}},
|
||||
{`git github.com/user/repo`, false, &git.Repo{
|
||||
Url: "https://github.com/user/repo.git",
|
||||
URL: "https://github.com/user/repo.git",
|
||||
}},
|
||||
{`git git@github.com/user/repo`, true, nil},
|
||||
{`git http://github.com/user/repo`, false, &git.Repo{
|
||||
Url: "https://github.com/user/repo.git",
|
||||
URL: "https://github.com/user/repo.git",
|
||||
}},
|
||||
{`git https://github.com/user/repo`, false, &git.Repo{
|
||||
Url: "https://github.com/user/repo.git",
|
||||
URL: "https://github.com/user/repo.git",
|
||||
}},
|
||||
{`git http://github.com/user/repo {
|
||||
key ~/.key
|
||||
}`, false, &git.Repo{
|
||||
KeyPath: "~/.key",
|
||||
Url: "git@github.com:user/repo.git",
|
||||
URL: "git@github.com:user/repo.git",
|
||||
}},
|
||||
{`git git@github.com:user/repo {
|
||||
key ~/.key
|
||||
}`, false, &git.Repo{
|
||||
KeyPath: "~/.key",
|
||||
Url: "git@github.com:user/repo.git",
|
||||
URL: "git@github.com:user/repo.git",
|
||||
}},
|
||||
{`git `, true, nil},
|
||||
{`git {
|
||||
|
@ -66,7 +66,7 @@ func TestGitParse(t *testing.T) {
|
|||
key ~/.key
|
||||
}`, false, &git.Repo{
|
||||
KeyPath: "~/.key",
|
||||
Url: "git@github.com:user/repo.git",
|
||||
URL: "git@github.com:user/repo.git",
|
||||
}},
|
||||
{`git {
|
||||
repo git@github.com:user/repo
|
||||
|
@ -74,7 +74,7 @@ func TestGitParse(t *testing.T) {
|
|||
interval 600
|
||||
}`, false, &git.Repo{
|
||||
KeyPath: "~/.key",
|
||||
Url: "git@github.com:user/repo.git",
|
||||
URL: "git@github.com:user/repo.git",
|
||||
Interval: time.Second * 600,
|
||||
}},
|
||||
{`git {
|
||||
|
@ -82,7 +82,7 @@ func TestGitParse(t *testing.T) {
|
|||
branch dev
|
||||
}`, false, &git.Repo{
|
||||
Branch: "dev",
|
||||
Url: "https://github.com/user/repo.git",
|
||||
URL: "https://github.com/user/repo.git",
|
||||
}},
|
||||
{`git {
|
||||
key ~/.key
|
||||
|
@ -93,7 +93,7 @@ func TestGitParse(t *testing.T) {
|
|||
then echo hello world
|
||||
}`, false, &git.Repo{
|
||||
KeyPath: "~/.key",
|
||||
Url: "git@github.com:user/repo.git",
|
||||
URL: "git@github.com:user/repo.git",
|
||||
Then: "echo hello world",
|
||||
}},
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ func reposEqual(expected, repo *git.Repo) bool {
|
|||
if expected.Then != "" && expected.Then != repo.Then {
|
||||
return false
|
||||
}
|
||||
if expected.Url != "" && expected.Url != repo.Url {
|
||||
if expected.URL != "" && expected.URL != repo.URL {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
caddylog "github.com/mholt/caddy/middleware/log"
|
||||
)
|
||||
|
||||
// Log sets up the logging middleware.
|
||||
func Log(c *Controller) (middleware.Middleware, error) {
|
||||
rules, err := logParse(c)
|
||||
if err != nil {
|
||||
|
@ -42,22 +43,22 @@ func Log(c *Controller) (middleware.Middleware, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func logParse(c *Controller) ([]caddylog.LogRule, error) {
|
||||
var rules []caddylog.LogRule
|
||||
func logParse(c *Controller) ([]caddylog.Rule, error) {
|
||||
var rules []caddylog.Rule
|
||||
|
||||
for c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
|
||||
if len(args) == 0 {
|
||||
// Nothing specified; use defaults
|
||||
rules = append(rules, caddylog.LogRule{
|
||||
rules = append(rules, caddylog.Rule{
|
||||
PathScope: "/",
|
||||
OutputFile: caddylog.DefaultLogFilename,
|
||||
Format: caddylog.DefaultLogFormat,
|
||||
})
|
||||
} else if len(args) == 1 {
|
||||
// Only an output file specified
|
||||
rules = append(rules, caddylog.LogRule{
|
||||
rules = append(rules, caddylog.Rule{
|
||||
PathScope: "/",
|
||||
OutputFile: args[0],
|
||||
Format: caddylog.DefaultLogFormat,
|
||||
|
@ -78,7 +79,7 @@ func logParse(c *Controller) ([]caddylog.LogRule, error) {
|
|||
}
|
||||
}
|
||||
|
||||
rules = append(rules, caddylog.LogRule{
|
||||
rules = append(rules, caddylog.Rule{
|
||||
PathScope: args[0],
|
||||
OutputFile: args[1],
|
||||
Format: format,
|
||||
|
|
|
@ -41,16 +41,14 @@ func (a BasicAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
|
|||
isAuthenticated = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if hasAuth {
|
||||
if !isAuthenticated {
|
||||
w.Header().Set("WWW-Authenticate", "Basic")
|
||||
return http.StatusUnauthorized, nil
|
||||
} else {
|
||||
// "It's an older code, sir, but it checks out. I was about to clear them."
|
||||
return a.Next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// "It's an older code, sir, but it checks out. I was about to clear them."
|
||||
return a.Next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// Pass-thru when no paths match
|
||||
|
|
|
@ -27,13 +27,10 @@ func TestBasicAuth(t *testing.T) {
|
|||
{"/testing", http.StatusUnauthorized, "ttest:test"},
|
||||
{"/testing", http.StatusOK, "test:ttest"},
|
||||
{"/testing", http.StatusUnauthorized, ""},
|
||||
|
||||
}
|
||||
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
|
||||
req, err := http.NewRequest("GET", test.from, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Test %d: Could not create HTTP request %v", i, err)
|
||||
|
@ -54,19 +51,17 @@ func TestBasicAuth(t *testing.T) {
|
|||
headers := rec.Header()
|
||||
if val, ok := headers["Www-Authenticate"]; ok {
|
||||
if val[0] != "Basic" {
|
||||
t.Errorf("Test %d, Www-Authenticate should be %s provided %s", i, "Basic", val[0])
|
||||
t.Errorf("Test %d, Www-Authenticate should be %s provided %s", i, "Basic", val[0])
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Test %d, should provide a header Www-Authenticate", i)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func TestMultipleOverlappingRules(t *testing.T) {
|
||||
rw := BasicAuth{
|
||||
Next: middleware.HandlerFunc(contentHandler),
|
||||
|
@ -75,7 +70,7 @@ func TestMultipleOverlappingRules(t *testing.T) {
|
|||
{Username: "t1", Password: "p2", Resources: []string{"/t/t"}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
tests := []struct {
|
||||
from string
|
||||
result int
|
||||
|
@ -89,9 +84,8 @@ func TestMultipleOverlappingRules(t *testing.T) {
|
|||
{"/t", http.StatusUnauthorized, "t1:p2"},
|
||||
}
|
||||
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
|
||||
req, err := http.NewRequest("GET", test.from, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Test %d: Could not create HTTP request %v", i, err)
|
||||
|
@ -108,14 +102,12 @@ func TestMultipleOverlappingRules(t *testing.T) {
|
|||
t.Errorf("Test %d: Expected Header '%d' but was '%d'",
|
||||
i, test.result, result)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
func contentHandler(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
fmt.Fprintf(w, r.URL.String())
|
||||
return http.StatusOK, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,10 +55,12 @@ type FileInfo struct {
|
|||
Mode os.FileMode
|
||||
}
|
||||
|
||||
// HumanSize returns the size of the file as a human-readable string.
|
||||
func (fi FileInfo) HumanSize() string {
|
||||
return humanize.Bytes(uint64(fi.Size))
|
||||
}
|
||||
|
||||
// HumanModTime returns the modified time of the file as a human-readable string.
|
||||
func (fi FileInfo) HumanModTime(format string) string {
|
||||
return fi.ModTime.Format(format)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Package extension is middleware for clean URLs.
|
||||
// Package extensions contains middleware for clean URLs.
|
||||
//
|
||||
// The root path of the site is passed in as well as possible extensions
|
||||
// to try internally for paths requested that don't match an existing
|
||||
|
|
|
@ -89,10 +89,10 @@ type header struct {
|
|||
// not synchronized because we don't care what the contents are
|
||||
var pad [maxPad]byte
|
||||
|
||||
func (h *header) init(recType uint8, reqId uint16, contentLength int) {
|
||||
func (h *header) init(recType uint8, reqID uint16, contentLength int) {
|
||||
h.Version = 1
|
||||
h.Type = recType
|
||||
h.Id = reqId
|
||||
h.Id = reqID
|
||||
h.ContentLength = uint16(contentLength)
|
||||
h.PaddingLength = uint8(-contentLength & 7)
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ type FCGIClient struct {
|
|||
reqId uint16
|
||||
}
|
||||
|
||||
// Connects to the fcgi responder at the specified network address.
|
||||
// Dial connects to the fcgi responder at the specified network address.
|
||||
// See func net.Dial for a description of the network and address parameters.
|
||||
func Dial(network, address string) (fcgi *FCGIClient, err error) {
|
||||
var conn net.Conn
|
||||
|
@ -154,43 +154,43 @@ func Dial(network, address string) (fcgi *FCGIClient, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Close fcgi connnection
|
||||
func (this *FCGIClient) Close() {
|
||||
this.rwc.Close()
|
||||
// Close closes fcgi connnection
|
||||
func (c *FCGIClient) Close() {
|
||||
c.rwc.Close()
|
||||
}
|
||||
|
||||
func (this *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
this.buf.Reset()
|
||||
this.h.init(recType, this.reqId, len(content))
|
||||
if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil {
|
||||
func (c *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
c.buf.Reset()
|
||||
c.h.init(recType, c.reqId, len(content))
|
||||
if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := this.buf.Write(content); err != nil {
|
||||
if _, err := c.buf.Write(content); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil {
|
||||
if _, err := c.buf.Write(pad[:c.h.PaddingLength]); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = this.rwc.Write(this.buf.Bytes())
|
||||
_, err = c.rwc.Write(c.buf.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func (this *FCGIClient) writeBeginRequest(role uint16, flags uint8) error {
|
||||
func (c *FCGIClient) writeBeginRequest(role uint16, flags uint8) error {
|
||||
b := [8]byte{byte(role >> 8), byte(role), flags}
|
||||
return this.writeRecord(FCGI_BEGIN_REQUEST, b[:])
|
||||
return c.writeRecord(FCGI_BEGIN_REQUEST, b[:])
|
||||
}
|
||||
|
||||
func (this *FCGIClient) writeEndRequest(appStatus int, protocolStatus uint8) error {
|
||||
func (c *FCGIClient) writeEndRequest(appStatus int, protocolStatus uint8) error {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint32(b, uint32(appStatus))
|
||||
b[4] = protocolStatus
|
||||
return this.writeRecord(FCGI_END_REQUEST, b)
|
||||
return c.writeRecord(FCGI_END_REQUEST, b)
|
||||
}
|
||||
|
||||
func (this *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
|
||||
w := newWriter(this, recType)
|
||||
func (c *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
|
||||
w := newWriter(c, recType)
|
||||
b := make([]byte, 8)
|
||||
nn := 0
|
||||
for k, v := range pairs {
|
||||
|
@ -333,32 +333,32 @@ func (w *streamReader) Read(p []byte) (n int, err error) {
|
|||
|
||||
// Do made the request and returns a io.Reader that translates the data read
|
||||
// from fcgi responder out of fcgi packet before returning it.
|
||||
func (this *FCGIClient) Do(p map[string]string, req io.Reader) (r io.Reader, err error) {
|
||||
err = this.writeBeginRequest(uint16(FCGI_RESPONDER), 0)
|
||||
func (c *FCGIClient) Do(p map[string]string, req io.Reader) (r io.Reader, err error) {
|
||||
err = c.writeBeginRequest(uint16(FCGI_RESPONDER), 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = this.writePairs(FCGI_PARAMS, p)
|
||||
err = c.writePairs(FCGI_PARAMS, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
body := newWriter(this, FCGI_STDIN)
|
||||
body := newWriter(c, FCGI_STDIN)
|
||||
if req != nil {
|
||||
io.Copy(body, req)
|
||||
}
|
||||
body.Close()
|
||||
|
||||
r = &streamReader{c: this}
|
||||
r = &streamReader{c: c}
|
||||
return
|
||||
}
|
||||
|
||||
// Request returns a HTTP Response with Header and Body
|
||||
// from fcgi responder
|
||||
func (this *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Response, err error) {
|
||||
|
||||
r, err := this.Do(p, req)
|
||||
r, err := c.Do(p, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -394,40 +394,39 @@ func (this *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.
|
|||
} else {
|
||||
resp.Body = ioutil.NopCloser(rb)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Get issues a GET request to the fcgi responder.
|
||||
func (this *FCGIClient) Get(p map[string]string) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Get(p map[string]string) (resp *http.Response, err error) {
|
||||
|
||||
p["REQUEST_METHOD"] = "GET"
|
||||
p["CONTENT_LENGTH"] = "0"
|
||||
|
||||
return this.Request(p, nil)
|
||||
return c.Request(p, nil)
|
||||
}
|
||||
|
||||
// Head issues a HEAD request to the fcgi responder.
|
||||
func (this *FCGIClient) Head(p map[string]string) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Head(p map[string]string) (resp *http.Response, err error) {
|
||||
|
||||
p["REQUEST_METHOD"] = "HEAD"
|
||||
p["CONTENT_LENGTH"] = "0"
|
||||
|
||||
return this.Request(p, nil)
|
||||
return c.Request(p, nil)
|
||||
}
|
||||
|
||||
// Options issues an OPTIONS request to the fcgi responder.
|
||||
func (this *FCGIClient) Options(p map[string]string) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Options(p map[string]string) (resp *http.Response, err error) {
|
||||
|
||||
p["REQUEST_METHOD"] = "OPTIONS"
|
||||
p["CONTENT_LENGTH"] = "0"
|
||||
|
||||
return this.Request(p, nil)
|
||||
return c.Request(p, nil)
|
||||
}
|
||||
|
||||
// Post issues a POST request to the fcgi responder. with request body
|
||||
// in the format that bodyType specified
|
||||
func (this *FCGIClient) Post(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Post(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
|
||||
if len(p["REQUEST_METHOD"]) == 0 || p["REQUEST_METHOD"] == "GET" {
|
||||
p["REQUEST_METHOD"] = "POST"
|
||||
|
@ -439,44 +438,44 @@ func (this *FCGIClient) Post(p map[string]string, bodyType string, body io.Reade
|
|||
p["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
|
||||
}
|
||||
|
||||
return this.Request(p, body)
|
||||
return c.Request(p, body)
|
||||
}
|
||||
|
||||
// Put issues a PUT request to the fcgi responder.
|
||||
func (this *FCGIClient) Put(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Put(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
|
||||
p["REQUEST_METHOD"] = "PUT"
|
||||
|
||||
return this.Post(p, bodyType, body, l)
|
||||
return c.Post(p, bodyType, body, l)
|
||||
}
|
||||
|
||||
// Patch issues a PATCH request to the fcgi responder.
|
||||
func (this *FCGIClient) Patch(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Patch(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
|
||||
p["REQUEST_METHOD"] = "PATCH"
|
||||
|
||||
return this.Post(p, bodyType, body, l)
|
||||
return c.Post(p, bodyType, body, l)
|
||||
}
|
||||
|
||||
// Delete issues a DELETE request to the fcgi responder.
|
||||
func (this *FCGIClient) Delete(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) Delete(p map[string]string, bodyType string, body io.Reader, l int) (resp *http.Response, err error) {
|
||||
|
||||
p["REQUEST_METHOD"] = "DELETE"
|
||||
|
||||
return this.Post(p, bodyType, body, l)
|
||||
return c.Post(p, bodyType, body, l)
|
||||
}
|
||||
|
||||
// PostForm issues a POST to the fcgi responder, with form
|
||||
// as a string key to a list values (url.Values)
|
||||
func (this *FCGIClient) PostForm(p map[string]string, data url.Values) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) PostForm(p map[string]string, data url.Values) (resp *http.Response, err error) {
|
||||
body := bytes.NewReader([]byte(data.Encode()))
|
||||
return this.Post(p, "application/x-www-form-urlencoded", body, body.Len())
|
||||
return c.Post(p, "application/x-www-form-urlencoded", body, body.Len())
|
||||
}
|
||||
|
||||
// PostFile issues a POST to the fcgi responder in multipart(RFC 2046) standard,
|
||||
// with form as a string key to a list values (url.Values),
|
||||
// and/or with file as a string key to a list file path.
|
||||
func (this *FCGIClient) PostFile(p map[string]string, data url.Values, file map[string]string) (resp *http.Response, err error) {
|
||||
func (c *FCGIClient) PostFile(p map[string]string, data url.Values, file map[string]string) (resp *http.Response, err error) {
|
||||
buf := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(buf)
|
||||
bodyType := writer.FormDataContentType()
|
||||
|
@ -509,7 +508,7 @@ func (this *FCGIClient) PostFile(p map[string]string, data url.Values, file map[
|
|||
return
|
||||
}
|
||||
|
||||
return this.Post(p, bodyType, buf, buf.Len())
|
||||
return c.Post(p, bodyType, buf, buf.Len())
|
||||
}
|
||||
|
||||
// Checks whether chunked is part of the encodings stack
|
||||
|
|
|
@ -28,7 +28,7 @@ var shell string
|
|||
|
||||
// initMutex prevents parallel attempt to validate
|
||||
// git requirements.
|
||||
var initMutex sync.Mutex = sync.Mutex{}
|
||||
var initMutex = sync.Mutex{}
|
||||
|
||||
// Logger is used to log errors; if nil, the default log.Logger is used.
|
||||
var Logger *log.Logger
|
||||
|
@ -44,7 +44,7 @@ func logger() *log.Logger {
|
|||
// Repo is the structure that holds required information
|
||||
// of a git repository.
|
||||
type Repo struct {
|
||||
Url string // Repository URL
|
||||
URL string // Repository URL
|
||||
Path string // Directory to pull to
|
||||
Host string // Git domain host e.g. github.com
|
||||
Branch string // Git branch
|
||||
|
@ -94,7 +94,7 @@ func (r *Repo) Pull() error {
|
|||
|
||||
// Pull performs git clone, or git pull if repository exists
|
||||
func (r *Repo) pull() error {
|
||||
params := []string{"clone", "-b", r.Branch, r.Url, r.Path}
|
||||
params := []string{"clone", "-b", r.Branch, r.URL, r.Path}
|
||||
if r.pulled {
|
||||
params = []string{"pull", "origin", r.Branch}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ func (r *Repo) pull() error {
|
|||
if err = runCmd(gitBinary, params, dir); err == nil {
|
||||
r.pulled = true
|
||||
r.lastPull = time.Now()
|
||||
logger().Printf("%v pulled.\n", r.Url)
|
||||
logger().Printf("%v pulled.\n", r.URL)
|
||||
r.lastCommit, err = r.getMostRecentCommit()
|
||||
}
|
||||
return err
|
||||
|
@ -122,11 +122,11 @@ func (r *Repo) pull() error {
|
|||
// pullWithKey is used for private repositories and requires an ssh key.
|
||||
// Note: currently only limited to Linux and OSX.
|
||||
func (r *Repo) pullWithKey(params []string) error {
|
||||
var gitSsh, script gitos.File
|
||||
var gitSSH, script gitos.File
|
||||
// ensure temporary files deleted after usage
|
||||
defer func() {
|
||||
if gitSsh != nil {
|
||||
gos.Remove(gitSsh.Name())
|
||||
if gitSSH != nil {
|
||||
gos.Remove(gitSSH.Name())
|
||||
}
|
||||
if script != nil {
|
||||
gos.Remove(script.Name())
|
||||
|
@ -135,13 +135,13 @@ func (r *Repo) pullWithKey(params []string) error {
|
|||
|
||||
var err error
|
||||
// write git.sh script to temp file
|
||||
gitSsh, err = writeScriptFile(gitWrapperScript())
|
||||
gitSSH, err = writeScriptFile(gitWrapperScript())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write git clone bash script to file
|
||||
script, err = writeScriptFile(bashScript(gitSsh.Name(), r, params))
|
||||
script, err = writeScriptFile(bashScript(gitSSH.Name(), r, params))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ func (r *Repo) pullWithKey(params []string) error {
|
|||
if err = runCmd(script.Name(), nil, dir); err == nil {
|
||||
r.pulled = true
|
||||
r.lastPull = time.Now()
|
||||
logger().Printf("%v pulled.\n", r.Url)
|
||||
logger().Printf("%v pulled.\n", r.URL)
|
||||
r.lastCommit, err = r.getMostRecentCommit()
|
||||
}
|
||||
return err
|
||||
|
@ -181,13 +181,13 @@ func (r *Repo) Prepare() error {
|
|||
|
||||
if isGit {
|
||||
// check if same repository
|
||||
var repoUrl string
|
||||
if repoUrl, err = r.getRepoUrl(); err == nil {
|
||||
var repoURL string
|
||||
if repoURL, err = r.getRepoURL(); err == nil {
|
||||
// add .git suffix if missing for adequate comparison.
|
||||
if !strings.HasSuffix(repoUrl, ".git") {
|
||||
repoUrl += ".git"
|
||||
if !strings.HasSuffix(repoURL, ".git") {
|
||||
repoURL += ".git"
|
||||
}
|
||||
if repoUrl == r.Url {
|
||||
if repoURL == r.URL {
|
||||
r.pulled = true
|
||||
return nil
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ func (r *Repo) Prepare() error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("Cannot retrieve repo url for %v Error: %v", r.Path, err)
|
||||
}
|
||||
return fmt.Errorf("Another git repo '%v' exists at %v", repoUrl, r.Path)
|
||||
return fmt.Errorf("Another git repo '%v' exists at %v", repoURL, r.Path)
|
||||
}
|
||||
return fmt.Errorf("Cannot git clone into %v, directory not empty.", r.Path)
|
||||
}
|
||||
|
@ -211,8 +211,8 @@ func (r *Repo) getMostRecentCommit() (string, error) {
|
|||
return runCmdOutput(c, args, r.Path)
|
||||
}
|
||||
|
||||
// getRepoUrl retrieves remote origin url for the git repository at path
|
||||
func (r *Repo) getRepoUrl() (string, error) {
|
||||
// getRepoURL retrieves remote origin url for the git repository at path
|
||||
func (r *Repo) getRepoURL() (string, error) {
|
||||
_, err := gos.Stat(r.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -63,7 +63,7 @@ func TestGit(t *testing.T) {
|
|||
// prepare
|
||||
repos := []*Repo{
|
||||
nil,
|
||||
&Repo{Path: "gitdir", Url: "success.git"},
|
||||
&Repo{Path: "gitdir", URL: "success.git"},
|
||||
}
|
||||
for _, r := range repos {
|
||||
repo := createRepo(r)
|
||||
|
@ -79,26 +79,26 @@ func TestGit(t *testing.T) {
|
|||
output string
|
||||
}{
|
||||
{
|
||||
&Repo{Path: "gitdir", Url: "git@github.com:user/repo.git", KeyPath: "~/.key", Then: "echo Hello"},
|
||||
&Repo{Path: "gitdir", URL: "git@github.com:user/repo.git", KeyPath: "~/.key", Then: "echo Hello"},
|
||||
`git@github.com:user/repo.git pulled.
|
||||
Command echo Hello successful.
|
||||
`,
|
||||
},
|
||||
{
|
||||
&Repo{Path: "gitdir", Url: "https://github.com/user/repo.git", Then: "echo Hello"},
|
||||
&Repo{Path: "gitdir", URL: "https://github.com/user/repo.git", Then: "echo Hello"},
|
||||
`https://github.com/user/repo.git pulled.
|
||||
Command echo Hello successful.
|
||||
`,
|
||||
},
|
||||
{
|
||||
&Repo{Url: "git@github.com:user/repo"},
|
||||
&Repo{URL: "git@github.com:user/repo"},
|
||||
`git@github.com:user/repo pulled.
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
gittest.CmdOutput = test.repo.Url
|
||||
gittest.CmdOutput = test.repo.URL
|
||||
|
||||
test.repo = createRepo(test.repo)
|
||||
|
||||
|
@ -117,8 +117,8 @@ Command echo Hello successful.
|
|||
|
||||
// pull with error
|
||||
repos = []*Repo{
|
||||
&Repo{Path: "gitdir", Url: "http://github.com:u/repo.git"},
|
||||
&Repo{Path: "gitdir", Url: "https://github.com/user/repo.git", Then: "echo Hello"},
|
||||
&Repo{Path: "gitdir", URL: "http://github.com:u/repo.git"},
|
||||
&Repo{Path: "gitdir", URL: "https://github.com/user/repo.git", Then: "echo Hello"},
|
||||
&Repo{Path: "gitdir"},
|
||||
&Repo{Path: "gitdir", KeyPath: ".key"},
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ Command echo Hello successful.
|
|||
|
||||
func createRepo(r *Repo) *Repo {
|
||||
repo := &Repo{
|
||||
Url: "git@github.com/user/test",
|
||||
URL: "git@github.com/user/test",
|
||||
Path: ".",
|
||||
Host: "github.com",
|
||||
Branch: "master",
|
||||
|
@ -170,8 +170,8 @@ func createRepo(r *Repo) *Repo {
|
|||
if r.Then != "" {
|
||||
repo.Then = r.Then
|
||||
}
|
||||
if r.Url != "" {
|
||||
repo.Url = r.Url
|
||||
if r.URL != "" {
|
||||
repo.URL = r.URL
|
||||
}
|
||||
|
||||
return repo
|
||||
|
|
|
@ -45,9 +45,8 @@ func (g Gzip) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
|||
gz.WriteHeader(status)
|
||||
fmt.Fprintf(gz, "%d %s", status, http.StatusText(status))
|
||||
return 0, err
|
||||
} else {
|
||||
return status, err
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
||||
// gzipResponeWriter wraps the underlying Write method
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// The package internal provides a simple middleware that (a) prevents access
|
||||
// Package internal provides a simple middleware that (a) prevents access
|
||||
// to internal locations and (b) allows to return files from internal location
|
||||
// by setting a special header, e.g. in a proxy response.
|
||||
package internal
|
||||
|
@ -85,7 +85,6 @@ func (w internalResponseWriter) WriteHeader(code int) {
|
|||
func (w internalResponseWriter) Write(b []byte) (int, error) {
|
||||
if isInternalRedirect(w) {
|
||||
return 0, nil
|
||||
} else {
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ import (
|
|||
"github.com/mholt/caddy/middleware"
|
||||
)
|
||||
|
||||
// Logger is a basic request logging middleware.
|
||||
type Logger struct {
|
||||
Next middleware.Handler
|
||||
Rules []LogRule
|
||||
Rules []Rule
|
||||
}
|
||||
|
||||
func (l Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
|
@ -26,7 +27,8 @@ func (l Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
|||
return l.Next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
type LogRule struct {
|
||||
// Rule configures the logging middleware.
|
||||
type Rule struct {
|
||||
PathScope string
|
||||
OutputFile string
|
||||
Format string
|
||||
|
|
|
@ -31,9 +31,9 @@ type Markdown struct {
|
|||
IndexFiles []string
|
||||
}
|
||||
|
||||
// Helper function to check if a file is an index file
|
||||
func (m Markdown) IsIndexFile(file string) bool {
|
||||
for _, f := range m.IndexFiles {
|
||||
// IsIndexFile checks to see if a file is an index file
|
||||
func (md Markdown) IsIndexFile(file string) bool {
|
||||
for _, f := range md.IndexFiles {
|
||||
if f == file {
|
||||
return true
|
||||
}
|
||||
|
@ -105,12 +105,11 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
|
|||
if html, err := ioutil.ReadFile(filepath); err == nil {
|
||||
w.Write(html)
|
||||
return http.StatusOK, nil
|
||||
} else {
|
||||
if os.IsPermission(err) {
|
||||
return http.StatusForbidden, err
|
||||
}
|
||||
return http.StatusNotFound, nil
|
||||
}
|
||||
if os.IsPermission(err) {
|
||||
return http.StatusForbidden, err
|
||||
}
|
||||
return http.StatusNotFound, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,8 +88,8 @@ func (j *JSONMetadataParser) Parse(b []byte) ([]byte, error) {
|
|||
return buf[:n], nil
|
||||
}
|
||||
|
||||
// Parsed metadata.
|
||||
// Should be called after a call to Parse returns no error
|
||||
// Metadata returns parsed metadata. It should be called
|
||||
// only after a call to Parse returns without error.
|
||||
func (j *JSONMetadataParser) Metadata() Metadata {
|
||||
return j.metadata
|
||||
}
|
||||
|
@ -123,8 +123,8 @@ func (t *TOMLMetadataParser) Parse(b []byte) ([]byte, error) {
|
|||
return markdown, nil
|
||||
}
|
||||
|
||||
// Parsed metadata.
|
||||
// Should be called after a call to Parse returns no error
|
||||
// Metadata returns parsed metadata. It should be called
|
||||
// only after a call to Parse returns without error.
|
||||
func (t *TOMLMetadataParser) Metadata() Metadata {
|
||||
return t.metadata
|
||||
}
|
||||
|
@ -171,8 +171,8 @@ func (y *YAMLMetadataParser) Parse(b []byte) ([]byte, error) {
|
|||
return markdown, nil
|
||||
}
|
||||
|
||||
// Parsed metadata.
|
||||
// Should be called after a call to Parse returns no error
|
||||
// Metadata returns parsed metadata. It should be called
|
||||
// only after a call to Parse returns without error.
|
||||
func (y *YAMLMetadataParser) Metadata() Metadata {
|
||||
return y.metadata
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import "strings"
|
|||
// Path represents a URI path, maybe with pattern characters.
|
||||
type Path string
|
||||
|
||||
// Matches checks to see if other matches p.
|
||||
//
|
||||
// Path matching will probably not always be a direct
|
||||
// comparison; this method assures that paths can be
|
||||
// easily and consistently matched.
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"sync/atomic"
|
||||
)
|
||||
|
||||
// HostPool is a collection of UpstreamHosts.
|
||||
type HostPool []*UpstreamHost
|
||||
|
||||
// Policy decides how a host will be selected from a pool.
|
||||
|
@ -12,9 +13,10 @@ type Policy interface {
|
|||
Select(pool HostPool) *UpstreamHost
|
||||
}
|
||||
|
||||
// The random policy randomly selected an up host from the pool.
|
||||
// Random is a policy that selects up hosts from a pool at random.
|
||||
type Random struct{}
|
||||
|
||||
// Select selects an up host at random from the specified pool.
|
||||
func (r *Random) Select(pool HostPool) *UpstreamHost {
|
||||
// instead of just generating a random index
|
||||
// this is done to prevent selecting a down host
|
||||
|
@ -37,11 +39,12 @@ func (r *Random) Select(pool HostPool) *UpstreamHost {
|
|||
return randHost
|
||||
}
|
||||
|
||||
// The least_conn policy selects a host with the least connections.
|
||||
// If multiple hosts have the least amount of connections, one is randomly
|
||||
// chosen.
|
||||
// LeastConn is a policy that selects the host with the least connections.
|
||||
type LeastConn struct{}
|
||||
|
||||
// Select selects the up host with the least number of connections in the
|
||||
// pool. If more than one host has the same least number of connections,
|
||||
// one of the hosts is chosen at random.
|
||||
func (r *LeastConn) Select(pool HostPool) *UpstreamHost {
|
||||
var bestHost *UpstreamHost
|
||||
count := 0
|
||||
|
@ -71,11 +74,12 @@ func (r *LeastConn) Select(pool HostPool) *UpstreamHost {
|
|||
return bestHost
|
||||
}
|
||||
|
||||
// The round_robin policy selects a host based on round robin ordering.
|
||||
// RoundRobin is a policy that selects hosts based on round robin ordering.
|
||||
type RoundRobin struct {
|
||||
Robin uint32
|
||||
}
|
||||
|
||||
// Select selects an up host from the pool using a round robin ordering scheme.
|
||||
func (r *RoundRobin) Select(pool HostPool) *UpstreamHost {
|
||||
poolLen := uint32(len(pool))
|
||||
selection := atomic.AddUint32(&r.Robin, 1) % poolLen
|
||||
|
|
|
@ -19,18 +19,19 @@ type Proxy struct {
|
|||
Upstreams []Upstream
|
||||
}
|
||||
|
||||
// An upstream manages a pool of proxy upstream hosts. Select should return a
|
||||
// Upstream manages a pool of proxy upstream hosts. Select should return a
|
||||
// suitable upstream host, or nil if no such hosts are available.
|
||||
type Upstream interface {
|
||||
//The path this upstream host should be routed on
|
||||
// The path this upstream host should be routed on
|
||||
From() string
|
||||
// Selects an upstream host to be routed to.
|
||||
Select() *UpstreamHost
|
||||
}
|
||||
|
||||
// UpstreamHostDownFunc can be used to customize how Down behaves.
|
||||
type UpstreamHostDownFunc func(*UpstreamHost) bool
|
||||
|
||||
// An UpstreamHost represents a single proxy upstream
|
||||
// UpstreamHost represents a single proxy upstream
|
||||
type UpstreamHost struct {
|
||||
// The hostname of this upstream host
|
||||
Name string
|
||||
|
@ -43,6 +44,9 @@ type UpstreamHost struct {
|
|||
CheckDown UpstreamHostDownFunc
|
||||
}
|
||||
|
||||
// Down checks whether the upstream host is down or not.
|
||||
// Down will try to use uh.CheckDown first, and will fall
|
||||
// back to some default criteria if necessary.
|
||||
func (uh *UpstreamHost) Down() bool {
|
||||
if uh.CheckDown == nil {
|
||||
// Default settings
|
||||
|
@ -70,10 +74,10 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
|||
proxy := host.ReverseProxy
|
||||
r.Host = host.Name
|
||||
|
||||
if baseUrl, err := url.Parse(host.Name); err == nil {
|
||||
r.Host = baseUrl.Host
|
||||
if baseURL, err := url.Parse(host.Name); err == nil {
|
||||
r.Host = baseURL.Host
|
||||
if proxy == nil {
|
||||
proxy = NewSingleHostReverseProxy(baseUrl)
|
||||
proxy = NewSingleHostReverseProxy(baseURL)
|
||||
}
|
||||
} else if proxy == nil {
|
||||
return http.StatusInternalServerError, err
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/mholt/caddy/config/parse"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -9,6 +8,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mholt/caddy/config/parse"
|
||||
)
|
||||
|
||||
type staticUpstream struct {
|
||||
|
@ -24,7 +25,7 @@ type staticUpstream struct {
|
|||
}
|
||||
}
|
||||
|
||||
// newStaticUpstreams parses the configuration input and sets up
|
||||
// NewStaticUpstreams parses the configuration input and sets up
|
||||
// static upstreams for the proxy middleware.
|
||||
func NewStaticUpstreams(c parse.Dispenser) ([]Upstream, error) {
|
||||
var upstreams []Upstream
|
||||
|
@ -130,8 +131,8 @@ func NewStaticUpstreams(c parse.Dispenser) ([]Upstream, error) {
|
|||
}
|
||||
}(upstream),
|
||||
}
|
||||
if baseUrl, err := url.Parse(uh.Name); err == nil {
|
||||
uh.ReverseProxy = NewSingleHostReverseProxy(baseUrl)
|
||||
if baseURL, err := url.Parse(uh.Name); err == nil {
|
||||
uh.ReverseProxy = NewSingleHostReverseProxy(baseURL)
|
||||
} else {
|
||||
return upstreams, err
|
||||
}
|
||||
|
@ -152,8 +153,8 @@ func (u *staticUpstream) From() string {
|
|||
|
||||
func (u *staticUpstream) healthCheck() {
|
||||
for _, host := range u.Hosts {
|
||||
hostUrl := host.Name + u.HealthCheck.Path
|
||||
if r, err := http.Get(hostUrl); err == nil {
|
||||
hostURL := host.Name + u.HealthCheck.Path
|
||||
if r, err := http.Get(hostURL); err == nil {
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
host.Unhealthy = r.StatusCode < 200 || r.StatusCode >= 400
|
||||
|
@ -199,7 +200,6 @@ func (u *staticUpstream) Select() *UpstreamHost {
|
|||
|
||||
if u.Policy == nil {
|
||||
return (&Random{}).Select(pool)
|
||||
} else {
|
||||
return u.Policy.Select(pool)
|
||||
}
|
||||
return u.Policy.Select(pool)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,13 @@ import (
|
|||
"net/http"
|
||||
|
||||
"fmt"
|
||||
"github.com/mholt/caddy/middleware"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy/middleware"
|
||||
)
|
||||
|
||||
// Rewrite is middleware to rewrite request locations internally before being handled.
|
||||
|
@ -96,7 +97,7 @@ func NewRegexpRule(base, pattern, to string, ext []string) (*RegexpRule, error)
|
|||
}
|
||||
|
||||
// regexpVars are variables that can be used for To (rewrite destination path).
|
||||
var regexpVars []string = []string{
|
||||
var regexpVars = []string{
|
||||
"{path}",
|
||||
"{query}",
|
||||
"{file}",
|
||||
|
|
|
@ -6,8 +6,9 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mholt/caddy/middleware"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy/middleware"
|
||||
)
|
||||
|
||||
func TestRewrite(t *testing.T) {
|
||||
|
|
|
@ -22,7 +22,7 @@ type (
|
|||
Sockets []Config
|
||||
}
|
||||
|
||||
// WSConfig holds the configuration for a single websocket
|
||||
// Config holds the configuration for a single websocket
|
||||
// endpoint which may serve multiple websocket connections.
|
||||
Config struct {
|
||||
Path string
|
||||
|
@ -50,9 +50,11 @@ func (ws WebSockets) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
|||
}
|
||||
|
||||
var (
|
||||
// See CGI spec, 4.1.4
|
||||
// GatewayInterface is the dialect of CGI being used by the server
|
||||
// to communicate with the script. See CGI spec, 4.1.4
|
||||
GatewayInterface string
|
||||
|
||||
// See CGI spec, 4.1.17
|
||||
// ServerSoftware is the name and version of the information server
|
||||
// software making the CGI request. See CGI spec, 4.1.17
|
||||
ServerSoftware string
|
||||
)
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/mholt/caddy/middleware/browse"
|
||||
)
|
||||
|
||||
// This FileServer is adapted from the one in net/http by
|
||||
// FileServer is adapted from the one in net/http by
|
||||
// the Go authors. Significant modifications have been made.
|
||||
//
|
||||
//
|
||||
|
@ -28,15 +28,16 @@ type fileHandler struct {
|
|||
hide []string // list of files to treat as "Not Found"
|
||||
}
|
||||
|
||||
func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
func (fh *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
upath := r.URL.Path
|
||||
if !strings.HasPrefix(upath, "/") {
|
||||
upath = "/" + upath
|
||||
r.URL.Path = upath
|
||||
}
|
||||
return f.serveFile(w, r, path.Clean(upath))
|
||||
return fh.serveFile(w, r, path.Clean(upath))
|
||||
}
|
||||
|
||||
// serveFile writes the specified file to the HTTP response.
|
||||
// name is '/'-separated, not filepath.Separator.
|
||||
func (fh *fileHandler) serveFile(w http.ResponseWriter, r *http.Request, name string) (int, error) {
|
||||
f, err := fh.root.Open(name)
|
||||
|
|
|
@ -97,9 +97,8 @@ func (s *Server) Serve() error {
|
|||
tlsConfigs = append(tlsConfigs, vh.config.TLS)
|
||||
}
|
||||
return ListenAndServeTLSWithSNI(server, tlsConfigs)
|
||||
} else {
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
// ListenAndServeTLSWithSNI serves TLS with Server Name Indication (SNI) support, which allows
|
||||
|
|
Loading…
Reference in New Issue
Block a user