error.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. /*
  17. Show nicely (but simple) formatted HTML error pages (or respond with JSON
  18. if the appropriate `Accept` header is set)) for the http package.
  19. */
  20. package http
  21. import (
  22. "encoding/json"
  23. "fmt"
  24. "html/template"
  25. "net/http"
  26. "time"
  27. "github.com/ethereum/go-ethereum/log"
  28. )
  29. //templateMap holds a mapping of an HTTP error code to a template
  30. var templateMap map[int]*template.Template
  31. //parameters needed for formatting the correct HTML page
  32. type ErrorParams struct {
  33. Msg string
  34. Code int
  35. Timestamp string
  36. template *template.Template
  37. Details template.HTML
  38. }
  39. //we init the error handling right on boot time, so lookup and http response is fast
  40. func init() {
  41. initErrHandling()
  42. }
  43. func initErrHandling() {
  44. //pages are saved as strings - get these strings
  45. genErrPage := GetGenericErrorPage()
  46. notFoundPage := GetNotFoundErrorPage()
  47. //map the codes to the available pages
  48. tnames := map[int]string{
  49. 0: genErrPage, //default
  50. 400: genErrPage,
  51. 404: notFoundPage,
  52. 500: genErrPage,
  53. }
  54. templateMap = make(map[int]*template.Template)
  55. for code, tname := range tnames {
  56. //assign formatted HTML to the code
  57. templateMap[code] = template.Must(template.New(fmt.Sprintf("%d", code)).Parse(tname))
  58. }
  59. }
  60. //ShowError is used to show an HTML error page to a client.
  61. //If there is an `Accept` header of `application/json`, JSON will be returned instead
  62. //The function just takes a string message which will be displayed in the error page.
  63. //The code is used to evaluate which template will be displayed
  64. //(and return the correct HTTP status code)
  65. func ShowError(w http.ResponseWriter, r *http.Request, msg string, code int) {
  66. if code == http.StatusInternalServerError {
  67. log.Error(msg)
  68. }
  69. respond(w, r, &ErrorParams{
  70. Code: code,
  71. Msg: msg,
  72. Timestamp: time.Now().Format(time.RFC1123),
  73. template: getTemplate(code),
  74. })
  75. }
  76. //evaluate if client accepts html or json response
  77. func respond(w http.ResponseWriter, r *http.Request, params *ErrorParams) {
  78. w.WriteHeader(params.Code)
  79. if r.Header.Get("Accept") == "application/json" {
  80. respondJson(w, params)
  81. } else {
  82. respondHtml(w, params)
  83. }
  84. }
  85. //return a HTML page
  86. func respondHtml(w http.ResponseWriter, params *ErrorParams) {
  87. err := params.template.Execute(w, params)
  88. if err != nil {
  89. log.Error(err.Error())
  90. }
  91. }
  92. //return JSON
  93. func respondJson(w http.ResponseWriter, params *ErrorParams) {
  94. w.Header().Set("Content-Type", "application/json")
  95. json.NewEncoder(w).Encode(params)
  96. }
  97. //get the HTML template for a given code
  98. func getTemplate(code int) *template.Template {
  99. if val, tmpl := templateMap[code]; tmpl {
  100. return val
  101. } else {
  102. return templateMap[0]
  103. }
  104. }