Commit 5ae1790e authored by Matthew Holt's avatar Matthew Holt

Moved controller into its own file; other minor cleanups

parent 16997d85
package config
// controller is a dispenser of tokens and also
// facilitates setup with the server by providing
// access to its configuration. It implements
// the middleware.Controller interface.
type controller struct {
dispenser
}
// newController returns a new controller.
func newController(p *parser) *controller {
return &controller{
dispenser: dispenser{
cursor: -1,
parser: p,
},
}
}
// Startup registers a function to execute when the server starts.
func (c *controller) Startup(fn func() error) {
c.parser.cfg.Startup = append(c.parser.cfg.Startup, fn)
}
// Root returns the server root file path.
func (c *controller) Root() string {
if c.parser.cfg.Root == "" {
return "."
} else {
return c.parser.cfg.Root
}
}
// Host returns the hostname the server is bound to.
func (c *controller) Host() string {
return c.parser.cfg.Host
}
// Port returns the port that the server is listening on.
func (c *controller) Port() string {
return c.parser.cfg.Port
}
......@@ -11,8 +11,8 @@ import (
// a particular directive and populates the config.
type dirFunc func(*parser) error
// validDirectives is a map of valid directive names to
// their parsing function.
// validDirectives is a map of valid, built-in directive names
// to their parsing function.
var validDirectives map[string]dirFunc
func init() {
......
......@@ -5,54 +5,10 @@ import (
"fmt"
)
// newController returns a new controller.
func newController(p *parser) *controller {
return &controller{
dispenser: dispenser{
cursor: -1,
parser: p,
},
}
}
// controller is a dispenser of tokens and also
// facilitates setup with the server by providing
// access to its configuration. It implements
// the middleware.Controller interface.
type controller struct {
dispenser
}
// Startup registers a function to execute when the server starts.
func (c *controller) Startup(fn func() error) {
c.parser.cfg.Startup = append(c.parser.cfg.Startup, fn)
}
// Root returns the server root file path.
func (c *controller) Root() string {
if c.parser.cfg.Root == "" {
return "."
} else {
return c.parser.cfg.Root
}
}
// Host returns the hostname the server is bound to.
func (c *controller) Host() string {
return c.parser.cfg.Host
}
// Port returns the port that the server is listening on.
func (c *controller) Port() string {
return c.parser.cfg.Port
}
// dispenser is a type that gets exposed to middleware
// generators so that they can parse tokens to configure
// their instance.
// TODO: Rename this; it does more than dispense tokens.
// It also provides access to the server to touch its
// configuration.
// their instance. It basically dispenses tokens but can
// do so in a structured manner.
type dispenser struct {
parser *parser
cursor int
......@@ -115,7 +71,9 @@ func (d *dispenser) NextLine() bool {
// 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 is consumed by this method.
// brace is consumed by this method. Usually, you would
// use this as the condition of a for loop to parse
// tokens while being inside the block.
func (d *dispenser) NextBlock() bool {
if d.nesting > 0 {
d.Next()
......
......@@ -62,7 +62,7 @@ func (p *parser) addressBlock() error {
// openCurlyBrace expects the current token to be an
// opening curly brace. This acts like an assertion
// because it returns an error if the token is not
// a opening curly brace.
// a opening curly brace. It does not advance the token.
func (p *parser) openCurlyBrace() error {
if p.tkn() != "{" {
return p.syntaxErr("{")
......@@ -73,7 +73,7 @@ func (p *parser) openCurlyBrace() error {
// closeCurlyBrace expects the current token to be
// a closing curly brace. This acts like an assertion
// because it returns an error if the token is not
// a closing curly brace.
// a closing curly brace. It does not advance the token.
func (p *parser) closeCurlyBrace() error {
if p.tkn() != "}" {
return p.syntaxErr("}")
......@@ -84,32 +84,80 @@ func (p *parser) closeCurlyBrace() error {
// directives parses through all the directives
// and it expects the current token to be the first
// directive. It goes until EOF or closing curly
// brace.
// brace which ends the address block.
func (p *parser) directives() error {
for p.next() {
if p.tkn() == "}" {
// end of address scope
break
}
if fn, ok := validDirectives[p.tkn()]; ok {
err := fn(p)
if err != nil {
return err
if p.tkn()[0] == '/' {
// Path scope (a.k.a. location context)
// TODO: The parser can handle the syntax (obviously), but the
// implementation is incomplete. This is intentional,
// until we can better decide what kind of feature set we
// want to support. Until this is ready, we leave this
// syntax undocumented.
// location := p.tkn()
if !p.next() {
return p.eofErr()
}
} else if middlewareRegistered(p.tkn()) {
err := p.collectTokens()
err := p.openCurlyBrace()
if err != nil {
return err
}
} else {
return p.err("Syntax", "Unexpected token '"+p.tkn()+"', expecting a valid directive")
for p.next() {
err := p.closeCurlyBrace()
if err == nil { // end of location context
break
}
// TODO: How should we give the context to the directives?
// Or how do we tell the server that these directives should only
// be executed for requests routed to the current path?
err = p.directive()
if err != nil {
return err
}
}
} else if err := p.directive(); err != nil {
return err
}
}
return nil
}
// directive asserts that the current token is either a built-in
// directive or a registered middleware directive; otherwise an error
// will be returned.
func (p *parser) directive() error {
if fn, ok := validDirectives[p.tkn()]; ok {
// Built-in (standard) directive
err := fn(p)
if err != nil {
return err
}
} else if middlewareRegistered(p.tkn()) {
// Middleware directive
err := p.collectTokens()
if err != nil {
return err
}
} else {
return p.err("Syntax", "Unexpected token '"+p.tkn()+"', expecting a valid directive")
}
return nil
}
// collectTokens consumes tokens until the directive's scope
// closes (either end of line or end of curly brace block).
// It creates a controller which is stored in the parser for
// later use by the middleware.
func (p *parser) collectTokens() error {
directive := p.tkn()
line := p.line()
......
......@@ -15,10 +15,6 @@ func New(c middleware.Controller) (middleware.Middleware, error) {
}
return func(next http.HandlerFunc) http.HandlerFunc {
head := Headers{
Next: next,
Rules: rules,
}
return head.ServeHTTP
return Headers{Next: next, Rules: rules}.ServeHTTP
}, nil
}
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