gin.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
  2. // Use of this source code is governed by a MIT style
  3. // license that can be found in the LICENSE file.
  4. package gin
  5. import (
  6. "crypto/tls"
  7. "html/template"
  8. "net"
  9. "net/http"
  10. "os"
  11. "sync"
  12. "github.com/gin-gonic/gin/render"
  13. "golang.org/x/crypto/acme/autocert"
  14. )
  15. // Version is Framework's version
  16. const Version = "v1.1.4"
  17. var default404Body = []byte("404 page not found")
  18. var default405Body = []byte("405 method not allowed")
  19. var defaultAppEngine bool
  20. type HandlerFunc func(*Context)
  21. type HandlersChain []HandlerFunc
  22. // Last returns the last handler in the chain. ie. the last handler is the main own.
  23. func (c HandlersChain) Last() HandlerFunc {
  24. length := len(c)
  25. if length > 0 {
  26. return c[length-1]
  27. }
  28. return nil
  29. }
  30. type (
  31. RoutesInfo []RouteInfo
  32. RouteInfo struct {
  33. Method string
  34. Path string
  35. Handler string
  36. }
  37. // Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
  38. // Create an instance of Engine, by using New() or Default()
  39. Engine struct {
  40. RouterGroup
  41. HTMLRender render.HTMLRender
  42. allNoRoute HandlersChain
  43. allNoMethod HandlersChain
  44. noRoute HandlersChain
  45. noMethod HandlersChain
  46. pool sync.Pool
  47. trees methodTrees
  48. // Enables automatic redirection if the current route can't be matched but a
  49. // handler for the path with (without) the trailing slash exists.
  50. // For example if /foo/ is requested but a route only exists for /foo, the
  51. // client is redirected to /foo with http status code 301 for GET requests
  52. // and 307 for all other request methods.
  53. RedirectTrailingSlash bool
  54. // If enabled, the router tries to fix the current request path, if no
  55. // handle is registered for it.
  56. // First superfluous path elements like ../ or // are removed.
  57. // Afterwards the router does a case-insensitive lookup of the cleaned path.
  58. // If a handle can be found for this route, the router makes a redirection
  59. // to the corrected path with status code 301 for GET requests and 307 for
  60. // all other request methods.
  61. // For example /FOO and /..//Foo could be redirected to /foo.
  62. // RedirectTrailingSlash is independent of this option.
  63. RedirectFixedPath bool
  64. // If enabled, the router checks if another method is allowed for the
  65. // current route, if the current request can not be routed.
  66. // If this is the case, the request is answered with 'Method Not Allowed'
  67. // and HTTP status code 405.
  68. // If no other Method is allowed, the request is delegated to the NotFound
  69. // handler.
  70. HandleMethodNotAllowed bool
  71. ForwardedByClientIP bool
  72. // #726 #755 If enabled, it will thrust some headers starting with
  73. // 'X-AppEngine...' for better integration with that PaaS.
  74. AppEngine bool
  75. // If enabled, the url.RawPath will be used to find parameters.
  76. UseRawPath bool
  77. // If true, the path value will be unescaped.
  78. // If UseRawPath is false (by default), the UnescapePathValues effectively is true,
  79. // as url.Path gonna be used, which is already unescaped.
  80. UnescapePathValues bool
  81. }
  82. )
  83. var _ IRouter = &Engine{}
  84. // New returns a new blank Engine instance without any middleware attached.
  85. // By default the configuration is:
  86. // - RedirectTrailingSlash: true
  87. // - RedirectFixedPath: false
  88. // - HandleMethodNotAllowed: false
  89. // - ForwardedByClientIP: true
  90. // - UseRawPath: false
  91. // - UnescapePathValues: true
  92. func New() *Engine {
  93. debugPrintWARNINGNew()
  94. engine := &Engine{
  95. RouterGroup: RouterGroup{
  96. Handlers: nil,
  97. basePath: "/",
  98. root: true,
  99. },
  100. RedirectTrailingSlash: true,
  101. RedirectFixedPath: false,
  102. HandleMethodNotAllowed: false,
  103. ForwardedByClientIP: true,
  104. AppEngine: defaultAppEngine,
  105. UseRawPath: false,
  106. UnescapePathValues: true,
  107. trees: make(methodTrees, 0, 9),
  108. }
  109. engine.RouterGroup.engine = engine
  110. engine.pool.New = func() interface{} {
  111. return engine.allocateContext()
  112. }
  113. return engine
  114. }
  115. // Default returns an Engine instance with the Logger and Recovery middleware already attached.
  116. func Default() *Engine {
  117. engine := New()
  118. engine.Use(Logger(), Recovery())
  119. return engine
  120. }
  121. func (engine *Engine) allocateContext() *Context {
  122. return &Context{engine: engine}
  123. }
  124. func (engine *Engine) LoadHTMLGlob(pattern string) {
  125. if IsDebugging() {
  126. debugPrintLoadTemplate(template.Must(template.ParseGlob(pattern)))
  127. engine.HTMLRender = render.HTMLDebug{Glob: pattern}
  128. } else {
  129. templ := template.Must(template.ParseGlob(pattern))
  130. engine.SetHTMLTemplate(templ)
  131. }
  132. }
  133. func (engine *Engine) LoadHTMLFiles(files ...string) {
  134. if IsDebugging() {
  135. engine.HTMLRender = render.HTMLDebug{Files: files}
  136. } else {
  137. templ := template.Must(template.ParseFiles(files...))
  138. engine.SetHTMLTemplate(templ)
  139. }
  140. }
  141. func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
  142. if len(engine.trees) > 0 {
  143. debugPrintWARNINGSetHTMLTemplate()
  144. }
  145. engine.HTMLRender = render.HTMLProduction{Template: templ}
  146. }
  147. // NoRoute adds handlers for NoRoute. It return a 404 code by default.
  148. func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
  149. engine.noRoute = handlers
  150. engine.rebuild404Handlers()
  151. }
  152. // NoMethod sets the handlers called when... TODO
  153. func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
  154. engine.noMethod = handlers
  155. engine.rebuild405Handlers()
  156. }
  157. // Use attachs a global middleware to the router. ie. the middleware attached though Use() will be
  158. // included in the handlers chain for every single request. Even 404, 405, static files...
  159. // For example, this is the right place for a logger or error management middleware.
  160. func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
  161. engine.RouterGroup.Use(middleware...)
  162. engine.rebuild404Handlers()
  163. engine.rebuild405Handlers()
  164. return engine
  165. }
  166. func (engine *Engine) rebuild404Handlers() {
  167. engine.allNoRoute = engine.combineHandlers(engine.noRoute)
  168. }
  169. func (engine *Engine) rebuild405Handlers() {
  170. engine.allNoMethod = engine.combineHandlers(engine.noMethod)
  171. }
  172. func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
  173. assert1(path[0] == '/', "path must begin with '/'")
  174. assert1(len(method) > 0, "HTTP method can not be empty")
  175. assert1(len(handlers) > 0, "there must be at least one handler")
  176. debugPrintRoute(method, path, handlers)
  177. root := engine.trees.get(method)
  178. if root == nil {
  179. root = new(node)
  180. engine.trees = append(engine.trees, methodTree{method: method, root: root})
  181. }
  182. root.addRoute(path, handlers)
  183. }
  184. // Routes returns a slice of registered routes, including some useful information, such as:
  185. // the http method, path and the handler name.
  186. func (engine *Engine) Routes() (routes RoutesInfo) {
  187. for _, tree := range engine.trees {
  188. routes = iterate("", tree.method, routes, tree.root)
  189. }
  190. return routes
  191. }
  192. func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
  193. path += root.path
  194. if len(root.handlers) > 0 {
  195. routes = append(routes, RouteInfo{
  196. Method: method,
  197. Path: path,
  198. Handler: nameOfFunction(root.handlers.Last()),
  199. })
  200. }
  201. for _, child := range root.children {
  202. routes = iterate(path, method, routes, child)
  203. }
  204. return routes
  205. }
  206. // Run attaches the router to a http.Server and starts listening and serving HTTP requests.
  207. // It is a shortcut for http.ListenAndServe(addr, router)
  208. // Note: this method will block the calling goroutine indefinitely unless an error happens.
  209. func (engine *Engine) Run(addr ...string) (err error) {
  210. defer func() { debugPrintError(err) }()
  211. address := resolveAddress(addr)
  212. debugPrint("Listening and serving HTTP on %s\n", address)
  213. err = http.ListenAndServe(address, engine)
  214. return
  215. }
  216. // RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
  217. // It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
  218. // Note: this method will block the calling goroutine indefinitely unless an error happens.
  219. func (engine *Engine) RunTLS(addr string, certFile string, keyFile string) (err error) {
  220. debugPrint("Listening and serving HTTPS on %s\n", addr)
  221. defer func() { debugPrintError(err) }()
  222. err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
  223. return
  224. }
  225. // RunAutoTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
  226. // It obtains and refreshes certificates automatically,
  227. // as well as providing them to a TLS server via tls.Config.
  228. func (engine *Engine) RunAutoTLS(addr string, cache string, domain ...string) (err error) {
  229. debugPrint("Listening and serving HTTPS on %s and host name is %s\n", addr, domain)
  230. defer func() { debugPrintError(err) }()
  231. m := autocert.Manager{
  232. Prompt: autocert.AcceptTOS,
  233. }
  234. //your domain here
  235. if len(domain) != 0 {
  236. m.HostPolicy = autocert.HostWhitelist(domain...)
  237. }
  238. // folder for storing certificates
  239. if cache != "" {
  240. m.Cache = autocert.DirCache(cache)
  241. }
  242. s := &http.Server{
  243. Addr: addr,
  244. TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
  245. Handler: engine,
  246. }
  247. err = s.ListenAndServeTLS("", "")
  248. return
  249. }
  250. // RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
  251. // through the specified unix socket (ie. a file).
  252. // Note: this method will block the calling goroutine indefinitely unless an error happens.
  253. func (engine *Engine) RunUnix(file string) (err error) {
  254. debugPrint("Listening and serving HTTP on unix:/%s", file)
  255. defer func() { debugPrintError(err) }()
  256. os.Remove(file)
  257. listener, err := net.Listen("unix", file)
  258. if err != nil {
  259. return
  260. }
  261. defer listener.Close()
  262. err = http.Serve(listener, engine)
  263. return
  264. }
  265. // Conforms to the http.Handler interface.
  266. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  267. c := engine.pool.Get().(*Context)
  268. c.writermem.reset(w)
  269. c.Request = req
  270. c.reset()
  271. engine.handleHTTPRequest(c)
  272. engine.pool.Put(c)
  273. }
  274. // Re-enter a context that has been rewritten.
  275. // This can be done by setting c.Request.Path to your new target.
  276. // Disclaimer: You can loop yourself to death with this, use wisely.
  277. func (engine *Engine) HandleContext(c *Context) {
  278. c.reset()
  279. engine.handleHTTPRequest(c)
  280. engine.pool.Put(c)
  281. }
  282. func (engine *Engine) handleHTTPRequest(context *Context) {
  283. httpMethod := context.Request.Method
  284. var path string
  285. var unescape bool
  286. if engine.UseRawPath && len(context.Request.URL.RawPath) > 0 {
  287. path = context.Request.URL.RawPath
  288. unescape = engine.UnescapePathValues
  289. } else {
  290. path = context.Request.URL.Path
  291. unescape = false
  292. }
  293. // Find root of the tree for the given HTTP method
  294. t := engine.trees
  295. for i, tl := 0, len(t); i < tl; i++ {
  296. if t[i].method == httpMethod {
  297. root := t[i].root
  298. // Find route in tree
  299. handlers, params, tsr := root.getValue(path, context.Params, unescape)
  300. if handlers != nil {
  301. context.handlers = handlers
  302. context.Params = params
  303. context.Next()
  304. context.writermem.WriteHeaderNow()
  305. return
  306. } else if httpMethod != "CONNECT" && path != "/" {
  307. if tsr && engine.RedirectTrailingSlash {
  308. redirectTrailingSlash(context)
  309. return
  310. }
  311. if engine.RedirectFixedPath && redirectFixedPath(context, root, engine.RedirectFixedPath) {
  312. return
  313. }
  314. }
  315. break
  316. }
  317. }
  318. // TODO: unit test
  319. if engine.HandleMethodNotAllowed {
  320. for _, tree := range engine.trees {
  321. if tree.method != httpMethod {
  322. if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
  323. context.handlers = engine.allNoMethod
  324. serveError(context, 405, default405Body)
  325. return
  326. }
  327. }
  328. }
  329. }
  330. context.handlers = engine.allNoRoute
  331. serveError(context, 404, default404Body)
  332. }
  333. var mimePlain = []string{MIMEPlain}
  334. func serveError(c *Context, code int, defaultMessage []byte) {
  335. c.writermem.status = code
  336. c.Next()
  337. if !c.writermem.Written() {
  338. if c.writermem.Status() == code {
  339. c.writermem.Header()["Content-Type"] = mimePlain
  340. c.Writer.Write(defaultMessage)
  341. } else {
  342. c.writermem.WriteHeaderNow()
  343. }
  344. }
  345. }
  346. func redirectTrailingSlash(c *Context) {
  347. req := c.Request
  348. path := req.URL.Path
  349. code := 301 // Permanent redirect, request with GET method
  350. if req.Method != "GET" {
  351. code = 307
  352. }
  353. if len(path) > 1 && path[len(path)-1] == '/' {
  354. req.URL.Path = path[:len(path)-1]
  355. } else {
  356. req.URL.Path = path + "/"
  357. }
  358. debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
  359. http.Redirect(c.Writer, req, req.URL.String(), code)
  360. c.writermem.WriteHeaderNow()
  361. }
  362. func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
  363. req := c.Request
  364. path := req.URL.Path
  365. fixedPath, found := root.findCaseInsensitivePath(
  366. cleanPath(path),
  367. trailingSlash,
  368. )
  369. if found {
  370. code := 301 // Permanent redirect, request with GET method
  371. if req.Method != "GET" {
  372. code = 307
  373. }
  374. req.URL.Path = string(fixedPath)
  375. debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
  376. http.Redirect(c.Writer, req, req.URL.String(), code)
  377. c.writermem.WriteHeaderNow()
  378. return true
  379. }
  380. return false
  381. }