Fix minify

This commit is contained in:
Jan-Lukas Else 2022-04-10 11:46:35 +02:00
parent 8d60057590
commit f42b3256a4
15 changed files with 101 additions and 95 deletions

View File

@ -22,6 +22,7 @@ import (
"github.com/go-fed/httpsig" "github.com/go-fed/httpsig"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/spf13/cast" "github.com/spf13/cast"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype" "go.goblog.app/app/pkgs/contenttype"
) )
@ -89,7 +90,10 @@ func (a *goBlog) apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
return return
} }
apIri := a.apIri(blog) apIri := a.apIri(blog)
b, _ := json.Marshal(map[string]any{ // Encode
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err := xml.NewEncoder(buf).Encode(map[string]any{
"subject": a.webfingerAccts[apIri], "subject": a.webfingerAccts[apIri],
"aliases": []string{ "aliases": []string{
a.webfingerAccts[apIri], a.webfingerAccts[apIri],
@ -107,9 +111,12 @@ func (a *goBlog) apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
"href": apIri, "href": apIri,
}, },
}, },
}) }); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, "application/jrd+json"+contenttype.CharsetUtf8Suffix) w.Header().Set(contentType, "application/jrd+json"+contenttype.CharsetUtf8Suffix)
_, _ = a.min.Write(w, contenttype.JSON, b) _ = a.min.Get().Minify(contenttype.JSON, w, buf)
} }
func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) { func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {

View File

@ -10,6 +10,7 @@ import (
"github.com/araddon/dateparse" "github.com/araddon/dateparse"
ct "github.com/elnormous/contenttype" ct "github.com/elnormous/contenttype"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype" "go.goblog.app/app/pkgs/contenttype"
) )
@ -90,9 +91,14 @@ type asEndpoints struct {
} }
func (a *goBlog) serveActivityStreamsPost(p *post, w http.ResponseWriter) { func (a *goBlog) serveActivityStreamsPost(p *post, w http.ResponseWriter) {
b, _ := json.Marshal(a.toASNote(p)) buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err := json.NewEncoder(buf).Encode(a.toASNote(p)); err != nil {
http.Error(w, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.ASUTF8) w.Header().Set(contentType, contenttype.ASUTF8)
_, _ = a.min.Write(w, contenttype.AS, b) _ = a.min.Get().Minify(contenttype.AS, w, buf)
} }
func (a *goBlog) toASNote(p *post) *asNote { func (a *goBlog) toASNote(p *post) *asNote {
@ -195,7 +201,13 @@ func (a *goBlog) serveActivityStreams(blog string, w http.ResponseWriter, r *htt
URL: a.cfg.User.Picture, URL: a.cfg.User.Picture,
} }
} }
jb, _ := json.Marshal(asBlog) // Encode
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err := json.NewEncoder(buf).Encode(asBlog); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.ASUTF8) w.Header().Set(contentType, contenttype.ASUTF8)
_, _ = a.min.Write(w, contenttype.AS, jb) a.min.Get().Minify(contenttype.AS, w, buf)
} }

View File

@ -3,7 +3,6 @@ package main
import ( import (
"bytes" "bytes"
"context" "context"
"io"
"log" "log"
"net/http" "net/http"
"sort" "sort"
@ -54,20 +53,17 @@ func (a *goBlog) serveBlogrollExport(w http.ResponseWriter, r *http.Request) {
} }
opmlBuf := bufferpool.Get() opmlBuf := bufferpool.Get()
defer bufferpool.Put(opmlBuf) defer bufferpool.Put(opmlBuf)
mw := a.min.Writer(contenttype.XML, opmlBuf) if err = opml.Render(opmlBuf, &opml.OPML{
err = opml.Render(mw, &opml.OPML{
Version: "2.0", Version: "2.0",
DateCreated: time.Now().UTC(), DateCreated: time.Now().UTC(),
Outlines: outlines.([]*opml.Outline), Outlines: outlines.([]*opml.Outline),
}) }); err != nil {
_ = mw.Close()
if err != nil {
log.Printf("Failed to render OPML: %v", err) log.Printf("Failed to render OPML: %v", err)
a.serveError(w, r, "", http.StatusInternalServerError) a.serveError(w, r, "", http.StatusInternalServerError)
return return
} }
w.Header().Set(contentType, contenttype.XMLUTF8) w.Header().Set(contentType, contenttype.XMLUTF8)
_, _ = io.Copy(w, opmlBuf) _ = a.min.Get().Minify(contenttype.XML, w, opmlBuf)
} }
func (a *goBlog) getBlogrollOutlines(blog string) ([]*opml.Outline, error) { func (a *goBlog) getBlogrollOutlines(blog string) ([]*opml.Outline, error) {

View File

@ -138,7 +138,7 @@ func (a *goBlog) serveEditorPost(w http.ResponseWriter, r *http.Request) {
a.serveError(w, r, err.Error(), http.StatusBadRequest) a.serveError(w, r, err.Error(), http.StatusBadRequest)
return return
} }
gpx, err := io.ReadAll(a.min.Reader(contenttype.XML, file)) gpx, err := io.ReadAll(a.min.Get().Reader(contenttype.XML, file))
if err != nil { if err != nil {
a.serveError(w, r, err.Error(), http.StatusBadRequest) a.serveError(w, r, err.Error(), http.StatusBadRequest)
return return

View File

@ -74,6 +74,6 @@ func (a *goBlog) generateFeed(blog string, f feedType, w http.ResponseWriter, r
_ = pipeWriter.CloseWithError(writeErr) _ = pipeWriter.CloseWithError(writeErr)
}() }()
w.Header().Set(contentType, feedMediaType+contenttype.CharsetUtf8Suffix) w.Header().Set(contentType, feedMediaType+contenttype.CharsetUtf8Suffix)
minifyErr := a.min.Minify(feedMediaType, w, pipeReader) minifyErr := a.min.Get().Minify(feedMediaType, w, pipeReader)
_ = pipeReader.CloseWithError(minifyErr) _ = pipeReader.CloseWithError(minifyErr)
} }

View File

@ -18,15 +18,15 @@ func (a *goBlog) serveFs(f fs.FS, basePath string) http.HandlerFunc {
a.serve404(w, r) a.serve404(w, r)
return return
} }
var read io.Reader = file
switch path.Ext(fileName) { switch path.Ext(fileName) {
case ".js": case ".js":
w.Header().Set(contentType, contenttype.JSUTF8) w.Header().Set(contentType, contenttype.JSUTF8)
read = a.min.Reader(contenttype.JS, read) _ = a.min.Get().Minify(contenttype.JS, w, file)
case ".css": case ".css":
w.Header().Set(contentType, contenttype.CSSUTF8) w.Header().Set(contentType, contenttype.CSSUTF8)
read = a.min.Reader(contenttype.CSS, read) _ = a.min.Get().Minify(contenttype.CSS, w, file)
default:
_, _ = io.Copy(w, file)
} }
_, _ = io.Copy(w, read)
} }
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hacdias/indieauth/v2" "github.com/hacdias/indieauth/v2"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype" "go.goblog.app/app/pkgs/contenttype"
) )
@ -137,9 +138,14 @@ func (a *goBlog) indieAuthVerification(w http.ResponseWriter, r *http.Request, w
resp.Token = token resp.Token = token
resp.Scope = strings.Join(data.Scopes, " ") resp.Scope = strings.Join(data.Scopes, " ")
} }
b, _ := json.Marshal(resp) buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err = json.NewEncoder(buf).Encode(resp); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8) w.Header().Set(contentType, contenttype.JSONUTF8)
_, _ = a.min.Write(w, contenttype.JSON, b) _ = a.min.Get().Minify(contenttype.JSON, w, buf)
} }
// Save the authorization request and return the code // Save the authorization request and return the code
@ -196,9 +202,14 @@ func (a *goBlog) indieAuthTokenVerification(w http.ResponseWriter, r *http.Reque
Me: a.getFullAddress("") + "/", // MUST contain a path component / trailing slash Me: a.getFullAddress("") + "/", // MUST contain a path component / trailing slash
ClientID: data.ClientID, ClientID: data.ClientID,
} }
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err = json.NewEncoder(buf).Encode(res); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8) w.Header().Set(contentType, contenttype.JSONUTF8)
b, _ := json.Marshal(res) _ = a.min.Get().Minify(contenttype.JSON, w, buf)
_, _ = a.min.Write(w, contenttype.JSON, b)
} }
// Checks the database for the token and returns the indieAuthData with client and scope. // Checks the database for the token and returns the indieAuthData with client and scope.

View File

@ -73,15 +73,12 @@ func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
} }
buf := bufferpool.Get() buf := bufferpool.Get()
defer bufferpool.Put(buf) defer bufferpool.Put(buf)
mw := a.min.Writer(contenttype.JSON, buf) if err := json.NewEncoder(buf).Encode(result); err != nil {
err := json.NewEncoder(mw).Encode(result)
_ = mw.Close()
if err != nil {
a.serveError(w, r, "Failed to encode json", http.StatusInternalServerError) a.serveError(w, r, "Failed to encode json", http.StatusInternalServerError)
return return
} }
w.Header().Set(contentType, contenttype.JSONUTF8) w.Header().Set(contentType, contenttype.JSONUTF8)
_, _ = io.Copy(w, buf) _ = a.min.Get().Minify(contenttype.JSON, w, buf)
} }
func (a *goBlog) serveMicropubPost(w http.ResponseWriter, r *http.Request) { func (a *goBlog) serveMicropubPost(w http.ResponseWriter, r *http.Request) {

View File

@ -38,22 +38,22 @@ func Test_micropubQuery(t *testing.T) {
testCases := []testCase{ testCases := []testCase{
{ {
query: "config", query: "config",
want: "{\"media-endpoint\":\"http://localhost:8080/micropub/media\"}\n", want: "{\"media-endpoint\":\"http://localhost:8080/micropub/media\"}",
wantStatus: http.StatusOK, wantStatus: http.StatusOK,
}, },
{ {
query: "source&url=http://localhost:8080/test/post", query: "source&url=http://localhost:8080/test/post",
want: "{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}\n", want: "{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}",
wantStatus: http.StatusOK, wantStatus: http.StatusOK,
}, },
{ {
query: "source", query: "source",
want: "{\"items\":[{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}]}\n", want: "{\"items\":[{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}]}",
wantStatus: http.StatusOK, wantStatus: http.StatusOK,
}, },
{ {
query: "category", query: "category",
want: "{\"categories\":[\"test\",\"test2\"]}\n", want: "{\"categories\":[\"test\",\"test2\"]}",
wantStatus: http.StatusOK, wantStatus: http.StatusOK,
}, },
{ {

View File

@ -25,7 +25,7 @@ func (a *goBlog) serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set(contentType, contenttype.JSONUTF8) w.Header().Set(contentType, contenttype.JSONUTF8)
mw := a.min.Writer(contenttype.JSON, w) mw := a.min.Get().Writer(contenttype.JSON, w)
_, _ = io.Copy(mw, buf) _, _ = io.Copy(mw, buf)
_ = mw.Close() _ = mw.Close()
} }
@ -36,7 +36,7 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
}) })
buf := bufferpool.Get() buf := bufferpool.Get()
defer bufferpool.Put(buf) defer bufferpool.Put(buf)
err := json.NewEncoder(buf).Encode(map[string]any{ if err := json.NewEncoder(buf).Encode(map[string]any{
"version": "2.1", "version": "2.1",
"software": map[string]any{ "software": map[string]any{
"name": "goblog", "name": "goblog",
@ -54,13 +54,10 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
"webmention", "webmention",
}, },
"metadata": map[string]any{}, "metadata": map[string]any{},
}) }); err != nil {
if err != nil {
a.serveError(w, r, "", http.StatusInternalServerError) a.serveError(w, r, "", http.StatusInternalServerError)
return return
} }
w.Header().Set(contentType, contenttype.JSONUTF8) w.Header().Set(contentType, contenttype.JSONUTF8)
mw := a.min.Writer(contenttype.JSON, w) _ = a.min.Get().Minify(contenttype.JSON, w, buf)
_, _ = io.Copy(mw, buf)
_ = mw.Close()
} }

View File

@ -2,9 +2,9 @@ package main
import ( import (
"encoding/xml" "encoding/xml"
"io"
"net/http" "net/http"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype" "go.goblog.app/app/pkgs/contenttype"
) )
@ -35,7 +35,6 @@ func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) {
_, b := a.getBlog(r) _, b := a.getBlog(r)
title := a.renderMdTitle(b.Title) title := a.renderMdTitle(b.Title)
sURL := a.getFullAddress(b.getRelativePath(defaultIfEmpty(b.Search.Path, defaultSearchPath))) sURL := a.getFullAddress(b.getRelativePath(defaultIfEmpty(b.Search.Path, defaultSearchPath)))
w.Header().Set(contentType, "application/opensearchdescription+xml"+contenttype.CharsetUtf8Suffix)
openSearch := &openSearchDescription{ openSearch := &openSearchDescription{
ShortName: title, ShortName: title,
Description: title, Description: title,
@ -50,10 +49,15 @@ func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) {
}, },
SearchForm: sURL, SearchForm: sURL,
} }
mw := a.min.Writer(contenttype.XML, w) buf := bufferpool.Get()
_, _ = io.WriteString(mw, xml.Header) defer bufferpool.Put(buf)
_ = xml.NewEncoder(mw).Encode(openSearch) _, _ = buf.WriteString(xml.Header)
_ = mw.Close() if err := xml.NewEncoder(buf).Encode(openSearch); err != nil {
a.serveError(w, r, "", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, "application/opensearchdescription+xml"+contenttype.CharsetUtf8Suffix)
_ = a.min.Get().Minify(contenttype.XML, w, buf)
} }
func openSearchUrl(b *configBlog) string { func openSearchUrl(b *configBlog) string {

View File

@ -1,7 +1,6 @@
package minify package minify
import ( import (
"io"
"sync" "sync"
"github.com/tdewolff/minify/v2" "github.com/tdewolff/minify/v2"
@ -21,12 +20,18 @@ type Minifier struct {
func (m *Minifier) init() { func (m *Minifier) init() {
m.i.Do(func() { m.i.Do(func() {
m.m = minify.New() m.m = minify.New()
// HTML
m.m.AddFunc(contenttype.HTML, mHtml.Minify) m.m.AddFunc(contenttype.HTML, mHtml.Minify)
// CSS
m.m.AddFunc(contenttype.CSS, mCss.Minify) m.m.AddFunc(contenttype.CSS, mCss.Minify)
m.m.AddFunc(contenttype.XML, mXml.Minify) // JS
m.m.AddFunc(contenttype.JS, mJs.Minify) m.m.AddFunc(contenttype.JS, mJs.Minify)
// XML
m.m.AddFunc(contenttype.XML, mXml.Minify)
m.m.AddFunc(contenttype.RSS, mXml.Minify) m.m.AddFunc(contenttype.RSS, mXml.Minify)
m.m.AddFunc(contenttype.ATOM, mXml.Minify) m.m.AddFunc(contenttype.ATOM, mXml.Minify)
// JSON
m.m.AddFunc(contenttype.JSON, mJson.Minify)
m.m.AddFunc(contenttype.JSONFeed, mJson.Minify) m.m.AddFunc(contenttype.JSONFeed, mJson.Minify)
m.m.AddFunc(contenttype.AS, mJson.Minify) m.m.AddFunc(contenttype.AS, mJson.Minify)
}) })
@ -36,21 +41,3 @@ func (m *Minifier) Get() *minify.M {
m.init() m.init()
return m.m return m.m
} }
func (m *Minifier) Write(w io.Writer, mediatype string, b []byte) (int, error) {
mw := m.Writer(mediatype, w)
defer mw.Close()
return mw.Write(b)
}
func (m *Minifier) Minify(mediatype string, w io.Writer, r io.Reader) error {
return m.Get().Minify(mediatype, w, r)
}
func (m *Minifier) Writer(mediatype string, w io.Writer) io.WriteCloser {
return m.Get().Writer(mediatype, w)
}
func (m *Minifier) Reader(mediatype string, r io.Reader) io.Reader {
return m.Get().Reader(mediatype, r)
}

View File

@ -41,13 +41,10 @@ func (a *goBlog) renderWithStatusCode(w http.ResponseWriter, r *http.Request, st
// Render // Render
pipeReader, pipeWriter := io.Pipe() pipeReader, pipeWriter := io.Pipe()
go func() { go func() {
minifyWriter := a.min.Writer(contenttype.HTML, pipeWriter) f(newHtmlBuilder(pipeWriter), data)
f(newHtmlBuilder(minifyWriter), data)
_ = minifyWriter.Close()
_ = pipeWriter.Close() _ = pipeWriter.Close()
}() }()
_, readErr := io.Copy(w, pipeReader) _ = pipeReader.CloseWithError(a.min.Get().Minify(contenttype.HTML, w, pipeReader))
_ = pipeReader.CloseWithError(readErr)
} }
func (a *goBlog) checkRenderData(r *http.Request, data *renderData) { func (a *goBlog) checkRenderData(r *http.Request, data *renderData) {

View File

@ -3,12 +3,12 @@ package main
import ( import (
"database/sql" "database/sql"
"encoding/xml" "encoding/xml"
"io"
"net/http" "net/http"
"time" "time"
"github.com/araddon/dateparse" "github.com/araddon/dateparse"
"github.com/snabb/sitemap" "github.com/snabb/sitemap"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype" "go.goblog.app/app/pkgs/contenttype"
) )
@ -20,7 +20,7 @@ const (
sitemapBlogPostsPath = "/sitemap-blog-posts.xml" sitemapBlogPostsPath = "/sitemap-blog-posts.xml"
) )
func (a *goBlog) serveSitemap(w http.ResponseWriter, _ *http.Request) { func (a *goBlog) serveSitemap(w http.ResponseWriter, r *http.Request) {
// Create sitemap // Create sitemap
sm := sitemap.NewSitemapIndex() sm := sitemap.NewSitemapIndex()
// Add blog sitemap indices // Add blog sitemap indices
@ -32,7 +32,7 @@ func (a *goBlog) serveSitemap(w http.ResponseWriter, _ *http.Request) {
}) })
} }
// Write sitemap // Write sitemap
a.writeSitemapXML(w, sm) a.writeSitemapXML(w, r, sm)
} }
func (a *goBlog) serveSitemapBlog(w http.ResponseWriter, r *http.Request) { func (a *goBlog) serveSitemapBlog(w http.ResponseWriter, r *http.Request) {
@ -54,7 +54,7 @@ func (a *goBlog) serveSitemapBlog(w http.ResponseWriter, r *http.Request) {
LastMod: &now, LastMod: &now,
}) })
// Write sitemap // Write sitemap
a.writeSitemapXML(w, sm) a.writeSitemapXML(w, r, sm)
} }
func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request) { func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request) {
@ -103,7 +103,7 @@ func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request
}) })
} }
// Write sitemap // Write sitemap
a.writeSitemapXML(w, sm) a.writeSitemapXML(w, r, sm)
} }
func (a *goBlog) serveSitemapBlogArchives(w http.ResponseWriter, r *http.Request) { func (a *goBlog) serveSitemapBlogArchives(w http.ResponseWriter, r *http.Request) {
@ -145,7 +145,7 @@ func (a *goBlog) serveSitemapBlogArchives(w http.ResponseWriter, r *http.Request
}) })
} }
// Write sitemap // Write sitemap
a.writeSitemapXML(w, sm) a.writeSitemapXML(w, r, sm)
} }
// Serve sitemap with all the blog's posts // Serve sitemap with all the blog's posts
@ -169,24 +169,22 @@ func (a *goBlog) serveSitemapBlogPosts(w http.ResponseWriter, r *http.Request) {
sm.Add(item) sm.Add(item)
} }
// Write sitemap // Write sitemap
a.writeSitemapXML(w, sm) a.writeSitemapXML(w, r, sm)
} }
func (a *goBlog) writeSitemapXML(w http.ResponseWriter, sm any) { func (a *goBlog) writeSitemapXML(w http.ResponseWriter, r *http.Request, sm any) {
buf := bufferpool.Get()
defer bufferpool.Put(buf)
_, _ = buf.WriteString(xml.Header)
_, _ = buf.WriteString(`<?xml-stylesheet type="text/xsl" href="`)
_, _ = buf.WriteString(a.assetFileName("sitemap.xsl"))
_, _ = buf.WriteString(`" ?>`)
if err := xml.NewEncoder(buf).Encode(sm); err != nil {
a.serveError(w, r, "Failed to encode sitemap", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.XMLUTF8) w.Header().Set(contentType, contenttype.XMLUTF8)
pipeReader, pipeWriter := io.Pipe() _ = a.min.Get().Minify(contenttype.XML, w, buf)
go func() {
mw := a.min.Writer(contenttype.XML, pipeWriter)
_, _ = io.WriteString(mw, xml.Header)
_, _ = io.WriteString(mw, `<?xml-stylesheet type="text/xsl" href="`)
_, _ = io.WriteString(mw, a.assetFileName("sitemap.xsl"))
_, _ = io.WriteString(mw, `" ?>`)
writeErr := xml.NewEncoder(mw).Encode(sm)
_ = mw.Close()
_ = pipeWriter.CloseWithError(writeErr)
}()
_, copyErr := io.Copy(w, pipeReader)
_ = pipeReader.CloseWithError(copyErr)
} }
const sitemapDatePathsSql = ` const sitemapDatePathsSql = `

View File

@ -53,11 +53,11 @@ func (a *goBlog) compileAsset(name string, read io.Reader) error {
ext := path.Ext(name) ext := path.Ext(name)
switch ext { switch ext {
case ".js": case ".js":
read = a.min.Reader(contenttype.JS, read) read = a.min.Get().Reader(contenttype.JS, read)
case ".css": case ".css":
read = a.min.Reader(contenttype.CSS, read) read = a.min.Get().Reader(contenttype.CSS, read)
case ".xml", ".xsl": case ".xml", ".xsl":
read = a.min.Reader(contenttype.XML, read) read = a.min.Get().Reader(contenttype.XML, read)
} }
// Read file // Read file
hash := sha256.New() hash := sha256.New()