Modify ServeContent file on the fly

Viewed 124

I'm writing a simple web server to serve static files. Any HTML file being served needs to be modified "on the go" to include some HTML just before its closing </body> tag.

I achieved it with the below code and it works, however is there perhaps a more efficient way of doing it? I'm beginner in Go and this code needs to be super performant.

// error handling etc omitted for brevity

dir := http.Dir("my/path")

content, _ := dir.Open("my_file")

var bodyBuf strings.Builder
var contentBuf *bytes.Buffer

io.Copy(&bodyBuf, content)
defer content.Close()

if strings.HasSuffix("some/web/uri", ".html") {
    new_html_content := "<whatever></body>"
    bodyRpld := strings.Replace(bodyBuf.String(), "</body>", new_html_content, 1)
    contentBuf = bytes.NewBuffer([]byte(bodyRpld))
} else {
    contentBuf = bytes.NewBuffer([]byte(bodyBuf.String()))
}

d, _ := content.Stat()

http.ServeContent(w, r, "my/path", d.ModTime(), bytes.NewReader(contentBuf.Bytes()))

Thanks!

1 Answers

To avoid creating large buffers for files that do no match your file-match pattern *.html, I would suggest using an io.Reader mechanism to pass-through files that you want to serve untouched. This avoids loading into memory potentially large assets (e.g. 100MB non-html video files).

For files that do match your html check - your string-replace is probably fine as .html are typically small in size.

So try something like this:

dir := http.Dir("my/path")
content, err := dir.Open("my_file") // check error

var r io.ReadSeeker // for http.ServeContent needs

if !strings.HasSuffix("some/web/uri", ".html") {

    r = content // pass-through file content (avoid memory allocs)

} else {

    // similar to what you had before
    b := new(bytes.Buffer)
    n, err := b.ReadFrom(content) // check err
    defer content.Close()

    new_html_content := "<whatever></body>"
    newContent := strings.Replace(b.String(),
        "</body>", new_html_content, 1)

    r = bytes.NewReader([]byte(newContent))
}

d, _ := content.Stat()

http.ServeContent(w, r, "my/path", d.ModTime(), r)
Related