Commit a8818388 authored by Abiola Ibrahim's avatar Abiola Ibrahim

Merge pull request #88 from zmb3/lintwarnings

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