go 99 lines · 3 tabs

Serving Partial Video Content with HTTP Range Requests in Go

Shared by codesnips Sep 2026
3 tabs
package main

import (
	"log"
	"net/http"
	"time"

	"example.com/app/media"
)

func main() {
	srv := &media.VideoServer{Root: "./media"}

	mux := http.NewServeMux()
	mux.Handle("/videos/", http.StripPrefix("/videos/",
		http.HandlerFunc(srv.ServeVideo)))

	handler := media.RangeLogger(mux)

	// No WriteTimeout: streaming responses may outlive it.
	s := &http.Server{
		Addr:              ":8080",
		Handler:           handler,
		ReadHeaderTimeout: 10 * time.Second,
		IdleTimeout:       120 * time.Second,
	}

	log.Println("serving video on :8080/videos/")
	log.Fatal(s.ListenAndServe())
}
3 files · go Explain with highlit

This snippet shows how to correctly serve seekable video files in Go so browsers can scrub, pause, and resume playback. The key insight is that partial content is not something to implement by hand: the standard library's http.ServeContent already speaks the full HTTP range protocol, including Range request parsing, 206 Partial Content responses, Accept-Ranges, Content-Range, conditional If-Range validation, and multipart byte ranges. All that is required is an io.ReadSeeker, a modification time, and a name for content-type sniffing.

In the videoHandler tab, ServeVideo opens the requested file, guards against path traversal by rejecting names containing .., and then defers to http.ServeContent. Because an *os.File implements io.ReadSeeker, ServeContent can seek to the requested offset and stream only the bytes the client asked for. The handler explicitly does NOT set Content-Length or Content-Type itself — ServeContent derives those, using the file extension and a peek at the first bytes to determine the MIME type, which matters because video/mp4 triggers native seeking in the browser while application/octet-stream does not. Passing info.ModTime() lets the library generate a validator so that stale ranges are rejected with 416 or re-fetched.

The rangeLogger middleware tab wraps the handler to make range behavior observable. It records the inbound Range header and captures the response status through a small statusRecorder that overrides WriteHeader. Seeing a 206 confirms partial delivery is working; a 200 means the client downloaded the whole file, and a 416 Requested Range Not Satisfiable means the offset was past end-of-file.

The main tab wires everything together with http.StripPrefix so URLs like /videos/clip.mp4 map onto files in a media directory. A read timeout is deliberately omitted on the server because long-lived streaming connections would otherwise be severed mid-playback; only header and idle timeouts are set. The trade-off of this approach is that it assumes files are local and seekable — for object storage one would wrap a ranged reader instead. For local media, though, this is the smallest correct implementation, offloading every tricky edge case of the range spec to well-tested standard-library code.


Related snips

Share this code

Here's the card — post it anywhere.

Serving Partial Video Content with HTTP Range Requests in Go — share card
Link copied