You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.1 KiB

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