aboutsummaryrefslogtreecommitdiff
path: root/cmd/golangorg/server.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2021-08-02 11:23:53 -0400
committerRuss Cox <rsc@golang.org>2021-08-17 13:59:37 +0000
commitef7fed48ece033b41e88ed9a4cf40cdf9bd9de05 (patch)
tree5de02efe25f644ee3eb124d5b3f9091d40aab750 /cmd/golangorg/server.go
parentf8f1822414a54ce50388ab00e3a4c20f0ae15046 (diff)
downloadgo-x-website-ef7fed48ece033b41e88ed9a4cf40cdf9bd9de05.tar.xz
internal/web: merge with go.dev/cmd/internal/site
internal/web was the framework left serving golang.org. go.dev/cmd/internal/site was the framework serving go.dev. This CL merges the two into a coherent, simple site serving framework that works for both sites, a step toward merging the sites themselves. The CL is difficult to break up, so it's a bit larger than would be ideal. The best place to start is the doc comment in internal/web/site.go and then the other changes in that directory. The rest of the CL is just minor adjustments to the repo to match. Change-Id: I927dea29396104a817bd81b6bf25fa43f996968f Reviewed-on: https://go-review.googlesource.com/c/website/+/339403 Trust: Russ Cox <rsc@golang.org> Website-Publish: Russ Cox <rsc@golang.org> Reviewed-by: Jamal Carvalho <jamal@golang.org>
Diffstat (limited to 'cmd/golangorg/server.go')
-rw-r--r--cmd/golangorg/server.go79
1 files changed, 69 insertions, 10 deletions
diff --git a/cmd/golangorg/server.go b/cmd/golangorg/server.go
index 8924abe8..a7073717 100644
--- a/cmd/golangorg/server.go
+++ b/cmd/golangorg/server.go
@@ -17,6 +17,7 @@ import (
"log"
"net/http"
"os"
+ "path"
"path/filepath"
"runtime"
"runtime/debug"
@@ -36,6 +37,7 @@ import (
"golang.org/x/website/internal/dl"
"golang.org/x/website/internal/env"
"golang.org/x/website/internal/gitfs"
+ "golang.org/x/website/internal/history"
"golang.org/x/website/internal/memcache"
"golang.org/x/website/internal/pkgdoc"
"golang.org/x/website/internal/proxy"
@@ -52,6 +54,8 @@ var (
contentDir = flag.String("content", "", "path to _content directory")
runningOnAppEngine = os.Getenv("PORT") != ""
+
+ googleAnalytics string
)
func usage() {
@@ -145,6 +149,9 @@ func NewHandler(contentDir, goroot string) http.Handler {
if err != nil {
log.Fatalf("newSite: %v", err)
}
+ if _, err := newSite(mux, "golang.google.cn", content, gorootFS); err != nil {
+ log.Fatalf("newSite: %v", err)
+ }
// tip.golang.org serves content from the very latest Git commit
// of the main Go repo, instead of the one the app is bundled with.
@@ -198,12 +205,15 @@ func NewHandler(contentDir, goroot string) http.Handler {
// and registers it in mux to handle requests for host.
// If host is the empty string, the registrations are for the wildcard host.
func newSite(mux *http.ServeMux, host string, content, goroot fs.FS) (*web.Site, error) {
- fsys := unionFS{content, goroot}
- site, err := web.NewSite(fsys)
- if err != nil {
- return nil, err
- }
- docs, err := pkgdoc.NewServer(fsys, site)
+ fsys := unionFS{content, &fixSpecsFS{goroot}}
+ site := web.NewSite(fsys)
+ site.Funcs(template.FuncMap{
+ "googleAnalytics": func() string { return googleAnalytics },
+ "googleCN": func() bool { return host == "golang.google.cn" },
+ "releases": func() []*history.Major { return history.Majors },
+ "version": func() string { return runtime.Version() },
+ })
+ docs, err := pkgdoc.NewServer(fsys, site, googleCN)
if err != nil {
return nil, err
}
@@ -282,7 +292,7 @@ func watchTip1(tipGoroot *atomicFS) {
}
func appEngineSetup(site *web.Site, mux *http.ServeMux) {
- site.GoogleAnalytics = os.Getenv("GOLANGORG_ANALYTICS")
+ googleAnalytics = os.Getenv("GOLANGORG_ANALYTICS")
ctx := context.Background()
@@ -302,7 +312,7 @@ func appEngineSetup(site *web.Site, mux *http.ServeMux) {
dl.RegisterHandlers(mux, site, datastoreClient, memcacheClient)
short.RegisterHandlers(mux, datastoreClient, memcacheClient)
- proxy.RegisterHandlers(mux)
+ proxy.RegisterHandlers(mux, googleCN)
log.Println("AppEngine initialization complete")
}
@@ -339,22 +349,30 @@ var validHosts = map[string]bool{
}
// hostEnforcerHandler redirects http://foo.golang.org/bar to https://golang.org/bar.
-// It permits golang.google.cn as an alias for golang.org, for use in China.
+// It also forces all requests coming from China to use golang.google.cn.
func hostEnforcerHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
isHTTPS := r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" || r.URL.Scheme == "https"
+ defaultHost := "golang.org"
isValidHost := validHosts[strings.ToLower(r.Host)]
+ if googleCN(r) {
+ // golang.google.cn is the only web site in China.
+ defaultHost = "golang.google.cn"
+ isValidHost = strings.ToLower(r.Host) == defaultHost
+ }
+
if !isHTTPS || !isValidHost {
r.URL.Scheme = "https"
if isValidHost {
r.URL.Host = r.Host
} else {
- r.URL.Host = "golang.org"
+ r.URL.Host = defaultHost
}
http.Redirect(w, r, r.URL.String(), http.StatusFound)
return
}
+
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
h.ServeHTTP(w, r)
})
@@ -543,6 +561,33 @@ func (fsys unionFS) ReadDir(name string) ([]fs.DirEntry, error) {
return nil, errOut
}
+// A fixSpecsFS is an FS mapping /ref/mem.html and /ref/spec.html to
+// /doc/go_mem.html and /doc/go_spec.html.
+var _ fs.FS = &fixSpecsFS{}
+
+type fixSpecsFS struct {
+ fs fs.FS
+}
+
+func (fsys fixSpecsFS) Open(name string) (fs.File, error) {
+ switch name {
+ case "ref/mem.html", "ref/spec.html":
+ if f, err := fsys.fs.Open(name); err == nil {
+ // Let Go distribution win if they move.
+ return f, nil
+ }
+ // Otherwise fall back to doc/go_*.html
+ name = "doc/go_" + strings.TrimPrefix(name, "ref/")
+ return fsys.fs.Open(name)
+
+ case "doc/go_mem.html", "doc/go_spec.html":
+ data := []byte("<!--{\n\t\"Redirect\": \"/ref/" + strings.TrimPrefix(strings.TrimSuffix(name, ".html"), "doc/go_") + "\"\n}-->\n")
+ return &memFile{path.Base(name), bytes.NewReader(data)}, nil
+ }
+
+ return fsys.fs.Open(name)
+}
+
// A seekableFS is an FS wrapper that makes every file seekable
// by reading it entirely into memory when it is opened and then
// serving read operations (including seek) from the memory copy.
@@ -587,6 +632,20 @@ func (f *seekableFile) Read(b []byte) (int, error) {
return f.Reader.Read(b)
}
+// A memFile is an fs.File implementation backed by in-memory data.
+type memFile struct {
+ name string
+ *bytes.Reader
+}
+
+func (f *memFile) Stat() (fs.FileInfo, error) { return f, nil }
+func (f *memFile) Name() string { return f.name }
+func (*memFile) Mode() fs.FileMode { return 0444 }
+func (*memFile) ModTime() time.Time { return time.Time{} }
+func (*memFile) IsDir() bool { return false }
+func (*memFile) Sys() interface{} { return nil }
+func (*memFile) Close() error { return nil }
+
// An atomicFS is an fs.FS value safe for reading from multiple goroutines
// as well as updating (assigning a different fs.FS to use in future read requests).
type atomicFS struct {