mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-03 19:17:29 -05:00 
			
		
		
		
	Merge pull request #267 from zmb3/reportcard
Ran gofmt -s, fixed some golint warnings, refactored some large functions Minor quality improvements (closes #253)
This commit is contained in:
		
						commit
						837c17c396
					
				@ -33,8 +33,8 @@ var (
 | 
				
			|||||||
	// Wg is used to wait for all servers to shut down
 | 
						// Wg is used to wait for all servers to shut down
 | 
				
			||||||
	Wg sync.WaitGroup
 | 
						Wg sync.WaitGroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Http2 indicates 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
 | 
				
			||||||
	Quiet bool
 | 
						Quiet bool
 | 
				
			||||||
 | 
				
			|||||||
@ -234,6 +234,8 @@ func validDirective(d string) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewDefault creates a default configuration using the default
 | 
				
			||||||
 | 
					// root, host, and port.
 | 
				
			||||||
func NewDefault() server.Config {
 | 
					func NewDefault() server.Config {
 | 
				
			||||||
	return server.Config{
 | 
						return server.Config{
 | 
				
			||||||
		Root: Root,
 | 
							Root: Root,
 | 
				
			||||||
@ -256,4 +258,5 @@ var (
 | 
				
			|||||||
	Port = DefaultPort
 | 
						Port = DefaultPort
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Group maps network addresses to their configurations.
 | 
				
			||||||
type Group map[*net.TCPAddr][]server.Config
 | 
					type Group map[*net.TCPAddr][]server.Config
 | 
				
			||||||
 | 
				
			|||||||
@ -74,7 +74,7 @@ type directive struct {
 | 
				
			|||||||
	setup SetupFunc
 | 
						setup SetupFunc
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A setup function takes a setup controller. Its return values may
 | 
					// SetupFunc takes a controller and may optionally return a middleware.
 | 
				
			||||||
// both be nil. If middleware is not nil, it will be chained into
 | 
					// If the resulting middleware is not nil, it will be chained into
 | 
				
			||||||
// the HTTP handlers in the order specified in this package.
 | 
					// the HTTP handlers in the order specified in this package.
 | 
				
			||||||
type SetupFunc func(c *setup.Controller) (middleware.Middleware, error)
 | 
					type SetupFunc func(c *setup.Controller) (middleware.Middleware, error)
 | 
				
			||||||
 | 
				
			|||||||
@ -119,6 +119,7 @@ func (d *Dispenser) NextBlock() bool {
 | 
				
			|||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IncrNest adds a level of nesting to the dispenser.
 | 
				
			||||||
func (d *Dispenser) IncrNest() {
 | 
					func (d *Dispenser) IncrNest() {
 | 
				
			||||||
	d.nesting++
 | 
						d.nesting++
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
@ -208,9 +209,9 @@ func (d *Dispenser) SyntaxErr(expected string) error {
 | 
				
			|||||||
	return errors.New(msg)
 | 
						return errors.New(msg)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EofErr returns an EOF error, meaning that end of input
 | 
					// EOFErr returns an error indicating that the dispenser reached
 | 
				
			||||||
// was found when another token was expected.
 | 
					// the end of the input when searching for the next token.
 | 
				
			||||||
func (d *Dispenser) EofErr() error {
 | 
					func (d *Dispenser) EOFErr() error {
 | 
				
			||||||
	return d.Errf("Unexpected EOF")
 | 
						return d.Errf("Unexpected EOF")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -108,7 +108,7 @@ func (p *parser) addresses() error {
 | 
				
			|||||||
		// Advance token and possibly break out of loop or return error
 | 
							// Advance token and possibly break out of loop or return error
 | 
				
			||||||
		hasNext := p.Next()
 | 
							hasNext := p.Next()
 | 
				
			||||||
		if expectingAnother && !hasNext {
 | 
							if expectingAnother && !hasNext {
 | 
				
			||||||
			return p.EofErr()
 | 
								return p.EOFErr()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !hasNext {
 | 
							if !hasNext {
 | 
				
			||||||
			p.eof = true
 | 
								p.eof = true
 | 
				
			||||||
@ -242,7 +242,7 @@ func (p *parser) directive() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if nesting > 0 {
 | 
						if nesting > 0 {
 | 
				
			||||||
		return p.EofErr()
 | 
							return p.EOFErr()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -338,9 +338,9 @@ func TestParseAll(t *testing.T) {
 | 
				
			|||||||
func setupParseTests() {
 | 
					func setupParseTests() {
 | 
				
			||||||
	// Set up some bogus directives for testing
 | 
						// Set up some bogus directives for testing
 | 
				
			||||||
	ValidDirectives = map[string]struct{}{
 | 
						ValidDirectives = map[string]struct{}{
 | 
				
			||||||
		"dir1": struct{}{},
 | 
							"dir1": {},
 | 
				
			||||||
		"dir2": struct{}{},
 | 
							"dir2": {},
 | 
				
			||||||
		"dir3": struct{}{},
 | 
							"dir3": {},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -68,62 +68,8 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Load any other configuration parameters
 | 
							// Load any other configuration parameters
 | 
				
			||||||
		for c.NextBlock() {
 | 
							for c.NextBlock() {
 | 
				
			||||||
			switch c.Val() {
 | 
								if err := loadParams(c, md); err != nil {
 | 
				
			||||||
			case "ext":
 | 
									return mdconfigs, err
 | 
				
			||||||
				exts := c.RemainingArgs()
 | 
					 | 
				
			||||||
				if len(exts) == 0 {
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				md.Extensions = append(md.Extensions, exts...)
 | 
					 | 
				
			||||||
			case "css":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				md.Styles = append(md.Styles, c.Val())
 | 
					 | 
				
			||||||
			case "js":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				md.Scripts = append(md.Scripts, c.Val())
 | 
					 | 
				
			||||||
			case "template":
 | 
					 | 
				
			||||||
				tArgs := c.RemainingArgs()
 | 
					 | 
				
			||||||
				switch len(tArgs) {
 | 
					 | 
				
			||||||
				case 0:
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				case 1:
 | 
					 | 
				
			||||||
					if _, ok := md.Templates[markdown.DefaultTemplate]; ok {
 | 
					 | 
				
			||||||
						return mdconfigs, c.Err("only one default template is allowed, use alias.")
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					fpath := filepath.Clean(c.Root + string(filepath.Separator) + tArgs[0])
 | 
					 | 
				
			||||||
					md.Templates[markdown.DefaultTemplate] = fpath
 | 
					 | 
				
			||||||
				case 2:
 | 
					 | 
				
			||||||
					fpath := filepath.Clean(c.Root + string(filepath.Separator) + tArgs[1])
 | 
					 | 
				
			||||||
					md.Templates[tArgs[0]] = fpath
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case "sitegen":
 | 
					 | 
				
			||||||
				if c.NextArg() {
 | 
					 | 
				
			||||||
					md.StaticDir = path.Join(c.Root, c.Val())
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					md.StaticDir = path.Join(c.Root, markdown.DefaultStaticDir)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if c.NextArg() {
 | 
					 | 
				
			||||||
					// only 1 argument allowed
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case "dev":
 | 
					 | 
				
			||||||
				if c.NextArg() {
 | 
					 | 
				
			||||||
					md.Development = strings.ToLower(c.Val()) == "true"
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					md.Development = true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if c.NextArg() {
 | 
					 | 
				
			||||||
					// only 1 argument allowed
 | 
					 | 
				
			||||||
					return mdconfigs, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				return mdconfigs, c.Err("Expected valid markdown configuration property")
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,3 +83,70 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return mdconfigs, nil
 | 
						return mdconfigs, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadParams(c *Controller, mdc *markdown.Config) error {
 | 
				
			||||||
 | 
						switch c.Val() {
 | 
				
			||||||
 | 
						case "ext":
 | 
				
			||||||
 | 
							exts := c.RemainingArgs()
 | 
				
			||||||
 | 
							if len(exts) == 0 {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							mdc.Extensions = append(mdc.Extensions, exts...)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						case "css":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							mdc.Styles = append(mdc.Styles, c.Val())
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						case "js":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							mdc.Scripts = append(mdc.Scripts, c.Val())
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						case "template":
 | 
				
			||||||
 | 
							tArgs := c.RemainingArgs()
 | 
				
			||||||
 | 
							switch len(tArgs) {
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								if _, ok := mdc.Templates[markdown.DefaultTemplate]; ok {
 | 
				
			||||||
 | 
									return c.Err("only one default template is allowed, use alias.")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								fpath := filepath.Clean(c.Root + string(filepath.Separator) + tArgs[0])
 | 
				
			||||||
 | 
								mdc.Templates[markdown.DefaultTemplate] = fpath
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							case 2:
 | 
				
			||||||
 | 
								fpath := filepath.Clean(c.Root + string(filepath.Separator) + tArgs[1])
 | 
				
			||||||
 | 
								mdc.Templates[tArgs[0]] = fpath
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case "sitegen":
 | 
				
			||||||
 | 
							if c.NextArg() {
 | 
				
			||||||
 | 
								mdc.StaticDir = path.Join(c.Root, c.Val())
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								mdc.StaticDir = path.Join(c.Root, markdown.DefaultStaticDir)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if c.NextArg() {
 | 
				
			||||||
 | 
								// only 1 argument allowed
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						case "dev":
 | 
				
			||||||
 | 
							if c.NextArg() {
 | 
				
			||||||
 | 
								mdc.Development = strings.ToLower(c.Val()) == "true"
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								mdc.Development = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if c.NextArg() {
 | 
				
			||||||
 | 
								// only 1 argument allowed
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return c.Err("Expected valid markdown configuration property")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,11 +7,11 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Proxy configures a new Proxy middleware instance.
 | 
					// Proxy configures a new Proxy middleware instance.
 | 
				
			||||||
func Proxy(c *Controller) (middleware.Middleware, error) {
 | 
					func Proxy(c *Controller) (middleware.Middleware, error) {
 | 
				
			||||||
	if upstreams, err := proxy.NewStaticUpstreams(c.Dispenser); err == nil {
 | 
						upstreams, err := proxy.NewStaticUpstreams(c.Dispenser)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return func(next middleware.Handler) middleware.Handler {
 | 
						return func(next middleware.Handler) middleware.Handler {
 | 
				
			||||||
		return proxy.Proxy{Next: next, Upstreams: upstreams}
 | 
							return proxy.Proxy{Next: next, Upstreams: upstreams}
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -46,9 +46,8 @@ func registerCallback(c *Controller, list *[]func() error) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if nonblock {
 | 
								if nonblock {
 | 
				
			||||||
				return cmd.Start()
 | 
									return cmd.Start()
 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				return cmd.Run()
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								return cmd.Run()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		*list = append(*list, fn)
 | 
							*list = append(*list, fn)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.go
									
									
									
									
									
								
							@ -26,7 +26,7 @@ var (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	flag.StringVar(&conf, "conf", "", "Configuration file to use (default="+config.DefaultConfigFile+")")
 | 
						flag.StringVar(&conf, "conf", "", "Configuration file to use (default="+config.DefaultConfigFile+")")
 | 
				
			||||||
	flag.BoolVar(&app.Http2, "http2", true, "Enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib
 | 
						flag.BoolVar(&app.HTTP2, "http2", true, "Enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib
 | 
				
			||||||
	flag.BoolVar(&app.Quiet, "quiet", false, "Quiet mode (no initialization output)")
 | 
						flag.BoolVar(&app.Quiet, "quiet", false, "Quiet mode (no initialization output)")
 | 
				
			||||||
	flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
 | 
						flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
 | 
				
			||||||
	flag.StringVar(&config.Root, "root", config.DefaultRoot, "Root path to default site")
 | 
						flag.StringVar(&config.Root, "root", config.DefaultRoot, "Root path to default site")
 | 
				
			||||||
@ -61,7 +61,7 @@ func main() {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatal(err)
 | 
								log.Fatal(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		s.HTTP2 = app.Http2 // TODO: This setting is temporary
 | 
							s.HTTP2 = app.HTTP2 // TODO: This setting is temporary
 | 
				
			||||||
		app.Wg.Add(1)
 | 
							app.Wg.Add(1)
 | 
				
			||||||
		go func(s *server.Server) {
 | 
							go func(s *server.Server) {
 | 
				
			||||||
			defer app.Wg.Done()
 | 
								defer app.Wg.Done()
 | 
				
			||||||
 | 
				
			|||||||
@ -78,6 +78,7 @@ type Rule struct {
 | 
				
			|||||||
	Resources []string
 | 
						Resources []string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PasswordMatcher determines whether a password mathes a rule.
 | 
				
			||||||
type PasswordMatcher func(pw string) bool
 | 
					type PasswordMatcher func(pw string) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@ -137,6 +138,8 @@ func parseHtpasswd(pm map[string]PasswordMatcher, r io.Reader) error {
 | 
				
			|||||||
	return scanner.Err()
 | 
						return scanner.Err()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PlainMatcher returns a PasswordMatcher that does a constant-time
 | 
				
			||||||
 | 
					// byte-wise comparison.
 | 
				
			||||||
func PlainMatcher(passw string) PasswordMatcher {
 | 
					func PlainMatcher(passw string) PasswordMatcher {
 | 
				
			||||||
	return func(pw string) bool {
 | 
						return func(pw string) bool {
 | 
				
			||||||
		return subtle.ConstantTimeCompare([]byte(pw), []byte(passw)) == 1
 | 
							return subtle.ConstantTimeCompare([]byte(pw), []byte(passw)) == 1
 | 
				
			||||||
 | 
				
			|||||||
@ -117,7 +117,7 @@ func TestBrowseTemplate(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
		Root: "./testdata",
 | 
							Root: "./testdata",
 | 
				
			||||||
		Configs: []Config{
 | 
							Configs: []Config{
 | 
				
			||||||
			Config{
 | 
								{
 | 
				
			||||||
				PathScope: "/photos",
 | 
									PathScope: "/photos",
 | 
				
			||||||
				Template:  tmpl,
 | 
									Template:  tmpl,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@ -172,7 +172,7 @@ func TestBrowseJson(t *testing.T) {
 | 
				
			|||||||
		}),
 | 
							}),
 | 
				
			||||||
		Root: "./testdata",
 | 
							Root: "./testdata",
 | 
				
			||||||
		Configs: []Config{
 | 
							Configs: []Config{
 | 
				
			||||||
			Config{
 | 
								{
 | 
				
			||||||
				PathScope: "/photos/",
 | 
									PathScope: "/photos/",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@ -283,7 +283,7 @@ func TestBrowseJson(t *testing.T) {
 | 
				
			|||||||
			t.Fatalf("Expected Content type to be application/json; charset=utf-8, but got %s ", rec.HeaderMap.Get("Content-Type"))
 | 
								t.Fatalf("Expected Content type to be application/json; charset=utf-8, but got %s ", rec.HeaderMap.Get("Content-Type"))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		actualJsonResponseString := rec.Body.String()
 | 
							actualJSONResponse := rec.Body.String()
 | 
				
			||||||
		copyOflisting := listing
 | 
							copyOflisting := listing
 | 
				
			||||||
		if test.SortBy == "" {
 | 
							if test.SortBy == "" {
 | 
				
			||||||
			copyOflisting.Sort = "name"
 | 
								copyOflisting.Sort = "name"
 | 
				
			||||||
@ -308,12 +308,11 @@ func TestBrowseJson(t *testing.T) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("Unable to Marshal the listing ")
 | 
								t.Fatalf("Unable to Marshal the listing ")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		expectedJsonString := string(marsh)
 | 
							expectedJSON := string(marsh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if actualJsonResponseString != expectedJsonString {
 | 
							if actualJSONResponse != expectedJSON {
 | 
				
			||||||
			t.Errorf("JSON response doesn't match the expected for test number %d with sort=%s, order=%s\nExpected response %s\nActual response = %s\n",
 | 
								t.Errorf("JSON response doesn't match the expected for test number %d with sort=%s, order=%s\nExpected response %s\nActual response = %s\n",
 | 
				
			||||||
				i+1, test.SortBy, test.OrderBy, expectedJsonString, actualJsonResponseString)
 | 
									i+1, test.SortBy, test.OrderBy, expectedJSON, actualJSONResponse)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -37,9 +37,8 @@ func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, er
 | 
				
			|||||||
			w.WriteHeader(status)
 | 
								w.WriteHeader(status)
 | 
				
			||||||
			fmt.Fprintln(w, errMsg)
 | 
								fmt.Fprintln(w, errMsg)
 | 
				
			||||||
			return 0, err // returning < 400 signals that a response has been written
 | 
								return 0, err // returning < 400 signals that a response has been written
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			h.Log.Println(errMsg)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							h.Log.Println(errMsg)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if status >= 400 {
 | 
						if status >= 400 {
 | 
				
			||||||
 | 
				
			|||||||
@ -58,17 +58,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Connect to FastCGI gateway
 | 
								// Connect to FastCGI gateway
 | 
				
			||||||
			var fcgi *FCGIClient
 | 
								fcgi, err := getClient(&rule)
 | 
				
			||||||
 | 
					 | 
				
			||||||
			// check if unix socket or tcp
 | 
					 | 
				
			||||||
			if strings.HasPrefix(rule.Address, "/") || strings.HasPrefix(rule.Address, "unix:") {
 | 
					 | 
				
			||||||
				if strings.HasPrefix(rule.Address, "unix:") {
 | 
					 | 
				
			||||||
					rule.Address = rule.Address[len("unix:"):]
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				fcgi, err = Dial("unix", rule.Address)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				fcgi, err = Dial("tcp", rule.Address)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return http.StatusBadGateway, err
 | 
									return http.StatusBadGateway, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -102,13 +92,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
 | 
				
			|||||||
				return http.StatusBadGateway, err
 | 
									return http.StatusBadGateway, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Write the response header
 | 
								writeHeader(w, resp)
 | 
				
			||||||
			for key, vals := range resp.Header {
 | 
					 | 
				
			||||||
				for _, val := range vals {
 | 
					 | 
				
			||||||
					w.Header().Add(key, val)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			w.WriteHeader(resp.StatusCode)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Write the response body
 | 
								// Write the response body
 | 
				
			||||||
			// TODO: If this has an error, the response will already be
 | 
								// TODO: If this has an error, the response will already be
 | 
				
			||||||
@ -126,6 +110,26 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
 | 
				
			|||||||
	return h.Next.ServeHTTP(w, r)
 | 
						return h.Next.ServeHTTP(w, r)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getClient(r *Rule) (*FCGIClient, error) {
 | 
				
			||||||
 | 
						// check if unix socket or TCP
 | 
				
			||||||
 | 
						if trim := strings.HasPrefix(r.Address, "unix"); strings.HasPrefix(r.Address, "/") || trim {
 | 
				
			||||||
 | 
							if trim {
 | 
				
			||||||
 | 
								r.Address = r.Address[len("unix:"):]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return Dial("unix", r.Address)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Dial("tcp", r.Address)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func writeHeader(w http.ResponseWriter, r *http.Response) {
 | 
				
			||||||
 | 
						for key, vals := range r.Header {
 | 
				
			||||||
 | 
							for _, val := range vals {
 | 
				
			||||||
 | 
								w.Header().Add(key, val)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						w.WriteHeader(r.StatusCode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (h Handler) exists(path string) bool {
 | 
					func (h Handler) exists(path string) bool {
 | 
				
			||||||
	if _, err := os.Stat(h.Root + path); err == nil {
 | 
						if _, err := os.Stat(h.Root + path); err == nil {
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
 | 
				
			|||||||
@ -30,45 +30,45 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FCGI_LISTENSOCK_FILENO uint8 = 0
 | 
					const FCGIListenSockFileno uint8 = 0
 | 
				
			||||||
const FCGI_HEADER_LEN uint8 = 8
 | 
					const FCGIHeaderLen uint8 = 8
 | 
				
			||||||
const VERSION_1 uint8 = 1
 | 
					const Version1 uint8 = 1
 | 
				
			||||||
const FCGI_NULL_REQUEST_ID uint8 = 0
 | 
					const FCGINullRequestID uint8 = 0
 | 
				
			||||||
const FCGI_KEEP_CONN uint8 = 1
 | 
					const FCGIKeepConn uint8 = 1
 | 
				
			||||||
const doubleCRLF = "\r\n\r\n"
 | 
					const doubleCRLF = "\r\n\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	FCGI_BEGIN_REQUEST uint8 = iota + 1
 | 
						BeginRequest uint8 = iota + 1
 | 
				
			||||||
	FCGI_ABORT_REQUEST
 | 
						AbortRequest
 | 
				
			||||||
	FCGI_END_REQUEST
 | 
						EndRequest
 | 
				
			||||||
	FCGI_PARAMS
 | 
						Params
 | 
				
			||||||
	FCGI_STDIN
 | 
						Stdin
 | 
				
			||||||
	FCGI_STDOUT
 | 
						Stdout
 | 
				
			||||||
	FCGI_STDERR
 | 
						Stderr
 | 
				
			||||||
	FCGI_DATA
 | 
						Data
 | 
				
			||||||
	FCGI_GET_VALUES
 | 
						GetValues
 | 
				
			||||||
	FCGI_GET_VALUES_RESULT
 | 
						GetValuesResult
 | 
				
			||||||
	FCGI_UNKNOWN_TYPE
 | 
						UnknownType
 | 
				
			||||||
	FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
 | 
						MaxType = UnknownType
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	FCGI_RESPONDER uint8 = iota + 1
 | 
						Responder uint8 = iota + 1
 | 
				
			||||||
	FCGI_AUTHORIZER
 | 
						Authorizer
 | 
				
			||||||
	FCGI_FILTER
 | 
						Filter
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	FCGI_REQUEST_COMPLETE uint8 = iota
 | 
						RequestComplete uint8 = iota
 | 
				
			||||||
	FCGI_CANT_MPX_CONN
 | 
						CantMultiplexConns
 | 
				
			||||||
	FCGI_OVERLOADED
 | 
						Overloaded
 | 
				
			||||||
	FCGI_UNKNOWN_ROLE
 | 
						UnknownRole
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	FCGI_MAX_CONNS  string = "MAX_CONNS"
 | 
						MaxConns       string = "MAX_CONNS"
 | 
				
			||||||
	FCGI_MAX_REQS   string = "MAX_REQS"
 | 
						MaxRequests    string = "MAX_REQS"
 | 
				
			||||||
	FCGI_MPXS_CONNS string = "MPXS_CONNS"
 | 
						MultiplexConns string = "MPXS_CONNS"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@ -79,7 +79,7 @@ const (
 | 
				
			|||||||
type header struct {
 | 
					type header struct {
 | 
				
			||||||
	Version       uint8
 | 
						Version       uint8
 | 
				
			||||||
	Type          uint8
 | 
						Type          uint8
 | 
				
			||||||
	Id            uint16
 | 
						ID            uint16
 | 
				
			||||||
	ContentLength uint16
 | 
						ContentLength uint16
 | 
				
			||||||
	PaddingLength uint8
 | 
						PaddingLength uint8
 | 
				
			||||||
	Reserved      uint8
 | 
						Reserved      uint8
 | 
				
			||||||
@ -92,7 +92,7 @@ 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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -110,7 +110,7 @@ func (rec *record) read(r io.Reader) (buf []byte, err error) {
 | 
				
			|||||||
		err = errors.New("fcgi: invalid header version")
 | 
							err = errors.New("fcgi: invalid header version")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if rec.h.Type == FCGI_END_REQUEST {
 | 
						if rec.h.Type == EndRequest {
 | 
				
			||||||
		err = io.EOF
 | 
							err = io.EOF
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -126,13 +126,15 @@ func (rec *record) read(r io.Reader) (buf []byte, err error) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FCGIClient implements a FastCGI client, which is a standard for
 | 
				
			||||||
 | 
					// interfacing external applications with Web servers.
 | 
				
			||||||
type FCGIClient struct {
 | 
					type FCGIClient struct {
 | 
				
			||||||
	mutex     sync.Mutex
 | 
						mutex     sync.Mutex
 | 
				
			||||||
	rwc       io.ReadWriteCloser
 | 
						rwc       io.ReadWriteCloser
 | 
				
			||||||
	h         header
 | 
						h         header
 | 
				
			||||||
	buf       bytes.Buffer
 | 
						buf       bytes.Buffer
 | 
				
			||||||
	keepAlive bool
 | 
						keepAlive bool
 | 
				
			||||||
	reqId     uint16
 | 
						reqID     uint16
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Dial connects to the fcgi responder at the specified network address.
 | 
					// Dial connects to the fcgi responder at the specified network address.
 | 
				
			||||||
@ -148,7 +150,7 @@ func Dial(network, address string) (fcgi *FCGIClient, err error) {
 | 
				
			|||||||
	fcgi = &FCGIClient{
 | 
						fcgi = &FCGIClient{
 | 
				
			||||||
		rwc:       conn,
 | 
							rwc:       conn,
 | 
				
			||||||
		keepAlive: false,
 | 
							keepAlive: false,
 | 
				
			||||||
		reqId:     1,
 | 
							reqID:     1,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
@ -163,7 +165,7 @@ func (c *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
 | 
				
			|||||||
	c.mutex.Lock()
 | 
						c.mutex.Lock()
 | 
				
			||||||
	defer c.mutex.Unlock()
 | 
						defer c.mutex.Unlock()
 | 
				
			||||||
	c.buf.Reset()
 | 
						c.buf.Reset()
 | 
				
			||||||
	c.h.init(recType, c.reqId, len(content))
 | 
						c.h.init(recType, c.reqID, len(content))
 | 
				
			||||||
	if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {
 | 
						if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -179,14 +181,14 @@ func (c *FCGIClient) writeRecord(recType uint8, content []byte) (err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (c *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 c.writeRecord(FCGI_BEGIN_REQUEST, b[:])
 | 
						return c.writeRecord(BeginRequest, b[:])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *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 c.writeRecord(FCGI_END_REQUEST, b)
 | 
						return c.writeRecord(EndRequest, b)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
 | 
					func (c *FCGIClient) writePairs(recType uint8, pairs map[string]string) error {
 | 
				
			||||||
@ -334,17 +336,17 @@ 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 (c *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 = c.writeBeginRequest(uint16(FCGI_RESPONDER), 0)
 | 
						err = c.writeBeginRequest(uint16(Responder), 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = c.writePairs(FCGI_PARAMS, p)
 | 
						err = c.writePairs(Params, p)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	body := newWriter(c, FCGI_STDIN)
 | 
						body := newWriter(c, Stdin)
 | 
				
			||||||
	if req != nil {
 | 
						if req != nil {
 | 
				
			||||||
		io.Copy(body, req)
 | 
							io.Copy(body, req)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,13 +34,13 @@ import (
 | 
				
			|||||||
// test failed if the remote fcgi(script) failed md5 verification
 | 
					// test failed if the remote fcgi(script) failed md5 verification
 | 
				
			||||||
// and output "FAILED" in response
 | 
					// and output "FAILED" in response
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	script_file = "/tank/www/fcgic_test.php"
 | 
						scriptFile = "/tank/www/fcgic_test.php"
 | 
				
			||||||
	//ip_port = "remote-php-serv:59000"
 | 
						//ipPort = "remote-php-serv:59000"
 | 
				
			||||||
	ip_port = "127.0.0.1:59000"
 | 
						ipPort = "127.0.0.1:59000"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	t_ *testing.T = nil
 | 
						t_ *testing.T
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FastCGIServer struct{}
 | 
					type FastCGIServer struct{}
 | 
				
			||||||
@ -51,7 +51,7 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	stat := "PASSED"
 | 
						stat := "PASSED"
 | 
				
			||||||
	fmt.Fprintln(resp, "-")
 | 
						fmt.Fprintln(resp, "-")
 | 
				
			||||||
	file_num := 0
 | 
						fileNum := 0
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		length := 0
 | 
							length := 0
 | 
				
			||||||
		for k0, v0 := range req.Form {
 | 
							for k0, v0 := range req.Form {
 | 
				
			||||||
@ -69,7 +69,7 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if req.MultipartForm != nil {
 | 
							if req.MultipartForm != nil {
 | 
				
			||||||
			file_num = len(req.MultipartForm.File)
 | 
								fileNum = len(req.MultipartForm.File)
 | 
				
			||||||
			for kn, fns := range req.MultipartForm.File {
 | 
								for kn, fns := range req.MultipartForm.File {
 | 
				
			||||||
				//fmt.Fprintln(resp, "server:filekey ", kn )
 | 
									//fmt.Fprintln(resp, "server:filekey ", kn )
 | 
				
			||||||
				length += len(kn)
 | 
									length += len(kn)
 | 
				
			||||||
@ -101,11 +101,11 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		fmt.Fprintln(resp, "server:got data length", length)
 | 
							fmt.Fprintln(resp, "server:got data length", length)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fmt.Fprintln(resp, "-"+stat+"-POST(", len(req.Form), ")-FILE(", file_num, ")--")
 | 
						fmt.Fprintln(resp, "-"+stat+"-POST(", len(req.Form), ")-FILE(", fileNum, ")--")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func sendFcgi(reqType int, fcgi_params map[string]string, data []byte, posts map[string]string, files map[string]string) (content []byte) {
 | 
					func sendFcgi(reqType int, fcgiParams map[string]string, data []byte, posts map[string]string, files map[string]string) (content []byte) {
 | 
				
			||||||
	fcgi, err := Dial("tcp", ip_port)
 | 
						fcgi, err := Dial("tcp", ipPort)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Println("err:", err)
 | 
							log.Println("err:", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@ -119,16 +119,16 @@ func sendFcgi(reqType int, fcgi_params map[string]string, data []byte, posts map
 | 
				
			|||||||
		if len(data) > 0 {
 | 
							if len(data) > 0 {
 | 
				
			||||||
			length = len(data)
 | 
								length = len(data)
 | 
				
			||||||
			rd := bytes.NewReader(data)
 | 
								rd := bytes.NewReader(data)
 | 
				
			||||||
			resp, err = fcgi.Post(fcgi_params, "", rd, rd.Len())
 | 
								resp, err = fcgi.Post(fcgiParams, "", rd, rd.Len())
 | 
				
			||||||
		} else if len(posts) > 0 {
 | 
							} else if len(posts) > 0 {
 | 
				
			||||||
			values := url.Values{}
 | 
								values := url.Values{}
 | 
				
			||||||
			for k, v := range posts {
 | 
								for k, v := range posts {
 | 
				
			||||||
				values.Set(k, v)
 | 
									values.Set(k, v)
 | 
				
			||||||
				length += len(k) + 2 + len(v)
 | 
									length += len(k) + 2 + len(v)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			resp, err = fcgi.PostForm(fcgi_params, values)
 | 
								resp, err = fcgi.PostForm(fcgiParams, values)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			resp, err = fcgi.Get(fcgi_params)
 | 
								resp, err = fcgi.Get(fcgiParams)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@ -142,7 +142,7 @@ func sendFcgi(reqType int, fcgi_params map[string]string, data []byte, posts map
 | 
				
			|||||||
			fi, _ := os.Lstat(v)
 | 
								fi, _ := os.Lstat(v)
 | 
				
			||||||
			length += len(k) + int(fi.Size())
 | 
								length += len(k) + int(fi.Size())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		resp, err = fcgi.PostFile(fcgi_params, values, files)
 | 
							resp, err = fcgi.PostFile(fcgiParams, values, files)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -191,7 +191,7 @@ func generateRandFile(size int) (p string, m string) {
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Disabled_Test(t *testing.T) {
 | 
					func DisabledTest(t *testing.T) {
 | 
				
			||||||
	// TODO: test chunked reader
 | 
						// TODO: test chunked reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t_ = t
 | 
						t_ = t
 | 
				
			||||||
@ -199,7 +199,7 @@ func Disabled_Test(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// server
 | 
						// server
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		listener, err := net.Listen("tcp", ip_port)
 | 
							listener, err := net.Listen("tcp", ipPort)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			// handle error
 | 
								// handle error
 | 
				
			||||||
			log.Println("listener creatation failed: ", err)
 | 
								log.Println("listener creatation failed: ", err)
 | 
				
			||||||
@ -212,19 +212,19 @@ func Disabled_Test(t *testing.T) {
 | 
				
			|||||||
	time.Sleep(1 * time.Second)
 | 
						time.Sleep(1 * time.Second)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// init
 | 
						// init
 | 
				
			||||||
	fcgi_params := make(map[string]string)
 | 
						fcgiParams := make(map[string]string)
 | 
				
			||||||
	fcgi_params["REQUEST_METHOD"] = "GET"
 | 
						fcgiParams["REQUEST_METHOD"] = "GET"
 | 
				
			||||||
	fcgi_params["SERVER_PROTOCOL"] = "HTTP/1.1"
 | 
						fcgiParams["SERVER_PROTOCOL"] = "HTTP/1.1"
 | 
				
			||||||
	//fcgi_params["GATEWAY_INTERFACE"] = "CGI/1.1"
 | 
						//fcgi_params["GATEWAY_INTERFACE"] = "CGI/1.1"
 | 
				
			||||||
	fcgi_params["SCRIPT_FILENAME"] = script_file
 | 
						fcgiParams["SCRIPT_FILENAME"] = scriptFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// simple GET
 | 
						// simple GET
 | 
				
			||||||
	log.Println("test:", "get")
 | 
						log.Println("test:", "get")
 | 
				
			||||||
	sendFcgi(0, fcgi_params, nil, nil, nil)
 | 
						sendFcgi(0, fcgiParams, nil, nil, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// simple post data
 | 
						// simple post data
 | 
				
			||||||
	log.Println("test:", "post")
 | 
						log.Println("test:", "post")
 | 
				
			||||||
	sendFcgi(0, fcgi_params, []byte("c4ca4238a0b923820dcc509a6f75849b=1&7b8b965ad4bca0e41ab51de7b31363a1=n"), nil, nil)
 | 
						sendFcgi(0, fcgiParams, []byte("c4ca4238a0b923820dcc509a6f75849b=1&7b8b965ad4bca0e41ab51de7b31363a1=n"), nil, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post data (more than 60KB)")
 | 
						log.Println("test:", "post data (more than 60KB)")
 | 
				
			||||||
	data := ""
 | 
						data := ""
 | 
				
			||||||
@ -240,13 +240,13 @@ func Disabled_Test(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		data += k0 + "=" + url.QueryEscape(v0) + "&"
 | 
							data += k0 + "=" + url.QueryEscape(v0) + "&"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sendFcgi(0, fcgi_params, []byte(data), nil, nil)
 | 
						sendFcgi(0, fcgiParams, []byte(data), nil, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post form (use url.Values)")
 | 
						log.Println("test:", "post form (use url.Values)")
 | 
				
			||||||
	p0 := make(map[string]string, 1)
 | 
						p0 := make(map[string]string, 1)
 | 
				
			||||||
	p0["c4ca4238a0b923820dcc509a6f75849b"] = "1"
 | 
						p0["c4ca4238a0b923820dcc509a6f75849b"] = "1"
 | 
				
			||||||
	p0["7b8b965ad4bca0e41ab51de7b31363a1"] = "n"
 | 
						p0["7b8b965ad4bca0e41ab51de7b31363a1"] = "n"
 | 
				
			||||||
	sendFcgi(1, fcgi_params, nil, p0, nil)
 | 
						sendFcgi(1, fcgiParams, nil, p0, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post forms (256 keys, more than 1MB)")
 | 
						log.Println("test:", "post forms (256 keys, more than 1MB)")
 | 
				
			||||||
	p1 := make(map[string]string, 1)
 | 
						p1 := make(map[string]string, 1)
 | 
				
			||||||
@ -257,25 +257,25 @@ func Disabled_Test(t *testing.T) {
 | 
				
			|||||||
		k0 := fmt.Sprintf("%x", h.Sum(nil))
 | 
							k0 := fmt.Sprintf("%x", h.Sum(nil))
 | 
				
			||||||
		p1[k0] = v0
 | 
							p1[k0] = v0
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sendFcgi(1, fcgi_params, nil, p1, nil)
 | 
						sendFcgi(1, fcgiParams, nil, p1, nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post file (1 file, 500KB)) ")
 | 
						log.Println("test:", "post file (1 file, 500KB)) ")
 | 
				
			||||||
	f0 := make(map[string]string, 1)
 | 
						f0 := make(map[string]string, 1)
 | 
				
			||||||
	path0, m0 := generateRandFile(500000)
 | 
						path0, m0 := generateRandFile(500000)
 | 
				
			||||||
	f0[m0] = path0
 | 
						f0[m0] = path0
 | 
				
			||||||
	sendFcgi(1, fcgi_params, nil, p1, f0)
 | 
						sendFcgi(1, fcgiParams, nil, p1, f0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post multiple files (2 files, 5M each) and forms (256 keys, more than 1MB data")
 | 
						log.Println("test:", "post multiple files (2 files, 5M each) and forms (256 keys, more than 1MB data")
 | 
				
			||||||
	path1, m1 := generateRandFile(5000000)
 | 
						path1, m1 := generateRandFile(5000000)
 | 
				
			||||||
	f0[m1] = path1
 | 
						f0[m1] = path1
 | 
				
			||||||
	sendFcgi(1, fcgi_params, nil, p1, f0)
 | 
						sendFcgi(1, fcgiParams, nil, p1, f0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post only files (2 files, 5M each)")
 | 
						log.Println("test:", "post only files (2 files, 5M each)")
 | 
				
			||||||
	sendFcgi(1, fcgi_params, nil, nil, f0)
 | 
						sendFcgi(1, fcgiParams, nil, nil, f0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Println("test:", "post only 1 file")
 | 
						log.Println("test:", "post only 1 file")
 | 
				
			||||||
	delete(f0, "m0")
 | 
						delete(f0, "m0")
 | 
				
			||||||
	sendFcgi(1, fcgi_params, nil, nil, f0)
 | 
						sendFcgi(1, fcgiParams, nil, nil, f0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	os.Remove(path0)
 | 
						os.Remove(path0)
 | 
				
			||||||
	os.Remove(path1)
 | 
						os.Remove(path1)
 | 
				
			||||||
 | 
				
			|||||||
@ -81,7 +81,7 @@ func (s Set) Contains(value string) bool {
 | 
				
			|||||||
// elements in the set and passes each to f. It returns true
 | 
					// elements in the set and passes each to f. It returns true
 | 
				
			||||||
// on the first call to f that returns true and false otherwise.
 | 
					// on the first call to f that returns true and false otherwise.
 | 
				
			||||||
func (s Set) ContainsFunc(f func(string) bool) bool {
 | 
					func (s Set) ContainsFunc(f func(string) bool) bool {
 | 
				
			||||||
	for k, _ := range s {
 | 
						for k := range s {
 | 
				
			||||||
		if f(k) {
 | 
							if f(k) {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ func TestGzipHandler(t *testing.T) {
 | 
				
			|||||||
		extFilter.Exts.Add(e)
 | 
							extFilter.Exts.Add(e)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	gz := Gzip{Configs: []Config{
 | 
						gz := Gzip{Configs: []Config{
 | 
				
			||||||
		Config{Filters: []Filter{pathFilter, extFilter}},
 | 
							{Filters: []Filter{pathFilter, extFilter}},
 | 
				
			||||||
	}}
 | 
						}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	w := httptest.NewRecorder()
 | 
						w := httptest.NewRecorder()
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ func TestMarkdown(t *testing.T) {
 | 
				
			|||||||
		Root:    "./testdata",
 | 
							Root:    "./testdata",
 | 
				
			||||||
		FileSys: http.Dir("./testdata"),
 | 
							FileSys: http.Dir("./testdata"),
 | 
				
			||||||
		Configs: []*Config{
 | 
							Configs: []*Config{
 | 
				
			||||||
			&Config{
 | 
								{
 | 
				
			||||||
				Renderer:    blackfriday.HtmlRenderer(0, "", ""),
 | 
									Renderer:    blackfriday.HtmlRenderer(0, "", ""),
 | 
				
			||||||
				PathScope:   "/blog",
 | 
									PathScope:   "/blog",
 | 
				
			||||||
				Extensions:  []string{".md"},
 | 
									Extensions:  []string{".md"},
 | 
				
			||||||
@ -32,7 +32,7 @@ func TestMarkdown(t *testing.T) {
 | 
				
			|||||||
				StaticDir:   DefaultStaticDir,
 | 
									StaticDir:   DefaultStaticDir,
 | 
				
			||||||
				StaticFiles: make(map[string]string),
 | 
									StaticFiles: make(map[string]string),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			&Config{
 | 
								{
 | 
				
			||||||
				Renderer:    blackfriday.HtmlRenderer(0, "", ""),
 | 
									Renderer:    blackfriday.HtmlRenderer(0, "", ""),
 | 
				
			||||||
				PathScope:   "/log",
 | 
									PathScope:   "/log",
 | 
				
			||||||
				Extensions:  []string{".md"},
 | 
									Extensions:  []string{".md"},
 | 
				
			||||||
@ -42,7 +42,7 @@ func TestMarkdown(t *testing.T) {
 | 
				
			|||||||
				StaticDir:   DefaultStaticDir,
 | 
									StaticDir:   DefaultStaticDir,
 | 
				
			||||||
				StaticFiles: make(map[string]string),
 | 
									StaticFiles: make(map[string]string),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			&Config{
 | 
								{
 | 
				
			||||||
				Renderer:    blackfriday.HtmlRenderer(0, "", ""),
 | 
									Renderer:    blackfriday.HtmlRenderer(0, "", ""),
 | 
				
			||||||
				PathScope:   "/og",
 | 
									PathScope:   "/og",
 | 
				
			||||||
				Extensions:  []string{".md"},
 | 
									Extensions:  []string{".md"},
 | 
				
			||||||
@ -52,7 +52,7 @@ func TestMarkdown(t *testing.T) {
 | 
				
			|||||||
				StaticDir:   "testdata/og_static",
 | 
									StaticDir:   "testdata/og_static",
 | 
				
			||||||
				StaticFiles: map[string]string{"/og/first.md": "testdata/og_static/og/first.md/index.html"},
 | 
									StaticFiles: map[string]string{"/og/first.md": "testdata/og_static/og/first.md/index.html"},
 | 
				
			||||||
				Links: []PageLink{
 | 
									Links: []PageLink{
 | 
				
			||||||
					PageLink{
 | 
										{
 | 
				
			||||||
						Title:   "first",
 | 
											Title:   "first",
 | 
				
			||||||
						Summary: "",
 | 
											Summary: "",
 | 
				
			||||||
						Date:    time.Now(),
 | 
											Date:    time.Now(),
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ const (
 | 
				
			|||||||
	DefaultStaticDir = "generated_site"
 | 
						DefaultStaticDir = "generated_site"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MarkdownData struct {
 | 
					type Data struct {
 | 
				
			||||||
	middleware.Context
 | 
						middleware.Context
 | 
				
			||||||
	Doc   map[string]string
 | 
						Doc   map[string]string
 | 
				
			||||||
	Links []PageLink
 | 
						Links []PageLink
 | 
				
			||||||
@ -95,7 +95,7 @@ func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, m
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mdData := MarkdownData{
 | 
						mdData := Data{
 | 
				
			||||||
		Context: ctx,
 | 
							Context: ctx,
 | 
				
			||||||
		Doc:     metadata.Variables,
 | 
							Doc:     metadata.Variables,
 | 
				
			||||||
		Links:   c.Links,
 | 
							Links:   c.Links,
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,8 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultInterval is the default interval at which the markdown watcher
 | 
				
			||||||
 | 
					// checks for changes.
 | 
				
			||||||
const DefaultInterval = time.Second * 60
 | 
					const DefaultInterval = time.Second * 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Watch monitors the configured markdown directory for changes. It calls GenerateLinks
 | 
					// Watch monitors the configured markdown directory for changes. It calls GenerateLinks
 | 
				
			||||||
 | 
				
			|||||||
@ -12,13 +12,13 @@ func (r *customPolicy) Select(pool HostPool) *UpstreamHost {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func testPool() HostPool {
 | 
					func testPool() HostPool {
 | 
				
			||||||
	pool := []*UpstreamHost{
 | 
						pool := []*UpstreamHost{
 | 
				
			||||||
		&UpstreamHost{
 | 
							{
 | 
				
			||||||
			Name: "http://google.com", // this should resolve (healthcheck test)
 | 
								Name: "http://google.com", // this should resolve (healthcheck test)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		&UpstreamHost{
 | 
							{
 | 
				
			||||||
			Name: "http://shouldnot.resolve", // this shouldn't
 | 
								Name: "http://shouldnot.resolve", // this shouldn't
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		&UpstreamHost{
 | 
							{
 | 
				
			||||||
			Name: "http://C",
 | 
								Name: "http://C",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,8 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	supportedPolicies map[string]func() Policy = make(map[string]func() Policy)
 | 
						supportedPolicies = make(map[string]func() Policy)
 | 
				
			||||||
	proxyHeaders      http.Header              = make(http.Header)
 | 
						proxyHeaders      = make(http.Header)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type staticUpstream struct {
 | 
					type staticUpstream struct {
 | 
				
			||||||
@ -53,65 +53,9 @@ func NewStaticUpstreams(c parse.Dispenser) ([]Upstream, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for c.NextBlock() {
 | 
							for c.NextBlock() {
 | 
				
			||||||
			switch c.Val() {
 | 
								if err := parseBlock(&c, upstream); err != nil {
 | 
				
			||||||
			case "policy":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if policyCreateFunc, ok := supportedPolicies[c.Val()]; ok {
 | 
					 | 
				
			||||||
					upstream.Policy = policyCreateFunc()
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case "fail_timeout":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if dur, err := time.ParseDuration(c.Val()); err == nil {
 | 
					 | 
				
			||||||
					upstream.FailTimeout = dur
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
				return upstreams, err
 | 
									return upstreams, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			case "max_fails":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if n, err := strconv.Atoi(c.Val()); err == nil {
 | 
					 | 
				
			||||||
					upstream.MaxFails = int32(n)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					return upstreams, err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case "health_check":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				upstream.HealthCheck.Path = c.Val()
 | 
					 | 
				
			||||||
				upstream.HealthCheck.Interval = 30 * time.Second
 | 
					 | 
				
			||||||
				if c.NextArg() {
 | 
					 | 
				
			||||||
					if dur, err := time.ParseDuration(c.Val()); err == nil {
 | 
					 | 
				
			||||||
						upstream.HealthCheck.Interval = dur
 | 
					 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						return upstreams, err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case "proxy_header":
 | 
					 | 
				
			||||||
				var header, value string
 | 
					 | 
				
			||||||
				if !c.Args(&header, &value) {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				proxyHeaders.Add(header, value)
 | 
					 | 
				
			||||||
			case "websocket":
 | 
					 | 
				
			||||||
				proxyHeaders.Add("Connection", "{>Connection}")
 | 
					 | 
				
			||||||
				proxyHeaders.Add("Upgrade", "{>Upgrade}")
 | 
					 | 
				
			||||||
			case "without":
 | 
					 | 
				
			||||||
				if !c.NextArg() {
 | 
					 | 
				
			||||||
					return upstreams, c.ArgErr()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				upstream.WithoutPathPrefix = c.Val()
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				return upstreams, c.Errf("unknown property '%s'", c.Val())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		upstream.Hosts = make([]*UpstreamHost, len(to))
 | 
							upstream.Hosts = make([]*UpstreamHost, len(to))
 | 
				
			||||||
@ -165,6 +109,68 @@ func (u *staticUpstream) From() string {
 | 
				
			|||||||
	return u.from
 | 
						return u.from
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func parseBlock(c *parse.Dispenser, u *staticUpstream) error {
 | 
				
			||||||
 | 
						switch c.Val() {
 | 
				
			||||||
 | 
						case "policy":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							policyCreateFunc, ok := supportedPolicies[c.Val()]
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							u.Policy = policyCreateFunc()
 | 
				
			||||||
 | 
						case "fail_timeout":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dur, err := time.ParseDuration(c.Val())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							u.FailTimeout = dur
 | 
				
			||||||
 | 
						case "max_fails":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							n, err := strconv.Atoi(c.Val())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							u.MaxFails = int32(n)
 | 
				
			||||||
 | 
						case "health_check":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							u.HealthCheck.Path = c.Val()
 | 
				
			||||||
 | 
							u.HealthCheck.Interval = 30 * time.Second
 | 
				
			||||||
 | 
							if c.NextArg() {
 | 
				
			||||||
 | 
								dur, err := time.ParseDuration(c.Val())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								u.HealthCheck.Interval = dur
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case "proxy_header":
 | 
				
			||||||
 | 
							var header, value string
 | 
				
			||||||
 | 
							if !c.Args(&header, &value) {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							proxyHeaders.Add(header, value)
 | 
				
			||||||
 | 
						case "websocket":
 | 
				
			||||||
 | 
							proxyHeaders.Add("Connection", "{>Connection}")
 | 
				
			||||||
 | 
							proxyHeaders.Add("Upgrade", "{>Upgrade}")
 | 
				
			||||||
 | 
						case "without":
 | 
				
			||||||
 | 
							if !c.NextArg() {
 | 
				
			||||||
 | 
								return c.ArgErr()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							u.WithoutPathPrefix = c.Val()
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return c.Errf("unknown property '%s'", c.Val())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 | 
				
			|||||||
@ -10,9 +10,9 @@ import (
 | 
				
			|||||||
func TestNewReplacer(t *testing.T) {
 | 
					func TestNewReplacer(t *testing.T) {
 | 
				
			||||||
	w := httptest.NewRecorder()
 | 
						w := httptest.NewRecorder()
 | 
				
			||||||
	recordRequest := NewResponseRecorder(w)
 | 
						recordRequest := NewResponseRecorder(w)
 | 
				
			||||||
	userJson := `{"username": "dennis"}`
 | 
						userJSON := `{"username": "dennis"}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reader := strings.NewReader(userJson) //Convert string to reader
 | 
						reader := strings.NewReader(userJSON) //Convert string to reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request, err := http.NewRequest("POST", "http://caddyserver.com", reader) //Create request with JSON body
 | 
						request, err := http.NewRequest("POST", "http://caddyserver.com", reader) //Create request with JSON body
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -41,9 +41,9 @@ func TestNewReplacer(t *testing.T) {
 | 
				
			|||||||
func TestReplace(t *testing.T) {
 | 
					func TestReplace(t *testing.T) {
 | 
				
			||||||
	w := httptest.NewRecorder()
 | 
						w := httptest.NewRecorder()
 | 
				
			||||||
	recordRequest := NewResponseRecorder(w)
 | 
						recordRequest := NewResponseRecorder(w)
 | 
				
			||||||
	userJson := `{"username": "dennis"}`
 | 
						userJSON := `{"username": "dennis"}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reader := strings.NewReader(userJson) //Convert string to reader
 | 
						reader := strings.NewReader(userJSON) //Convert string to reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request, err := http.NewRequest("POST", "http://caddyserver.com", reader) //Create request with JSON body
 | 
						request, err := http.NewRequest("POST", "http://caddyserver.com", reader) //Create request with JSON body
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -115,7 +115,7 @@ func (r *RegexpRule) Rewrite(req *http.Request) bool {
 | 
				
			|||||||
	// include trailing slash in regexp if present
 | 
						// include trailing slash in regexp if present
 | 
				
			||||||
	start := len(r.Base)
 | 
						start := len(r.Base)
 | 
				
			||||||
	if strings.HasSuffix(r.Base, "/") {
 | 
						if strings.HasSuffix(r.Base, "/") {
 | 
				
			||||||
		start -= 1
 | 
							start--
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// validate regexp
 | 
						// validate regexp
 | 
				
			||||||
 | 
				
			|||||||
@ -21,15 +21,15 @@ func TestRewrite(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regexpRules := [][]string{
 | 
						regexpRules := [][]string{
 | 
				
			||||||
		[]string{"/reg/", ".*", "/to", ""},
 | 
							{"/reg/", ".*", "/to", ""},
 | 
				
			||||||
		[]string{"/r/", "[a-z]+", "/toaz", "!.html|"},
 | 
							{"/r/", "[a-z]+", "/toaz", "!.html|"},
 | 
				
			||||||
		[]string{"/url/", "a([a-z0-9]*)s([A-Z]{2})", "/to/{path}", ""},
 | 
							{"/url/", "a([a-z0-9]*)s([A-Z]{2})", "/to/{path}", ""},
 | 
				
			||||||
		[]string{"/ab/", "ab", "/ab?{query}", ".txt|"},
 | 
							{"/ab/", "ab", "/ab?{query}", ".txt|"},
 | 
				
			||||||
		[]string{"/ab/", "ab", "/ab?type=html&{query}", ".html|"},
 | 
							{"/ab/", "ab", "/ab?type=html&{query}", ".html|"},
 | 
				
			||||||
		[]string{"/abc/", "ab", "/abc/{file}", ".html|"},
 | 
							{"/abc/", "ab", "/abc/{file}", ".html|"},
 | 
				
			||||||
		[]string{"/abcd/", "ab", "/a/{dir}/{file}", ".html|"},
 | 
							{"/abcd/", "ab", "/a/{dir}/{file}", ".html|"},
 | 
				
			||||||
		[]string{"/abcde/", "ab", "/a#{fragment}", ".html|"},
 | 
							{"/abcde/", "ab", "/a#{fragment}", ".html|"},
 | 
				
			||||||
		[]string{"/ab/", `.*\.jpg`, "/ajpg", ""},
 | 
							{"/ab/", `.*\.jpg`, "/ajpg", ""},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, regexpRule := range regexpRules {
 | 
						for _, regexpRule := range regexpRules {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import (
 | 
				
			|||||||
	"gopkg.in/natefinch/lumberjack.v2"
 | 
						"gopkg.in/natefinch/lumberjack.v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LogRoller implements a middleware that provides a rolling logger.
 | 
				
			||||||
type LogRoller struct {
 | 
					type LogRoller struct {
 | 
				
			||||||
	Filename   string
 | 
						Filename   string
 | 
				
			||||||
	MaxSize    int
 | 
						MaxSize    int
 | 
				
			||||||
@ -14,6 +15,7 @@ type LogRoller struct {
 | 
				
			|||||||
	LocalTime  bool
 | 
						LocalTime  bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetLogWriter returns an io.Writer that writes to a rolling logger.
 | 
				
			||||||
func (l LogRoller) GetLogWriter() io.Writer {
 | 
					func (l LogRoller) GetLogWriter() io.Writer {
 | 
				
			||||||
	return &lumberjack.Logger{
 | 
						return &lumberjack.Logger{
 | 
				
			||||||
		Filename:   l.Filename,
 | 
							Filename:   l.Filename,
 | 
				
			||||||
 | 
				
			|||||||
@ -14,12 +14,12 @@ func Test(t *testing.T) {
 | 
				
			|||||||
			return 0, nil
 | 
								return 0, nil
 | 
				
			||||||
		}),
 | 
							}),
 | 
				
			||||||
		Rules: []Rule{
 | 
							Rules: []Rule{
 | 
				
			||||||
			Rule{
 | 
								{
 | 
				
			||||||
				Extensions: []string{".html"},
 | 
									Extensions: []string{".html"},
 | 
				
			||||||
				IndexFiles: []string{"index.html"},
 | 
									IndexFiles: []string{"index.html"},
 | 
				
			||||||
				Path:       "/photos",
 | 
									Path:       "/photos",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Rule{
 | 
								{
 | 
				
			||||||
				Extensions: []string{".html", ".htm"},
 | 
									Extensions: []string{".html", ".htm"},
 | 
				
			||||||
				IndexFiles: []string{"index.html", "index.htm"},
 | 
									IndexFiles: []string{"index.html", "index.htm"},
 | 
				
			||||||
				Path:       "/images",
 | 
									Path:       "/images",
 | 
				
			||||||
@ -34,7 +34,7 @@ func Test(t *testing.T) {
 | 
				
			|||||||
			return 0, nil
 | 
								return 0, nil
 | 
				
			||||||
		}),
 | 
							}),
 | 
				
			||||||
		Rules: []Rule{
 | 
							Rules: []Rule{
 | 
				
			||||||
			Rule{
 | 
								{
 | 
				
			||||||
				Extensions: []string{".html"},
 | 
									Extensions: []string{".html"},
 | 
				
			||||||
				IndexFiles: []string{"index.html"},
 | 
									IndexFiles: []string{"index.html"},
 | 
				
			||||||
				Path:       "/",
 | 
									Path:       "/",
 | 
				
			||||||
 | 
				
			|||||||
@ -264,6 +264,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultErrorFunc responds to an HTTP request with a simple description
 | 
				
			||||||
 | 
					// of the specified HTTP status code.
 | 
				
			||||||
func DefaultErrorFunc(w http.ResponseWriter, r *http.Request, status int) {
 | 
					func DefaultErrorFunc(w http.ResponseWriter, r *http.Request, status int) {
 | 
				
			||||||
	w.WriteHeader(status)
 | 
						w.WriteHeader(status)
 | 
				
			||||||
	fmt.Fprintf(w, "%d %s", status, http.StatusText(status))
 | 
						fmt.Fprintf(w, "%d %s", status, http.StatusText(status))
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user