iris.go 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. package iris
  2. import (
  3. "bytes"
  4. stdContext "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "log"
  9. "net"
  10. "net/http"
  11. "os"
  12. "regexp"
  13. "strings"
  14. "sync"
  15. "time"
  16. "github.com/kataras/iris/v12/context"
  17. "github.com/kataras/iris/v12/core/host"
  18. "github.com/kataras/iris/v12/core/netutil"
  19. "github.com/kataras/iris/v12/core/router"
  20. "github.com/kataras/iris/v12/i18n"
  21. "github.com/kataras/iris/v12/middleware/cors"
  22. "github.com/kataras/iris/v12/middleware/recover"
  23. "github.com/kataras/iris/v12/middleware/requestid"
  24. "github.com/kataras/iris/v12/view"
  25. "github.com/kataras/golog"
  26. "github.com/kataras/tunnel"
  27. "github.com/tdewolff/minify/v2"
  28. "github.com/tdewolff/minify/v2/css"
  29. "github.com/tdewolff/minify/v2/html"
  30. "github.com/tdewolff/minify/v2/js"
  31. "github.com/tdewolff/minify/v2/json"
  32. "github.com/tdewolff/minify/v2/svg"
  33. "github.com/tdewolff/minify/v2/xml"
  34. )
  35. // Version is the current version of the Iris Web Framework.
  36. const Version = "12.2.8"
  37. // Byte unit helpers.
  38. const (
  39. B = 1 << (10 * iota)
  40. KB
  41. MB
  42. GB
  43. TB
  44. PB
  45. EB
  46. )
  47. // Application is responsible to manage the state of the application.
  48. // It contains and handles all the necessary parts to create a fast web server.
  49. type Application struct {
  50. // routing embedded | exposing APIBuilder's and Router's public API.
  51. *router.APIBuilder
  52. *router.Router
  53. router.HTTPErrorHandler // if Router is Downgraded this is nil.
  54. ContextPool *context.Pool
  55. // See SetContextErrorHandler, defaults to nil.
  56. contextErrorHandler context.ErrorHandler
  57. // config contains the configuration fields
  58. // all fields defaults to something that is working, developers don't have to set it.
  59. config *Configuration
  60. // the golog logger instance, defaults to "Info" level messages (all except "Debug")
  61. logger *golog.Logger
  62. // I18n contains localization and internationalization support.
  63. // Use the `Load` or `LoadAssets` to locale language files.
  64. //
  65. // See `Context#Tr` method for request-based translations.
  66. I18n *i18n.I18n
  67. // Validator is the request body validator, defaults to nil.
  68. Validator context.Validator
  69. // Minifier to minify responses.
  70. minifier *minify.M
  71. // view engine
  72. view *view.View
  73. // used for build
  74. builded bool
  75. defaultMode bool
  76. // OnBuild is a single function which
  77. // is fired on the first `Build` method call.
  78. // If reports an error then the execution
  79. // is stopped and the error is logged.
  80. // It's nil by default except when `Switch` instead of `New` or `Default`
  81. // is used to initialize the Application.
  82. // Users can wrap it to accept more events.
  83. OnBuild func() error
  84. mu sync.Mutex
  85. // name is the application name and the log prefix for
  86. // that Application instance's Logger. See `SetName` and `String`.
  87. // Defaults to IRIS_APP_NAME envrinoment variable otherwise empty.
  88. name string
  89. // Hosts contains a list of all servers (Host Supervisors) that this app is running on.
  90. //
  91. // Hosts may be empty only if application ran(`app.Run`) with `iris.Raw` option runner,
  92. // otherwise it contains a single host (`app.Hosts[0]`).
  93. //
  94. // Additional Host Supervisors can be added to that list by calling the `app.NewHost` manually.
  95. //
  96. // Hosts field is available after `Run` or `NewHost`.
  97. Hosts []*host.Supervisor
  98. hostConfigurators []host.Configurator
  99. }
  100. // New creates and returns a fresh empty iris *Application instance.
  101. func New() *Application {
  102. config := DefaultConfiguration()
  103. app := &Application{
  104. config: &config,
  105. Router: router.NewRouter(),
  106. I18n: i18n.New(),
  107. minifier: newMinifier(),
  108. view: new(view.View),
  109. }
  110. logger := newLogger(app)
  111. app.logger = logger
  112. app.APIBuilder = router.NewAPIBuilder(logger)
  113. app.ContextPool = context.New(func() interface{} {
  114. return context.NewContext(app)
  115. })
  116. context.RegisterApplication(app)
  117. return app
  118. }
  119. // Default returns a new Application.
  120. // Default with "debug" Logger Level.
  121. // Localization enabled on "./locales" directory
  122. // and HTML templates on "./views" or "./templates" directory.
  123. // CORS (allow all), Recovery and
  124. // Request ID middleware already registered.
  125. func Default() *Application {
  126. app := New()
  127. // Set default log level.
  128. app.logger.SetLevel("debug")
  129. app.logger.Debugf(`Log level set to "debug"`)
  130. /* #2046.
  131. // Register the accesslog middleware.
  132. logFile, err := os.OpenFile("./access.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600)
  133. if err == nil {
  134. // Close the file on shutdown.
  135. app.ConfigureHost(func(su *Supervisor) {
  136. su.RegisterOnShutdown(func() {
  137. logFile.Close()
  138. })
  139. })
  140. ac := accesslog.New(logFile)
  141. ac.AddOutput(app.logger.Printer)
  142. app.UseRouter(ac.Handler)
  143. app.logger.Debugf("Using <%s> to log requests", logFile.Name())
  144. }
  145. */
  146. // Register the requestid middleware
  147. // before recover so current Context.GetID() contains the info on panic logs.
  148. app.UseRouter(requestid.New())
  149. app.logger.Debugf("Using <UUID4> to identify requests")
  150. // Register the recovery, after accesslog and recover,
  151. // before end-developer's middleware.
  152. app.UseRouter(recover.New())
  153. // Register CORS (allow any origin to pass through) middleware.
  154. app.UseRouter(cors.New().
  155. ExtractOriginFunc(cors.DefaultOriginExtractor).
  156. ReferrerPolicy(cors.NoReferrerWhenDowngrade).
  157. AllowOriginFunc(cors.AllowAnyOrigin).
  158. Handler())
  159. app.defaultMode = true
  160. return app
  161. }
  162. func newLogger(app *Application) *golog.Logger {
  163. logger := golog.Default.Child(app)
  164. if name := os.Getenv("IRIS_APP_NAME"); name != "" {
  165. app.name = name
  166. logger.SetChildPrefix(name)
  167. }
  168. return logger
  169. }
  170. // SetName sets a unique name to this Iris Application.
  171. // It sets a child prefix for the current Application's Logger.
  172. // Look `String` method too.
  173. //
  174. // It returns this Application.
  175. func (app *Application) SetName(appName string) *Application {
  176. app.mu.Lock()
  177. defer app.mu.Unlock()
  178. if app.name == "" {
  179. app.logger.SetChildPrefix(appName)
  180. }
  181. app.name = appName
  182. return app
  183. }
  184. // String completes the fmt.Stringer interface and it returns
  185. // the application's name.
  186. // If name was not set by `SetName` or `IRIS_APP_NAME` environment variable
  187. // then this will return an empty string.
  188. func (app *Application) String() string {
  189. return app.name
  190. }
  191. // WWW creates and returns a "www." subdomain.
  192. // The difference from `app.Subdomain("www")` or `app.Party("www.")` is that the `app.WWW()` method
  193. // wraps the router so all http(s)://mydomain.com will be redirect to http(s)://www.mydomain.com.
  194. // Other subdomains can be registered using the app: `sub := app.Subdomain("mysubdomain")`,
  195. // child subdomains can be registered using the www := app.WWW(); www.Subdomain("wwwchildSubdomain").
  196. func (app *Application) WWW() router.Party {
  197. return app.SubdomainRedirect(app, app.Subdomain("www"))
  198. }
  199. // SubdomainRedirect registers a router wrapper which
  200. // redirects(StatusMovedPermanently) a (sub)domain to another subdomain or to the root domain as fast as possible,
  201. // before the router's try to execute route's handler(s).
  202. //
  203. // It receives two arguments, they are the from and to/target locations,
  204. // 'from' can be a wildcard subdomain as well (app.WildcardSubdomain())
  205. // 'to' is not allowed to be a wildcard for obvious reasons,
  206. // 'from' can be the root domain(app) when the 'to' is not the root domain and visa-versa.
  207. //
  208. // Usage:
  209. // www := app.Subdomain("www") <- same as app.Party("www.")
  210. // app.SubdomainRedirect(app, www)
  211. // This will redirect all http(s)://mydomain.com/%anypath% to http(s)://www.mydomain.com/%anypath%.
  212. //
  213. // One or more subdomain redirects can be used to the same app instance.
  214. //
  215. // If you need more information about this implementation then you have to navigate through
  216. // the `core/router#NewSubdomainRedirectWrapper` function instead.
  217. //
  218. // Example: https://github.com/kataras/iris/tree/main/_examples/routing/subdomains/redirect
  219. func (app *Application) SubdomainRedirect(from, to router.Party) router.Party {
  220. sd := router.NewSubdomainRedirectWrapper(app.ConfigurationReadOnly().GetVHost, from.GetRelPath(), to.GetRelPath())
  221. app.Router.AddRouterWrapper(sd)
  222. return to
  223. }
  224. // Configure can called when modifications to the framework instance needed.
  225. // It accepts the framework instance
  226. // and returns an error which if it's not nil it's printed to the logger.
  227. // See configuration.go for more.
  228. //
  229. // Returns itself in order to be used like `app:= New().Configure(...)`
  230. func (app *Application) Configure(configurators ...Configurator) *Application {
  231. for _, cfg := range configurators {
  232. if cfg != nil {
  233. cfg(app)
  234. }
  235. }
  236. return app
  237. }
  238. // ConfigurationReadOnly returns an object which doesn't allow field writing.
  239. func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
  240. return app.config
  241. }
  242. // Logger returns the golog logger instance(pointer) that is being used inside the "app".
  243. //
  244. // Available levels:
  245. // - "disable"
  246. // - "fatal"
  247. // - "error"
  248. // - "warn"
  249. // - "info"
  250. // - "debug"
  251. // Usage: app.Logger().SetLevel("error")
  252. // Or set the level through Configurartion's LogLevel or WithLogLevel functional option.
  253. // Defaults to "info" level.
  254. //
  255. // Callers can use the application's logger which is
  256. // the same `golog.Default.LastChild()` logger,
  257. // to print custom logs too.
  258. // Usage:
  259. // app.Logger().Error/Errorf("...")
  260. // app.Logger().Warn/Warnf("...")
  261. // app.Logger().Info/Infof("...")
  262. // app.Logger().Debug/Debugf("...")
  263. //
  264. // Setting one or more outputs: app.Logger().SetOutput(io.Writer...)
  265. // Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
  266. //
  267. // Adding custom levels requires import of the `github.com/kataras/golog` package:
  268. //
  269. // First we create our level to a golog.Level
  270. // in order to be used in the Log functions.
  271. // var SuccessLevel golog.Level = 6
  272. // Register our level, just three fields.
  273. // golog.Levels[SuccessLevel] = &golog.LevelMetadata{
  274. // Name: "success",
  275. // RawText: "[SUCC]",
  276. // // ColorfulText (Green Color[SUCC])
  277. // ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
  278. // }
  279. //
  280. // Usage:
  281. // app.Logger().SetLevel("success")
  282. // app.Logger().Logf(SuccessLevel, "a custom leveled log message")
  283. func (app *Application) Logger() *golog.Logger {
  284. return app.logger
  285. }
  286. // IsDebug reports whether the application is running
  287. // under debug/development mode.
  288. // It's just a shortcut of Logger().Level >= golog.DebugLevel.
  289. // The same method existss as Context.IsDebug() too.
  290. func (app *Application) IsDebug() bool {
  291. return app.logger.Level >= golog.DebugLevel
  292. }
  293. // I18nReadOnly returns the i18n's read-only features.
  294. // See `I18n` method for more.
  295. func (app *Application) I18nReadOnly() context.I18nReadOnly {
  296. return app.I18n
  297. }
  298. // Validate validates a value and returns nil if passed or
  299. // the failure reason if does not.
  300. func (app *Application) Validate(v interface{}) error {
  301. if app.Validator == nil {
  302. return nil
  303. }
  304. // val := reflect.ValueOf(v)
  305. // if val.Kind() == reflect.Ptr && !val.IsNil() {
  306. // val = val.Elem()
  307. // }
  308. // if val.Kind() == reflect.Struct && val.Type() != timeType {
  309. // return app.Validator.Struct(v)
  310. // }
  311. // no need to check the kind, underline lib does it but in the future this may change (look above).
  312. err := app.Validator.Struct(v)
  313. if err != nil {
  314. if !strings.HasPrefix(err.Error(), "validator: ") {
  315. return err
  316. }
  317. }
  318. return nil
  319. }
  320. func newMinifier() *minify.M {
  321. m := minify.New()
  322. m.AddFunc("text/css", css.Minify)
  323. m.AddFunc("text/html", html.Minify)
  324. m.AddFunc("image/svg+xml", svg.Minify)
  325. m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify)
  326. m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
  327. m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)
  328. return m
  329. }
  330. // Minify is a middleware which minifies the responses
  331. // based on the response content type.
  332. // Note that minification might be slower, caching is advised.
  333. // Customize the minifier through `Application.Minifier()`.
  334. // Usage:
  335. // app.Use(iris.Minify)
  336. func Minify(ctx Context) {
  337. w := ctx.Application().Minifier().ResponseWriter(ctx.ResponseWriter().Naive(), ctx.Request())
  338. // Note(@kataras):
  339. // We don't use defer w.Close()
  340. // because this response writer holds a sync.WaitGroup under the hoods
  341. // and we MUST be sure that its wg.Wait is called on request cancelation
  342. // and not in the end of handlers chain execution
  343. // (which if running a time-consuming task it will delay its resource release).
  344. ctx.OnCloseErr(w.Close)
  345. ctx.ResponseWriter().SetWriter(w)
  346. ctx.Next()
  347. }
  348. // Minifier returns the minifier instance.
  349. // By default it can minifies:
  350. // - text/html
  351. // - text/css
  352. // - image/svg+xml
  353. // - application/text(javascript, ecmascript, json, xml).
  354. // Use that instance to add custom Minifiers before server ran.
  355. func (app *Application) Minifier() *minify.M {
  356. return app.minifier
  357. }
  358. // RegisterView registers a view engine for the application.
  359. // Children can register their own too. If no Party view Engine is registered
  360. // then this one will be used to render the templates instead.
  361. func (app *Application) RegisterView(viewEngine view.Engine) {
  362. app.view.Register(viewEngine)
  363. }
  364. // View executes and writes the result of a template file to the writer.
  365. //
  366. // First parameter is the writer to write the parsed template.
  367. // Second parameter is the relative, to templates directory, template filename, including extension.
  368. // Third parameter is the layout, can be empty string.
  369. // Forth parameter is the bindable data to the template, can be nil.
  370. //
  371. // Use context.View to render templates to the client instead.
  372. // Returns an error on failure, otherwise nil.
  373. func (app *Application) View(writer io.Writer, filename string, layout string, bindingData interface{}) error {
  374. if !app.view.Registered() {
  375. err := errors.New("view engine is missing, use `RegisterView`")
  376. app.logger.Error(err)
  377. return err
  378. }
  379. return app.view.ExecuteWriter(writer, filename, layout, bindingData)
  380. }
  381. // GetContextPool returns the Iris sync.Pool which holds the contexts values.
  382. // Iris automatically releases the request context, so you don't have to use it.
  383. // It's only useful to manually release the context on cases that connection
  384. // is hijacked by a third-party middleware and the http handler return too fast.
  385. func (app *Application) GetContextPool() *context.Pool {
  386. return app.ContextPool
  387. }
  388. // SetContextErrorHandler can optionally register a handler to handle
  389. // and fire a customized error body to the client on JSON write failures.
  390. //
  391. // ExampleCode:
  392. //
  393. // type contextErrorHandler struct{}
  394. // func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
  395. // errors.InvalidArgument.Err(ctx, err)
  396. // }
  397. // ...
  398. // app.SetContextErrorHandler(new(contextErrorHandler))
  399. func (app *Application) SetContextErrorHandler(errHandler context.ErrorHandler) *Application {
  400. app.contextErrorHandler = errHandler
  401. return app
  402. }
  403. // GetContextErrorHandler returns the handler which handles errors
  404. // on JSON write failures.
  405. func (app *Application) GetContextErrorHandler() context.ErrorHandler {
  406. return app.contextErrorHandler
  407. }
  408. // ConfigureHost accepts one or more `host#Configuration`, these configurators functions
  409. // can access the host created by `app.Run` or `app.Listen`,
  410. // they're being executed when application is ready to being served to the public.
  411. //
  412. // It's an alternative way to interact with a host that is automatically created by
  413. // `app.Run`.
  414. //
  415. // These "configurators" can work side-by-side with the `iris#Addr, iris#Server, iris#TLS, iris#AutoTLS, iris#Listener`
  416. // final arguments("hostConfigs") too.
  417. //
  418. // Note that these application's host "configurators" will be shared with the rest of
  419. // the hosts that this app will may create (using `app.NewHost`), meaning that
  420. // `app.NewHost` will execute these "configurators" everytime that is being called as well.
  421. //
  422. // These "configurators" should be registered before the `app.Run` or `host.Serve/Listen` functions.
  423. func (app *Application) ConfigureHost(configurators ...host.Configurator) *Application {
  424. app.mu.Lock()
  425. app.hostConfigurators = append(app.hostConfigurators, configurators...)
  426. app.mu.Unlock()
  427. return app
  428. }
  429. const serverLoggerPrefix = "[HTTP Server] "
  430. type customHostServerLogger struct { // see #1875
  431. parent io.Writer
  432. ignoreLogs [][]byte
  433. }
  434. var newLineBytes = []byte("\n")
  435. func newCustomHostServerLogger(w io.Writer, ignoreLogs []string) *customHostServerLogger {
  436. prefixAsByteSlice := []byte(serverLoggerPrefix)
  437. // build the ignore lines.
  438. ignoreLogsAsByteSlice := make([][]byte, 0, len(ignoreLogs))
  439. for _, s := range ignoreLogs {
  440. ignoreLogsAsByteSlice = append(ignoreLogsAsByteSlice, append(prefixAsByteSlice, []byte(s)...)) // append([]byte(s), newLineBytes...)
  441. }
  442. return &customHostServerLogger{
  443. parent: w,
  444. ignoreLogs: ignoreLogsAsByteSlice,
  445. }
  446. }
  447. func (l *customHostServerLogger) Write(p []byte) (int, error) {
  448. for _, ignoredLogBytes := range l.ignoreLogs {
  449. if bytes.Equal(bytes.TrimSuffix(p, newLineBytes), ignoredLogBytes) {
  450. return 0, nil
  451. }
  452. }
  453. return l.parent.Write(p)
  454. }
  455. // NewHost accepts a standard *http.Server object,
  456. // completes the necessary missing parts of that "srv"
  457. // and returns a new, ready-to-use, host (supervisor).
  458. func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
  459. app.mu.Lock()
  460. defer app.mu.Unlock()
  461. // set the server's handler to the framework's router
  462. if srv.Handler == nil {
  463. srv.Handler = app.Router
  464. }
  465. // check if different ErrorLog provided, if not bind it with the framework's logger.
  466. if srv.ErrorLog == nil {
  467. serverLogger := newCustomHostServerLogger(app.logger.Printer.Output, app.config.IgnoreServerErrors)
  468. srv.ErrorLog = log.New(serverLogger, serverLoggerPrefix, 0)
  469. }
  470. if addr := srv.Addr; addr == "" {
  471. addr = ":8080"
  472. if len(app.Hosts) > 0 {
  473. if v := app.Hosts[0].Server.Addr; v != "" {
  474. addr = v
  475. }
  476. }
  477. srv.Addr = addr
  478. }
  479. // app.logger.Debugf("Host: addr is %s", srv.Addr)
  480. // create the new host supervisor
  481. // bind the constructed server and return it
  482. su := host.New(srv)
  483. if app.config.VHost == "" { // vhost now is useful for router subdomain on wildcard subdomains,
  484. // in order to correct decide what to do on:
  485. // mydomain.com -> invalid
  486. // localhost -> invalid
  487. // sub.mydomain.com -> valid
  488. // sub.localhost -> valid
  489. // we need the host (without port if 80 or 443) in order to validate these, so:
  490. app.config.VHost = netutil.ResolveVHost(srv.Addr)
  491. } else {
  492. context.GetDomain = func(_ string) string { // #1886
  493. return app.config.VHost
  494. }
  495. }
  496. // app.logger.Debugf("Host: virtual host is %s", app.config.VHost)
  497. // the below schedules some tasks that will run among the server
  498. if !app.config.DisableStartupLog {
  499. printer := app.logger.Printer.Output
  500. hostPrinter := host.WriteStartupLogOnServe(printer)
  501. if len(app.Hosts) == 0 { // print the version info on the first running host.
  502. su.RegisterOnServe(func(h host.TaskHost) {
  503. hasBuildInfo := BuildTime != "" && BuildRevision != ""
  504. tab := " "
  505. if hasBuildInfo {
  506. tab = " "
  507. }
  508. fmt.Fprintf(printer, "Iris Version:%s%s\n", tab, Version)
  509. if hasBuildInfo {
  510. fmt.Fprintf(printer, "Build Time: %s\nBuild Revision: %s\n", BuildTime, BuildRevision)
  511. }
  512. fmt.Fprintln(printer)
  513. hostPrinter(h)
  514. })
  515. } else {
  516. su.RegisterOnServe(hostPrinter)
  517. }
  518. // app.logger.Debugf("Host: register startup notifier")
  519. }
  520. if !app.config.DisableInterruptHandler {
  521. // when CTRL/CMD+C pressed.
  522. shutdownTimeout := 10 * time.Second
  523. RegisterOnInterrupt(host.ShutdownOnInterrupt(su, shutdownTimeout))
  524. // app.logger.Debugf("Host: register server shutdown on interrupt(CTRL+C/CMD+C)")
  525. }
  526. su.IgnoredErrors = append(su.IgnoredErrors, app.config.IgnoreServerErrors...)
  527. if len(su.IgnoredErrors) > 0 {
  528. app.logger.Debugf("Host: server will ignore the following errors: %s", su.IgnoredErrors)
  529. }
  530. su.Configure(app.hostConfigurators...)
  531. app.Hosts = append(app.Hosts, su)
  532. return su
  533. }
  534. // func (app *Application) OnShutdown(closers ...func()) {
  535. // for _,cb := range closers {
  536. // if cb == nil {
  537. // continue
  538. // }
  539. // RegisterOnInterrupt(cb)
  540. // }
  541. // }
  542. // Shutdown gracefully terminates all the application's server hosts and any tunnels.
  543. // Returns an error on the first failure, otherwise nil.
  544. func (app *Application) Shutdown(ctx stdContext.Context) error {
  545. app.mu.Lock()
  546. defer app.mu.Unlock()
  547. for i, su := range app.Hosts {
  548. app.logger.Debugf("Host[%d]: Shutdown now", i)
  549. if err := su.Shutdown(ctx); err != nil {
  550. app.logger.Debugf("Host[%d]: Error while trying to shutdown", i)
  551. return err
  552. }
  553. }
  554. for _, t := range app.config.Tunneling.Tunnels {
  555. if t.Name == "" {
  556. continue
  557. }
  558. if err := app.config.Tunneling.StopTunnel(t); err != nil {
  559. return err
  560. }
  561. }
  562. return nil
  563. }
  564. // Build sets up, once, the framework.
  565. // It builds the default router with its default macros
  566. // and the template functions that are very-closed to iris.
  567. //
  568. // If error occurred while building the Application, the returns type of error will be an *errgroup.Group
  569. // which let the callers to inspect the errors and cause, usage:
  570. //
  571. // import "github.com/kataras/iris/v12/core/errgroup"
  572. //
  573. // errgroup.Walk(app.Build(), func(typ interface{}, err error) {
  574. // app.Logger().Errorf("%s: %s", typ, err)
  575. // })
  576. func (app *Application) Build() error {
  577. if app.builded {
  578. return nil
  579. }
  580. if cb := app.OnBuild; cb != nil {
  581. if err := cb(); err != nil {
  582. return fmt.Errorf("build: %w", err)
  583. }
  584. }
  585. // start := time.Now()
  586. app.builded = true // even if fails.
  587. // check if a prior app.Logger().SetLevel called and if not
  588. // then set the defined configuration's log level.
  589. if app.logger.Level == golog.InfoLevel /* the default level */ {
  590. app.logger.SetLevel(app.config.LogLevel)
  591. }
  592. if app.defaultMode { // the app.I18n and app.View will be not available until Build.
  593. if !app.I18n.Loaded() {
  594. for _, s := range []string{"./locales/*/*", "./locales/*", "./translations"} {
  595. if _, err := os.Stat(s); err != nil {
  596. continue
  597. }
  598. if err := app.I18n.Load(s); err != nil {
  599. continue
  600. }
  601. app.I18n.SetDefault("en-US")
  602. break
  603. }
  604. }
  605. if !app.view.Registered() {
  606. for _, s := range []string{"./views", "./templates", "./web/views"} {
  607. if _, err := os.Stat(s); err != nil {
  608. continue
  609. }
  610. app.RegisterView(HTML(s, ".html"))
  611. break
  612. }
  613. }
  614. }
  615. if app.I18n.Loaded() {
  616. // {{ tr "lang" "key" arg1 arg2 }}
  617. app.view.AddFunc("tr", app.I18n.Tr)
  618. app.Router.PrependRouterWrapper(app.I18n.Wrapper())
  619. }
  620. if app.view.Registered() {
  621. app.logger.Debugf("Application: view engine %q is registered", app.view.Name())
  622. // view engine
  623. // here is where we declare the closed-relative framework functions.
  624. // Each engine has their defaults, i.e yield,render,render_r,partial, params...
  625. rv := router.NewRoutePathReverser(app.APIBuilder)
  626. app.view.AddFunc("urlpath", rv.Path)
  627. // app.view.AddFunc("url", rv.URL)
  628. if err := app.view.Load(); err != nil {
  629. return fmt.Errorf("build: view engine: %v", err)
  630. }
  631. }
  632. if !app.Router.Downgraded() {
  633. // router
  634. if _, err := injectLiveReload(app); err != nil {
  635. return fmt.Errorf("build: inject live reload: failed: %v", err)
  636. }
  637. if app.config.ForceLowercaseRouting {
  638. // This should always be executed first.
  639. app.Router.PrependRouterWrapper(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  640. r.Host = strings.ToLower(r.Host)
  641. r.URL.Host = strings.ToLower(r.URL.Host)
  642. r.URL.Path = strings.ToLower(r.URL.Path)
  643. next(w, r)
  644. })
  645. }
  646. // create the request handler, the default routing handler
  647. routerHandler := router.NewDefaultHandler(app.config, app.logger)
  648. err := app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false)
  649. if err != nil {
  650. return fmt.Errorf("build: router: %w", err)
  651. }
  652. app.HTTPErrorHandler = routerHandler
  653. if app.config.Timeout > 0 {
  654. app.Router.SetTimeoutHandler(app.config.Timeout, app.config.TimeoutMessage)
  655. app.ConfigureHost(func(su *Supervisor) {
  656. if su.Server.ReadHeaderTimeout == 0 {
  657. su.Server.ReadHeaderTimeout = app.config.Timeout + 5*time.Second
  658. }
  659. if su.Server.ReadTimeout == 0 {
  660. su.Server.ReadTimeout = app.config.Timeout + 10*time.Second
  661. }
  662. if su.Server.WriteTimeout == 0 {
  663. su.Server.WriteTimeout = app.config.Timeout + 15*time.Second
  664. }
  665. if su.Server.IdleTimeout == 0 {
  666. su.Server.IdleTimeout = app.config.Timeout + 25*time.Second
  667. }
  668. })
  669. }
  670. // re-build of the router from outside can be done with
  671. // app.RefreshRouter()
  672. }
  673. // if end := time.Since(start); end.Seconds() > 5 {
  674. // app.logger.Debugf("Application: build took %s", time.Since(start))
  675. return nil
  676. }
  677. // Runner is just an interface which accepts the framework instance
  678. // and returns an error.
  679. //
  680. // It can be used to register a custom runner with `Run` in order
  681. // to set the framework's server listen action.
  682. //
  683. // Currently `Runner` is being used to declare the builtin server listeners.
  684. //
  685. // See `Run` for more.
  686. type Runner func(*Application) error
  687. // Listener can be used as an argument for the `Run` method.
  688. // It can start a server with a custom net.Listener via server's `Serve`.
  689. //
  690. // Second argument is optional, it accepts one or more
  691. // `func(*host.Configurator)` that are being executed
  692. // on that specific host that this function will create to start the server.
  693. // Via host configurators you can configure the back-end host supervisor,
  694. // i.e to add events for shutdown, serve or error.
  695. // An example of this use case can be found at:
  696. // https://github.com/kataras/iris/blob/main/_examples/http-server/notify-on-shutdown/main.go
  697. // Look at the `ConfigureHost` too.
  698. //
  699. // See `Run` for more.
  700. func Listener(l net.Listener, hostConfigs ...host.Configurator) Runner {
  701. return func(app *Application) error {
  702. app.config.VHost = netutil.ResolveVHost(l.Addr().String())
  703. return app.NewHost(&http.Server{Addr: l.Addr().String()}).
  704. Configure(hostConfigs...).
  705. Serve(l)
  706. }
  707. }
  708. // Server can be used as an argument for the `Run` method.
  709. // It can start a server with a *http.Server.
  710. //
  711. // Second argument is optional, it accepts one or more
  712. // `func(*host.Configurator)` that are being executed
  713. // on that specific host that this function will create to start the server.
  714. // Via host configurators you can configure the back-end host supervisor,
  715. // i.e to add events for shutdown, serve or error.
  716. // An example of this use case can be found at:
  717. // https://github.com/kataras/iris/blob/main/_examples/http-server/notify-on-shutdown/main.go
  718. // Look at the `ConfigureHost` too.
  719. //
  720. // See `Run` for more.
  721. func Server(srv *http.Server, hostConfigs ...host.Configurator) Runner {
  722. return func(app *Application) error {
  723. return app.NewHost(srv).
  724. Configure(hostConfigs...).
  725. ListenAndServe()
  726. }
  727. }
  728. // Addr can be used as an argument for the `Run` method.
  729. // It accepts a host address which is used to build a server
  730. // and a listener which listens on that host and port.
  731. //
  732. // Addr should have the form of [host]:port, i.e localhost:8080 or :8080.
  733. //
  734. // Second argument is optional, it accepts one or more
  735. // `func(*host.Configurator)` that are being executed
  736. // on that specific host that this function will create to start the server.
  737. // Via host configurators you can configure the back-end host supervisor,
  738. // i.e to add events for shutdown, serve or error.
  739. // An example of this use case can be found at:
  740. // https://github.com/kataras/iris/blob/main/_examples/http-server/notify-on-shutdown/main.go
  741. // Look at the `ConfigureHost` too.
  742. //
  743. // See `Run` for more.
  744. func Addr(addr string, hostConfigs ...host.Configurator) Runner {
  745. return func(app *Application) error {
  746. return app.NewHost(&http.Server{Addr: addr}).
  747. Configure(hostConfigs...).
  748. ListenAndServe()
  749. }
  750. }
  751. var (
  752. // TLSNoRedirect is a `host.Configurator` which can be passed as last argument
  753. // to the `TLS` runner function. It disables the automatic
  754. // registration of redirection from "http://" to "https://" requests.
  755. // Applies only to the `TLS` runner.
  756. // See `AutoTLSNoRedirect` to register a custom fallback server for `AutoTLS` runner.
  757. TLSNoRedirect = func(su *host.Supervisor) { su.NoRedirect() }
  758. // AutoTLSNoRedirect is a `host.Configurator`.
  759. // It registers a fallback HTTP/1.1 server for the `AutoTLS` one.
  760. // The function accepts the letsencrypt wrapper and it
  761. // should return a valid instance of http.Server which its handler should be the result
  762. // of the "acmeHandler" wrapper.
  763. // Usage:
  764. // getServer := func(acme func(http.Handler) http.Handler) *http.Server {
  765. // srv := &http.Server{Handler: acme(yourCustomHandler), ...otherOptions}
  766. // go srv.ListenAndServe()
  767. // return srv
  768. // }
  769. // app.Run(iris.AutoTLS(":443", "example.com example2.com", "mail@example.com", getServer))
  770. //
  771. // Note that if Server.Handler is nil then the server is automatically ran
  772. // by the framework and the handler set to automatic redirection, it's still
  773. // a valid option when the caller wants just to customize the server's fields (except Addr).
  774. // With this host configurator the caller can customize the server
  775. // that letsencrypt relies to perform the challenge.
  776. // LetsEncrypt Certification Manager relies on http://example.com/.well-known/acme-challenge/<TOKEN>.
  777. AutoTLSNoRedirect = func(getFallbackServer func(acmeHandler func(fallback http.Handler) http.Handler) *http.Server) host.Configurator {
  778. return func(su *host.Supervisor) {
  779. su.NoRedirect()
  780. su.Fallback = getFallbackServer
  781. }
  782. }
  783. )
  784. // TLS can be used as an argument for the `Run` method.
  785. // It will start the Application's secure server.
  786. //
  787. // Use it like you used to use the http.ListenAndServeTLS function.
  788. //
  789. // Addr should have the form of [host]:port, i.e localhost:443 or :443.
  790. // "certFileOrContents" & "keyFileOrContents" should be filenames with their extensions
  791. // or raw contents of the certificate and the private key.
  792. //
  793. // Last argument is optional, it accepts one or more
  794. // `func(*host.Configurator)` that are being executed
  795. // on that specific host that this function will create to start the server.
  796. // Via host configurators you can configure the back-end host supervisor,
  797. // i.e to add events for shutdown, serve or error.
  798. // An example of this use case can be found at:
  799. // https://github.com/kataras/iris/blob/main/_examples/http-server/notify-on-shutdown/main.go
  800. // Look at the `ConfigureHost` too.
  801. //
  802. // See `Run` for more.
  803. func TLS(addr string, certFileOrContents, keyFileOrContents string, hostConfigs ...host.Configurator) Runner {
  804. return func(app *Application) error {
  805. return app.NewHost(&http.Server{Addr: addr}).
  806. Configure(hostConfigs...).
  807. ListenAndServeTLS(certFileOrContents, keyFileOrContents)
  808. }
  809. }
  810. // AutoTLS can be used as an argument for the `Run` method.
  811. // It will start the Application's secure server using
  812. // certifications created on the fly by the "autocert" golang/x package,
  813. // so localhost may not be working, use it at "production" machine.
  814. //
  815. // Addr should have the form of [host]:port, i.e mydomain.com:443.
  816. //
  817. // The whitelisted domains are separated by whitespace in "domain" argument,
  818. // i.e "iris-go.com", can be different than "addr".
  819. // If empty, all hosts are currently allowed. This is not recommended,
  820. // as it opens a potential attack where clients connect to a server
  821. // by IP address and pretend to be asking for an incorrect host name.
  822. // Manager will attempt to obtain a certificate for that host, incorrectly,
  823. // eventually reaching the CA's rate limit for certificate requests
  824. // and making it impossible to obtain actual certificates.
  825. //
  826. // For an "e-mail" use a non-public one, letsencrypt needs that for your own security.
  827. //
  828. // Note: `AutoTLS` will start a new server for you
  829. // which will redirect all http versions to their https, including subdomains as well.
  830. //
  831. // Last argument is optional, it accepts one or more
  832. // `func(*host.Configurator)` that are being executed
  833. // on that specific host that this function will create to start the server.
  834. // Via host configurators you can configure the back-end host supervisor,
  835. // i.e to add events for shutdown, serve or error.
  836. // An example of this use case can be found at:
  837. // https://github.com/kataras/iris/blob/main/_examples/http-server/notify-on-shutdown/main.go
  838. // Look at the `ConfigureHost` too.
  839. //
  840. // Usage:
  841. // app.Run(iris.AutoTLS("iris-go.com:443", "iris-go.com www.iris-go.com", "mail@example.com"))
  842. //
  843. // See `Run` and `core/host/Supervisor#ListenAndServeAutoTLS` for more.
  844. func AutoTLS(
  845. addr string,
  846. domain string, email string,
  847. hostConfigs ...host.Configurator,
  848. ) Runner {
  849. return func(app *Application) error {
  850. return app.NewHost(&http.Server{Addr: addr}).
  851. Configure(hostConfigs...).
  852. ListenAndServeAutoTLS(domain, email, "letscache")
  853. }
  854. }
  855. // Raw can be used as an argument for the `Run` method.
  856. // It accepts any (listen) function that returns an error,
  857. // this function should be block and return an error
  858. // only when the server exited or a fatal error caused.
  859. //
  860. // With this option you're not limited to the servers
  861. // that iris can run by-default.
  862. //
  863. // See `Run` for more.
  864. func Raw(f func() error) Runner {
  865. return func(app *Application) error {
  866. app.logger.Debugf("HTTP Server will start from unknown, external function")
  867. return f()
  868. }
  869. }
  870. var (
  871. // ErrServerClosed is logged by the standard net/http server when the server is terminated.
  872. // Ignore it by passing this error to the `iris.WithoutServerError` configurator
  873. // on `Application.Run/Listen` method.
  874. //
  875. // An alias of the `http#ErrServerClosed`.
  876. ErrServerClosed = http.ErrServerClosed
  877. // ErrURLQuerySemicolon is logged by the standard net/http server when
  878. // the request contains a semicolon (;) wihch, after go1.17 it's not used as a key-value separator character.
  879. //
  880. // Ignore it by passing this error to the `iris.WithoutServerError` configurator
  881. // on `Application.Run/Listen` method.
  882. //
  883. // An alias of the `http#ErrServerClosed`.
  884. ErrURLQuerySemicolon = errors.New("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192")
  885. )
  886. // Listen builds the application and starts the server
  887. // on the TCP network address "host:port" which
  888. // handles requests on incoming connections.
  889. //
  890. // Listen always returns a non-nil error.
  891. // Ignore specific errors by using an `iris.WithoutServerError(iris.ErrServerClosed)`
  892. // as a second input argument.
  893. //
  894. // Listen is a shortcut of `app.Run(iris.Addr(hostPort, withOrWithout...))`.
  895. // See `Run` for details.
  896. func (app *Application) Listen(hostPort string, withOrWithout ...Configurator) error {
  897. return app.Run(Addr(hostPort), withOrWithout...)
  898. }
  899. // Run builds the framework and starts the desired `Runner` with or without configuration edits.
  900. //
  901. // Run should be called only once per Application instance, it blocks like http.Server.
  902. //
  903. // If more than one server needed to run on the same iris instance
  904. // then create a new host and run it manually by `go NewHost(*http.Server).Serve/ListenAndServe` etc...
  905. // or use an already created host:
  906. // h := NewHost(*http.Server)
  907. // Run(Raw(h.ListenAndServe), WithCharset("utf-8"), WithRemoteAddrHeader("CF-Connecting-IP"))
  908. //
  909. // The Application can go online with any type of server or iris's host with the help of
  910. // the following runners:
  911. // `Listener`, `Server`, `Addr`, `TLS`, `AutoTLS` and `Raw`.
  912. func (app *Application) Run(serve Runner, withOrWithout ...Configurator) error {
  913. app.Configure(withOrWithout...)
  914. if err := app.Build(); err != nil {
  915. app.logger.Error(err)
  916. return err
  917. }
  918. app.ConfigureHost(func(host *Supervisor) {
  919. host.SocketSharding = app.config.SocketSharding
  920. host.KeepAlive = app.config.KeepAlive
  921. })
  922. app.tryStartTunneling()
  923. if len(app.Hosts) > 0 {
  924. app.logger.Debugf("Application: running using %d host(s)", len(app.Hosts)+1 /* +1 the current */)
  925. }
  926. // this will block until an error(unless supervisor's DeferFlow called from a Task).
  927. err := serve(app)
  928. if err != nil {
  929. app.logger.Error(err)
  930. }
  931. return err
  932. }
  933. // https://ngrok.com/docs
  934. func (app *Application) tryStartTunneling() {
  935. if len(app.config.Tunneling.Tunnels) == 0 {
  936. return
  937. }
  938. app.ConfigureHost(func(su *host.Supervisor) {
  939. su.RegisterOnServe(func(h host.TaskHost) {
  940. publicAddrs, err := tunnel.Start(app.config.Tunneling)
  941. if err != nil {
  942. app.logger.Errorf("Host: tunneling error: %v", err)
  943. return
  944. }
  945. publicAddr := publicAddrs[0]
  946. // to make subdomains resolution still based on this new remote, public addresses.
  947. app.config.VHost = publicAddr[strings.Index(publicAddr, "://")+3:]
  948. directLog := []byte(fmt.Sprintf("• Public Address: %s\n", publicAddr))
  949. app.logger.Printer.Write(directLog) // nolint:errcheck
  950. })
  951. })
  952. }