iris.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. package iris
  2. import (
  3. // std packages
  4. stdContext "context"
  5. "io"
  6. "log"
  7. "net"
  8. "net/http"
  9. "sync"
  10. "time"
  11. "github.com/kataras/golog"
  12. // context for the handlers
  13. "github.com/kataras/iris/context"
  14. // core packages, needed to build the application
  15. "github.com/kataras/iris/core/errors"
  16. "github.com/kataras/iris/core/host"
  17. "github.com/kataras/iris/core/maintenance"
  18. "github.com/kataras/iris/core/netutil"
  19. "github.com/kataras/iris/core/router"
  20. // handlerconv conversions
  21. "github.com/kataras/iris/core/handlerconv"
  22. // cache conversions
  23. "github.com/kataras/iris/cache"
  24. // view
  25. "github.com/kataras/iris/view"
  26. // middleware used in Default method
  27. requestLogger "github.com/kataras/iris/middleware/logger"
  28. "github.com/kataras/iris/middleware/recover"
  29. )
  30. var (
  31. // Version is the current version number of the Iris Web Framework.
  32. Version = maintenance.Version
  33. )
  34. // HTTP status codes as registered with IANA.
  35. // See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
  36. // Raw Copy from the net/http std package in order to recude the import path of "net/http" for the users.
  37. //
  38. // Copied from `net/http` package.
  39. const (
  40. StatusContinue = 100 // RFC 7231, 6.2.1
  41. StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
  42. StatusProcessing = 102 // RFC 2518, 10.1
  43. StatusOK = 200 // RFC 7231, 6.3.1
  44. StatusCreated = 201 // RFC 7231, 6.3.2
  45. StatusAccepted = 202 // RFC 7231, 6.3.3
  46. StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
  47. StatusNoContent = 204 // RFC 7231, 6.3.5
  48. StatusResetContent = 205 // RFC 7231, 6.3.6
  49. StatusPartialContent = 206 // RFC 7233, 4.1
  50. StatusMultiStatus = 207 // RFC 4918, 11.1
  51. StatusAlreadyReported = 208 // RFC 5842, 7.1
  52. StatusIMUsed = 226 // RFC 3229, 10.4.1
  53. StatusMultipleChoices = 300 // RFC 7231, 6.4.1
  54. StatusMovedPermanently = 301 // RFC 7231, 6.4.2
  55. StatusFound = 302 // RFC 7231, 6.4.3
  56. StatusSeeOther = 303 // RFC 7231, 6.4.4
  57. StatusNotModified = 304 // RFC 7232, 4.1
  58. StatusUseProxy = 305 // RFC 7231, 6.4.5
  59. _ = 306 // RFC 7231, 6.4.6 (Unused)
  60. StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
  61. StatusPermanentRedirect = 308 // RFC 7538, 3
  62. StatusBadRequest = 400 // RFC 7231, 6.5.1
  63. StatusUnauthorized = 401 // RFC 7235, 3.1
  64. StatusPaymentRequired = 402 // RFC 7231, 6.5.2
  65. StatusForbidden = 403 // RFC 7231, 6.5.3
  66. StatusNotFound = 404 // RFC 7231, 6.5.4
  67. StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5
  68. StatusNotAcceptable = 406 // RFC 7231, 6.5.6
  69. StatusProxyAuthRequired = 407 // RFC 7235, 3.2
  70. StatusRequestTimeout = 408 // RFC 7231, 6.5.7
  71. StatusConflict = 409 // RFC 7231, 6.5.8
  72. StatusGone = 410 // RFC 7231, 6.5.9
  73. StatusLengthRequired = 411 // RFC 7231, 6.5.10
  74. StatusPreconditionFailed = 412 // RFC 7232, 4.2
  75. StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11
  76. StatusRequestURITooLong = 414 // RFC 7231, 6.5.12
  77. StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13
  78. StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
  79. StatusExpectationFailed = 417 // RFC 7231, 6.5.14
  80. StatusTeapot = 418 // RFC 7168, 2.3.3
  81. StatusUnprocessableEntity = 422 // RFC 4918, 11.2
  82. StatusLocked = 423 // RFC 4918, 11.3
  83. StatusFailedDependency = 424 // RFC 4918, 11.4
  84. StatusUpgradeRequired = 426 // RFC 7231, 6.5.15
  85. StatusPreconditionRequired = 428 // RFC 6585, 3
  86. StatusTooManyRequests = 429 // RFC 6585, 4
  87. StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5
  88. StatusUnavailableForLegalReasons = 451 // RFC 7725, 3
  89. StatusInternalServerError = 500 // RFC 7231, 6.6.1
  90. StatusNotImplemented = 501 // RFC 7231, 6.6.2
  91. StatusBadGateway = 502 // RFC 7231, 6.6.3
  92. StatusServiceUnavailable = 503 // RFC 7231, 6.6.4
  93. StatusGatewayTimeout = 504 // RFC 7231, 6.6.5
  94. StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6
  95. StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1
  96. StatusInsufficientStorage = 507 // RFC 4918, 11.5
  97. StatusLoopDetected = 508 // RFC 5842, 7.2
  98. StatusNotExtended = 510 // RFC 2774, 7
  99. StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
  100. )
  101. // HTTP Methods copied from `net/http`.
  102. const (
  103. MethodGet = "GET"
  104. MethodPost = "POST"
  105. MethodPut = "PUT"
  106. MethodDelete = "DELETE"
  107. MethodConnect = "CONNECT"
  108. MethodHead = "HEAD"
  109. MethodPatch = "PATCH"
  110. MethodOptions = "OPTIONS"
  111. MethodTrace = "TRACE"
  112. )
  113. // MethodNone is an iris-specific "virtual" method
  114. // to store the "offline" routes.
  115. const MethodNone = "NONE"
  116. // Application is responsible to manage the state of the application.
  117. // It contains and handles all the necessary parts to create a fast web server.
  118. type Application struct {
  119. // routing embedded | exposing APIBuilder's and Router's public API.
  120. *router.APIBuilder
  121. *router.Router
  122. ContextPool *context.Pool
  123. // config contains the configuration fields
  124. // all fields defaults to something that is working, developers don't have to set it.
  125. config *Configuration
  126. // the golog logger instance, defaults to "Info" level messages (all except "Debug")
  127. logger *golog.Logger
  128. // view engine
  129. view view.View
  130. // used for build
  131. once sync.Once
  132. mu sync.Mutex
  133. // Hosts contains a list of all servers (Host Supervisors) that this app is running on.
  134. //
  135. // Hosts may be empty only if application ran(`app.Run`) with `iris.Raw` option runner,
  136. // otherwise it contains a single host (`app.Hosts[0]`).
  137. //
  138. // Additional Host Supervisors can be added to that list by calling the `app.NewHost` manually.
  139. //
  140. // Hosts field is available after `Run` or `NewHost`.
  141. Hosts []*host.Supervisor
  142. hostConfigurators []host.Configurator
  143. }
  144. // New creates and returns a fresh empty iris *Application instance.
  145. func New() *Application {
  146. config := DefaultConfiguration()
  147. app := &Application{
  148. config: &config,
  149. logger: golog.Default,
  150. APIBuilder: router.NewAPIBuilder(),
  151. Router: router.NewRouter(),
  152. }
  153. app.ContextPool = context.New(func() context.Context {
  154. return context.NewContext(app)
  155. })
  156. return app
  157. }
  158. // Default returns a new Application instance which, unlike `New`,
  159. // recovers on panics and logs the incoming http requests.
  160. func Default() *Application {
  161. app := New()
  162. app.Use(recover.New())
  163. app.Use(requestLogger.New())
  164. return app
  165. }
  166. // WWW creates and returns a "www." subdomain.
  167. // The difference from `app.Subdomain("www")` or `app.Party("www.")` is that the `app.WWW()` method
  168. // wraps the router so all http(s)://mydomain.com will be redirect to http(s)://www.mydomain.com.
  169. // Other subdomains can be registered using the app: `sub := app.Subdomain("mysubdomain")`,
  170. // child subdomains can be registered using the www := app.WWW(); www.Subdomain("wwwchildSubdomain").
  171. func (app *Application) WWW() router.Party {
  172. return app.SubdomainRedirect(app, app.Subdomain("www"))
  173. }
  174. // SubdomainRedirect registers a router wrapper which
  175. // redirects(StatusMovedPermanently) a (sub)domain to another subdomain or to the root domain as fast as possible,
  176. // before the router's try to execute route's handler(s).
  177. //
  178. // It receives two arguments, they are the from and to/target locations,
  179. // 'from' can be a wildcard subdomain as well (app.WildcardSubdomain())
  180. // 'to' is not allowed to be a wildcard for obvious reasons,
  181. // 'from' can be the root domain(app) when the 'to' is not the root domain and visa-versa.
  182. //
  183. // Usage:
  184. // www := app.Subdomain("www") <- same as app.Party("www.")
  185. // app.SubdomainRedirect(app, www)
  186. // This will redirect all http(s)://mydomain.com/%anypath% to http(s)://www.mydomain.com/%anypath%.
  187. //
  188. // One or more subdomain redirects can be used to the same app instance.
  189. //
  190. // If you need more information about this implementation then you have to navigate through
  191. // the `core/router#NewSubdomainRedirectWrapper` function instead.
  192. //
  193. // Example: https://github.com/kataras/iris/tree/master/_examples/subdomains/redirect
  194. func (app *Application) SubdomainRedirect(from, to router.Party) router.Party {
  195. sd := router.NewSubdomainRedirectWrapper(app.ConfigurationReadOnly().GetVHost, from.GetRelPath(), to.GetRelPath())
  196. app.WrapRouter(sd)
  197. return to
  198. }
  199. // Configure can called when modifications to the framework instance needed.
  200. // It accepts the framework instance
  201. // and returns an error which if it's not nil it's printed to the logger.
  202. // See configuration.go for more.
  203. //
  204. // Returns itself in order to be used like `app:= New().Configure(...)`
  205. func (app *Application) Configure(configurators ...Configurator) *Application {
  206. for _, cfg := range configurators {
  207. cfg(app)
  208. }
  209. return app
  210. }
  211. // ConfigurationReadOnly returns an object which doesn't allow field writing.
  212. func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
  213. return app.config
  214. }
  215. // Logger returns the golog logger instance(pointer) that is being used inside the "app".
  216. //
  217. // Available levels:
  218. // - "disable"
  219. // - "fatal"
  220. // - "error"
  221. // - "warn"
  222. // - "info"
  223. // - "debug"
  224. // Usage: app.Logger().SetLevel("error")
  225. // Defaults to "info" level.
  226. //
  227. // Callers can use the application's logger which is
  228. // the same `golog.Default` logger,
  229. // to print custom logs too.
  230. // Usage:
  231. // app.Logger().Error/Errorf("...")
  232. // app.Logger().Warn/Warnf("...")
  233. // app.Logger().Info/Infof("...")
  234. // app.Logger().Debug/Debugf("...")
  235. //
  236. // Setting one or more outputs: app.Logger().SetOutput(io.Writer...)
  237. // Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
  238. //
  239. // Adding custom levels requires import of the `github.com/kataras/golog` package:
  240. // First we create our level to a golog.Level
  241. // in order to be used in the Log functions.
  242. // var SuccessLevel golog.Level = 6
  243. // Register our level, just three fields.
  244. // golog.Levels[SuccessLevel] = &golog.LevelMetadata{
  245. // Name: "success",
  246. // RawText: "[SUCC]",
  247. // // ColorfulText (Green Color[SUCC])
  248. // ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
  249. // }
  250. // Usage:
  251. // app.Logger().SetLevel("success")
  252. // app.Logger().Logf(SuccessLevel, "a custom leveled log message")
  253. func (app *Application) Logger() *golog.Logger {
  254. return app.logger
  255. }
  256. var (
  257. // HTML view engine.
  258. // Conversion for the view.HTML.
  259. HTML = view.HTML
  260. // Django view engine.
  261. // Conversion for the view.Django.
  262. Django = view.Django
  263. // Handlebars view engine.
  264. // Conversion for the view.Handlebars.
  265. Handlebars = view.Handlebars
  266. // Pug view engine.
  267. // Conversion for the view.Pug.
  268. Pug = view.Pug
  269. // Amber view engine.
  270. // Conversion for the view.Amber.
  271. Amber = view.Amber
  272. )
  273. // NoLayout to disable layout for a particular template file
  274. // A shortcut for the `view#NoLayout`.
  275. const NoLayout = view.NoLayout
  276. // RegisterView should be used to register view engines mapping to a root directory
  277. // and the template file(s) extension.
  278. func (app *Application) RegisterView(viewEngine view.Engine) {
  279. app.view.Register(viewEngine)
  280. }
  281. // View executes and writes the result of a template file to the writer.
  282. //
  283. // First parameter is the writer to write the parsed template.
  284. // Second parameter is the relative, to templates directory, template filename, including extension.
  285. // Third parameter is the layout, can be empty string.
  286. // Forth parameter is the bindable data to the template, can be nil.
  287. //
  288. // Use context.View to render templates to the client instead.
  289. // Returns an error on failure, otherwise nil.
  290. func (app *Application) View(writer io.Writer, filename string, layout string, bindingData interface{}) error {
  291. if app.view.Len() == 0 {
  292. err := errors.New("view engine is missing, use `RegisterView`")
  293. app.Logger().Error(err)
  294. return err
  295. }
  296. err := app.view.ExecuteWriter(writer, filename, layout, bindingData)
  297. if err != nil {
  298. app.Logger().Error(err)
  299. }
  300. return err
  301. }
  302. var (
  303. // LimitRequestBodySize is a middleware which sets a request body size limit
  304. // for all next handlers in the chain.
  305. //
  306. // A shortcut for the `context#LimitRequestBodySize`.
  307. LimitRequestBodySize = context.LimitRequestBodySize
  308. // StaticEmbeddedHandler returns a Handler which can serve
  309. // embedded into executable files.
  310. //
  311. //
  312. // Examples: https://github.com/kataras/iris/tree/master/_examples/file-server
  313. StaticEmbeddedHandler = router.StaticEmbeddedHandler
  314. // StripPrefix returns a handler that serves HTTP requests
  315. // by removing the given prefix from the request URL's Path
  316. // and invoking the handler h. StripPrefix handles a
  317. // request for a path that doesn't begin with prefix by
  318. // replying with an HTTP 404 not found error.
  319. //
  320. // Usage:
  321. // fileserver := Party#StaticHandler("./static_files", false, false)
  322. // h := iris.StripPrefix("/static", fileserver)
  323. // app.Get("/static/{f:path}", h)
  324. // app.Head("/static/{f:path}", h)
  325. StripPrefix = router.StripPrefix
  326. // Gzip is a middleware which enables writing
  327. // using gzip compression, if client supports.
  328. //
  329. // A shortcut for the `context#Gzip`.
  330. Gzip = context.Gzip
  331. // FromStd converts native http.Handler, http.HandlerFunc & func(w, r, next) to context.Handler.
  332. //
  333. // Supported form types:
  334. // .FromStd(h http.Handler)
  335. // .FromStd(func(w http.ResponseWriter, r *http.Request))
  336. // .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
  337. //
  338. // A shortcut for the `handlerconv#FromStd`.
  339. FromStd = handlerconv.FromStd
  340. // Cache is a middleware providing server-side cache functionalities
  341. // to the next handlers, can be used as: `app.Get("/", iris.Cache, aboutHandler)`.
  342. // It should be used after Static methods.
  343. // See `iris#Cache304` for an alternative, faster way.
  344. //
  345. // Examples can be found at: https://github.com/kataras/iris/tree/master/_examples/#caching
  346. Cache = cache.Handler
  347. // NoCache is a middleware which overrides the Cache-Control, Pragma and Expires headers
  348. // in order to disable the cache during the browser's back and forward feature.
  349. //
  350. // A good use of this middleware is on HTML routes; to refresh the page even on "back" and "forward" browser's arrow buttons.
  351. //
  352. // See `iris#StaticCache` for the opposite behavior.
  353. //
  354. // A shortcut of the `cache#NoCache`
  355. NoCache = cache.NoCache
  356. // StaticCache middleware for caching static files by sending the "Cache-Control" and "Expires" headers to the client.
  357. // It accepts a single input parameter, the "cacheDur", a time.Duration that it's used to calculate the expiration.
  358. //
  359. // If "cacheDur" <=0 then it returns the `NoCache` middleware instaed to disable the caching between browser's "back" and "forward" actions.
  360. //
  361. // Usage: `app.Use(iris.StaticCache(24 * time.Hour))` or `app.Use(iris.Staticcache(-1))`.
  362. // A middleware, which is a simple Handler can be called inside another handler as well, example:
  363. // cacheMiddleware := iris.StaticCache(...)
  364. // func(ctx iris.Context){
  365. // cacheMiddleware(ctx)
  366. // [...]
  367. // }
  368. //
  369. // A shortcut of the `cache#StaticCache`
  370. StaticCache = cache.StaticCache
  371. // Cache304 sends a `StatusNotModified` (304) whenever
  372. // the "If-Modified-Since" request header (time) is before the
  373. // time.Now() + expiresEvery (always compared to their UTC values).
  374. // Use this, which is a shortcut of the, `chache#Cache304` instead of the "github.com/kataras/iris/cache" or iris.Cache
  375. // for better performance.
  376. // Clients that are compatible with the http RCF (all browsers are and tools like postman)
  377. // will handle the caching.
  378. // The only disadvantage of using that instead of server-side caching
  379. // is that this method will send a 304 status code instead of 200,
  380. // So, if you use it side by side with other micro services
  381. // you have to check for that status code as well for a valid response.
  382. //
  383. // Developers are free to extend this method's behavior
  384. // by watching system directories changes manually and use of the `ctx.WriteWithExpiration`
  385. // with a "modtime" based on the file modified date,
  386. // simillary to the `StaticWeb`(which sends status OK(200) and browser disk caching instead of 304).
  387. //
  388. // A shortcut of the `cache#Cache304`.
  389. Cache304 = cache.Cache304
  390. // CookiePath is a `CookieOption`.
  391. // Use it to change the cookie's Path field.
  392. //
  393. // A shortcut for the `context#CookiePath`.
  394. CookiePath = context.CookiePath
  395. // CookieCleanPath is a `CookieOption`.
  396. // Use it to clear the cookie's Path field, exactly the same as `CookiePath("")`.
  397. //
  398. // A shortcut for the `context#CookieCleanPath`.
  399. CookieCleanPath = context.CookieCleanPath
  400. // CookieExpires is a `CookieOption`.
  401. // Use it to change the cookie's Expires and MaxAge fields by passing the lifetime of the cookie.
  402. //
  403. // A shortcut for the `context#CookieExpires`.
  404. CookieExpires = context.CookieExpires
  405. // CookieHTTPOnly is a `CookieOption`.
  406. // Use it to set the cookie's HttpOnly field to false or true.
  407. // HttpOnly field defaults to true for `RemoveCookie` and `SetCookieKV`.
  408. //
  409. // A shortcut for the `context#CookieHTTPOnly`.
  410. CookieHTTPOnly = context.CookieHTTPOnly
  411. // CookieEncode is a `CookieOption`.
  412. // Provides encoding functionality when adding a cookie.
  413. // Accepts a `context#CookieEncoder` and sets the cookie's value to the encoded value.
  414. // Users of that is the `context#SetCookie` and `context#SetCookieKV`.
  415. //
  416. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
  417. //
  418. // A shortcut for the `context#CookieEncode`.
  419. CookieEncode = context.CookieEncode
  420. // CookieDecode is a `CookieOption`.
  421. // Provides decoding functionality when retrieving a cookie.
  422. // Accepts a `context#CookieDecoder` and sets the cookie's value to the decoded value before return by the `GetCookie`.
  423. // User of that is the `context#GetCookie`.
  424. //
  425. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
  426. //
  427. // A shortcut for the `context#CookieDecode`.
  428. CookieDecode = context.CookieDecode
  429. )
  430. // SPA accepts an "assetHandler" which can be the result of an
  431. // app.StaticHandler or app.StaticEmbeddedHandler.
  432. // Use that when you want to navigate from /index.html to / automatically
  433. // it's a helper function which just makes some checks based on the `IndexNames` and `AssetValidators`
  434. // before the assetHandler call.
  435. //
  436. // Example: https://github.com/kataras/iris/tree/master/_examples/file-server/single-page-application
  437. func (app *Application) SPA(assetHandler context.Handler) *router.SPABuilder {
  438. s := router.NewSPABuilder(assetHandler)
  439. app.APIBuilder.HandleMany("GET HEAD", "/{f:path}", s.Handler)
  440. return s
  441. }
  442. // ConfigureHost accepts one or more `host#Configuration`, these configurators functions
  443. // can access the host created by `app.Run`,
  444. // they're being executed when application is ready to being served to the public.
  445. //
  446. // It's an alternative way to interact with a host that is automatically created by
  447. // `app.Run`.
  448. //
  449. // These "configurators" can work side-by-side with the `iris#Addr, iris#Server, iris#TLS, iris#AutoTLS, iris#Listener`
  450. // final arguments("hostConfigs") too.
  451. //
  452. // Note that these application's host "configurators" will be shared with the rest of
  453. // the hosts that this app will may create (using `app.NewHost`), meaning that
  454. // `app.NewHost` will execute these "configurators" everytime that is being called as well.
  455. //
  456. // These "configurators" should be registered before the `app.Run` or `host.Serve/Listen` functions.
  457. func (app *Application) ConfigureHost(configurators ...host.Configurator) *Application {
  458. app.mu.Lock()
  459. app.hostConfigurators = append(app.hostConfigurators, configurators...)
  460. app.mu.Unlock()
  461. return app
  462. }
  463. // NewHost accepts a standar *http.Server object,
  464. // completes the necessary missing parts of that "srv"
  465. // and returns a new, ready-to-use, host (supervisor).
  466. func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
  467. app.mu.Lock()
  468. defer app.mu.Unlock()
  469. // set the server's handler to the framework's router
  470. if srv.Handler == nil {
  471. srv.Handler = app.Router
  472. }
  473. // check if different ErrorLog provided, if not bind it with the framework's logger
  474. if srv.ErrorLog == nil {
  475. srv.ErrorLog = log.New(app.logger.Printer.Output, "[HTTP Server] ", 0)
  476. }
  477. if srv.Addr == "" {
  478. srv.Addr = ":8080"
  479. }
  480. app.logger.Debugf("Host: addr is %s", srv.Addr)
  481. // create the new host supervisor
  482. // bind the constructed server and return it
  483. su := host.New(srv)
  484. if app.config.vhost == "" { // vhost now is useful for router subdomain on wildcard subdomains,
  485. // in order to correct decide what to do on:
  486. // mydomain.com -> invalid
  487. // localhost -> invalid
  488. // sub.mydomain.com -> valid
  489. // sub.localhost -> valid
  490. // we need the host (without port if 80 or 443) in order to validate these, so:
  491. app.config.vhost = netutil.ResolveVHost(srv.Addr)
  492. }
  493. app.logger.Debugf("Host: virtual host is %s", app.config.vhost)
  494. // the below schedules some tasks that will run among the server
  495. if !app.config.DisableStartupLog {
  496. // show the available info to exit from app.
  497. su.RegisterOnServe(host.WriteStartupLogOnServe(app.logger.Printer.Output)) // app.logger.Writer -> Info
  498. app.logger.Debugf("Host: register startup notifier")
  499. }
  500. if !app.config.DisableInterruptHandler {
  501. // when CTRL+C/CMD+C pressed.
  502. shutdownTimeout := 5 * time.Second
  503. host.RegisterOnInterrupt(host.ShutdownOnInterrupt(su, shutdownTimeout))
  504. app.logger.Debugf("Host: register server shutdown on interrupt(CTRL+C/CMD+C)")
  505. }
  506. su.IgnoredErrors = append(su.IgnoredErrors, app.config.IgnoreServerErrors...)
  507. if len(su.IgnoredErrors) > 0 {
  508. app.logger.Debugf("Host: server will ignore the following errors: %s", su.IgnoredErrors)
  509. }
  510. su.Configure(app.hostConfigurators...)
  511. app.Hosts = append(app.Hosts, su)
  512. return su
  513. }
  514. // RegisterOnInterrupt registers a global function to call when CTRL+C/CMD+C pressed or a unix kill command received.
  515. //
  516. // A shortcut for the `host#RegisterOnInterrupt`.
  517. var RegisterOnInterrupt = host.RegisterOnInterrupt
  518. // Shutdown gracefully terminates all the application's server hosts.
  519. // Returns an error on the first failure, otherwise nil.
  520. func (app *Application) Shutdown(ctx stdContext.Context) error {
  521. for i, su := range app.Hosts {
  522. app.logger.Debugf("Host[%d]: Shutdown now", i)
  523. if err := su.Shutdown(ctx); err != nil {
  524. app.logger.Debugf("Host[%d]: Error while trying to shutdown", i)
  525. return err
  526. }
  527. }
  528. return nil
  529. }
  530. // Runner is just an interface which accepts the framework instance
  531. // and returns an error.
  532. //
  533. // It can be used to register a custom runner with `Run` in order
  534. // to set the framework's server listen action.
  535. //
  536. // Currently Runner is being used to declare the built'n server listeners.
  537. //
  538. // See `Run` for more.
  539. type Runner func(*Application) error
  540. // Listener can be used as an argument for the `Run` method.
  541. // It can start a server with a custom net.Listener via server's `Serve`.
  542. //
  543. // Second argument is optional, it accepts one or more
  544. // `func(*host.Configurator)` that are being executed
  545. // on that specific host that this function will create to start the server.
  546. // Via host configurators you can configure the back-end host supervisor,
  547. // i.e to add events for shutdown, serve or error.
  548. // An example of this use case can be found at:
  549. // https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
  550. // Look at the `ConfigureHost` too.
  551. //
  552. // See `Run` for more.
  553. func Listener(l net.Listener, hostConfigs ...host.Configurator) Runner {
  554. return func(app *Application) error {
  555. app.config.vhost = netutil.ResolveVHost(l.Addr().String())
  556. return app.NewHost(&http.Server{Addr: l.Addr().String()}).
  557. Configure(hostConfigs...).
  558. Serve(l)
  559. }
  560. }
  561. // Server can be used as an argument for the `Run` method.
  562. // It can start a server with a *http.Server.
  563. //
  564. // Second argument is optional, it accepts one or more
  565. // `func(*host.Configurator)` that are being executed
  566. // on that specific host that this function will create to start the server.
  567. // Via host configurators you can configure the back-end host supervisor,
  568. // i.e to add events for shutdown, serve or error.
  569. // An example of this use case can be found at:
  570. // https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
  571. // Look at the `ConfigureHost` too.
  572. //
  573. // See `Run` for more.
  574. func Server(srv *http.Server, hostConfigs ...host.Configurator) Runner {
  575. return func(app *Application) error {
  576. return app.NewHost(srv).
  577. Configure(hostConfigs...).
  578. ListenAndServe()
  579. }
  580. }
  581. // Addr can be used as an argument for the `Run` method.
  582. // It accepts a host address which is used to build a server
  583. // and a listener which listens on that host and port.
  584. //
  585. // Addr should have the form of [host]:port, i.e localhost:8080 or :8080.
  586. //
  587. // Second argument is optional, it accepts one or more
  588. // `func(*host.Configurator)` that are being executed
  589. // on that specific host that this function will create to start the server.
  590. // Via host configurators you can configure the back-end host supervisor,
  591. // i.e to add events for shutdown, serve or error.
  592. // An example of this use case can be found at:
  593. // https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
  594. // Look at the `ConfigureHost` too.
  595. //
  596. // See `Run` for more.
  597. func Addr(addr string, hostConfigs ...host.Configurator) Runner {
  598. return func(app *Application) error {
  599. return app.NewHost(&http.Server{Addr: addr}).
  600. Configure(hostConfigs...).
  601. ListenAndServe()
  602. }
  603. }
  604. // TLS can be used as an argument for the `Run` method.
  605. // It will start the Application's secure server.
  606. //
  607. // Use it like you used to use the http.ListenAndServeTLS function.
  608. //
  609. // Addr should have the form of [host]:port, i.e localhost:443 or :443.
  610. // CertFile & KeyFile should be filenames with their extensions.
  611. //
  612. // Second argument is optional, it accepts one or more
  613. // `func(*host.Configurator)` that are being executed
  614. // on that specific host that this function will create to start the server.
  615. // Via host configurators you can configure the back-end host supervisor,
  616. // i.e to add events for shutdown, serve or error.
  617. // An example of this use case can be found at:
  618. // https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
  619. // Look at the `ConfigureHost` too.
  620. //
  621. // See `Run` for more.
  622. func TLS(addr string, certFile, keyFile string, hostConfigs ...host.Configurator) Runner {
  623. return func(app *Application) error {
  624. return app.NewHost(&http.Server{Addr: addr}).
  625. Configure(hostConfigs...).
  626. ListenAndServeTLS(certFile, keyFile)
  627. }
  628. }
  629. // AutoTLS can be used as an argument for the `Run` method.
  630. // It will start the Application's secure server using
  631. // certifications created on the fly by the "autocert" golang/x package,
  632. // so localhost may not be working, use it at "production" machine.
  633. //
  634. // Addr should have the form of [host]:port, i.e mydomain.com:443.
  635. //
  636. // The whitelisted domains are separated by whitespace in "domain" argument,
  637. // i.e "iris-go.com", can be different than "addr".
  638. // If empty, all hosts are currently allowed. This is not recommended,
  639. // as it opens a potential attack where clients connect to a server
  640. // by IP address and pretend to be asking for an incorrect host name.
  641. // Manager will attempt to obtain a certificate for that host, incorrectly,
  642. // eventually reaching the CA's rate limit for certificate requests
  643. // and making it impossible to obtain actual certificates.
  644. //
  645. // For an "e-mail" use a non-public one, letsencrypt needs that for your own security.
  646. //
  647. // Note: `AutoTLS` will start a new server for you
  648. // which will redirect all http versions to their https, including subdomains as well.
  649. //
  650. // Last argument is optional, it accepts one or more
  651. // `func(*host.Configurator)` that are being executed
  652. // on that specific host that this function will create to start the server.
  653. // Via host configurators you can configure the back-end host supervisor,
  654. // i.e to add events for shutdown, serve or error.
  655. // An example of this use case can be found at:
  656. // https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
  657. // Look at the `ConfigureHost` too.
  658. //
  659. // Usage:
  660. // app.Run(iris.AutoTLS("iris-go.com:443", "iris-go.com www.iris-go.com", "mail@example.com"))
  661. //
  662. // See `Run` and `core/host/Supervisor#ListenAndServeAutoTLS` for more.
  663. func AutoTLS(
  664. addr string,
  665. domain string, email string,
  666. hostConfigs ...host.Configurator) Runner {
  667. return func(app *Application) error {
  668. return app.NewHost(&http.Server{Addr: addr}).
  669. Configure(hostConfigs...).
  670. ListenAndServeAutoTLS(domain, email, "letscache")
  671. }
  672. }
  673. // Raw can be used as an argument for the `Run` method.
  674. // It accepts any (listen) function that returns an error,
  675. // this function should be block and return an error
  676. // only when the server exited or a fatal error caused.
  677. //
  678. // With this option you're not limited to the servers
  679. // that iris can run by-default.
  680. //
  681. // See `Run` for more.
  682. func Raw(f func() error) Runner {
  683. return func(app *Application) error {
  684. app.logger.Debugf("HTTP Server will start from unknown, external function")
  685. return f()
  686. }
  687. }
  688. // Build sets up, once, the framework.
  689. // It builds the default router with its default macros
  690. // and the template functions that are very-closed to iris.
  691. func (app *Application) Build() error {
  692. rp := errors.NewReporter()
  693. app.once.Do(func() {
  694. rp.Describe("api builder: %v", app.APIBuilder.GetReport())
  695. if !app.Router.Downgraded() {
  696. // router
  697. // create the request handler, the default routing handler
  698. routerHandler := router.NewDefaultHandler()
  699. rp.Describe("router: %v", app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder))
  700. // re-build of the router from outside can be done with;
  701. // app.RefreshRouter()
  702. }
  703. if app.view.Len() > 0 {
  704. app.logger.Debugf("Application: %d registered view engine(s)", app.view.Len())
  705. // view engine
  706. // here is where we declare the closed-relative framework functions.
  707. // Each engine has their defaults, i.e yield,render,render_r,partial, params...
  708. rv := router.NewRoutePathReverser(app.APIBuilder)
  709. app.view.AddFunc("urlpath", rv.Path)
  710. // app.view.AddFunc("url", rv.URL)
  711. rp.Describe("view: %v", app.view.Load())
  712. }
  713. })
  714. return rp.Return()
  715. }
  716. // ErrServerClosed is returned by the Server's Serve, ServeTLS, ListenAndServe,
  717. // and ListenAndServeTLS methods after a call to Shutdown or Close.
  718. //
  719. // A shortcut for the `http#ErrServerClosed`.
  720. var ErrServerClosed = http.ErrServerClosed
  721. // Run builds the framework and starts the desired `Runner` with or without configuration edits.
  722. //
  723. // Run should be called only once per Application instance, it blocks like http.Server.
  724. //
  725. // If more than one server needed to run on the same iris instance
  726. // then create a new host and run it manually by `go NewHost(*http.Server).Serve/ListenAndServe` etc...
  727. // or use an already created host:
  728. // h := NewHost(*http.Server)
  729. // Run(Raw(h.ListenAndServe), WithCharset("UTF-8"), WithRemoteAddrHeader("CF-Connecting-IP"))
  730. //
  731. // The Application can go online with any type of server or iris's host with the help of
  732. // the following runners:
  733. // `Listener`, `Server`, `Addr`, `TLS`, `AutoTLS` and `Raw`.
  734. func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error {
  735. // first Build because it doesn't need anything from configuration,
  736. // this gives the user the chance to modify the router inside a configurator as well.
  737. if err := app.Build(); err != nil {
  738. return errors.PrintAndReturnErrors(err, app.logger.Errorf)
  739. }
  740. app.Configure(withOrWithout...)
  741. app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1)
  742. if !app.config.DisableVersionChecker {
  743. go maintenance.Start()
  744. }
  745. // this will block until an error(unless supervisor's DeferFlow called from a Task).
  746. err := serve(app)
  747. if err != nil {
  748. app.Logger().Error(err)
  749. }
  750. return err
  751. }