Commit 35225fe2 authored by Matthew Holt's avatar Matthew Holt

Docs and comments, la la

parent 01266ece
...@@ -47,6 +47,7 @@ func (c *controller) Port() string { ...@@ -47,6 +47,7 @@ func (c *controller) Port() string {
return c.parser.cfg.Port return c.parser.cfg.Port
} }
// Context returns the path scope that the Controller is in.
func (c *controller) Context() middleware.Path { func (c *controller) Context() middleware.Path {
return middleware.Path(c.pathScope) return middleware.Path(c.pathScope)
} }
...@@ -5,10 +5,11 @@ import ( ...@@ -5,10 +5,11 @@ import (
"fmt" "fmt"
) )
// dispenser is a type that gets exposed to middleware // dispenser is a type that dispenses tokens, similarly to
// generators so that they can parse tokens to configure // a lexer, except that it can do so with some notion of
// their instance. It basically dispenses tokens but can // structure. Its methods implement part of the
// do so in a structured manner. // middleware.Controller interface, so refer to that
// documentation for more info.
type dispenser struct { type dispenser struct {
filename string filename string
cursor int cursor int
...@@ -18,15 +19,13 @@ type dispenser struct { ...@@ -18,15 +19,13 @@ type dispenser struct {
// Next loads the next token. Returns true if a token // Next loads the next token. Returns true if a token
// was loaded; false otherwise. If false, all tokens // was loaded; false otherwise. If false, all tokens
// have been consumed. // have already been consumed.
// TODO: Have the other Next functions call this one...?
func (d *dispenser) Next() bool { func (d *dispenser) Next() bool {
if d.cursor >= len(d.tokens)-1 { if d.cursor < len(d.tokens)-1 {
return false
} else {
d.cursor++ d.cursor++
return true return true
} }
return false
} }
// NextArg loads the next token if it is on the same // NextArg loads the next token if it is on the same
...@@ -49,8 +48,10 @@ func (d *dispenser) NextArg() bool { ...@@ -49,8 +48,10 @@ func (d *dispenser) NextArg() bool {
return false return false
} }
// TODO: Assert that there's a line break and only advance // NextLine loads the next token only if it is not on the same
// the token if that's the case? (store an error otherwise) // line as the current token, and returns true if a token was
// loaded; false otherwise. If false, there is not another token
// or it is on the same line.
func (d *dispenser) NextLine() bool { func (d *dispenser) NextLine() bool {
if d.cursor < 0 { if d.cursor < 0 {
d.cursor++ d.cursor++
...@@ -96,7 +97,8 @@ func (d *dispenser) NextBlock() bool { ...@@ -96,7 +97,8 @@ func (d *dispenser) NextBlock() bool {
return true return true
} }
// Val gets the text of the current token. // Val gets the text of the current token. If there is no token
// loaded, it returns empty string.
func (d *dispenser) Val() string { func (d *dispenser) Val() string {
if d.cursor < 0 || d.cursor >= len(d.tokens) { if d.cursor < 0 || d.cursor >= len(d.tokens) {
return "" return ""
...@@ -105,23 +107,6 @@ func (d *dispenser) Val() string { ...@@ -105,23 +107,6 @@ func (d *dispenser) Val() string {
} }
} }
// ArgErr returns an argument error, meaning that another
// argument was expected but not found. In other words,
// a line break or open curly brace was encountered instead of
// an argument.
func (d *dispenser) ArgErr() error {
if d.Val() == "{" {
return d.Err("Unexpected token '{', expecting argument")
}
return d.Err("Unexpected line break after '" + d.Val() + "' (missing arguments?)")
}
// Err generates a custom parse error with a message of msg.
func (d *dispenser) Err(msg string) error {
msg = fmt.Sprintf("%s:%d - Parse error: %s", d.filename, d.tokens[d.cursor].line, msg)
return errors.New(msg)
}
// Args is a convenience function that loads the next arguments // Args is a convenience function that loads the next arguments
// (tokens on the same line) into an arbitrary number of strings // (tokens on the same line) into an arbitrary number of strings
// pointed to in targets. If there are fewer tokens available // pointed to in targets. If there are fewer tokens available
...@@ -157,3 +142,20 @@ func (d *dispenser) RemainingArgs() []string { ...@@ -157,3 +142,20 @@ func (d *dispenser) RemainingArgs() []string {
return args return args
} }
// ArgErr returns an argument error, meaning that another
// argument was expected but not found. In other words,
// a line break or open curly brace was encountered instead of
// an argument.
func (d *dispenser) ArgErr() error {
if d.Val() == "{" {
return d.Err("Unexpected token '{', expecting argument")
}
return d.Err("Unexpected line break after '" + d.Val() + "' (missing arguments?)")
}
// Err generates a custom parse error with a message of msg.
func (d *dispenser) Err(msg string) error {
msg = fmt.Sprintf("%s:%d - Parse error: %s", d.filename, d.tokens[d.cursor].line, msg)
return errors.New(msg)
}
...@@ -119,13 +119,18 @@ func (p *parser) parseOne() error { ...@@ -119,13 +119,18 @@ func (p *parser) parseOne() error {
// executes the top-level functions (the generator function) // executes the top-level functions (the generator function)
// to expose the second layers which are the actual middleware. // to expose the second layers which are the actual middleware.
// This function should be called only after p has filled out // This function should be called only after p has filled out
// p.other and that the entire server block has been consumed. // p.other and the entire server block has already been consumed.
func (p *parser) unwrap() error { func (p *parser) unwrap() error {
if len(p.other) == 0 {
// no middlewares were invoked
return nil
}
for _, directive := range registry.ordered { for _, directive := range registry.ordered {
// TODO: For now, we only support the first and default path scope ("/") // TODO: For now, we only support the first and default path scope ("/", held in p.other[0])
// but when we implement support for path scopes, we will have to // but when we implement support for path scopes, we will have to change this logic
// change this logic to loop over them and order them. We need to account // to loop over them and order them. We need to account for situations where multiple
// for situations where multiple path scopes overlap, regex (??), etc... // path scopes overlap, regex (??), etc...
if disp, ok := p.other[0].directives[directive]; ok { if disp, ok := p.other[0].directives[directive]; ok {
if generator, ok := registry.directiveMap[directive]; ok { if generator, ok := registry.directiveMap[directive]; ok {
mid, err := generator(disp) mid, err := generator(disp)
...@@ -141,6 +146,7 @@ func (p *parser) unwrap() error { ...@@ -141,6 +146,7 @@ func (p *parser) unwrap() error {
} }
} }
} }
return nil return nil
} }
......
...@@ -11,6 +11,11 @@ import ( ...@@ -11,6 +11,11 @@ import (
"github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware"
) )
// Gzip is a http.Handler middleware type which gzips HTTP responses.
type Gzip struct {
Next http.HandlerFunc
}
// New creates a new gzip middleware instance. // New creates a new gzip middleware instance.
func New(c middleware.Controller) (middleware.Middleware, error) { func New(c middleware.Controller) (middleware.Middleware, error) {
return func(next http.HandlerFunc) http.HandlerFunc { return func(next http.HandlerFunc) http.HandlerFunc {
...@@ -19,12 +24,6 @@ func New(c middleware.Controller) (middleware.Middleware, error) { ...@@ -19,12 +24,6 @@ func New(c middleware.Controller) (middleware.Middleware, error) {
}, nil }, nil
} }
// Gzip is a http.Handler middleware type which gzips HTTP responses.
type Gzip struct {
Next http.HandlerFunc
// TODO: Compression level, other settings
}
// ServeHTTP serves a gzipped response if the client supports it. // ServeHTTP serves a gzipped response if the client supports it.
func (g Gzip) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (g Gzip) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
......
...@@ -13,23 +13,76 @@ type ( ...@@ -13,23 +13,76 @@ type (
// and returns the inner layer, which is the actual HandlerFunc. // and returns the inner layer, which is the actual HandlerFunc.
Middleware func(http.HandlerFunc) http.HandlerFunc Middleware func(http.HandlerFunc) http.HandlerFunc
// Controller is the type which middleware generators use to access // A Control provides structured access to tokens from a configuration file
// tokens and the server and any other information they need to // and also to properties of the server being configured. Middleware generators
// configure themselves. // use a Controller to construct their middleware instance.
Controller interface { Controller interface {
// Next loads the next token. Returns true if a token
// was loaded; false otherwise. If false, all tokens
// have already been consumed.
Next() bool Next() bool
// NextArg loads the next token if it is on the same
// line. Returns true if a token was loaded; false
// otherwise. If false, all tokens on the line have
// been consumed.
NextArg() bool NextArg() bool
// NextLine loads the next token only if it is NOT on the same
// line as the current token, and returns true if a token was
// loaded; false otherwise. If false, there is not another token
// or it is on the same line.
NextLine() bool NextLine() bool
// NextBlock advances the cursor to the next token only
// if the current token is an open curly brace on the
// same line. If so, that token is consumed and this
// function will return true until the closing curly
// brace gets consumed by this method. Usually, you would
// use this as the condition of a for loop to parse
// tokens while being inside a block.
NextBlock() bool NextBlock() bool
// Val gets the text of the current token.
Val() string Val() string
// Args is a convenience function that loads the next arguments
// (tokens on the same line) into an arbitrary number of strings
// pointed to in arguments. If there are fewer tokens available
// than string pointers, the remaining strings will not be changed
// and false will be returned. If there were enough tokens available
// to fill the arguments, then true will be returned.
Args(...*string) bool Args(...*string) bool
// RemainingArgs is a convenience function that loads any more arguments
// (tokens on the same line) into a slice and returns them. If an open curly
// brace token is encountered before the end of the line, that token is
// considered the end of the arguments (and the curly brace is not consumed).
RemainingArgs() []string RemainingArgs() []string
// ArgErr returns an argument error, meaning that another
// argument was expected but not found. In other words,
// a line break, EOF, or open curly brace was encountered instead of
// an argument.
ArgErr() error ArgErr() error
// Err generates a custom parse error with a message of msg.
Err(string) error Err(string) error
// Startup registers a function to execute when the server starts.
Startup(func() error) Startup(func() error)
// Root returns the file path from which the server is serving.
Root() string Root() string
// Host returns the hostname the server is bound to.
Host() string Host() string
// Port returns the port that the server is listening on.
Port() string Port() string
// Context returns the path scope that the Controller is in.
// Note: This is not currently used, but may be in the future.
Context() Path Context() Path
} }
) )
...@@ -71,7 +71,6 @@ func (s *Server) Serve() error { ...@@ -71,7 +71,6 @@ func (s *Server) Serve() error {
server := &http.Server{ server := &http.Server{
Addr: s.config.Address(), Addr: s.config.Address(),
Handler: s, Handler: s,
// TODO: Make more of the server configurable, also more http2 configurability
} }
http2.ConfigureServer(server, nil) // TODO: This may not be necessary after HTTP/2 merged into std lib http2.ConfigureServer(server, nil) // TODO: This may not be necessary after HTTP/2 merged into std lib
......
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