Multiline headers


(Lucas) #1

I’m trying to add some headers to my Caddy files, and everything works fine, as expected, but the headers I’m adding tend to get quite long. For example the Feature-Policy header, or the Content-Security-Policy header.

Is there a way in a Caddy config file to split the header across multiple lines to make it easier to read/edit?

I know you can use a + in front of a header name to append another header of the same name, but what I want to know is if there’s a way to define a single header over multiple lines but have it sent from the server as a single line?

If there isn’t then that’s fine, but it would just make long header values easier to read if it were possible.


(Matt Holt) #2

I usually just use regular quotes:

header / {
	Content-Security-Policy "style-src   'self' https://fonts.googleapis.com;
                          script-src  'self' data: https://www.google-analytics.com https://checkout.stripe.com;
                          img-src     'self' data: https:;
                          font-src    'self' data: https: blob:;
                          media-src   'self' https:;
                          connect-src 'self' https:;
                          object-src  'none';"
}

(Lucas) #3

Thanks for the example, but unfortunately this is one of the things I tried and it doesn’t seem to work.

When I put all of the values onto a single line I can see the header in the Chrome network tab, but when I split it over multiple lines like that it stops appearing.


(Matthew Fay) #4
whitestrake at apollo in ~/Projects/test
❯ caddy -version
Caddy 0.11.0 (unofficial)

whitestrake at apollo in ~/Projects/test
❯ cat Caddyfile
:2015 {
  status 200 /
  header / {
    X-My-Test-Header "This is
                      a multiline
                      header for
                      testing."
  }
}

whitestrake at apollo in ~/Projects/test
❯ caddy
Activating privacy features... done.
http://:2015

From another terminal:

whitestrake at apollo in ~
❯ curl -IL http://localhost:2015/
HTTP/1.1 200 OK
Server: Caddy
X-My-Test-Header: This is                       a multiline                       header for                       testing.
Date: Tue, 25 Sep 2018 23:05:48 GMT

The relevant docs outlining the behaviour of tokens and quotes:

https://caddyserver.com/docs/caddyfile#lexical-syntax


(Lucas) #5

This is what I’m doing:

D:\devenv>
λ caddy -version
Caddy 0.11.0 (+d47b041 Thu Sep 06 11:08:30 UTC 2018) (unofficial)
1 file changed, 1 insertion(+), 1 deletion(-)
caddy/caddymain/run.go

D:\devenv>
λ cat caddy\Caddyfile
import "sites/*"

D:\devenv>
λ cat caddy\sites\_default.caddyfile
:80,
:443 {
    tls self_signed

    root "d:/devenv/caddy/default"

    header / {
        X-My-Test-Header "This is
                          a multiline
                          header for
                          testing."
    }
}

D:\devenv>
λ cd caddy\

D:\devenv\caddy>
λ caddy
Activating privacy features... done.
https://
http://

And then in another window:

D:\devenv>
λ curl -kIL https://localhost/
HTTP/2 200
accept-ranges: bytes
content-type: text/html; charset=utf-8
etag: "p7eoxp54"
last-modified: Thu, 19 Apr 2018 00:20:13 GMT
server: Caddy
content-length: 184
date: Wed, 26 Sep 2018 00:51:52 GMT

It seems to work on HTTP though:

D:\devenv>
λ curl -kIL http://localhost/
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 184
Content-Type: text/html; charset=utf-8
Etag: "p7eoxp54"
Last-Modified: Thu, 19 Apr 2018 00:20:13 GMT
Server: Caddy
X-My-Test-Header: This is                           a multiline                           header for                           testing.
Date: Wed, 26 Sep 2018 00:56:50 GMT

(Matthew Fay) #6

I modified my earlier attempt to add a HTTPS listener and was able to replicate the issue. Looks like we’ve got a bug.

The header doesn’t appear when:

  1. The header content is given as a multiline token in the Caddyfile, AND;
  2. The site is accessed over HTTPS

A single-line header works over HTTPS and both work over HTTP. Very strange. Time to take this to the Github issue tracker so we can investigate the cause, I think.

@Lucas, would you mind filling out the issue template at https://github.com/mholt/caddy/issues/new and linking to this thread?


(Lucas) #7

Thanks for the help so far, and thanks for testing it out on your machine too.

I’ve created a new issue on the GitHub project, so for now I’ll stick to single line header values :slight_smile:


(Alwin S) #8

Hi there,

I was just testing the multiline headers and for me it does work, but I noticed the all the spaces from the indentation of the multiline header is also in the response (make kinda sense):

So

	header / {
		Content-Security-Policy "base-uri 'self';
			default-src 'self'"
        }

yields (where spaces are replaced with _ for readability)

Content-Security-Policy: base-uri 'self'_____;default-src 'self'

Any way to get rid of the additional spaces?


(Alwin S) #9

On a related note, I also tried to use appending headers syntax, like:

header / {
    Content-Security-Policy "base-uri 'self';"
    +Content-Security-Policy "default-src 'self'"
}

but this yielded in two separate response headers. I could not find any documentation if browser are able to work with that.


(Matthew Fay) #10

There is no way to remove the additional spaces, other than not including them in your Caddyfile. The extra spaces don’t impact header function whatsoever, and the Caddyfile parser treats the whole string from opening quote to closing quote as a single token, feeding it to the header directive without modification (such as stripping spaces).


(Alwin S) #11

Thanks. Already got used to it, and figured it would hurt. It felt just a bit weird… :slight_smile:


(Matthew Fay) #12

No worries. Even https://caddyserver.com/ does this, heheh:

Content-Security-Policy: style-src   'self' 'unsafe-inline' https://fonts.googleapis.com;                                         script-src  'self' data: https://www.google-analytics.com https://checkout.stripe.com;                                          img-src     'self' data: https:;                                        font-src    'self' data: https: blob:;                                          media-src   'self' https:;                                      connect-src 'self' https:;                                      object-src  'none';