@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 124 lines 4.57 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package templates
16
17 import (
18 "errors"
19 "net/http"
20 "net/http/httptest"
21 "strconv"
22 "testing"
23
24 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
25 )
26
27 func TestServeHTTPErrorDeletesFileHeaders(t *testing.T) {
28 for i, tc := range []struct {
29 body string
30 wantStatus int
31 }{
32 {body: `{{httpError 404}}`, wantStatus: http.StatusNotFound},
33 {body: `{{nosuchfunc}}`, wantStatus: http.StatusInternalServerError},
34 {body: `{{include "missing.html"}}`, wantStatus: http.StatusInternalServerError},
35 } {
36 tmpl := &Templates{MIMETypes: defaultMIMETypes}
37 next := caddyhttp.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
38 w.Header().Set("Content-Type", "text/html; charset=utf-8")
39 w.Header().Set("Content-Length", "123")
40 w.Header().Set("Etag", `"abc"`)
41 w.Header().Set("Last-Modified", "Mon, 02 Jan 2006 15:04:05 GMT")
42 w.Header().Set("Accept-Ranges", "bytes")
43 w.Header().Set("Content-Encoding", "gzip")
44 w.Header().Set("Content-Range", "bytes 0-122/456")
45 _, err := w.Write([]byte(tc.body))
46 return err
47 })
48
49 w := httptest.NewRecorder()
50 r := httptest.NewRequest(http.MethodGet, "/index.html", nil)
51
52 err := tmpl.ServeHTTP(w, r, next)
53 handlerErr, ok := errors.AsType[caddyhttp.HandlerError](err)
54 if !ok {
55 t.Fatalf("Test %d: expected a handler error, got %v", i, err)
56 }
57 if handlerErr.StatusCode != tc.wantStatus {
58 t.Errorf("Test %d: expected status %d, got %d", i, tc.wantStatus, handlerErr.StatusCode)
59 }
60 for _, name := range []string{"Content-Length", "Content-Type", "Etag", "Last-Modified", "Accept-Ranges", "Content-Encoding", "Content-Range"} {
61 if got := w.Header().Get(name); got != "" {
62 t.Errorf("Test %d: expected %s to be deleted, got %q", i, name, got)
63 }
64 }
65 }
66 }
67
68 func TestServeHTTPContentLength(t *testing.T) {
69 const (
70 source = `{{"hello"}} world`
71 rendered = "hello world"
72 )
73
74 for _, tc := range []struct {
75 name string
76 method string
77 status int
78 wantLength string // empty means the header must be absent
79 wantBody string
80 }{
81 {name: "GET reports rendered length", method: http.MethodGet, status: http.StatusOK, wantLength: strconv.Itoa(len(rendered)), wantBody: rendered},
82 {name: "HEAD drops stale length", method: http.MethodHead, status: http.StatusOK},
83 {name: "204 drops stale length", method: http.MethodGet, status: http.StatusNoContent},
84 {name: "304 drops stale length", method: http.MethodGet, status: http.StatusNotModified},
85 {name: "CONNECT 200 drops stale length", method: http.MethodConnect, status: http.StatusOK},
86 {name: "CONNECT 407 reports rendered length", method: http.MethodConnect, status: http.StatusProxyAuthRequired, wantLength: strconv.Itoa(len(rendered)), wantBody: rendered},
87 } {
88 t.Run(tc.name, func(t *testing.T) {
89 // next behaves like file_server: it advertises the length of the
90 // unrendered template and writes a body only when one is allowed
91 next := caddyhttp.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
92 w.Header().Set("Content-Type", "text/html")
93 w.Header().Set("Content-Length", strconv.Itoa(len(source)))
94 w.WriteHeader(tc.status)
95 if tc.wantBody != "" {
96 _, err := w.Write([]byte(source))
97 return err
98 }
99 return nil
100 })
101
102 tmpl := &Templates{MIMETypes: []string{"text/html"}}
103 rec := httptest.NewRecorder()
104 req := httptest.NewRequest(tc.method, "/", nil)
105 if err := tmpl.ServeHTTP(rec, req, next); err != nil {
106 t.Fatalf("ServeHTTP: %v", err)
107 }
108
109 if rec.Code != tc.status {
110 t.Errorf("expected status %d, got %d", tc.status, rec.Code)
111 }
112 gotLength, ok := rec.Header()["Content-Length"]
113 switch {
114 case tc.wantLength == "" && ok:
115 t.Errorf("expected no Content-Length, got %q", gotLength)
116 case tc.wantLength != "" && rec.Header().Get("Content-Length") != tc.wantLength:
117 t.Errorf("expected Content-Length %q, got %q", tc.wantLength, rec.Header().Get("Content-Length"))
118 }
119 if body := rec.Body.String(); body != tc.wantBody {
120 t.Errorf("expected body %q, got %q", tc.wantBody, body)
121 }
122 })
123 }
124 }