Commit 38719765 authored by Matthew Holt's avatar Matthew Holt

Don't share sync.Once with all directives

If each server block had only one sync.Once then all directives would refer to it and only the first directive would be able to use it! So this commit changes it to a map of sync.Once instances, keyed by directive. So by creating a new map for every server block, each directive in that block can get its own sync.Once which is exactly what is needed. They won't step on each other this way.
parent f3596f73
...@@ -45,7 +45,7 @@ func Load(filename string, input io.Reader) (Group, error) { ...@@ -45,7 +45,7 @@ func Load(filename string, input io.Reader) (Group, error) {
// Iterate each server block and make a config for each one, // Iterate each server block and make a config for each one,
// executing the directives that were parsed. // executing the directives that were parsed.
for _, sb := range serverBlocks { for _, sb := range serverBlocks {
var once sync.Once onces := makeOnces()
for _, addr := range sb.Addresses { for _, addr := range sb.Addresses {
config := server.Config{ config := server.Config{
...@@ -68,7 +68,7 @@ func Load(filename string, input io.Reader) (Group, error) { ...@@ -68,7 +68,7 @@ func Load(filename string, input io.Reader) (Group, error) {
controller := &setup.Controller{ controller := &setup.Controller{
Config: &config, Config: &config,
Dispenser: parse.NewDispenserTokens(filename, tokens), Dispenser: parse.NewDispenserTokens(filename, tokens),
OncePerServerBlock: func(f func()) { once.Do(f) }, OncePerServerBlock: func(f func()) { onces[dir.name].Do(f) },
} }
midware, err := dir.setup(controller) midware, err := dir.setup(controller)
...@@ -96,6 +96,23 @@ func Load(filename string, input io.Reader) (Group, error) { ...@@ -96,6 +96,23 @@ func Load(filename string, input io.Reader) (Group, error) {
return arrangeBindings(configs) return arrangeBindings(configs)
} }
// makeOnces makes a map of directive name to sync.Once
// instance. This is intended to be called once per server
// block when setting up configs so that Setup functions
// for each directive can perform a task just once per
// server block, even if there are multiple hosts on the block.
//
// We need one Once per directive, otherwise the first
// directive to use it would exclude other directives from
// using it at all, which would be a bug.
func makeOnces() map[string]*sync.Once {
onces := make(map[string]*sync.Once)
for _, dir := range directiveOrder {
onces[dir.name] = new(sync.Once)
}
return onces
}
// arrangeBindings groups configurations by their bind address. For example, // arrangeBindings groups configurations by their bind address. For example,
// a server that should listen on localhost and another on 127.0.0.1 will // a server that should listen on localhost and another on 127.0.0.1 will
// be grouped into the same address: 127.0.0.1. It will return an error // be grouped into the same address: 127.0.0.1. It will return an error
......
...@@ -11,10 +11,15 @@ import ( ...@@ -11,10 +11,15 @@ import (
) )
// Controller is given to the setup function of middlewares which // Controller is given to the setup function of middlewares which
// gives them access to be able to read tokens and set config. // gives them access to be able to read tokens and set config. Each
// virtualhost gets their own server config and dispenser.
type Controller struct { type Controller struct {
*server.Config *server.Config
parse.Dispenser parse.Dispenser
// OncePerServerBlock is a function that executes f
// exactly once per server block, no matter how many
// hosts are associated with it.
OncePerServerBlock func(f func()) OncePerServerBlock func(f func())
} }
......
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