Range Request File Server
Serve a single file from a confined root and rely on ServeContent for partial content, conditional requests, and range headers.
Code
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"strings"
)
func fileHandler(root string) http.HandlerFunc {
absoluteRoot, err := filepath.Abs(root)
if err != nil {
panic(err)
}
return func(w http.ResponseWriter, r *http.Request) {
cleaned := path.Clean("/" + r.URL.Path)
full := filepath.Join(absoluteRoot, filepath.FromSlash(strings.TrimPrefix(cleaned, "/")))
if !strings.HasPrefix(full, absoluteRoot+string(os.PathSeparator)) {
http.Error(w, "invalid path", http.StatusBadRequest)
return
}
file, err := os.Open(full)
if err != nil {
http.Error(w, "not found", http.StatusNotFound)
return
}
defer file.Close()
info, err := file.Stat()
if err != nil || info.IsDir() {
http.Error(w, "not found", http.StatusNotFound)
return
}
http.ServeContent(w, r, info.Name(), info.ModTime(), file)
}
}
func main() {
root, err := os.MkdirTemp("", "range-server-*")
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
if err := os.WriteFile(filepath.Join(root, "report.txt"), []byte("hello range world"), 0o644); err != nil {
panic(err)
}
server := httptest.NewServer(fileHandler(root))
defer server.Close()
request, err := http.NewRequest(http.MethodGet, server.URL+"/report.txt", nil)
if err != nil {
panic(err)
}
request.Header.Set("Range", "bytes=6-10")
response, err := http.DefaultClient.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
panic(err)
}
fmt.Println("status:", response.StatusCode)
fmt.Println("content-range:", response.Header.Get("Content-Range"))
fmt.Println("body:", string(body))
}Report a problem with this exampleOpens a pre-filled issue on GitHub.