Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
974acbf3
Commit
974acbf3
authored
Mar 03, 2015
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Partial support for location contexts in config files
parent
634b8b70
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
113 additions
and
34 deletions
+113
-34
config/config.go
config/config.go
+1
-1
config/controller.go
config/controller.go
+8
-1
config/directives.go
config/directives.go
+3
-1
config/parser.go
config/parser.go
+36
-16
config/parsing.go
config/parsing.go
+55
-14
middleware/headers/parse.go
middleware/headers/parse.go
+4
-0
middleware/middleware.go
middleware/middleware.go
+1
-0
server/server.go
server/server.go
+5
-1
No files found.
config/config.go
View file @
974acbf3
...
...
@@ -63,7 +63,7 @@ type Config struct {
Port
string
Root
string
TLS
TLSConfig
Middleware
[]
middleware
.
Middleware
Middleware
map
[
string
]
[]
middleware
.
Middleware
Startup
[]
func
()
error
MaxCPU
int
}
...
...
config/controller.go
View file @
974acbf3
package
config
import
"github.com/mholt/caddy/middleware"
// 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
parser
*
parser
parser
*
parser
pathScope
string
}
// newController returns a new controller.
...
...
@@ -43,3 +46,7 @@ func (c *controller) Host() string {
func
(
c
*
controller
)
Port
()
string
{
return
c
.
parser
.
cfg
.
Port
}
func
(
c
*
controller
)
Context
()
middleware
.
Path
{
return
middleware
.
Path
(
c
.
pathScope
)
}
config/directives.go
View file @
974acbf3
...
...
@@ -12,7 +12,9 @@ import (
type
dirFunc
func
(
*
parser
)
error
// validDirectives is a map of valid, built-in directive names
// to their parsing function.
// to their parsing function. Built-in directives cannot be
// ordered, so they should only be used for internal server
// configuration; not directly handling requests.
var
validDirectives
map
[
string
]
dirFunc
func
init
()
{
...
...
config/parser.go
View file @
974acbf3
...
...
@@ -5,16 +5,30 @@ import (
"fmt"
"os"
"strings"
"github.com/mholt/caddy/middleware"
)
// parser is a type which can parse config files.
type
parser
struct
{
filename
string
// the name of the file that we're parsing
lexer
lexer
// the lexer that is giving us tokens from the raw input
cfg
Config
// each server gets one Config; this is the one we're currently building
other
map
[
string
]
*
controller
// tokens to be parsed later by others (middleware generators)
unused
bool
// sometimes the token won't be immediately consumed
}
type
(
// parser is a type which can parse config files.
parser
struct
{
filename
string
// the name of the file that we're parsing
lexer
lexer
// the lexer that is giving us tokens from the raw input
cfg
Config
// each server gets one Config; this is the one we're currently building
other
[]
locationContext
// tokens to be 'parsed' later by middleware generators
scope
*
locationContext
// the current location context (path scope) being populated
unused
bool
// sometimes a token will be read but not immediately consumed
}
// locationContext represents a location context
// (path block) in a config file. If no context
// is explicitly defined, the default location
// context is "/".
locationContext
struct
{
path
string
directives
map
[
string
]
*
controller
}
)
// newParser makes a new parser and prepares it for parsing, given
// the input to parse.
...
...
@@ -78,13 +92,14 @@ func (p *parser) next() bool {
// file for a single Config object (each server or
// virtualhost instance gets their own Config struct),
// which is until the next address/server block.
// Call this only
after
you know that the lexer has another
// another token and you're not in
the middle of a
server
// Call this only
when
you know that the lexer has another
// another token and you're not in
another
server
// block already.
func
(
p
*
parser
)
parseOne
()
error
{
p
.
cfg
=
Config
{}
p
.
other
=
make
(
map
[
string
]
*
controller
)
p
.
cfg
=
Config
{
Middleware
:
make
(
map
[
string
][]
middleware
.
Middleware
),
}
p
.
other
=
[]
locationContext
{}
err
:=
p
.
begin
()
if
err
!=
nil
{
...
...
@@ -102,19 +117,24 @@ func (p *parser) parseOne() error {
// unwrap gets the middleware generators from the middleware
// package in the order in which they are registered, and
// executes the top-level functions (the generator function)
// to expose the second layers which
is
the actual middleware.
// to expose the second layers which
are
the actual middleware.
// This function should be called only after p has filled out
// p.other and that the entire server block has been consumed.
func
(
p
*
parser
)
unwrap
()
error
{
for
_
,
directive
:=
range
registry
.
ordered
{
if
disp
,
ok
:=
p
.
other
[
directive
];
ok
{
// TODO: For now, we only support the first and default path scope ("/")
// but when we implement support for path scopes, we will have to
// change this logic to loop over them and order them. We need to account
// for situations where multiple path scopes overlap, regex (??), etc...
if
disp
,
ok
:=
p
.
other
[
0
]
.
directives
[
directive
];
ok
{
if
generator
,
ok
:=
registry
.
directiveMap
[
directive
];
ok
{
mid
,
err
:=
generator
(
disp
)
if
err
!=
nil
{
return
err
}
if
mid
!=
nil
{
p
.
cfg
.
Middleware
=
append
(
p
.
cfg
.
Middleware
,
mid
)
// TODO: Again, we assume the default path scope here...
p
.
cfg
.
Middleware
[
p
.
other
[
0
]
.
path
]
=
append
(
p
.
cfg
.
Middleware
[
p
.
other
[
0
]
.
path
],
mid
)
}
}
else
{
return
errors
.
New
(
"No middleware bound to directive '"
+
directive
+
"'"
)
...
...
config/parsing.go
View file @
974acbf3
package
config
import
"errors"
// This file contains the recursive-descent parsing
// functions.
...
...
@@ -47,6 +49,14 @@ func (p *parser) addressBlock() error {
return
p
.
directives
()
}
// When we enter an address block, we also implicitly
// enter a path block where the path is all paths ("/")
p
.
other
=
append
(
p
.
other
,
locationContext
{
path
:
"/"
,
directives
:
make
(
map
[
string
]
*
controller
),
})
p
.
scope
=
&
p
.
other
[
0
]
err
=
p
.
directives
()
if
err
!=
nil
{
return
err
...
...
@@ -91,40 +101,66 @@ func (p *parser) directives() error {
// end of address scope
break
}
if
p
.
tkn
()[
0
]
==
'/'
{
if
p
.
tkn
()[
0
]
==
'/'
||
p
.
tkn
()[
0
]
==
'*'
{
// Path scope (a.k.a. location context)
// Starts with / ('starts with') or * ('ends with').
// 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.
// want to support and how exactly we want these location
// scopes to work. Until this is ready, we leave this
// syntax undocumented. Some changes will need to be
// made in parser.go also (the unwrap function) and
// probably in server.go when we do this... see those TODOs.
var
scope
*
locationContext
// If the path block is a duplicate, append to existing one
for
i
:=
0
;
i
<
len
(
p
.
other
);
i
++
{
if
p
.
other
[
i
]
.
path
==
p
.
tkn
()
{
scope
=
&
p
.
other
[
i
]
break
}
}
// location := p.tkn()
// Otherwise, for a new path we haven't seen before, create a new context
if
scope
==
nil
{
scope
=
&
locationContext
{
path
:
p
.
tkn
(),
directives
:
make
(
map
[
string
]
*
controller
),
}
}
// Consume the opening curly brace
if
!
p
.
next
()
{
return
p
.
eofErr
()
}
err
:=
p
.
openCurlyBrace
()
if
err
!=
nil
{
return
err
}
// Use this path scope as our current context for just a moment
p
.
scope
=
scope
// Consume each directive in the path block
for
p
.
next
()
{
err
:=
p
.
closeCurlyBrace
()
if
err
==
nil
{
// end of location context
if
err
==
nil
{
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
}
}
// Save the new scope and put the current scope back to "/"
p
.
other
=
append
(
p
.
other
,
*
scope
)
p
.
scope
=
&
p
.
other
[
0
]
}
else
if
err
:=
p
.
directive
();
err
!=
nil
{
return
err
}
...
...
@@ -134,10 +170,11 @@ func (p *parser) directives() error {
// directive asserts that the current token is either a built-in
// directive or a registered middleware directive; otherwise an error
// will be returned.
// will be returned. If it is a valid directive, tokens will be
// collected.
func
(
p
*
parser
)
directive
()
error
{
if
fn
,
ok
:=
validDirectives
[
p
.
tkn
()];
ok
{
// Built-in (standard) directive
// Built-in (standard
, or 'core'
) directive
err
:=
fn
(
p
)
if
err
!=
nil
{
return
err
...
...
@@ -159,6 +196,10 @@ func (p *parser) directive() error {
// It creates a controller which is stored in the parser for
// later use by the middleware.
func
(
p
*
parser
)
collectTokens
()
error
{
if
p
.
scope
==
nil
{
return
errors
.
New
(
"Current scope cannot be nil"
)
}
directive
:=
p
.
tkn
()
line
:=
p
.
line
()
nesting
:=
0
...
...
@@ -169,7 +210,7 @@ func (p *parser) collectTokens() error {
// (the parsing logic in the middleware generator must
// account for multiple occurrences of its directive, even
// if that means returning an error or overwriting settings)
if
existing
,
ok
:=
p
.
other
[
directive
];
ok
{
if
existing
,
ok
:=
p
.
scope
.
directives
[
directive
];
ok
{
cont
=
existing
}
...
...
@@ -195,6 +236,6 @@ func (p *parser) collectTokens() error {
return
p
.
eofErr
()
}
p
.
other
[
directive
]
=
cont
p
.
scope
.
directives
[
directive
]
=
cont
return
nil
}
middleware/headers/parse.go
View file @
974acbf3
...
...
@@ -29,6 +29,8 @@ func parse(c middleware.Controller) ([]HeaderRule, error) {
}
for
c
.
NextBlock
()
{
// A block of headers was opened...
h
:=
Header
{
Name
:
c
.
Val
()}
if
c
.
NextArg
()
{
...
...
@@ -38,6 +40,8 @@ func parse(c middleware.Controller) ([]HeaderRule, error) {
head
.
Headers
=
append
(
head
.
Headers
,
h
)
}
if
c
.
NextArg
()
{
// ... or single header was defined as an argument instead.
h
:=
Header
{
Name
:
c
.
Val
()}
h
.
Value
=
c
.
Val
()
...
...
middleware/middleware.go
View file @
974acbf3
...
...
@@ -29,5 +29,6 @@ type (
Root
()
string
Host
()
string
Port
()
string
Context
()
Path
}
)
server/server.go
View file @
974acbf3
...
...
@@ -101,7 +101,11 @@ func (s *Server) buildStack() error {
}
}
s
.
compile
(
s
.
config
.
Middleware
)
// TODO: We only compile middleware for the "/" scope.
// Partial support for multiple location contexts already
// exists in the parser and config levels, but until full
// support is implemented, this is all we do right here.
s
.
compile
(
s
.
config
.
Middleware
[
"/"
])
return
nil
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment