Skip to content

Commit

Permalink
Process HEAD requests in the /retrieve/file handler.
Browse files Browse the repository at this point in the history
This allows remote clients to check if the file has changed so that their
caches can be invalidated for a fresh download.
  • Loading branch information
LTLA committed May 4, 2024
1 parent dd7edff commit 2887572
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 3 deletions.
33 changes: 30 additions & 3 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (

"os"
"path/filepath"
"io"
"io/fs"
"syscall"

"net/http"
"net/url"
"mime"

"encoding/json"
"errors"
"strings"
Expand Down Expand Up @@ -469,12 +472,11 @@ func newRetrieveFileHandler(db *sql.DB) func(http.ResponseWriter, *http.Request)
if configureCors(w, r) {
return
}
if r.Method != "GET" {
if r.Method != "GET" && r.Method != "HEAD" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}


params := r.URL.Query()
path, err := getRetrievePath(params)
if err != nil {
Expand Down Expand Up @@ -513,7 +515,32 @@ func newRetrieveFileHandler(db *sql.DB) func(http.ResponseWriter, *http.Request)
return
}

http.ServeFile(w, r, path)
if (r.Method == "HEAD") {
w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))
w.Header().Set("Last-Modified", info.ModTime().UTC().Format(http.TimeFormat))
w.Header().Set("Accept-Ranges", "bytes")

ctype := mime.TypeByExtension(filepath.Ext(path))
if (ctype == "") {
r, err := os.Open(path)
if err == nil {
// Copied from https://cs.opensource.google/go/go/+/refs/tags/go1.22.2:src/net/http/fs.go;l=239-246.
defer r.Close()
buf := make([]byte, 512)
n, err := io.ReadFull(r, buf[:])
if err == nil {
ctype = http.DetectContentType(buf[:n])
}
}
}
if (ctype != "") {
w.Header().Set("Content-Type", ctype)
}

w.WriteHeader(http.StatusOK);
} else {
http.ServeFile(w, r, path)
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"net/url"
"encoding/json"
"sort"
"time"
"strconv"
)

func TestDumpJsonResponse(t *testing.T) {
Expand Down Expand Up @@ -980,6 +982,36 @@ func TestRetrieveFileHandler(t *testing.T) {
}
})

t.Run("head", func (t *testing.T) {
req, err := http.NewRequest("HEAD", "/retrieve/file?path=" + url.QueryEscape(filepath.Join(to_add, "metadata.json")), nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("should have succeeded")
}

headers := rr.Header()
cl, err := strconv.Atoi(headers.Get("content-length"))
if err != nil || cl == 0 {
t.Fatal("expected a non-zero content-length header");
}

ct := headers.Get("content-type")
if ct != "application/json" {
t.Fatal("expected a JSON content type header");
}

lm := headers.Get("last-modified")
_, err = time.Parse(time.RFC1123, lm)
if err != nil {
t.Fatalf("failed to parse the last-modified header; %v", err);
}
})

t.Run("not found", func (t *testing.T) {
req, err := http.NewRequest("GET", "/retrieve/file?path=" + url.QueryEscape(filepath.Join(to_add, "other.json")), nil)
if err != nil {
Expand Down

0 comments on commit 2887572

Please sign in to comment.