add cache headers (#14)

Fixes #13
This commit is contained in:
Ross Light 2017-09-29 09:23:29 -07:00 committed by GitHub
parent e9dc433ca5
commit feb3a1564d
3 changed files with 68 additions and 4 deletions

View File

@ -59,6 +59,7 @@ handler into larger Go servers.
``` ```
host: example.com host: example.com
cache_age: 3600
paths: paths:
/foo: /foo:
repo: https://github.com/example/foo repo: https://github.com/example/foo
@ -75,6 +76,11 @@ paths:
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<th scope="row"><code>cache_age</code></th>
<td>optional</td>
<td>The amount of time to cache package pages in seconds. Controls the <code>max-age</code> directive sent in the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"><code>Cache-Control</code></a> HTTP header.</td>
</tr>
<tr> <tr>
<th scope="row"><code>host</code></th> <th scope="row"><code>host</code></th>
<td>optional</td> <td>optional</td>

View File

@ -16,6 +16,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"html/template" "html/template"
"net/http" "net/http"
@ -26,8 +27,9 @@ import (
) )
type handler struct { type handler struct {
host string host string
paths pathConfigSet cacheControl string
paths pathConfigSet
} }
type pathConfig struct { type pathConfig struct {
@ -39,8 +41,9 @@ type pathConfig struct {
func newHandler(config []byte) (*handler, error) { func newHandler(config []byte) (*handler, error) {
var parsed struct { var parsed struct {
Host string `yaml:"host,omitempty"` Host string `yaml:"host,omitempty"`
Paths map[string]struct { CacheAge *int64 `yaml:"cache_max_age,omitempty"`
Paths map[string]struct {
Repo string `yaml:"repo,omitempty"` Repo string `yaml:"repo,omitempty"`
Display string `yaml:"display,omitempty"` Display string `yaml:"display,omitempty"`
VCS string `yaml:"vcs,omitempty"` VCS string `yaml:"vcs,omitempty"`
@ -50,6 +53,14 @@ func newHandler(config []byte) (*handler, error) {
return nil, err return nil, err
} }
h := &handler{host: parsed.Host} h := &handler{host: parsed.Host}
cacheAge := int64(86400) // 24 hpurs (in seconds)
if parsed.CacheAge != nil {
cacheAge = *parsed.CacheAge
if cacheAge < 0 {
return nil, errors.New("cache_max_age is negative")
}
}
h.cacheControl = fmt.Sprintf("public, max-age=%d", cacheAge)
for path, e := range parsed.Paths { for path, e := range parsed.Paths {
pc := pathConfig{ pc := pathConfig{
path: strings.TrimSuffix(path, "/"), path: strings.TrimSuffix(path, "/"),
@ -94,6 +105,7 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set("Cache-Control", h.cacheControl)
if err := vanityTmpl.Execute(w, struct { if err := vanityTmpl.Execute(w, struct {
Import string Import string
Subpath string Subpath string

View File

@ -139,6 +139,10 @@ func TestBadConfigs(t *testing.T) {
" /unknownvcs:\n" + " /unknownvcs:\n" +
" repo: https://bitbucket.org/zombiezen/gopdf\n" + " repo: https://bitbucket.org/zombiezen/gopdf\n" +
" vcs: xyzzy\n", " vcs: xyzzy\n",
"cache_max_age: -1\n" +
"paths:\n" +
" /portmidi:\n" +
" repo: https://github.com/rakyll/portmidi\n",
} }
for _, config := range badConfigs { for _, config := range badConfigs {
_, err := newHandler([]byte(config)) _, err := newHandler([]byte(config))
@ -227,3 +231,45 @@ func TestPathConfigSetFind(t *testing.T) {
} }
} }
} }
func TestCacheHeader(t *testing.T) {
tests := []struct {
name string
config string
cacheControl string
}{
{
name: "default",
cacheControl: "public, max-age=86400",
},
{
name: "specify time",
config: "cache_max_age: 60\n",
cacheControl: "public, max-age=60",
},
{
name: "zero",
config: "cache_max_age: 0\n",
cacheControl: "public, max-age=0",
},
}
for _, test := range tests {
h, err := newHandler([]byte("paths:\n /portmidi:\n repo: https://github.com/rakyll/portmidi\n" +
test.config))
if err != nil {
t.Errorf("%s: newHandler: %v", test.name, err)
continue
}
s := httptest.NewServer(h)
resp, err := http.Get(s.URL + "/portmidi")
if err != nil {
t.Errorf("%s: http.Get: %v", test.name, err)
continue
}
resp.Body.Close()
got := resp.Header.Get("Cache-Control")
if got != test.cacheControl {
t.Errorf("%s: Cache-Control header = %q; want %q", test.name, got, test.cacheControl)
}
}
}