mirror of
https://github.com/caddyserver/caddy.git
synced 2025-10-19 07:43:17 +00:00
caddyfile: Fix importing nested tokens for {block}
(#7189)
This commit is contained in:
parent
4564261d83
commit
551f793700
6 changed files with 214 additions and 23 deletions
|
@ -308,9 +308,9 @@ func (d *Dispenser) CountRemainingArgs() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemainingArgs loads any more arguments (tokens on the same line)
|
// RemainingArgs loads any more arguments (tokens on the same line)
|
||||||
// into a slice and returns them. Open curly brace tokens also indicate
|
// into a slice of strings and returns them. Open curly brace tokens
|
||||||
// the end of arguments, and the curly brace is not included in
|
// also indicate the end of arguments, and the curly brace is not
|
||||||
// the return value nor is it loaded.
|
// included in the return value nor is it loaded.
|
||||||
func (d *Dispenser) RemainingArgs() []string {
|
func (d *Dispenser) RemainingArgs() []string {
|
||||||
var args []string
|
var args []string
|
||||||
for d.NextArg() {
|
for d.NextArg() {
|
||||||
|
@ -320,9 +320,9 @@ func (d *Dispenser) RemainingArgs() []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemainingArgsRaw loads any more arguments (tokens on the same line,
|
// RemainingArgsRaw loads any more arguments (tokens on the same line,
|
||||||
// retaining quotes) into a slice and returns them. Open curly brace
|
// retaining quotes) into a slice of strings and returns them.
|
||||||
// tokens also indicate the end of arguments, and the curly brace is
|
// Open curly brace tokens also indicate the end of arguments,
|
||||||
// not included in the return value nor is it loaded.
|
// and the curly brace is not included in the return value nor is it loaded.
|
||||||
func (d *Dispenser) RemainingArgsRaw() []string {
|
func (d *Dispenser) RemainingArgsRaw() []string {
|
||||||
var args []string
|
var args []string
|
||||||
for d.NextArg() {
|
for d.NextArg() {
|
||||||
|
@ -331,6 +331,18 @@ func (d *Dispenser) RemainingArgsRaw() []string {
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemainingArgsAsTokens loads any more arguments (tokens on the same line)
|
||||||
|
// into a slice of Token-structs and returns them. Open curly brace tokens
|
||||||
|
// also indicate the end of arguments, and the curly brace is not included
|
||||||
|
// in the return value nor is it loaded.
|
||||||
|
func (d *Dispenser) RemainingArgsAsTokens() []Token {
|
||||||
|
var args []Token
|
||||||
|
for d.NextArg() {
|
||||||
|
args = append(args, d.Token())
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
// NewFromNextSegment returns a new dispenser with a copy of
|
// NewFromNextSegment returns a new dispenser with a copy of
|
||||||
// the tokens from the current token until the end of the
|
// the tokens from the current token until the end of the
|
||||||
// "directive" whether that be to the end of the line or
|
// "directive" whether that be to the end of the line or
|
||||||
|
|
|
@ -274,6 +274,66 @@ func TestDispenser_RemainingArgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDispenser_RemainingArgsAsTokens(t *testing.T) {
|
||||||
|
input := `dir1 arg1 arg2 arg3
|
||||||
|
dir2 arg4 arg5
|
||||||
|
dir3 arg6 { arg7
|
||||||
|
dir4`
|
||||||
|
d := NewTestDispenser(input)
|
||||||
|
|
||||||
|
d.Next() // dir1
|
||||||
|
|
||||||
|
args := d.RemainingArgsAsTokens()
|
||||||
|
|
||||||
|
tokenTexts := make([]string, 0, len(args))
|
||||||
|
for _, arg := range args {
|
||||||
|
tokenTexts = append(tokenTexts, arg.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := []string{"arg1", "arg2", "arg3"}; !reflect.DeepEqual(tokenTexts, expected) {
|
||||||
|
t.Errorf("RemainingArgsAsTokens(): Expected %v, got %v", expected, tokenTexts)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Next() // dir2
|
||||||
|
|
||||||
|
args = d.RemainingArgsAsTokens()
|
||||||
|
|
||||||
|
tokenTexts = tokenTexts[:0]
|
||||||
|
for _, arg := range args {
|
||||||
|
tokenTexts = append(tokenTexts, arg.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := []string{"arg4", "arg5"}; !reflect.DeepEqual(tokenTexts, expected) {
|
||||||
|
t.Errorf("RemainingArgsAsTokens(): Expected %v, got %v", expected, tokenTexts)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Next() // dir3
|
||||||
|
|
||||||
|
args = d.RemainingArgsAsTokens()
|
||||||
|
tokenTexts = tokenTexts[:0]
|
||||||
|
for _, arg := range args {
|
||||||
|
tokenTexts = append(tokenTexts, arg.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expected := []string{"arg6"}; !reflect.DeepEqual(tokenTexts, expected) {
|
||||||
|
t.Errorf("RemainingArgsAsTokens(): Expected %v, got %v", expected, tokenTexts)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Next() // {
|
||||||
|
d.Next() // arg7
|
||||||
|
d.Next() // dir4
|
||||||
|
|
||||||
|
args = d.RemainingArgsAsTokens()
|
||||||
|
tokenTexts = tokenTexts[:0]
|
||||||
|
for _, arg := range args {
|
||||||
|
tokenTexts = append(tokenTexts, arg.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) != 0 {
|
||||||
|
t.Errorf("RemainingArgsAsTokens(): Expected %v, got %v", []string{}, tokenTexts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDispenser_ArgErr_Err(t *testing.T) {
|
func TestDispenser_ArgErr_Err(t *testing.T) {
|
||||||
input := `dir1 {
|
input := `dir1 {
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,28 +379,23 @@ func (p *parser) doImport(nesting int) error {
|
||||||
if len(blockTokens) > 0 {
|
if len(blockTokens) > 0 {
|
||||||
// use such tokens to create a new dispenser, and then use it to parse each block
|
// use such tokens to create a new dispenser, and then use it to parse each block
|
||||||
bd := NewDispenser(blockTokens)
|
bd := NewDispenser(blockTokens)
|
||||||
|
|
||||||
|
// one iteration processes one sub-block inside the import
|
||||||
for bd.Next() {
|
for bd.Next() {
|
||||||
// see if we can grab a key
|
currentMappingKey := bd.Val()
|
||||||
var currentMappingKey string
|
|
||||||
if bd.Val() == "{" {
|
if currentMappingKey == "{" {
|
||||||
return p.Err("anonymous blocks are not supported")
|
return p.Err("anonymous blocks are not supported")
|
||||||
}
|
}
|
||||||
currentMappingKey = bd.Val()
|
|
||||||
currentMappingTokens := []Token{}
|
// load up all arguments (if there even are any)
|
||||||
// read all args until end of line / {
|
currentMappingTokens := bd.RemainingArgsAsTokens()
|
||||||
if bd.NextArg() {
|
|
||||||
|
// load up the entire block
|
||||||
|
for mappingNesting := bd.Nesting(); bd.NextBlock(mappingNesting); {
|
||||||
currentMappingTokens = append(currentMappingTokens, bd.Token())
|
currentMappingTokens = append(currentMappingTokens, bd.Token())
|
||||||
for bd.NextArg() {
|
|
||||||
currentMappingTokens = append(currentMappingTokens, bd.Token())
|
|
||||||
}
|
|
||||||
// TODO(elee1766): we don't enter another mapping here because it's annoying to extract the { and } properly.
|
|
||||||
// maybe someone can do that in the future
|
|
||||||
} else {
|
|
||||||
// attempt to enter a block and add tokens to the currentMappingTokens
|
|
||||||
for mappingNesting := bd.Nesting(); bd.NextBlock(mappingNesting); {
|
|
||||||
currentMappingTokens = append(currentMappingTokens, bd.Token())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blockMapping[currentMappingKey] = currentMappingTokens
|
blockMapping[currentMappingKey] = currentMappingTokens
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -884,6 +885,51 @@ func TestRejectsGlobalMatcher(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRejectAnonymousImportBlock(t *testing.T) {
|
||||||
|
p := testParser(`
|
||||||
|
(site) {
|
||||||
|
http://{args[0]} https://{args[0]} {
|
||||||
|
{block}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import site test.domain {
|
||||||
|
{
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
_, err := p.parseAll()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Expected an error, but got nil")
|
||||||
|
}
|
||||||
|
expected := "anonymous blocks are not supported"
|
||||||
|
if !strings.HasPrefix(err.Error(), "anonymous blocks are not supported") {
|
||||||
|
t.Errorf("Expected error to start with '%s' but got '%v'", expected, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAcceptSiteImportWithBraces(t *testing.T) {
|
||||||
|
p := testParser(`
|
||||||
|
(site) {
|
||||||
|
http://{args[0]} https://{args[0]} {
|
||||||
|
{block}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import site test.domain {
|
||||||
|
reverse_proxy http://192.168.1.1:8080 {
|
||||||
|
header_up Host {host}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
_, err := p.parseAll()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected error to be nil but got '%v'", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testParser(input string) parser {
|
func testParser(input string) parser {
|
||||||
return parser{Dispenser: NewTestDispenser(input)}
|
return parser{Dispenser: NewTestDispenser(input)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
(site) {
|
||||||
|
http://{args[0]} https://{args[0]} {
|
||||||
|
{block}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
import site test.domain {
|
||||||
|
{
|
||||||
|
header_up Host {host}
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
anonymous blocks are not supported
|
|
@ -0,0 +1,65 @@
|
||||||
|
(site) {
|
||||||
|
https://{args[0]} {
|
||||||
|
{block}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import site test.domain {
|
||||||
|
reverse_proxy http://192.168.1.1:8080 {
|
||||||
|
header_up Host {host}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"test.domain"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "reverse_proxy",
|
||||||
|
"headers": {
|
||||||
|
"request": {
|
||||||
|
"set": {
|
||||||
|
"Host": [
|
||||||
|
"{http.request.host}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"upstreams": [
|
||||||
|
{
|
||||||
|
"dial": "192.168.1.1:8080"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue