github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/cmd/godoc/handlers.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // The /doc/codewalk/ tree is synthesized from codewalk descriptions, 6 // files named $GOROOT/doc/codewalk/*.xml. 7 // For an example and a description of the format, see 8 // http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060 9 // and see http://localhost:6060/doc/codewalk/codewalk . 10 // That page is itself a codewalk; the source code for it is 11 // $GOROOT/doc/codewalk/codewalk.xml. 12 13 package main 14 15 import ( 16 "encoding/json" 17 "go/format" 18 "log" 19 "net/http" 20 "strings" 21 "text/template" 22 23 "golang.org/x/tools/godoc" 24 "golang.org/x/tools/godoc/redirect" 25 "golang.org/x/tools/godoc/vfs" 26 ) 27 28 var ( 29 pres *godoc.Presentation 30 fs = vfs.NameSpace{} 31 ) 32 33 var enforceHosts = false // set true in production on app engine 34 35 // hostEnforcerHandler redirects requests to "http://foo.golang.org/bar" 36 // to "https://golang.org/bar". 37 // It permits requests to the host "godoc-test.golang.org" for testing. 38 type hostEnforcerHandler struct { 39 h http.Handler 40 } 41 42 func (h hostEnforcerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 43 if !enforceHosts { 44 h.h.ServeHTTP(w, r) 45 return 46 } 47 if r.TLS == nil || !h.validHost(r.Host) { 48 r.URL.Scheme = "https" 49 if h.validHost(r.Host) { 50 r.URL.Host = r.Host 51 } else { 52 r.URL.Host = "golang.org" 53 } 54 http.Redirect(w, r, r.URL.String(), http.StatusFound) 55 return 56 } 57 h.h.ServeHTTP(w, r) 58 } 59 60 func (h hostEnforcerHandler) validHost(host string) bool { 61 switch strings.ToLower(host) { 62 case "golang.org", "godoc-test.golang.org": 63 return true 64 } 65 return false 66 } 67 68 func registerHandlers(pres *godoc.Presentation) *http.ServeMux { 69 if pres == nil { 70 panic("nil Presentation") 71 } 72 mux := http.NewServeMux() 73 mux.HandleFunc("/doc/codewalk/", codewalk) 74 mux.Handle("/doc/play/", pres.FileServer()) 75 mux.Handle("/robots.txt", pres.FileServer()) 76 mux.Handle("/", pres) 77 mux.Handle("/pkg/C/", redirect.Handler("/cmd/cgo/")) 78 mux.HandleFunc("/fmt", fmtHandler) 79 redirect.Register(mux) 80 81 http.Handle("/", hostEnforcerHandler{mux}) 82 83 return mux 84 } 85 86 func readTemplate(name string) *template.Template { 87 if pres == nil { 88 panic("no global Presentation set yet") 89 } 90 path := "lib/godoc/" + name 91 92 // use underlying file system fs to read the template file 93 // (cannot use template ParseFile functions directly) 94 data, err := vfs.ReadFile(fs, path) 95 if err != nil { 96 log.Fatal("readTemplate: ", err) 97 } 98 // be explicit with errors (for app engine use) 99 t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data)) 100 if err != nil { 101 log.Fatal("readTemplate: ", err) 102 } 103 return t 104 } 105 106 func readTemplates(p *godoc.Presentation, html bool) { 107 p.PackageText = readTemplate("package.txt") 108 p.SearchText = readTemplate("search.txt") 109 110 if html || p.HTMLMode { 111 codewalkHTML = readTemplate("codewalk.html") 112 codewalkdirHTML = readTemplate("codewalkdir.html") 113 p.CallGraphHTML = readTemplate("callgraph.html") 114 p.DirlistHTML = readTemplate("dirlist.html") 115 p.ErrorHTML = readTemplate("error.html") 116 p.ExampleHTML = readTemplate("example.html") 117 p.GodocHTML = readTemplate("godoc.html") 118 p.ImplementsHTML = readTemplate("implements.html") 119 p.MethodSetHTML = readTemplate("methodset.html") 120 p.PackageHTML = readTemplate("package.html") 121 p.SearchHTML = readTemplate("search.html") 122 p.SearchDocHTML = readTemplate("searchdoc.html") 123 p.SearchCodeHTML = readTemplate("searchcode.html") 124 p.SearchTxtHTML = readTemplate("searchtxt.html") 125 p.SearchDescXML = readTemplate("opensearch.xml") 126 } 127 } 128 129 type fmtResponse struct { 130 Body string 131 Error string 132 } 133 134 // fmtHandler takes a Go program in its "body" form value, formats it with 135 // standard gofmt formatting, and writes a fmtResponse as a JSON object. 136 func fmtHandler(w http.ResponseWriter, r *http.Request) { 137 resp := new(fmtResponse) 138 body, err := format.Source([]byte(r.FormValue("body"))) 139 if err != nil { 140 resp.Error = err.Error() 141 } else { 142 resp.Body = string(body) 143 } 144 w.Header().Set("Content-type", "application/json; charset=utf-8") 145 json.NewEncoder(w).Encode(resp) 146 }