Server push is back. But only for Chrome and Firefox.

Added the DisableServerPush and EnableCDNPush config.json settings.
This commit is contained in:
Azareal 2019-04-02 17:43:11 +10:00
parent 167bb230b4
commit af9a56a9a9
9 changed files with 116 additions and 33 deletions

View File

@ -10,10 +10,10 @@ import (
"github.com/Azareal/Gosora/common/phrases"
)
type HResource struct {
/*type HResource struct {
Name string
Hash string
}
}*/
// TODO: Allow resources in spots other than /static/ and possibly even external domains (e.g. CDNs)
// TODO: Preload Trumboyg on Cosora on the forum list
@ -21,11 +21,11 @@ type Header struct {
Title string
//Title []byte // Experimenting with []byte for increased efficiency, let's avoid converting too many things to []byte, as it involves a lot of extra boilerplate
NoticeList []string
Scripts []HResource
PreScriptsAsync []HResource
ScriptsAsync []HResource
Scripts []string
PreScriptsAsync []string
ScriptsAsync []string
//Preload []string
Stylesheets []HResource
Stylesheets []string
Widgets PageWidgets
Site *site
Settings SettingMap
@ -51,40 +51,48 @@ type Header struct {
func (header *Header) AddScript(name string) {
fname := "/static/" + name
var hash string
var oname string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
oname = name + "?h=" + file.Sha256
}
}
//log.Print("name:", name)
//log.Print("hash:", hash)
header.Scripts = append(header.Scripts, HResource{name, hash})
if oname == "" {
oname = name
}
//log.Print("oname:", oname)
header.Scripts = append(header.Scripts, oname)
}
func (header *Header) AddPreScriptAsync(name string) {
fname := "/static/" + name
var hash string
var oname string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
oname = name + "?h=" + file.Sha256
}
}
header.PreScriptsAsync = append(header.PreScriptsAsync, HResource{name, hash})
if oname == "" {
oname = name
}
header.PreScriptsAsync = append(header.PreScriptsAsync, oname)
}
func (header *Header) AddScriptAsync(name string) {
fname := "/static/" + name
var hash string
var oname string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
oname = name + "?h=" + file.Sha256
}
}
header.ScriptsAsync = append(header.ScriptsAsync, HResource{name, hash})
if oname == "" {
oname = name
}
header.ScriptsAsync = append(header.ScriptsAsync, oname)
}
/*func (header *Header) Preload(name string) {
@ -93,14 +101,17 @@ func (header *Header) AddScriptAsync(name string) {
func (header *Header) AddSheet(name string) {
fname := "/static/" + name
var hash string
var oname string
if fname[0] == '/' && fname[1] != '/' {
file, ok := StaticFiles.Get(fname)
if ok {
hash = file.Sha256
oname = name + "?h=" + file.Sha256
}
}
header.Stylesheets = append(header.Stylesheets, HResource{name, hash})
if oname == "" {
oname = name
}
header.Stylesheets = append(header.Stylesheets, oname)
}
func (header *Header) AddNotice(name string) {

View File

@ -90,6 +90,8 @@ type config struct {
DisableLiveTopicList bool
DisableJSAntispam bool
//LooseCSP bool
DisableServerPush bool
EnableCDNPush bool
Noavatar string // ? - Move this into the settings table?
ItemsPerPage int // ? - Move this into the settings table?

View File

@ -89,14 +89,14 @@ var Template_account_handle = genIntTmpl("account")
func tmplInitUsers() (User, User, User) {
avatar, microAvatar := BuildAvatar(62, "")
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", "", "", 0, 0, 0, "0.0.0.0.0", 0}
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", "", "", 0, 0, 0, "0.0.0.0.0", "", 0}
// TODO: Do a more accurate level calculation for this?
avatar, microAvatar = BuildAvatar(1, "")
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 58, 1000, 0, "127.0.0.1", 0}
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 58, 1000, 0, "127.0.0.1", "", 0}
avatar, microAvatar = BuildAvatar(2, "")
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 42, 900, 0, "::1", 0}
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 42, 900, 0, "::1", "", 0}
return user, user2, user3
}
@ -108,10 +108,10 @@ func tmplInitHeaders(user User, user2 User, user3 User) (*Header, *Header, *Head
Theme: Themes[DefaultThemeBox.Load().(string)],
CurrentUser: user,
NoticeList: []string{"test"},
Stylesheets: []HResource{HResource{"panel.css", "d"}},
Scripts: []HResource{HResource{"whatever.js", "d"}},
PreScriptsAsync: []HResource{HResource{"whatever.js", "d"}},
ScriptsAsync: []HResource{HResource{"whatever.js", "d"}},
Stylesheets: []string{"panel.css"},
Scripts: []string{"whatever.js"},
PreScriptsAsync: []string{"whatever.js"},
ScriptsAsync: []string{"whatever.js"},
Widgets: PageWidgets{
LeftSidebar: template.HTML("lalala"),
},

View File

@ -53,6 +53,7 @@ type User struct {
Score int
Liked int
LastIP string // ! This part of the UserCache data might fall out of date
LastAgent string // ! Temporary hack, don't use
TempGroup int
}

View File

@ -76,6 +76,10 @@ DisableLiveTopicList - This switch allows you to disable the live topic list.
DisableJSAntispam - This switch lets you disable the JS anti-spam feature. It may be useful if you primarily get users who for one reason or another have decided to disable JavaScript.
DisableServerPush - This switch lets you disable the HTTP/2 server push feature.
EnableCDNPush - This switch lets you enable the HTTP/2 CDN Server Push feature. This operates by sending a Link header on every request and may also work with reverse-proxies like Nginx for doing HTTP/2 server pushes.
NoAvatar - The default avatar to use for users when they don't have their own. The default for this may change in the near future to better utilise HTTP/2. Example: https://api.adorable.io/avatars/{width}/{id}.png
ItemsPerPage - The number of posts, topics, etc. you want on each page.

View File

@ -824,6 +824,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Add a setting to disable this?
// TODO: Use a more efficient detector instead of smashing every possible combination in
ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another
var agent string
if ua == "" {
counters.AgentViewCounter.Bump(26)
if common.Dev.DebugMode {
@ -878,7 +879,6 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
// Iterate over this in reverse as the real UA tends to be on the right side
var agent string
for i := len(items) - 1; i >= 0; i-- {
fAgent, ok := markToAgent[items[i]]
if ok {
@ -974,6 +974,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !ok {
return
}
user.LastAgent = agent
if common.Dev.SuperDebug {
r.requestLogger.Print(
"after PreRoute\n" +

View File

@ -603,6 +603,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Add a setting to disable this?
// TODO: Use a more efficient detector instead of smashing every possible combination in
ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another
var agent string
if ua == "" {
counters.AgentViewCounter.Bump({{.AllAgentMap.blank}})
if common.Dev.DebugMode {
@ -657,7 +658,6 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
// Iterate over this in reverse as the real UA tends to be on the right side
var agent string
for i := len(items) - 1; i >= 0; i-- {
fAgent, ok := markToAgent[items[i]]
if ok {
@ -753,6 +753,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !ok {
return
}
user.LastAgent = agent
if common.Dev.SuperDebug {
r.requestLogger.Print(
"after PreRoute\n" +

View File

@ -1,6 +1,7 @@
package routes
import (
//"fmt"
"net/http"
"strconv"
"strings"
@ -20,6 +21,60 @@ func ParseSEOURL(urlBit string) (slug string, id int, err error) {
return halves[0], tid, err
}
func doPush(w http.ResponseWriter, header *common.Header) {
//fmt.Println("in doPush")
if common.Config.EnableCDNPush {
// TODO: Faster string building...
var sbuf string
var push = func(in []string) {
for _, path := range in {
sbuf += "</static/" + path + ">; rel=preload; as=script,"
}
}
push(header.Scripts)
//push(header.PreScriptsAsync)
push(header.ScriptsAsync)
if len(header.Stylesheets) > 0 {
for _, path := range header.Stylesheets {
sbuf += "</static/" + path + ">; rel=preload; as=style,"
}
}
// TODO: Push avatars?
if len(sbuf) > 0 {
sbuf = sbuf[:len(sbuf)-1]
w.Header().Set("Link", sbuf)
}
} else if !common.Config.DisableServerPush {
//fmt.Println("push enabled")
gzw, ok := w.(common.GzipResponseWriter)
if ok {
w = gzw.ResponseWriter
}
pusher, ok := w.(http.Pusher)
if !ok {
return
}
//fmt.Println("has pusher")
var push = func(in []string) {
for _, path := range in {
//fmt.Println("pushing /static/" + path)
err := pusher.Push("/static/"+path, nil)
if err != nil {
break
}
}
}
push(header.Scripts)
//push(header.PreScriptsAsync)
push(header.ScriptsAsync)
push(header.Stylesheets)
// TODO: Push avatars?
}
}
func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *common.Header, pi interface{}) common.RouteError {
if header.CurrentUser.Loggedin {
header.MetaDesc = ""
@ -32,6 +87,14 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com;upgrade-insecure-requests")
}
header.AddScript("global.js")
// Server pushes can backfire on certain browsers, so we want to make sure it's only triggered for ones where it'll help
lastAgent := header.CurrentUser.LastAgent
//fmt.Println("lastAgent:", lastAgent)
if lastAgent == "chrome" || lastAgent == "firefox" {
doPush(w, header)
}
if header.CurrentUser.IsAdmin {
header.Elapsed1 = time.Since(header.StartedAt).String()
}

View File

@ -3,16 +3,16 @@
<head>
<title>{{.Title}} | {{.Header.Site.Name}}</title>
{{range .Header.Stylesheets}}
<link href="/static/{{.Name}}{{if .Hash}}?h={{.Hash}}{{end}}" rel="stylesheet" type="text/css">{{end}}
<link href="/static/{{.}}" rel="stylesheet" type="text/css">{{end}}
{{range .Header.PreScriptsAsync}}
<script async type="text/javascript" src="/static/{{.Name}}{{if .Hash}}?h={{.Hash}}{{end}}"></script>{{end}}
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
<script type="text/javascript" src="/static/init.js"></script>
{{range .Header.ScriptsAsync}}
<script async type="text/javascript" src="/static/{{.Name}}{{if .Hash}}?h={{.Hash}}{{end}}"></script>{{end}}
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
<script type="text/javascript" src="/static/jquery-3.1.1.min.js"></script>
{{range .Header.Scripts}}
<script type="text/javascript" src="/static/{{.Name}}{{if .Hash}}?h={{.Hash}}{{end}}"></script>{{end}}
<script type="text/javascript" src="/static/{{.}}"></script>{{end}}
<meta name="viewport" content="width=device-width,initial-scale = 1.0, maximum-scale=1.0,user-scalable=no" />
{{if .Header.MetaDesc}}<meta name="description" content="{{.Header.MetaDesc}}" />{{end}}
{{/** TODO: Have page / forum / topic level tags and descriptions below as-well **/}}