Caddy: Multiline headers only work in HTTP

Created on 26 Sep 2018  路  6Comments  路  Source: caddyserver/caddy

1. What version of Caddy are you using (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

2. What are you trying to do?

Add newlines to header string values to define them over multiple lines.

3. What is your entire Caddyfile?

:80,
:443 {
    tls self_signed

    root "d:/devenv/caddy/default"

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

4. How did you run Caddy (give the full command and describe the execution environment)?

Nothing special is set up as far as environment goes. All you need to do is run caddy.

It's important to note though, that this problem only occurs on secure connections, so you must test with HTTPS.

5. Please paste any relevant HTTP request(s) here.

curl -kIL https://localhost/

6. What did you expect to see?

I expected to see the x-my-test-header name in the response headers with the multiline value.

7. What did you see instead (give full error messages and/or log)?

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

There is no x-my-test-header name in the response headers.

8. How can someone who is starting from scratch reproduce the bug as minimally as possible?

All you need to do is set up a site with a multiline header and inspect the response headers.

This issue only occurs on secure connections. If you make a request to plain HTTP, for example curl -IL http://localhost/ then the header appears correctly.

bug good first issue

Most helpful comment

@francislavoie I just tried using it and \n has no effect.

The main purpose for using multiple lines though, is to improve readability in the config files.

So I'm still expecting the header to come out on a single line in the response, but using multiple lines in the config file can help with readability and editing for potentially long headers, like Content-Security-Policy or Feature-Policy.

All 6 comments

Did you try \n? Not sure if that would work or not.

@francislavoie I just tried using it and \n has no effect.

The main purpose for using multiple lines though, is to improve readability in the config files.

So I'm still expecting the header to come out on a single line in the response, but using multiple lines in the config file can help with readability and editing for potentially long headers, like Content-Security-Policy or Feature-Policy.

It seems like this issue was fixed at some point. I just tried creating a multiline header with quotes and it works fine over both HTTP and HTTPS.

Here's an excerpt from my Caddyfile, for reference:

header / {
    Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    X-XSS-Protection "1; mode=block"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "sameorigin"
    Referrer-Policy "same-origin"
    Expect-CT "max-age=86400, enforce, report-uri=\"https://datahoarder.report-uri.com/r/d/ct/enforce\""
    Feature-Policy "geolocation 'none'; camera 'none'; microphone 'none'"
    Content-Security-Policy "
      default-src 'none' ;
      script-src 'self' 
        'sha256-cecXKP7KMOZMsFpYnnSCvdcCU6aS02wUdHhXQz+rzBY=' 
        'sha256-/7v/RBsCYSwEKfNm3GKddoMHIwFQ+LfJpRWy80yIag4=' ;
      style-src 'self' 
        'sha256-PNU+0KaVWZj7tiWyHGw3pEsZuO7kRmnu5/l6YGevQT8=' 
        'sha256-aqNNdDLnnrDOnTNdkJpYlAxKVJtLt9CtFLklmInuUAE=' 
        'sha256-JzqfVewwP10gJQP4wR5aRX/QBEDQqm4aNzeNDSlmFMA=' 
        'sha256-6HXkwoFqJhqd+PP4Vxf73UzS42TYUDqU+itLbeA5gkg=' 
        'sha256-xU719XNBJeO/eH/EjSQB+kSzlP6mmB8IQMtMQXFyp+o=' 
        'sha256-aIzxslm0qrBPPo+5scCOmx10sNTFpcpSd4f3MmyjjFM=' 
        'sha256-H8+aYwf/B0lGGDHV2VNReccOGfuYjzG52CWxEhAPqJs=' ;
      img-src * ;
      font-src 'self' data: ; 
      connect-src 'self' data: ; 
      media-src 'self' data: ; 
      object-src 'none' ; 
      worker-src 'self' ; 
      manifest-src 'self' ; 
      frame-ancestors 'self' ; 
      form-action 'self' ; 
      upgrade-insecure-requests ; 
      block-all-mixed-content ;"
    -Server
    }

Edit: Fixed formatting.

Thanks for the follow-up!

I haven't looked into this, but corroborating the existence of the bug has been difficult, so since it works for you (and I haven't had issues like this either and I also use a complex CSP), I'll close this.

I can reproduce this problem with Caddy 1.0.3. Multiline headers only work in HTTP.

Example Caddyfile:

http://localhost:8080 {
    root /var/www/

    tls off

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

    log / stdout
    errors stderr
}

https://localhost:8443 {
    root /var/www/

    tls self_signed

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

    log / stdout
    errors stderr
}

cURL response:

$ curl -kI 'http://localhost:8080/'
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 0
Content-Type: text/html; charset=utf-8
Etag: "px3lc70"
Last-Modified: Sat, 31 Aug 2019 11:02:31 GMT
Server: Caddy
X-My-Test-Header: This is           a multiline             header for          testing.
Date: Sat, 31 Aug 2019 11:04:08 GMT

$ curl -kI 'https://localhost:8443/'
HTTP/2 200 
accept-ranges: bytes
content-type: text/html; charset=utf-8
etag: "px3lc70"
last-modified: Sat, 31 Aug 2019 11:02:31 GMT
server: Caddy
content-length: 0
date: Sat, 31 Aug 2019 11:04:36 GMT

It seems that the problem is related with HTTP/2.

$ curl -kI --http1.1 'https://localhost:8443/'
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 0
Content-Type: text/html; charset=utf-8
Etag: "px3lc70"
Last-Modified: Sat, 31 Aug 2019 11:02:31 GMT
Server: Caddy
X-My-Test-Header: This is           a multiline             header for          testing.
Date: Sat, 31 Aug 2019 11:12:40 GMT
$ curl -I 'https://caddyserver.com/'
HTTP/2 200 
accept-ranges: bytes
content-type: text/html; charset=utf-8
referrer-policy: no-referrer-when-downgrade
server: Caddy
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
content-length: 0
date: Sat, 31 Aug 2019 11:14:21 GMT

$ curl -I --http1.1 'https://caddyserver.com/'
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 0
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';
Content-Type: text/html; charset=utf-8
Referrer-Policy: no-referrer-when-downgrade
Server: Caddy
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
Date: Sat, 31 Aug 2019 11:15:08 GMT
Was this page helpful?
0 / 5 - 0 ratings

Related issues

klaasel picture klaasel  路  3Comments

kilpatty picture kilpatty  路  3Comments

mholt picture mholt  路  3Comments

ericmdantas picture ericmdantas  路  3Comments

muhammadmuzzammil1998 picture muhammadmuzzammil1998  路  3Comments