Compress HTML responses to Gzip/Deflate if supported by browser

This commit is contained in:
Frédéric Guillot 2018-07-06 20:39:28 -07:00
parent 53deb0b8cd
commit 34a3fe426b
40 changed files with 82 additions and 58 deletions

View File

@ -7,13 +7,14 @@ package html
import (
"net/http"
"github.com/miniflux/miniflux/http/response"
"github.com/miniflux/miniflux/logger"
)
// OK writes a standard HTML response.
func OK(w http.ResponseWriter, b []byte) {
func OK(w http.ResponseWriter, r *http.Request, b []byte) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write(b)
response.Compress(w, r, b)
}
// ServerError sends a 500 error to the browser.

View File

@ -5,7 +5,10 @@
package response
import (
"compress/flate"
"compress/gzip"
"net/http"
"strings"
"time"
)
@ -32,3 +35,23 @@ func Cache(w http.ResponseWriter, r *http.Request, mimeType, etag string, conten
w.Write(content)
}
}
// Compress the response sent to the browser.
func Compress(w http.ResponseWriter, r *http.Request, data []byte) {
acceptEncoding := r.Header.Get("Accept-Encoding")
switch {
case strings.Contains(acceptEncoding, "gzip"):
w.Header().Set("Content-Encoding", "gzip")
gzipWriter := gzip.NewWriter(w)
defer gzipWriter.Close()
gzipWriter.Write(data)
case strings.Contains(acceptEncoding, "deflate"):
w.Header().Set("Content-Encoding", "deflate")
flateWriter, _ := flate.NewWriter(w, -1)
defer flateWriter.Close()
flateWriter.Write(data)
default:
w.Write(data)
}
}

View File

@ -32,5 +32,5 @@ func (c *Controller) About(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("about"))
html.OK(w, r, view.Render("about"))
}

View File

@ -58,5 +58,5 @@ func (c *Controller) ShowStarredPage(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("bookmark_entries"))
html.OK(w, r, view.Render("bookmark_entries"))
}

View File

@ -29,5 +29,5 @@ func (c *Controller) CreateCategory(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("create_category"))
html.OK(w, r, view.Render("create_category"))
}

View File

@ -54,5 +54,5 @@ func (c *Controller) EditCategory(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("edit_category"))
html.OK(w, r, view.Render("edit_category"))
}

View File

@ -75,5 +75,5 @@ func (c *Controller) CategoryEntries(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("category_entries"))
html.OK(w, r, view.Render("category_entries"))
}

View File

@ -37,5 +37,5 @@ func (c *Controller) CategoryList(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("categories"))
html.OK(w, r, view.Render("categories"))
}

View File

@ -39,7 +39,7 @@ func (c *Controller) SaveCategory(w http.ResponseWriter, r *http.Request) {
if err := categoryForm.Validate(); err != nil {
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("create_category"))
html.OK(w, r, view.Render("create_category"))
return
}
@ -51,7 +51,7 @@ func (c *Controller) SaveCategory(w http.ResponseWriter, r *http.Request) {
if duplicateCategory != nil {
view.Set("errorMessage", "This category already exists.")
html.OK(w, view.Render("create_category"))
html.OK(w, r, view.Render("create_category"))
return
}
@ -63,7 +63,7 @@ func (c *Controller) SaveCategory(w http.ResponseWriter, r *http.Request) {
if err = c.store.CreateCategory(&category); err != nil {
logger.Error("[Controller:CreateCategory] %v", err)
view.Set("errorMessage", "Unable to create this category.")
html.OK(w, view.Render("create_category"))
html.OK(w, r, view.Render("create_category"))
return
}

View File

@ -57,13 +57,13 @@ func (c *Controller) UpdateCategory(w http.ResponseWriter, r *http.Request) {
if err := categoryForm.Validate(); err != nil {
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("edit_category"))
html.OK(w, r, view.Render("edit_category"))
return
}
if c.store.AnotherCategoryExists(user.ID, category.ID, categoryForm.Title) {
view.Set("errorMessage", "This category already exists.")
html.OK(w, view.Render("edit_category"))
html.OK(w, r, view.Render("edit_category"))
return
}
@ -71,7 +71,7 @@ func (c *Controller) UpdateCategory(w http.ResponseWriter, r *http.Request) {
if err != nil {
logger.Error("[Controller:UpdateCategory] %v", err)
view.Set("errorMessage", "Unable to update this category.")
html.OK(w, view.Render("edit_category"))
html.OK(w, r, view.Render("edit_category"))
return
}

View File

@ -88,5 +88,5 @@ func (c *Controller) ShowStarredEntry(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("entry"))
html.OK(w, r, view.Render("entry"))
}

View File

@ -95,5 +95,5 @@ func (c *Controller) ShowCategoryEntry(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("entry"))
html.OK(w, r, view.Render("entry"))
}

View File

@ -95,5 +95,5 @@ func (c *Controller) ShowFeedEntry(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("entry"))
html.OK(w, r, view.Render("entry"))
}

View File

@ -78,5 +78,5 @@ func (c *Controller) ShowReadEntry(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("entry"))
html.OK(w, r, view.Render("entry"))
}

View File

@ -91,5 +91,5 @@ func (c *Controller) ShowSearchEntry(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("entry"))
html.OK(w, r, view.Render("entry"))
}

View File

@ -99,5 +99,5 @@ func (c *Controller) ShowUnreadEntry(w http.ResponseWriter, r *http.Request) {
// Fetching the counter here avoid to be off by one.
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("entry"))
html.OK(w, r, view.Render("entry"))
}

View File

@ -69,5 +69,5 @@ func (c *Controller) EditFeed(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("edit_feed"))
html.OK(w, r, view.Render("edit_feed"))
}

View File

@ -75,5 +75,5 @@ func (c *Controller) ShowFeedEntries(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("feed_entries"))
html.OK(w, r, view.Render("feed_entries"))
}

View File

@ -37,5 +37,5 @@ func (c *Controller) ShowFeedsPage(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("feeds"))
html.OK(w, r, view.Render("feeds"))
}

View File

@ -64,7 +64,7 @@ func (c *Controller) UpdateFeed(w http.ResponseWriter, r *http.Request) {
if err := feedForm.ValidateModification(); err != nil {
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("edit_feed"))
html.OK(w, r, view.Render("edit_feed"))
return
}
@ -72,7 +72,7 @@ func (c *Controller) UpdateFeed(w http.ResponseWriter, r *http.Request) {
if err != nil {
logger.Error("[Controller:EditFeed] %v", err)
view.Set("errorMessage", "Unable to update this feed.")
html.OK(w, view.Render("edit_feed"))
html.OK(w, r, view.Render("edit_feed"))
return
}

View File

@ -56,5 +56,5 @@ func (c *Controller) ShowHistoryPage(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("history_entries"))
html.OK(w, r, view.Render("history_entries"))
}

View File

@ -63,5 +63,5 @@ func (c *Controller) ShowIntegrations(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasPocketConsumerKeyConfigured", c.cfg.PocketConsumerKey("") != "")
html.OK(w, view.Render("integrations"))
html.OK(w, r, view.Render("integrations"))
}

View File

@ -28,13 +28,13 @@ func (c *Controller) CheckLogin(w http.ResponseWriter, r *http.Request) {
if err := authForm.Validate(); err != nil {
logger.Error("[Controller:CheckLogin] %v", err)
html.OK(w, view.Render("login"))
html.OK(w, r, view.Render("login"))
return
}
if err := c.store.CheckPassword(authForm.Username, authForm.Password); err != nil {
logger.Error("[Controller:CheckLogin] %v", err)
html.OK(w, view.Render("login"))
html.OK(w, r, view.Render("login"))
return
}

View File

@ -25,5 +25,5 @@ func (c *Controller) ShowLoginPage(w http.ResponseWriter, r *http.Request) {
sess := session.New(c.store, ctx)
view := view.New(c.tpl, ctx, sess)
html.OK(w, view.Render("login"))
html.OK(w, r, view.Render("login"))
}

View File

@ -29,5 +29,5 @@ func (c *Controller) Import(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("import"))
html.OK(w, r, view.Render("import"))
}

View File

@ -50,13 +50,13 @@ func (c *Controller) UploadOPML(w http.ResponseWriter, r *http.Request) {
if fileHeader.Size == 0 {
view.Set("errorMessage", "This file is empty")
html.OK(w, view.Render("import"))
html.OK(w, r, view.Render("import"))
return
}
if impErr := opml.NewHandler(c.store).Import(user.ID, file); impErr != nil {
view.Set("errorMessage", impErr)
html.OK(w, view.Render("import"))
html.OK(w, r, view.Render("import"))
return
}

View File

@ -62,5 +62,5 @@ func (c *Controller) ShowSearchEntries(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("search_entries"))
html.OK(w, r, view.Render("search_entries"))
}

View File

@ -40,5 +40,5 @@ func (c *Controller) ShowSessions(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("sessions"))
html.OK(w, r, view.Render("sessions"))
}

View File

@ -50,5 +50,5 @@ func (c *Controller) ShowSettings(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("settings"))
html.OK(w, r, view.Render("settings"))
}

View File

@ -49,13 +49,13 @@ func (c *Controller) UpdateSettings(w http.ResponseWriter, r *http.Request) {
if err := settingsForm.Validate(); err != nil {
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("settings"))
html.OK(w, r, view.Render("settings"))
return
}
if c.store.AnotherUserExists(user.ID, settingsForm.Username) {
view.Set("errorMessage", "This user already exists.")
html.OK(w, view.Render("settings"))
html.OK(w, r, view.Render("settings"))
return
}
@ -63,7 +63,7 @@ func (c *Controller) UpdateSettings(w http.ResponseWriter, r *http.Request) {
if err != nil {
logger.Error("[Controller:UpdateSettings] %v", err)
view.Set("errorMessage", "Unable to update this user.")
html.OK(w, view.Render("settings"))
html.OK(w, r, view.Render("settings"))
return
}

View File

@ -36,5 +36,5 @@ func (c *Controller) AddSubscription(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("add_subscription"))
html.OK(w, r, view.Render("add_subscription"))
}

View File

@ -41,5 +41,5 @@ func (c *Controller) Bookmarklet(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("add_subscription"))
html.OK(w, r, view.Render("add_subscription"))
}

View File

@ -43,7 +43,7 @@ func (c *Controller) ChooseSubscription(w http.ResponseWriter, r *http.Request)
if err := subscriptionForm.Validate(); err != nil {
view.Set("form", subscriptionForm)
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("add_subscription"))
html.OK(w, r, view.Render("add_subscription"))
return
}
@ -58,7 +58,7 @@ func (c *Controller) ChooseSubscription(w http.ResponseWriter, r *http.Request)
if err != nil {
view.Set("form", subscriptionForm)
view.Set("errorMessage", err)
html.OK(w, view.Render("add_subscription"))
html.OK(w, r, view.Render("add_subscription"))
return
}

View File

@ -45,7 +45,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
if err := subscriptionForm.Validate(); err != nil {
v.Set("form", subscriptionForm)
v.Set("errorMessage", err.Error())
html.OK(w, v.Render("add_subscription"))
html.OK(w, r, v.Render("add_subscription"))
return
}
@ -58,7 +58,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
logger.Error("[Controller:SubmitSubscription] %v", err)
v.Set("form", subscriptionForm)
v.Set("errorMessage", err)
html.OK(w, v.Render("add_subscription"))
html.OK(w, r, v.Render("add_subscription"))
return
}
@ -69,7 +69,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
case n == 0:
v.Set("form", subscriptionForm)
v.Set("errorMessage", "Unable to find any subscription.")
html.OK(w, v.Render("add_subscription"))
html.OK(w, r, v.Render("add_subscription"))
case n == 1:
feed, err := c.feedHandler.CreateFeed(
user.ID,
@ -82,7 +82,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
if err != nil {
v.Set("form", subscriptionForm)
v.Set("errorMessage", err)
html.OK(w, v.Render("add_subscription"))
html.OK(w, r, v.Render("add_subscription"))
return
}
@ -95,6 +95,6 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
v.Set("user", user)
v.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, v.Render("choose_subscription"))
html.OK(w, r, v.Render("choose_subscription"))
}
}

View File

@ -60,5 +60,5 @@ func (c *Controller) ShowUnreadPage(w http.ResponseWriter, r *http.Request) {
view.Set("countUnread", countUnread)
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, view.Render("unread_entries"))
html.OK(w, r, view.Render("unread_entries"))
}

View File

@ -36,5 +36,5 @@ func (c *Controller) CreateUser(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("create_user"))
html.OK(w, r, view.Render("create_user"))
}

View File

@ -60,5 +60,5 @@ func (c *Controller) EditUser(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("edit_user"))
html.OK(w, r, view.Render("edit_user"))
}

View File

@ -43,5 +43,5 @@ func (c *Controller) ShowUsers(w http.ResponseWriter, r *http.Request) {
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
html.OK(w, view.Render("users"))
html.OK(w, r, view.Render("users"))
}

View File

@ -43,13 +43,13 @@ func (c *Controller) SaveUser(w http.ResponseWriter, r *http.Request) {
if err := userForm.ValidateCreation(); err != nil {
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("create_user"))
html.OK(w, r, view.Render("create_user"))
return
}
if c.store.UserExists(userForm.Username) {
view.Set("errorMessage", "This user already exists.")
html.OK(w, view.Render("create_user"))
html.OK(w, r, view.Render("create_user"))
return
}
@ -57,7 +57,7 @@ func (c *Controller) SaveUser(w http.ResponseWriter, r *http.Request) {
if err := c.store.CreateUser(newUser); err != nil {
logger.Error("[Controller:SaveUser] %v", err)
view.Set("errorMessage", "Unable to create this user.")
html.OK(w, view.Render("create_user"))
html.OK(w, r, view.Render("create_user"))
return
}

View File

@ -62,13 +62,13 @@ func (c *Controller) UpdateUser(w http.ResponseWriter, r *http.Request) {
if err := userForm.ValidateModification(); err != nil {
view.Set("errorMessage", err.Error())
html.OK(w, view.Render("edit_user"))
html.OK(w, r, view.Render("edit_user"))
return
}
if c.store.AnotherUserExists(selectedUser.ID, userForm.Username) {
view.Set("errorMessage", "This user already exists.")
html.OK(w, view.Render("edit_user"))
html.OK(w, r, view.Render("edit_user"))
return
}
@ -76,7 +76,7 @@ func (c *Controller) UpdateUser(w http.ResponseWriter, r *http.Request) {
if err := c.store.UpdateUser(selectedUser); err != nil {
logger.Error("[Controller:UpdateUser] %v", err)
view.Set("errorMessage", "Unable to update this user.")
html.OK(w, view.Render("edit_user"))
html.OK(w, r, view.Render("edit_user"))
return
}