cmd/golangorg: merge into single source file

There is so little left here that the file
boundaries make no sense anymore.
Move all the functions into main.go.
registerHandlers was inlined instead of
copied.

Change-Id: If91a5d1dc75834747b9d803ec44790950d503aed
Reviewed-on: https://go-review.googlesource.com/c/website/+/328011
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
This commit is contained in:
Russ Cox 2021-06-14 15:28:42 -04:00
Родитель fdd9055814
Коммит 7e9c28a76a
7 изменённых файлов: 192 добавлений и 270 удалений

Просмотреть файл

@ -1,32 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"net/http"
"strings"
"golang.org/x/website/internal/env"
)
// googleCN reports whether request r is considered
// to be served from golang.google.cn.
// TODO: This is duplicated within internal/proxy. Move to a common location.
func googleCN(r *http.Request) bool {
if r.FormValue("googlecn") != "" {
return true
}
if strings.HasSuffix(r.Host, ".cn") {
return true
}
if !env.CheckCountry() {
return false
}
switch r.Header.Get("X-Appengine-Country") {
case "", "ZZ", "CN":
return true
}
return false
}

Просмотреть файл

@ -1,98 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"encoding/json"
"go/format"
"net/http"
"strings"
"golang.org/x/website/internal/backport/io/fs"
"golang.org/x/website/internal/codewalk"
"golang.org/x/website/internal/env"
"golang.org/x/website/internal/redirect"
"golang.org/x/website/internal/web"
)
// hostEnforcerHandler redirects http://foo.golang.org/bar to https://golang.org/bar.
// It permits golang.google.cn for China and *-dot-golang-org.appspot.com for testing.
type hostEnforcerHandler struct {
h http.Handler
}
func (h hostEnforcerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !env.EnforceHosts() {
h.h.ServeHTTP(w, r)
return
}
if !h.isHTTPS(r) || !h.validHost(r.Host) {
r.URL.Scheme = "https"
if h.validHost(r.Host) {
r.URL.Host = r.Host
} else {
r.URL.Host = "golang.org"
}
http.Redirect(w, r, r.URL.String(), http.StatusFound)
return
}
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
h.h.ServeHTTP(w, r)
}
func (h hostEnforcerHandler) isHTTPS(r *http.Request) bool {
return r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"
}
func (h hostEnforcerHandler) validHost(host string) bool {
switch strings.ToLower(host) {
case "golang.org", "golang.google.cn":
return true
}
if strings.HasSuffix(host, "-dot-golang-org.appspot.com") {
// staging/test
return true
}
return false
}
func registerHandlers(fsys fs.FS, site *web.Site) *http.ServeMux {
if site == nil {
panic("nil Site")
}
mux := http.NewServeMux()
mux.Handle("/", site)
mux.Handle("/doc/codewalk/", codewalk.NewServer(fsys, site))
mux.Handle("/fmt", http.HandlerFunc(fmtHandler))
mux.Handle("/x/", http.HandlerFunc(xHandler))
redirect.Register(mux)
http.Handle("/", hostEnforcerHandler{mux})
return mux
}
type fmtResponse struct {
Body string
Error string
}
// fmtHandler takes a Go program in its "body" form value, formats it with
// standard gofmt formatting, and writes a fmtResponse as a JSON object.
func fmtHandler(w http.ResponseWriter, r *http.Request) {
resp := new(fmtResponse)
body, err := format.Source([]byte(r.FormValue("body")))
if err != nil {
resp.Error = err.Error()
} else {
resp.Body = string(body)
}
w.Header().Set("Content-type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(resp)
}
func blogHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "https://blog.golang.org"+strings.TrimPrefix(r.URL.Path, "/blog"), http.StatusFound)
}

Просмотреть файл

@ -1,26 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Regression tests to run against a production instance of golangorg.
package main_test
import (
"flag"
"strings"
"testing"
"golang.org/x/website/internal/webtest"
)
var host = flag.String("regtest.host", "", "host to run regression test against")
func TestLiveServer(t *testing.T) {
*host = strings.TrimSuffix(*host, "/")
if *host == "" {
t.Skip("regtest.host flag missing.")
}
webtest.TestServer(t, "testdata/*.txt", *host)
}

Просмотреть файл

@ -19,8 +19,10 @@ package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"go/format"
"io"
"log"
"net/http"
@ -30,11 +32,15 @@ import (
"strings"
"cloud.google.com/go/datastore"
"golang.org/x/build/repos"
"golang.org/x/website"
"golang.org/x/website/internal/backport/archive/zip"
"golang.org/x/website/internal/backport/html/template"
"golang.org/x/website/internal/backport/io/fs"
"golang.org/x/website/internal/backport/osfs"
"golang.org/x/website/internal/codewalk"
"golang.org/x/website/internal/dl"
"golang.org/x/website/internal/env"
"golang.org/x/website/internal/memcache"
"golang.org/x/website/internal/proxy"
"golang.org/x/website/internal/redirect"
@ -62,13 +68,6 @@ func usage() {
os.Exit(2)
}
func loggingHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
log.Printf("%s\t%s", req.RemoteAddr, req.URL)
h.ServeHTTP(w, req)
})
}
func main() {
repoRoot := "../.."
if _, err := os.Stat("_content"); err == nil {
@ -130,7 +129,13 @@ func main() {
}
site.GoogleCN = googleCN
mux := registerHandlers(fsys, site)
mux := http.NewServeMux()
mux.Handle("/", site)
mux.Handle("/doc/codewalk/", codewalk.NewServer(fsys, site))
mux.Handle("/fmt", http.HandlerFunc(fmtHandler))
mux.Handle("/x/", http.HandlerFunc(xHandler))
redirect.Register(mux)
http.Handle("/", hostEnforcerHandler{mux})
http.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "User-agent: *\nDisallow: /search\n")
@ -163,6 +168,169 @@ func main() {
}
}
func appEngineSetup(site *web.Site, mux *http.ServeMux) {
site.GoogleAnalytics = os.Getenv("GOLANGORG_ANALYTICS")
ctx := context.Background()
datastoreClient, err := datastore.NewClient(ctx, "")
if err != nil {
if strings.Contains(err.Error(), "missing project") {
log.Fatalf("Missing datastore project. Set the DATASTORE_PROJECT_ID env variable. Use `gcloud beta emulators datastore` to start a local datastore.")
}
log.Fatalf("datastore.NewClient: %v.", err)
}
redisAddr := os.Getenv("GOLANGORG_REDIS_ADDR")
if redisAddr == "" {
log.Fatalf("Missing redis server for golangorg in production mode. set GOLANGORG_REDIS_ADDR environment variable.")
}
memcacheClient := memcache.New(redisAddr)
dl.RegisterHandlers(mux, site, datastoreClient, memcacheClient)
short.RegisterHandlers(mux, datastoreClient, memcacheClient)
// Register /compile and /share handlers against the default serve mux
// so that other app modules can make plain HTTP requests to those
// hosts. (For reasons, HTTPS communication between modules is broken.)
proxy.RegisterHandlers(http.DefaultServeMux)
log.Println("AppEngine initialization complete")
}
// googleCN reports whether request r is considered
// to be served from golang.google.cn.
// TODO: This is duplicated within internal/proxy. Move to a common location.
func googleCN(r *http.Request) bool {
if r.FormValue("googlecn") != "" {
return true
}
if strings.HasSuffix(r.Host, ".cn") {
return true
}
if !env.CheckCountry() {
return false
}
switch r.Header.Get("X-Appengine-Country") {
case "", "ZZ", "CN":
return true
}
return false
}
func blogHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "https://blog.golang.org"+strings.TrimPrefix(r.URL.Path, "/blog"), http.StatusFound)
}
type fmtResponse struct {
Body string
Error string
}
// fmtHandler takes a Go program in its "body" form value, formats it with
// standard gofmt formatting, and writes a fmtResponse as a JSON object.
func fmtHandler(w http.ResponseWriter, r *http.Request) {
resp := new(fmtResponse)
body, err := format.Source([]byte(r.FormValue("body")))
if err != nil {
resp.Error = err.Error()
} else {
resp.Body = string(body)
}
w.Header().Set("Content-type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(resp)
}
// hostEnforcerHandler redirects http://foo.golang.org/bar to https://golang.org/bar.
// It permits golang.google.cn for China and *-dot-golang-org.appspot.com for testing.
type hostEnforcerHandler struct {
h http.Handler
}
func (h hostEnforcerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !env.EnforceHosts() {
h.h.ServeHTTP(w, r)
return
}
if !h.isHTTPS(r) || !h.validHost(r.Host) {
r.URL.Scheme = "https"
if h.validHost(r.Host) {
r.URL.Host = r.Host
} else {
r.URL.Host = "golang.org"
}
http.Redirect(w, r, r.URL.String(), http.StatusFound)
return
}
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
h.h.ServeHTTP(w, r)
}
func (h hostEnforcerHandler) isHTTPS(r *http.Request) bool {
return r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"
}
func (h hostEnforcerHandler) validHost(host string) bool {
switch strings.ToLower(host) {
case "golang.org", "golang.google.cn":
return true
}
if strings.HasSuffix(host, "-dot-golang-org.appspot.com") {
// staging/test
return true
}
return false
}
func loggingHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
log.Printf("%s\t%s", req.RemoteAddr, req.URL)
h.ServeHTTP(w, req)
})
}
func xHandler(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/x/") {
// Shouldn't happen if handler is registered correctly.
http.Redirect(w, r, "https://pkg.go.dev/search?q=golang.org/x", http.StatusTemporaryRedirect)
return
}
proj, suffix := strings.TrimPrefix(r.URL.Path, "/x/"), ""
if i := strings.Index(proj, "/"); i != -1 {
proj, suffix = proj[:i], proj[i:]
}
if proj == "" {
http.Redirect(w, r, "https://pkg.go.dev/search?q=golang.org/x", http.StatusTemporaryRedirect)
return
}
repo, ok := repos.ByGerritProject[proj]
if !ok || !strings.HasPrefix(repo.ImportPath, "golang.org/x/") {
http.NotFound(w, r)
return
}
data := struct {
Proj string // Gerrit project ("net", "sys", etc)
Suffix string // optional "/path" for requests like /x/PROJ/path
}{proj, suffix}
if err := xTemplate.Execute(w, data); err != nil {
log.Println("xHandler:", err)
}
}
var xTemplate = template.Must(template.New("x").Parse(`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="golang.org/x/{{.Proj}} git https://go.googlesource.com/{{.Proj}}">
<meta name="go-source" content="golang.org/x/{{.Proj}} https://github.com/golang/{{.Proj}}/ https://github.com/golang/{{.Proj}}/tree/master{/dir} https://github.com/golang/{{.Proj}}/blob/master{/dir}/{file}#L{line}">
<meta http-equiv="refresh" content="0; url=https://pkg.go.dev/golang.org/x/{{.Proj}}{{.Suffix}}">
</head>
<body>
<a href="https://pkg.go.dev/golang.org/x/{{.Proj}}{{.Suffix}}">Redirecting to documentation...</a>
</body>
</html>
`))
var _ fs.ReadDirFS = unionFS{}
// A unionFS is an FS presenting the union of the file systems in the slice.
@ -224,33 +392,3 @@ func (fsys unionFS) ReadDir(name string) ([]fs.DirEntry, error) {
}
return nil, errOut
}
func appEngineSetup(site *web.Site, mux *http.ServeMux) {
site.GoogleAnalytics = os.Getenv("GOLANGORG_ANALYTICS")
ctx := context.Background()
datastoreClient, err := datastore.NewClient(ctx, "")
if err != nil {
if strings.Contains(err.Error(), "missing project") {
log.Fatalf("Missing datastore project. Set the DATASTORE_PROJECT_ID env variable. Use `gcloud beta emulators datastore` to start a local datastore.")
}
log.Fatalf("datastore.NewClient: %v.", err)
}
redisAddr := os.Getenv("GOLANGORG_REDIS_ADDR")
if redisAddr == "" {
log.Fatalf("Missing redis server for golangorg in production mode. set GOLANGORG_REDIS_ADDR environment variable.")
}
memcacheClient := memcache.New(redisAddr)
dl.RegisterHandlers(mux, site, datastoreClient, memcacheClient)
short.RegisterHandlers(mux, datastoreClient, memcacheClient)
// Register /compile and /share handlers against the default serve mux
// so that other app modules can make plain HTTP requests to those
// hosts. (For reasons, HTTPS communication between modules is broken.)
proxy.RegisterHandlers(http.DefaultServeMux)
log.Println("AppEngine initialization complete")
}

Просмотреть файл

@ -6,12 +6,14 @@ package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
"strings"
"testing"
"time"
@ -101,4 +103,18 @@ func TestWeb(t *testing.T) {
webtest.TestServer(t, "testdata/web.txt", addr)
webtest.TestServer(t, "testdata/release.txt", addr)
webtest.TestServer(t, "testdata/x.txt", addr)
}
// Regression tests to run against a production instance of golangorg.
var host = flag.String("regtest.host", "", "host to run regression test against")
func TestLiveServer(t *testing.T) {
*host = strings.TrimSuffix(*host, "/")
if *host == "" {
t.Skip("regtest.host flag missing.")
}
webtest.TestServer(t, "testdata/*.txt", *host)
}

Просмотреть файл

@ -1,60 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains the handlers that serve go-import redirects for Go
// sub-repositories. It specifies the mapping from import paths like
// "golang.org/x/tools" to the actual repository locations.
package main
import (
"log"
"net/http"
"strings"
"golang.org/x/build/repos"
"golang.org/x/website/internal/backport/html/template"
)
func xHandler(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, "/x/") {
// Shouldn't happen if handler is registered correctly.
http.Redirect(w, r, "https://pkg.go.dev/search?q=golang.org/x", http.StatusTemporaryRedirect)
return
}
proj, suffix := strings.TrimPrefix(r.URL.Path, "/x/"), ""
if i := strings.Index(proj, "/"); i != -1 {
proj, suffix = proj[:i], proj[i:]
}
if proj == "" {
http.Redirect(w, r, "https://pkg.go.dev/search?q=golang.org/x", http.StatusTemporaryRedirect)
return
}
repo, ok := repos.ByGerritProject[proj]
if !ok || !strings.HasPrefix(repo.ImportPath, "golang.org/x/") {
http.NotFound(w, r)
return
}
data := struct {
Proj string // Gerrit project ("net", "sys", etc)
Suffix string // optional "/path" for requests like /x/PROJ/path
}{proj, suffix}
if err := xTemplate.Execute(w, data); err != nil {
log.Println("xHandler:", err)
}
}
var xTemplate = template.Must(template.New("x").Parse(`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="golang.org/x/{{.Proj}} git https://go.googlesource.com/{{.Proj}}">
<meta name="go-source" content="golang.org/x/{{.Proj}} https://github.com/golang/{{.Proj}}/ https://github.com/golang/{{.Proj}}/tree/master{/dir} https://github.com/golang/{{.Proj}}/blob/master{/dir}/{file}#L{line}">
<meta http-equiv="refresh" content="0; url=https://pkg.go.dev/golang.org/x/{{.Proj}}{{.Suffix}}">
</head>
<body>
<a href="https://pkg.go.dev/golang.org/x/{{.Proj}}{{.Suffix}}">Redirecting to documentation...</a>
</body>
</html>
`))

Просмотреть файл

@ -1,16 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"net/http"
"testing"
"golang.org/x/website/internal/webtest"
)
func TestXHandler(t *testing.T) {
webtest.TestHandler(t, "testdata/x.txt", http.HandlerFunc(xHandler))
}