From 6cea1f239d01fc065bc6f4b22d765d89b6db0152 Mon Sep 17 00:00:00 2001 From: Matt Holt Date: Mon, 20 Jul 2020 12:28:40 -0600 Subject: push: Implement HTTP/2 server push (#3573) * push: Implement HTTP/2 server push (close #3551) * push: Abstract header ops by embedding into new struct type This will allow us to add more fields to customize headers in push-specific ways in the future. * push: Ensure Link resources are pushed before response is written * Change header name from X-Caddy-Push to Caddy-Push --- modules/caddyhttp/push/caddyfile.go | 99 +++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 modules/caddyhttp/push/caddyfile.go (limited to 'modules/caddyhttp/push/caddyfile.go') diff --git a/modules/caddyhttp/push/caddyfile.go b/modules/caddyhttp/push/caddyfile.go new file mode 100644 index 0000000..a70d5d5 --- /dev/null +++ b/modules/caddyhttp/push/caddyfile.go @@ -0,0 +1,99 @@ +// Copyright 2015 Matthew Holt and The Caddy Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package push + +import ( + "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "github.com/caddyserver/caddy/v2/modules/caddyhttp/headers" +) + +func init() { + httpcaddyfile.RegisterHandlerDirective("push", parseCaddyfile) +} + +// parseCaddyfile sets up the push handler. Syntax: +// +// push [] [] { +// [GET|HEAD] +// headers { +// [+] [ []] +// - +// } +// } +// +// A single resource can be specified inline without opening a +// block for the most common/simple case. Or, a block can be +// opened and multiple resources can be specified, one per +// line, optionally preceded by the method. The headers +// subdirective can be used to customize the headers that +// are set on each (synthetic) push request, using the same +// syntax as the 'header' directive for request headers. +// Placeholders are accepted in resource and header field +// name and value and replacement tokens. +func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { + handler := new(Handler) + + for h.Next() { + if h.NextArg() { + handler.Resources = append(handler.Resources, Resource{Target: h.Val()}) + } + + // optional block + for outerNesting := h.Nesting(); h.NextBlock(outerNesting); { + switch h.Val() { + case "headers": + if h.NextArg() { + return nil, h.ArgErr() + } + for innerNesting := h.Nesting(); h.NextBlock(innerNesting); { + // include current token, which we treat as an argument here + args := []string{h.Val()} + args = append(args, h.RemainingArgs()...) + + if handler.Headers == nil { + handler.Headers = new(HeaderConfig) + } + switch len(args) { + case 1: + headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], "", "") + case 2: + headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], "") + case 3: + headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], args[2]) + default: + return nil, h.ArgErr() + } + } + + case "GET", "HEAD": + method := h.Val() + if !h.NextArg() { + return nil, h.ArgErr() + } + target := h.Val() + handler.Resources = append(handler.Resources, Resource{ + Method: method, + Target: target, + }) + + default: + handler.Resources = append(handler.Resources, Resource{Target: h.Val()}) + } + } + } + + return handler, nil +} -- cgit v1.2.3