From 3a21f8a9865d1112d1b847fb20710e6b735174ec Mon Sep 17 00:00:00 2001
From: silverwind <me@silverwind.io>
Date: Tue, 22 Dec 2020 12:13:50 +0100
Subject: [PATCH] Inline manifest.json (#14038)

* Inline manifest.json

Improve performance by eliminating this separate request and just inline
this small JSON in HTML directly as a data uri.

Also update previously static app name scripts to use AppName.

I've confirmed this as working via "Add to Homescreen" feature which
offered to save the shortcut under the new app name.

* prerender manifest data on startup

* move to settings

* restore setting.AppStartTime and use it on admin page

* use double quotes because template.URL escapes everything

* fix lint

* move variable to global context variable

* delete template file

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
---
 modules/context/context.go       |  2 ++
 modules/setting/setting.go       | 13 +++++++++++++
 routers/admin/admin.go           |  6 +-----
 routers/routes/macaron.go        |  9 ---------
 templates/base/head.tmpl         |  2 +-
 templates/pwa/manifest_json.tmpl | 31 -------------------------------
 6 files changed, 17 insertions(+), 46 deletions(-)
 delete mode 100644 templates/pwa/manifest_json.tmpl

diff --git a/modules/context/context.go b/modules/context/context.go
index c6597cf02..2e43088ff 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -345,6 +345,8 @@ func Contexter() macaron.Handler {
 		ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
 		ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
 
+		ctx.Data["ManifestData"] = setting.ManifestData
+
 		c.Map(ctx)
 	}
 }
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 63ae15af9..290ec94c4 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -8,6 +8,7 @@ package setting
 import (
 	"encoding/base64"
 	"fmt"
+	"html/template"
 	"io"
 	"io/ioutil"
 	"math"
@@ -293,6 +294,8 @@ var (
 	CSRFCookieName     = "_csrf"
 	CSRFCookieHTTPOnly = true
 
+	ManifestData template.URL
+
 	// Mirror settings
 	Mirror struct {
 		DefaultInterval time.Duration
@@ -642,6 +645,8 @@ func NewContext() {
 		LandingPageURL = LandingPageHome
 	}
 
+	ManifestData = makeManifestData()
+
 	if len(SSH.Domain) == 0 {
 		SSH.Domain = Domain
 	}
@@ -1040,6 +1045,14 @@ func loadOrGenerateInternalToken(sec *ini.Section) string {
 	return token
 }
 
+func makeManifestData() template.URL {
+	name := url.QueryEscape(AppName)
+	prefix := url.QueryEscape(StaticURLPrefix)
+	subURL := url.QueryEscape(AppSubURL) + "/"
+
+	return template.URL(`data:application/json,{"short_name":"` + name + `","name":"` + name + `","icons":[{"src":"` + prefix + `/img/logo-lg.png","type":"image/png","sizes":"880x880"},{"src":"` + prefix + `/img/logo-sm.png","type":"image/png","sizes":"120x120"},{"src":"` + prefix + `/img/logo-512.png","type":"image/png","sizes":"512x512"},{"src":"` + prefix + `/img/logo-192.png","type":"image/png","sizes":"192x192"}],"start_url":"` + subURL + `","scope":"` + subURL + `","background_color":"%23FAFAFA","display":"standalone"}`)
+}
+
 // NewServices initializes the services
 func NewServices() {
 	InitDBConfig()
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index d0f027f5f..4180076b0 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -39,10 +39,6 @@ const (
 	tplQueue     base.TplName = "admin/queue"
 )
 
-var (
-	startTime = time.Now()
-)
-
 var sysStatus struct {
 	Uptime       string
 	NumGoroutine int
@@ -85,7 +81,7 @@ var sysStatus struct {
 }
 
 func updateSystemStatus() {
-	sysStatus.Uptime = timeutil.TimeSincePro(startTime, "en")
+	sysStatus.Uptime = timeutil.TimeSincePro(setting.AppStartTime, "en")
 
 	m := new(runtime.MemStats)
 	runtime.ReadMemStats(m)
diff --git a/routers/routes/macaron.go b/routers/routes/macaron.go
index 170bc7d49..16977b947 100644
--- a/routers/routes/macaron.go
+++ b/routers/routes/macaron.go
@@ -6,12 +6,10 @@ package routes
 
 import (
 	"encoding/gob"
-	"net/http"
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/auth"
 	"code.gitea.io/gitea/modules/context"
-	"code.gitea.io/gitea/modules/httpcache"
 	"code.gitea.io/gitea/modules/lfs"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/options"
@@ -977,13 +975,6 @@ func RegisterMacaronRoutes(m *macaron.Macaron) {
 		private.RegisterRoutes(m)
 	})
 
-	// Progressive Web App
-	m.Get("/manifest.json", templates.JSONRenderer(), func(ctx *context.Context) {
-		ctx.Resp.Header().Set("Cache-Control", httpcache.GetCacheControl())
-		ctx.Resp.Header().Set("Last-Modified", setting.AppStartTime.Format(http.TimeFormat))
-		ctx.HTML(200, "pwa/manifest_json")
-	})
-
 	// Not found handler.
 	m.NotFound(routers.NotFound)
 }
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
index 51d60c46f..99b942bcf 100644
--- a/templates/base/head.tmpl
+++ b/templates/base/head.tmpl
@@ -5,7 +5,7 @@
 	<meta name="viewport" content="width=device-width, initial-scale=1">
 	<meta http-equiv="x-ua-compatible" content="ie=edge">
 	<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}} </title>
-	<link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials">
+	<link rel="manifest" href="{{.ManifestData}}"/>
 	<meta name="theme-color" content="{{ThemeColorMetaTag}}">
 	<meta name="default-theme" content="{{DefaultTheme}}" />
 	<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}" />
diff --git a/templates/pwa/manifest_json.tmpl b/templates/pwa/manifest_json.tmpl
deleted file mode 100644
index 7eba1f45b..000000000
--- a/templates/pwa/manifest_json.tmpl
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-  "short_name": "Gitea",
-  "name": "Gitea - Git with a cup of tea",
-  "icons": [
-    {
-      "src": "{{StaticUrlPrefix}}/img/logo-lg.png",
-      "type": "image/png",
-      "sizes": "880x880"
-    },
-    {
-      "src": "{{StaticUrlPrefix}}/img/logo-sm.png",
-      "type": "image/png",
-      "sizes": "120x120"
-    },
-    {
-      "src": "{{StaticUrlPrefix}}/img/logo-512.png",
-      "type": "image/png",
-      "sizes": "512x512"
-    },
-    {
-      "src": "{{StaticUrlPrefix}}/img/logo-192.png",
-      "type": "image/png",
-      "sizes": "192x192"
-    }
-  ],
-  "start_url": "{{AppSubUrl}}/",
-  "scope": "{{AppSubUrl}}/",
-  "background_color": "#FAFAFA",
-  "display": "standalone",
-  "theme_color": "{{ThemeColorMetaTag}}"
-}