configuration.go 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442
  1. package iris
  2. import (
  3. "fmt"
  4. "os"
  5. "os/user"
  6. "path/filepath"
  7. "runtime"
  8. "strings"
  9. "time"
  10. "github.com/kataras/iris/v12/context"
  11. "github.com/kataras/iris/v12/core/netutil"
  12. "github.com/BurntSushi/toml"
  13. "github.com/kataras/golog"
  14. "github.com/kataras/sitemap"
  15. "github.com/kataras/tunnel"
  16. "gopkg.in/yaml.v3"
  17. )
  18. const globalConfigurationKeyword = "~"
  19. // homeConfigurationFilename returns the physical location of the global configuration(yaml or toml) file.
  20. // This is useful when we run multiple iris servers that share the same
  21. // configuration, even with custom values at its "Other" field.
  22. // It will return a file location
  23. // which targets to $HOME or %HOMEDRIVE%+%HOMEPATH% + "iris" + the given "ext".
  24. func homeConfigurationFilename(ext string) string {
  25. return filepath.Join(homeDir(), "iris"+ext)
  26. }
  27. func homeDir() (home string) {
  28. u, err := user.Current()
  29. if u != nil && err == nil {
  30. home = u.HomeDir
  31. }
  32. if home == "" {
  33. home = os.Getenv("HOME")
  34. }
  35. if home == "" {
  36. if runtime.GOOS == "plan9" {
  37. home = os.Getenv("home")
  38. } else if runtime.GOOS == "windows" {
  39. home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
  40. if home == "" {
  41. home = os.Getenv("USERPROFILE")
  42. }
  43. }
  44. }
  45. return
  46. }
  47. func parseYAML(filename string) (Configuration, error) {
  48. c := DefaultConfiguration()
  49. // get the abs
  50. // which will try to find the 'filename' from current workind dir too.
  51. yamlAbsPath, err := filepath.Abs(filename)
  52. if err != nil {
  53. return c, fmt.Errorf("parse yaml: %w", err)
  54. }
  55. // read the raw contents of the file
  56. data, err := os.ReadFile(yamlAbsPath)
  57. if err != nil {
  58. return c, fmt.Errorf("parse yaml: %w", err)
  59. }
  60. // put the file's contents as yaml to the default configuration(c)
  61. if err := yaml.Unmarshal(data, &c); err != nil {
  62. return c, fmt.Errorf("parse yaml: %w", err)
  63. }
  64. return c, nil
  65. }
  66. // YAML reads Configuration from a configuration.yml file.
  67. //
  68. // Accepts the absolute path of the cfg.yml.
  69. // An error will be shown to the user via panic with the error message.
  70. // Error may occur when the cfg.yml does not exist or is not formatted correctly.
  71. //
  72. // Note: if the char '~' passed as "filename" then it tries to load and return
  73. // the configuration from the $home_directory + iris.yml,
  74. // see `WithGlobalConfiguration` for more information.
  75. //
  76. // Usage:
  77. // app.Configure(iris.WithConfiguration(iris.YAML("myconfig.yml"))) or
  78. // app.Run([iris.Runner], iris.WithConfiguration(iris.YAML("myconfig.yml"))).
  79. func YAML(filename string) Configuration {
  80. // check for globe configuration file and use that, otherwise
  81. // return the default configuration if file doesn't exist.
  82. if filename == globalConfigurationKeyword {
  83. filename = homeConfigurationFilename(".yml")
  84. if _, err := os.Stat(filename); os.IsNotExist(err) {
  85. panic("default configuration file '" + filename + "' does not exist")
  86. }
  87. }
  88. c, err := parseYAML(filename)
  89. if err != nil {
  90. panic(err)
  91. }
  92. return c
  93. }
  94. // TOML reads Configuration from a toml-compatible document file.
  95. // Read more about toml's implementation at:
  96. // https://github.com/toml-lang/toml
  97. //
  98. // Accepts the absolute path of the configuration file.
  99. // An error will be shown to the user via panic with the error message.
  100. // Error may occur when the file does not exist or is not formatted correctly.
  101. //
  102. // Note: if the char '~' passed as "filename" then it tries to load and return
  103. // the configuration from the $home_directory + iris.tml,
  104. // see `WithGlobalConfiguration` for more information.
  105. //
  106. // Usage:
  107. // app.Configure(iris.WithConfiguration(iris.TOML("myconfig.tml"))) or
  108. // app.Run([iris.Runner], iris.WithConfiguration(iris.TOML("myconfig.tml"))).
  109. func TOML(filename string) Configuration {
  110. c := DefaultConfiguration()
  111. // check for globe configuration file and use that, otherwise
  112. // return the default configuration if file doesn't exist.
  113. if filename == globalConfigurationKeyword {
  114. filename = homeConfigurationFilename(".tml")
  115. if _, err := os.Stat(filename); os.IsNotExist(err) {
  116. panic("default configuration file '" + filename + "' does not exist")
  117. }
  118. }
  119. // get the abs
  120. // which will try to find the 'filename' from current workind dir too.
  121. tomlAbsPath, err := filepath.Abs(filename)
  122. if err != nil {
  123. panic(fmt.Errorf("toml: %w", err))
  124. }
  125. // read the raw contents of the file
  126. data, err := os.ReadFile(tomlAbsPath)
  127. if err != nil {
  128. panic(fmt.Errorf("toml :%w", err))
  129. }
  130. // put the file's contents as toml to the default configuration(c)
  131. if _, err := toml.Decode(string(data), &c); err != nil {
  132. panic(fmt.Errorf("toml :%w", err))
  133. }
  134. // Author's notes:
  135. // The toml's 'usual thing' for key naming is: the_config_key instead of TheConfigKey
  136. // but I am always prefer to use the specific programming language's syntax
  137. // and the original configuration name fields for external configuration files
  138. // so we do 'toml: "TheConfigKeySameAsTheConfigField" instead.
  139. return c
  140. }
  141. // Configurator is just an interface which accepts the framework instance.
  142. //
  143. // It can be used to register a custom configuration with `Configure` in order
  144. // to modify the framework instance.
  145. //
  146. // Currently Configurator is being used to describe the configuration's fields values.
  147. type Configurator func(*Application)
  148. // WithGlobalConfiguration will load the global yaml configuration file
  149. // from the home directory and it will set/override the whole app's configuration
  150. // to that file's contents. The global configuration file can be modified by user
  151. // and be used by multiple iris instances.
  152. //
  153. // This is useful when we run multiple iris servers that share the same
  154. // configuration, even with custom values at its "Other" field.
  155. //
  156. // Usage: `app.Configure(iris.WithGlobalConfiguration)` or `app.Run([iris.Runner], iris.WithGlobalConfiguration)`.
  157. var WithGlobalConfiguration = func(app *Application) {
  158. app.Configure(WithConfiguration(YAML(globalConfigurationKeyword)))
  159. }
  160. // WithLogLevel sets the `Configuration.LogLevel` field.
  161. func WithLogLevel(level string) Configurator {
  162. return func(app *Application) {
  163. if app.logger == nil {
  164. app.logger = golog.Default
  165. }
  166. app.logger.SetLevel(level) // can be fired through app.Configure.
  167. app.config.LogLevel = level
  168. }
  169. }
  170. // WithSocketSharding sets the `Configuration.SocketSharding` field to true.
  171. func WithSocketSharding(app *Application) {
  172. // Note(@kataras): It could be a host Configurator but it's an application setting in order
  173. // to configure it through yaml/toml files as well.
  174. app.config.SocketSharding = true
  175. }
  176. // WithKeepAlive sets the `Configuration.KeepAlive` field to the given duration.
  177. func WithKeepAlive(keepAliveDur time.Duration) Configurator {
  178. return func(app *Application) {
  179. app.config.KeepAlive = keepAliveDur
  180. }
  181. }
  182. // WithTimeout sets the `Configuration.Timeout` field to the given duration.
  183. func WithTimeout(timeoutDur time.Duration, htmlBody ...string) Configurator {
  184. return func(app *Application) {
  185. app.config.Timeout = timeoutDur
  186. if len(htmlBody) > 0 {
  187. app.config.TimeoutMessage = htmlBody[0]
  188. }
  189. }
  190. }
  191. // WithoutServerError will cause to ignore the matched "errors"
  192. // from the main application's `Run/Listen` function.
  193. //
  194. // Usage:
  195. // err := app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
  196. // will return `nil` if the server's error was `http/iris#ErrServerClosed`.
  197. //
  198. // See `Configuration#IgnoreServerErrors []string` too.
  199. //
  200. // Example: https://github.com/kataras/iris/tree/main/_examples/http-server/listen-addr/omit-server-errors
  201. func WithoutServerError(errors ...error) Configurator {
  202. return func(app *Application) {
  203. if len(errors) == 0 {
  204. return
  205. }
  206. errorsAsString := make([]string, len(errors))
  207. for i, e := range errors {
  208. errorsAsString[i] = e.Error()
  209. }
  210. app.config.IgnoreServerErrors = append(app.config.IgnoreServerErrors, errorsAsString...)
  211. }
  212. }
  213. // WithoutStartupLog turns off the information send, once, to the terminal when the main server is open.
  214. var WithoutStartupLog = func(app *Application) {
  215. app.config.DisableStartupLog = true
  216. }
  217. // WithoutBanner is a conversion for the `WithoutStartupLog` option.
  218. //
  219. // Turns off the information send, once, to the terminal when the main server is open.
  220. var WithoutBanner = WithoutStartupLog
  221. // WithoutInterruptHandler disables the automatic graceful server shutdown
  222. // when control/cmd+C pressed.
  223. var WithoutInterruptHandler = func(app *Application) {
  224. app.config.DisableInterruptHandler = true
  225. }
  226. // WithoutPathCorrection disables the PathCorrection setting.
  227. //
  228. // See `Configuration`.
  229. var WithoutPathCorrection = func(app *Application) {
  230. app.config.DisablePathCorrection = true
  231. }
  232. // WithPathIntelligence enables the EnablePathIntelligence setting.
  233. //
  234. // See `Configuration`.
  235. var WithPathIntelligence = func(app *Application) {
  236. app.config.EnablePathIntelligence = true
  237. }
  238. // WithoutPathCorrectionRedirection disables the PathCorrectionRedirection setting.
  239. //
  240. // See `Configuration`.
  241. var WithoutPathCorrectionRedirection = func(app *Application) {
  242. app.config.DisablePathCorrection = false
  243. app.config.DisablePathCorrectionRedirection = true
  244. }
  245. // WithoutBodyConsumptionOnUnmarshal disables BodyConsumptionOnUnmarshal setting.
  246. //
  247. // See `Configuration`.
  248. var WithoutBodyConsumptionOnUnmarshal = func(app *Application) {
  249. app.config.DisableBodyConsumptionOnUnmarshal = true
  250. }
  251. // WithEmptyFormError enables the setting `FireEmptyFormError`.
  252. //
  253. // See `Configuration`.
  254. var WithEmptyFormError = func(app *Application) {
  255. app.config.FireEmptyFormError = true
  256. }
  257. // WithPathEscape sets the EnablePathEscape setting to true.
  258. //
  259. // See `Configuration`.
  260. var WithPathEscape = func(app *Application) {
  261. app.config.EnablePathEscape = true
  262. }
  263. // WithLowercaseRouting enables for lowercase routing by
  264. // setting the `ForceLowercaseRoutes` to true.
  265. //
  266. // See `Configuration`.
  267. var WithLowercaseRouting = func(app *Application) {
  268. app.config.ForceLowercaseRouting = true
  269. }
  270. // WithDynamicHandler enables for dynamic routing by
  271. // setting the `EnableDynamicHandler` to true.
  272. //
  273. // See `Configuration`.
  274. var WithDynamicHandler = func(app *Application) {
  275. app.config.EnableDynamicHandler = true
  276. }
  277. // WithOptimizations can force the application to optimize for the best performance where is possible.
  278. //
  279. // See `Configuration`.
  280. var WithOptimizations = func(app *Application) {
  281. app.config.EnableOptimizations = true
  282. }
  283. // WithProtoJSON enables the proto marshaler on Context.JSON method.
  284. //
  285. // See `Configuration` for more.
  286. var WithProtoJSON = func(app *Application) {
  287. app.config.EnableProtoJSON = true
  288. }
  289. // WithEasyJSON enables the fast easy json marshaler on Context.JSON method.
  290. //
  291. // See `Configuration` for more.
  292. var WithEasyJSON = func(app *Application) {
  293. app.config.EnableEasyJSON = true
  294. }
  295. // WithFireMethodNotAllowed enables the FireMethodNotAllowed setting.
  296. //
  297. // See `Configuration`.
  298. var WithFireMethodNotAllowed = func(app *Application) {
  299. app.config.FireMethodNotAllowed = true
  300. }
  301. // WithoutAutoFireStatusCode sets the DisableAutoFireStatusCode setting to true.
  302. //
  303. // See `Configuration`.
  304. var WithoutAutoFireStatusCode = func(app *Application) {
  305. app.config.DisableAutoFireStatusCode = true
  306. }
  307. // WithResetOnFireErrorCode sets the ResetOnFireErrorCode setting to true.
  308. //
  309. // See `Configuration`.
  310. var WithResetOnFireErrorCode = func(app *Application) {
  311. app.config.ResetOnFireErrorCode = true
  312. }
  313. // WithURLParamSeparator sets the URLParamSeparator setting to "sep".
  314. //
  315. // See `Configuration`.
  316. var WithURLParamSeparator = func(sep string) Configurator {
  317. return func(app *Application) {
  318. app.config.URLParamSeparator = &sep
  319. }
  320. }
  321. // WithTimeFormat sets the TimeFormat setting.
  322. //
  323. // See `Configuration`.
  324. func WithTimeFormat(timeformat string) Configurator {
  325. return func(app *Application) {
  326. app.config.TimeFormat = timeformat
  327. }
  328. }
  329. // WithCharset sets the Charset setting.
  330. //
  331. // See `Configuration`.
  332. func WithCharset(charset string) Configurator {
  333. return func(app *Application) {
  334. app.config.Charset = charset
  335. }
  336. }
  337. // WithPostMaxMemory sets the maximum post data size
  338. // that a client can send to the server, this differs
  339. // from the overall request body size which can be modified
  340. // by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
  341. //
  342. // Defaults to 32MB or 32 << 20 or 32*iris.MB if you prefer.
  343. func WithPostMaxMemory(limit int64) Configurator {
  344. return func(app *Application) {
  345. app.config.PostMaxMemory = limit
  346. }
  347. }
  348. // WithRemoteAddrHeader adds a new request header name
  349. // that can be used to validate the client's real IP.
  350. func WithRemoteAddrHeader(header ...string) Configurator {
  351. return func(app *Application) {
  352. for _, h := range header {
  353. exists := false
  354. for _, v := range app.config.RemoteAddrHeaders {
  355. if v == h {
  356. exists = true
  357. }
  358. }
  359. if !exists {
  360. app.config.RemoteAddrHeaders = append(app.config.RemoteAddrHeaders, h)
  361. }
  362. }
  363. }
  364. }
  365. // WithoutRemoteAddrHeader removes an existing request header name
  366. // that can be used to validate and parse the client's real IP.
  367. //
  368. // Look `context.RemoteAddr()` for more.
  369. func WithoutRemoteAddrHeader(headerName string) Configurator {
  370. return func(app *Application) {
  371. tmp := app.config.RemoteAddrHeaders[:0]
  372. for _, v := range app.config.RemoteAddrHeaders {
  373. if v != headerName {
  374. tmp = append(tmp, v)
  375. }
  376. }
  377. app.config.RemoteAddrHeaders = tmp
  378. }
  379. }
  380. // WithRemoteAddrPrivateSubnet adds a new private sub-net to be excluded from `context.RemoteAddr`.
  381. // See `WithRemoteAddrHeader` too.
  382. func WithRemoteAddrPrivateSubnet(startIP, endIP string) Configurator {
  383. return func(app *Application) {
  384. app.config.RemoteAddrPrivateSubnets = append(app.config.RemoteAddrPrivateSubnets, netutil.IPRange{
  385. Start: startIP,
  386. End: endIP,
  387. })
  388. }
  389. }
  390. // WithSSLProxyHeader sets a SSLProxyHeaders key value pair.
  391. // Example: WithSSLProxyHeader("X-Forwarded-Proto", "https").
  392. // See `Context.IsSSL` for more.
  393. func WithSSLProxyHeader(headerKey, headerValue string) Configurator {
  394. return func(app *Application) {
  395. if app.config.SSLProxyHeaders == nil {
  396. app.config.SSLProxyHeaders = make(map[string]string)
  397. }
  398. app.config.SSLProxyHeaders[headerKey] = headerValue
  399. }
  400. }
  401. // WithHostProxyHeader sets a HostProxyHeaders key value pair.
  402. // Example: WithHostProxyHeader("X-Host").
  403. // See `Context.Host` for more.
  404. func WithHostProxyHeader(headers ...string) Configurator {
  405. return func(app *Application) {
  406. if app.config.HostProxyHeaders == nil {
  407. app.config.HostProxyHeaders = make(map[string]bool)
  408. }
  409. for _, k := range headers {
  410. app.config.HostProxyHeaders[k] = true
  411. }
  412. }
  413. }
  414. // WithOtherValue adds a value based on a key to the Other setting.
  415. //
  416. // See `Configuration.Other`.
  417. func WithOtherValue(key string, val interface{}) Configurator {
  418. return func(app *Application) {
  419. if app.config.Other == nil {
  420. app.config.Other = make(map[string]interface{})
  421. }
  422. app.config.Other[key] = val
  423. }
  424. }
  425. // WithSitemap enables the sitemap generator.
  426. // Use the Route's `SetLastMod`, `SetChangeFreq` and `SetPriority` to modify
  427. // the sitemap's URL child element properties.
  428. // Excluded routes:
  429. // - dynamic
  430. // - subdomain
  431. // - offline
  432. // - ExcludeSitemap method called
  433. //
  434. // It accepts a "startURL" input argument which
  435. // is the prefix for the registered routes that will be included in the sitemap.
  436. //
  437. // If more than 50,000 static routes are registered then sitemaps will be splitted and a sitemap index will be served in
  438. // /sitemap.xml.
  439. //
  440. // If `Application.I18n.Load/LoadAssets` is called then the sitemap will contain translated links for each static route.
  441. //
  442. // If the result does not complete your needs you can take control
  443. // and use the github.com/kataras/sitemap package to generate a customized one instead.
  444. //
  445. // Example: https://github.com/kataras/iris/tree/main/_examples/sitemap.
  446. func WithSitemap(startURL string) Configurator {
  447. sitemaps := sitemap.New(startURL)
  448. return func(app *Application) {
  449. var defaultLang string
  450. if tags := app.I18n.Tags(); len(tags) > 0 {
  451. defaultLang = tags[0].String()
  452. sitemaps.DefaultLang(defaultLang)
  453. }
  454. for _, r := range app.GetRoutes() {
  455. if !r.IsStatic() || r.Subdomain != "" || !r.IsOnline() || r.NoSitemap {
  456. continue
  457. }
  458. loc := r.StaticPath()
  459. var translatedLinks []sitemap.Link
  460. for _, tag := range app.I18n.Tags() {
  461. lang := tag.String()
  462. langPath := lang
  463. href := ""
  464. if lang == defaultLang {
  465. // http://domain.com/en-US/path to just http://domain.com/path if en-US is the default language.
  466. langPath = ""
  467. }
  468. if app.I18n.PathRedirect {
  469. // then use the path prefix.
  470. // e.g. http://domain.com/el-GR/path
  471. if langPath == "" { // fix double slashes http://domain.com// when self-included default language.
  472. href = loc
  473. } else {
  474. href = "/" + langPath + loc
  475. }
  476. } else if app.I18n.Subdomain {
  477. // then use the subdomain.
  478. // e.g. http://el.domain.com/path
  479. scheme := netutil.ResolveSchemeFromVHost(startURL)
  480. host := strings.TrimLeft(startURL, scheme)
  481. if langPath != "" {
  482. href = scheme + strings.Split(langPath, "-")[0] + "." + host + loc
  483. } else {
  484. href = loc
  485. }
  486. } else if p := app.I18n.URLParameter; p != "" {
  487. // then use the URL parameter.
  488. // e.g. http://domain.com/path?lang=el-GR
  489. href = loc + "?" + p + "=" + lang
  490. } else {
  491. // then skip it, we can't generate the link at this state.
  492. continue
  493. }
  494. translatedLinks = append(translatedLinks, sitemap.Link{
  495. Rel: "alternate",
  496. Hreflang: lang,
  497. Href: href,
  498. })
  499. }
  500. sitemaps.URL(sitemap.URL{
  501. Loc: loc,
  502. LastMod: r.LastMod,
  503. ChangeFreq: r.ChangeFreq,
  504. Priority: r.Priority,
  505. Links: translatedLinks,
  506. })
  507. }
  508. for _, s := range sitemaps.Build() {
  509. contentCopy := make([]byte, len(s.Content))
  510. copy(contentCopy, s.Content)
  511. handler := func(ctx Context) {
  512. ctx.ContentType(context.ContentXMLHeaderValue)
  513. ctx.Write(contentCopy) // nolint:errcheck
  514. }
  515. if app.builded {
  516. routes := app.CreateRoutes([]string{MethodGet, MethodHead, MethodOptions}, s.Path, handler)
  517. for _, r := range routes {
  518. if err := app.Router.AddRouteUnsafe(r); err != nil {
  519. app.Logger().Errorf("sitemap route: %v", err)
  520. }
  521. }
  522. } else {
  523. app.HandleMany("GET HEAD OPTIONS", s.Path, handler)
  524. }
  525. }
  526. }
  527. }
  528. // WithTunneling is the `iris.Configurator` for the `iris.Configuration.Tunneling` field.
  529. // It's used to enable http tunneling for an Iris Application, per registered host
  530. //
  531. // Alternatively use the `iris.WithConfiguration(iris.Configuration{Tunneling: iris.TunnelingConfiguration{ ...}}}`.
  532. var WithTunneling = func(app *Application) {
  533. conf := TunnelingConfiguration{
  534. Tunnels: []Tunnel{{}}, // create empty tunnel, its addr and name are set right before host serve.
  535. }
  536. app.config.Tunneling = conf
  537. }
  538. type (
  539. // TunnelingConfiguration contains configuration
  540. // for the optional tunneling through ngrok feature.
  541. // Note that the ngrok should be already installed at the host machine.
  542. TunnelingConfiguration = tunnel.Configuration
  543. // Tunnel is the Tunnels field of the TunnelingConfiguration structure.
  544. Tunnel = tunnel.Tunnel
  545. )
  546. // Configuration holds the necessary settings for an Iris Application instance.
  547. // All fields are optionally, the default values will work for a common web application.
  548. //
  549. // A Configuration value can be passed through `WithConfiguration` Configurator.
  550. // Usage:
  551. // conf := iris.Configuration{ ... }
  552. // app := iris.New()
  553. // app.Configure(iris.WithConfiguration(conf)) OR
  554. // app.Run/Listen(..., iris.WithConfiguration(conf)).
  555. type Configuration struct {
  556. // VHost lets you customize the trusted domain this server should run on.
  557. // Its value will be used as the return value of Context.Domain() too.
  558. // It can be retrieved by the context if needed (i.e router for subdomains)
  559. VHost string `ini:"v_host" json:"vHost" yaml:"VHost" toml:"VHost" env:"V_HOST"`
  560. // LogLevel is the log level the application should use to output messages.
  561. // Logger, by default, is mostly used on Build state but it is also possible
  562. // that debug error messages could be thrown when the app is running, e.g.
  563. // when malformed data structures try to be sent on Client (i.e Context.JSON/JSONP/XML...).
  564. //
  565. // Defaults to "info". Possible values are:
  566. // * "disable"
  567. // * "fatal"
  568. // * "error"
  569. // * "warn"
  570. // * "info"
  571. // * "debug"
  572. LogLevel string `ini:"log_level" json:"logLevel" yaml:"LogLevel" toml:"LogLevel" env:"LOG_LEVEL"`
  573. // SocketSharding enables SO_REUSEPORT (or SO_REUSEADDR for windows)
  574. // on all registered Hosts.
  575. // This option allows linear scaling server performance on multi-CPU servers.
  576. //
  577. // Please read the following:
  578. // 1. https://stackoverflow.com/a/14388707
  579. // 2. https://stackoverflow.com/a/59692868
  580. // 3. https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
  581. // 4. (BOOK) Learning HTTP/2: A Practical Guide for Beginners:
  582. // Page 37, To Shard or Not to Shard?
  583. //
  584. // Defaults to false.
  585. SocketSharding bool `ini:"socket_sharding" json:"socketSharding" yaml:"SocketSharding" toml:"SocketSharding" env:"SOCKET_SHARDING"`
  586. // KeepAlive sets the TCP connection's keep-alive duration.
  587. // If set to greater than zero then a tcp listener featured keep alive
  588. // will be used instead of the simple tcp one.
  589. //
  590. // Defaults to 0.
  591. KeepAlive time.Duration `ini:"keepalive" json:"keepAlive" yaml:"KeepAlive" toml:"KeepAlive" env:"KEEP_ALIVE"`
  592. // Timeout wraps the application's router with an http timeout handler
  593. // if the value is greater than zero.
  594. //
  595. // The underline response writer supports the Pusher interface but does not support
  596. // the Hijacker or Flusher interfaces when Timeout handler is registered.
  597. //
  598. // Read more at: https://pkg.go.dev/net/http#TimeoutHandler.
  599. Timeout time.Duration `ini:"timeout" json:"timeout" yaml:"Timeout" toml:"Timeout"`
  600. // TimeoutMessage specifies the HTML body when a handler hits its life time based
  601. // on the Timeout configuration field.
  602. TimeoutMessage string `ini:"timeout_message" json:"timeoutMessage" yaml:"TimeoutMessage" toml:"TimeoutMessage"`
  603. // Tunneling can be optionally set to enable ngrok http(s) tunneling for this Iris app instance.
  604. // See the `WithTunneling` Configurator too.
  605. Tunneling TunnelingConfiguration `ini:"tunneling" json:"tunneling,omitempty" yaml:"Tunneling" toml:"Tunneling"`
  606. // IgnoreServerErrors will cause to ignore the matched "errors"
  607. // from the main application's `Run` function.
  608. // This is a slice of string, not a slice of error
  609. // users can register these errors using yaml or toml configuration file
  610. // like the rest of the configuration fields.
  611. //
  612. // See `WithoutServerError(...)` function too.
  613. //
  614. // Example: https://github.com/kataras/iris/tree/main/_examples/http-server/listen-addr/omit-server-errors
  615. //
  616. // Defaults to an empty slice.
  617. IgnoreServerErrors []string `ini:"ignore_server_errors" json:"ignoreServerErrors,omitempty" yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`
  618. // DisableStartupLog if set to true then it turns off the write banner on server startup.
  619. //
  620. // Defaults to false.
  621. DisableStartupLog bool `ini:"disable_startup_log" json:"disableStartupLog,omitempty" yaml:"DisableStartupLog" toml:"DisableStartupLog"`
  622. // DisableInterruptHandler if set to true then it disables the automatic graceful server shutdown
  623. // when control/cmd+C pressed.
  624. // Turn this to true if you're planning to handle this by your own via a custom host.Task.
  625. //
  626. // Defaults to false.
  627. DisableInterruptHandler bool `ini:"disable_interrupt_handler" json:"disableInterruptHandler,omitempty" yaml:"DisableInterruptHandler" toml:"DisableInterruptHandler"`
  628. // DisablePathCorrection disables the correcting
  629. // and redirecting or executing directly the handler of
  630. // the requested path to the registered path
  631. // for example, if /home/ path is requested but no handler for this Route found,
  632. // then the Router checks if /home handler exists, if yes,
  633. // (permanent)redirects the client to the correct path /home.
  634. //
  635. // See `DisablePathCorrectionRedirection` to enable direct handler execution instead of redirection.
  636. //
  637. // Defaults to false.
  638. DisablePathCorrection bool `ini:"disable_path_correction" json:"disablePathCorrection,omitempty" yaml:"DisablePathCorrection" toml:"DisablePathCorrection"`
  639. // DisablePathCorrectionRedirection works whenever configuration.DisablePathCorrection is set to false
  640. // and if DisablePathCorrectionRedirection set to true then it will fire the handler of the matching route without
  641. // the trailing slash ("/") instead of send a redirection status.
  642. //
  643. // Defaults to false.
  644. DisablePathCorrectionRedirection bool `ini:"disable_path_correction_redirection" json:"disablePathCorrectionRedirection,omitempty" yaml:"DisablePathCorrectionRedirection" toml:"DisablePathCorrectionRedirection"`
  645. // EnablePathIntelligence if set to true,
  646. // the router will redirect HTTP "GET" not found pages to the most closest one path(if any). For example
  647. // you register a route at "/contact" path -
  648. // a client tries to reach it by "/cont", the path will be automatic fixed
  649. // and the client will be redirected to the "/contact" path
  650. // instead of getting a 404 not found response back.
  651. //
  652. // Defaults to false.
  653. EnablePathIntelligence bool `ini:"enable_path_intelligence" json:"enablePathIntelligence,omitempty" yaml:"EnablePathIntelligence" toml:"EnablePathIntelligence"`
  654. // EnablePathEscape when is true then its escapes the path and the named parameters (if any).
  655. // When do you need to Disable(false) it:
  656. // accepts parameters with slash '/'
  657. // Request: http://localhost:8080/details/Project%2FDelta
  658. // ctx.Param("project") returns the raw named parameter: Project%2FDelta
  659. // which you can escape it manually with net/url:
  660. // projectName, _ := url.QueryUnescape(c.Param("project").
  661. //
  662. // Defaults to false.
  663. EnablePathEscape bool `ini:"enable_path_escape" json:"enablePathEscape,omitempty" yaml:"EnablePathEscape" toml:"EnablePathEscape"`
  664. // ForceLowercaseRouting if enabled, converts all registered routes paths to lowercase
  665. // and it does lowercase the request path too for matching.
  666. //
  667. // Defaults to false.
  668. ForceLowercaseRouting bool `ini:"force_lowercase_routing" json:"forceLowercaseRouting,omitempty" yaml:"ForceLowercaseRouting" toml:"ForceLowercaseRouting"`
  669. // EnableOptimizations enables dynamic request handler.
  670. // It gives the router the feature to add routes while in serve-time,
  671. // when `RefreshRouter` is called.
  672. // If this setting is set to true, the request handler will use a mutex for data(trie routing) protection,
  673. // hence the performance cost.
  674. //
  675. // Defaults to false.
  676. EnableDynamicHandler bool `ini:"enable_dynamic_handler" json:"enableDynamicHandler,omitempty" yaml:"EnableDynamicHandler" toml:"EnableDynamicHandler"`
  677. // FireMethodNotAllowed if it's true router checks for StatusMethodNotAllowed(405) and
  678. // fires the 405 error instead of 404
  679. // Defaults to false.
  680. FireMethodNotAllowed bool `ini:"fire_method_not_allowed" json:"fireMethodNotAllowed,omitempty" yaml:"FireMethodNotAllowed" toml:"FireMethodNotAllowed"`
  681. // DisableAutoFireStatusCode if true then it turns off the http error status code
  682. // handler automatic execution on error code from a `Context.StatusCode` call.
  683. // By-default a custom http error handler will be fired when "Context.StatusCode(errorCode)" called.
  684. //
  685. // Defaults to false.
  686. DisableAutoFireStatusCode bool `ini:"disable_auto_fire_status_code" json:"disableAutoFireStatusCode,omitempty" yaml:"DisableAutoFireStatusCode" toml:"DisableAutoFireStatusCode"`
  687. // ResetOnFireErrorCode if true then any previously response body or headers through
  688. // response recorder will be ignored and the router
  689. // will fire the registered (or default) HTTP error handler instead.
  690. // See `core/router/handler#FireErrorCode` and `Context.EndRequest` for more details.
  691. //
  692. // Read more at: https://github.com/kataras/iris/issues/1531
  693. //
  694. // Defaults to false.
  695. ResetOnFireErrorCode bool `ini:"reset_on_fire_error_code" json:"resetOnFireErrorCode,omitempty" yaml:"ResetOnFireErrorCode" toml:"ResetOnFireErrorCode"`
  696. // URLParamSeparator defines the character(s) separator for Context.URLParamSlice.
  697. // If empty or null then request url parameters with comma separated values will be retrieved as one.
  698. //
  699. // Defaults to comma ",".
  700. URLParamSeparator *string `ini:"url_param_separator" json:"urlParamSeparator,omitempty" yaml:"URLParamSeparator" toml:"URLParamSeparator"`
  701. // EnableOptimization when this field is true
  702. // then the application tries to optimize for the best performance where is possible.
  703. //
  704. // Defaults to false.
  705. // Deprecated. As of version 12.2.x this field does nothing.
  706. EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
  707. // EnableProtoJSON when this field is true
  708. // enables the proto marshaler on given proto messages when calling the Context.JSON method.
  709. //
  710. // Defaults to false.
  711. EnableProtoJSON bool `ini:"enable_proto_json" json:"enableProtoJSON,omitempty" yaml:"EnableProtoJSON" toml:"EnableProtoJSON"`
  712. // EnableEasyJSON when this field is true
  713. // enables the fast easy json marshaler on compatible struct values when calling the Context.JSON method.
  714. //
  715. // Defaults to false.
  716. EnableEasyJSON bool `ini:"enable_easy_json" json:"enableEasyJSON,omitempty" yaml:"EnableEasyJSON" toml:"EnableEasyJSON"`
  717. // DisableBodyConsumptionOnUnmarshal manages the reading behavior of the context's body readers/binders.
  718. // If set to true then it
  719. // disables the body consumption by the `context.UnmarshalBody/ReadJSON/ReadXML`.
  720. //
  721. // By-default io.ReadAll` is used to read the body from the `context.Request.Body which is an `io.ReadCloser`,
  722. // if this field set to true then a new buffer will be created to read from and the request body.
  723. // The body will not be changed and existing data before the
  724. // context.UnmarshalBody/ReadJSON/ReadXML will be not consumed.
  725. //
  726. // See `Context.RecordRequestBody` method for the same feature, per-request.
  727. DisableBodyConsumptionOnUnmarshal bool `ini:"disable_body_consumption" json:"disableBodyConsumptionOnUnmarshal,omitempty" yaml:"DisableBodyConsumptionOnUnmarshal" toml:"DisableBodyConsumptionOnUnmarshal"`
  728. // FireEmptyFormError returns if set to tue true then the `context.ReadForm/ReadQuery/ReadBody`
  729. // will return an `iris.ErrEmptyForm` on empty request form data.
  730. FireEmptyFormError bool `ini:"fire_empty_form_error" json:"fireEmptyFormError,omitempty" yaml:"FireEmptyFormError" toml:"FireEmptyFormError"`
  731. // TimeFormat time format for any kind of datetime parsing
  732. // Defaults to "Mon, 02 Jan 2006 15:04:05 GMT".
  733. TimeFormat string `ini:"time_format" json:"timeFormat,omitempty" yaml:"TimeFormat" toml:"TimeFormat"`
  734. // Charset character encoding for various rendering
  735. // used for templates and the rest of the responses
  736. // Defaults to "utf-8".
  737. Charset string `ini:"charset" json:"charset,omitempty" yaml:"Charset" toml:"Charset"`
  738. // PostMaxMemory sets the maximum post data size
  739. // that a client can send to the server, this differs
  740. // from the overall request body size which can be modified
  741. // by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
  742. //
  743. // Defaults to 32MB or 32 << 20 if you prefer.
  744. PostMaxMemory int64 `ini:"post_max_memory" json:"postMaxMemory" yaml:"PostMaxMemory" toml:"PostMaxMemory"`
  745. // +----------------------------------------------------+
  746. // | Context's keys for values used on various featuers |
  747. // +----------------------------------------------------+
  748. // Context values' keys for various features.
  749. //
  750. // LocaleContextKey is used by i18n to get the current request's locale, which contains a translate function too.
  751. //
  752. // Defaults to "iris.locale".
  753. LocaleContextKey string `ini:"locale_context_key" json:"localeContextKey,omitempty" yaml:"LocaleContextKey" toml:"LocaleContextKey"`
  754. // LanguageContextKey is the context key which a language can be modified by a middleware.
  755. // It has the highest priority over the rest and if it is empty then it is ignored,
  756. // if it set to a static string of "default" or to the default language's code
  757. // then the rest of the language extractors will not be called at all and
  758. // the default language will be set instead.
  759. //
  760. // Use with `Context.SetLanguage("el-GR")`.
  761. //
  762. // See `i18n.ExtractFunc` for a more organised way of the same feature.
  763. // Defaults to "iris.locale.language".
  764. LanguageContextKey string `ini:"language_context_key" json:"languageContextKey,omitempty" yaml:"LanguageContextKey" toml:"LanguageContextKey"`
  765. // LanguageInputContextKey is the context key of a language that is given by the end-user.
  766. // It's the real user input of the language string, matched or not.
  767. //
  768. // Defaults to "iris.locale.language.input".
  769. LanguageInputContextKey string `ini:"language_input_context_key" json:"languageInputContextKey,omitempty" yaml:"LanguageInputContextKey" toml:"LanguageInputContextKey"`
  770. // VersionContextKey is the context key which an API Version can be modified
  771. // via a middleware through `SetVersion` method, e.g. `versioning.SetVersion(ctx, ">=1.0.0 <2.0.0")`.
  772. // Defaults to "iris.api.version".
  773. VersionContextKey string `ini:"version_context_key" json:"versionContextKey" yaml:"VersionContextKey" toml:"VersionContextKey"`
  774. // VersionAliasesContextKey is the context key which the versioning feature
  775. // can look up for alternative values of a version and fallback to that.
  776. // Head over to the versioning package for more.
  777. // Defaults to "iris.api.version.aliases"
  778. VersionAliasesContextKey string `ini:"version_aliases_context_key" json:"versionAliasesContextKey" yaml:"VersionAliasesContextKey" toml:"VersionAliasesContextKey"`
  779. // ViewEngineContextKey is the context's values key
  780. // responsible to store and retrieve(view.Engine) the current view engine.
  781. // A middleware or a Party can modify its associated value to change
  782. // a view engine that `ctx.View` will render through.
  783. // If not an engine is registered by the end-developer
  784. // then its associated value is always nil,
  785. // meaning that the default value is nil.
  786. // See `Party.RegisterView` and `Context.ViewEngine` methods as well.
  787. //
  788. // Defaults to "iris.view.engine".
  789. ViewEngineContextKey string `ini:"view_engine_context_key" json:"viewEngineContextKey,omitempty" yaml:"ViewEngineContextKey" toml:"ViewEngineContextKey"`
  790. // ViewLayoutContextKey is the context's values key
  791. // responsible to store and retrieve(string) the current view layout.
  792. // A middleware can modify its associated value to change
  793. // the layout that `ctx.View` will use to render a template.
  794. //
  795. // Defaults to "iris.view.layout".
  796. ViewLayoutContextKey string `ini:"view_layout_context_key" json:"viewLayoutContextKey,omitempty" yaml:"ViewLayoutContextKey" toml:"ViewLayoutContextKey"`
  797. // ViewDataContextKey is the context's values key
  798. // responsible to store and retrieve(interface{}) the current view binding data.
  799. // A middleware can modify its associated value to change
  800. // the template's data on-fly.
  801. //
  802. // Defaults to "iris.view.data".
  803. ViewDataContextKey string `ini:"view_data_context_key" json:"viewDataContextKey,omitempty" yaml:"ViewDataContextKey" toml:"ViewDataContextKey"`
  804. // FallbackViewContextKey is the context's values key
  805. // responsible to store the view fallback information.
  806. //
  807. // Defaults to "iris.view.fallback".
  808. FallbackViewContextKey string `ini:"fallback_view_context_key" json:"fallbackViewContextKey,omitempty" yaml:"FallbackViewContextKey" toml:"FallbackViewContextKey"`
  809. // RemoteAddrHeaders are the allowed request headers names
  810. // that can be valid to parse the client's IP based on.
  811. // By-default no "X-" header is consired safe to be used for retrieving the
  812. // client's IP address, because those headers can manually change by
  813. // the client. But sometimes are useful e.g. when behind a proxy
  814. // you want to enable the "X-Forwarded-For" or when cloudflare
  815. // you want to enable the "CF-Connecting-IP", indeed you
  816. // can allow the `ctx.RemoteAddr()` to use any header
  817. // that the client may sent.
  818. //
  819. // Defaults to an empty slice but an example usage is:
  820. // RemoteAddrHeaders {
  821. // "X-Real-Ip",
  822. // "X-Forwarded-For",
  823. // "CF-Connecting-IP",
  824. // "True-Client-Ip",
  825. // "X-Appengine-Remote-Addr",
  826. // }
  827. //
  828. // Look `context.RemoteAddr()` for more.
  829. RemoteAddrHeaders []string `ini:"remote_addr_headers" json:"remoteAddrHeaders,omitempty" yaml:"RemoteAddrHeaders" toml:"RemoteAddrHeaders"`
  830. // RemoteAddrHeadersForce forces the `Context.RemoteAddr()` method
  831. // to return the first entry of a request header as a fallback,
  832. // even if that IP is a part of the `RemoteAddrPrivateSubnets` list.
  833. // The default behavior, if a remote address is part of the `RemoteAddrPrivateSubnets`,
  834. // is to retrieve the IP from the `Request.RemoteAddr` field instead.
  835. RemoteAddrHeadersForce bool `ini:"remote_addr_headers_force" json:"remoteAddrHeadersForce,omitempty" yaml:"RemoteAddrHeadersForce" toml:"RemoteAddrHeadersForce"`
  836. // RemoteAddrPrivateSubnets defines the private sub-networks.
  837. // They are used to be compared against
  838. // IP Addresses fetched through `RemoteAddrHeaders` or `Context.Request.RemoteAddr`.
  839. // For details please navigate through: https://github.com/kataras/iris/issues/1453
  840. // Defaults to:
  841. // {
  842. // Start: "10.0.0.0",
  843. // End: "10.255.255.255",
  844. // },
  845. // {
  846. // Start: "100.64.0.0",
  847. // End: "100.127.255.255",
  848. // },
  849. // {
  850. // Start: "172.16.0.0",
  851. // End: "172.31.255.255",
  852. // },
  853. // {
  854. // Start: "192.0.0.0",
  855. // End: "192.0.0.255",
  856. // },
  857. // {
  858. // Start: "192.168.0.0",
  859. // End: "192.168.255.255",
  860. // },
  861. // {
  862. // Start: "198.18.0.0",
  863. // End: "198.19.255.255",
  864. // }
  865. //
  866. // Look `Context.RemoteAddr()` for more.
  867. RemoteAddrPrivateSubnets []netutil.IPRange `ini:"remote_addr_private_subnets" json:"remoteAddrPrivateSubnets" yaml:"RemoteAddrPrivateSubnets" toml:"RemoteAddrPrivateSubnets"`
  868. // SSLProxyHeaders defines the set of header key values
  869. // that would indicate a valid https Request (look `Context.IsSSL()`).
  870. // Example: `map[string]string{"X-Forwarded-Proto": "https"}`.
  871. //
  872. // Defaults to empty map.
  873. SSLProxyHeaders map[string]string `ini:"ssl_proxy_headers" json:"sslProxyHeaders" yaml:"SSLProxyHeaders" toml:"SSLProxyHeaders"`
  874. // HostProxyHeaders defines the set of headers that may hold a proxied hostname value for the clients.
  875. // Look `Context.Host()` for more.
  876. // Defaults to empty map.
  877. HostProxyHeaders map[string]bool `ini:"host_proxy_headers" json:"hostProxyHeaders" yaml:"HostProxyHeaders" toml:"HostProxyHeaders"`
  878. // Other are the custom, dynamic options, can be empty.
  879. // This field used only by you to set any app's options you want.
  880. //
  881. // Defaults to empty map.
  882. Other map[string]interface{} `ini:"other" json:"other,omitempty" yaml:"Other" toml:"Other"`
  883. }
  884. var _ context.ConfigurationReadOnly = (*Configuration)(nil)
  885. // GetVHost returns the non-exported vhost config field.
  886. func (c *Configuration) GetVHost() string {
  887. return c.VHost
  888. }
  889. // GetLogLevel returns the LogLevel field.
  890. func (c *Configuration) GetLogLevel() string {
  891. return c.LogLevel
  892. }
  893. // GetSocketSharding returns the SocketSharding field.
  894. func (c *Configuration) GetSocketSharding() bool {
  895. return c.SocketSharding
  896. }
  897. // GetKeepAlive returns the KeepAlive field.
  898. func (c *Configuration) GetKeepAlive() time.Duration {
  899. return c.KeepAlive
  900. }
  901. // GetTimeout returns the Timeout field.
  902. func (c *Configuration) GetTimeout() time.Duration {
  903. return c.Timeout
  904. }
  905. // GetTimeoutMessage returns the TimeoutMessage field.
  906. func (c *Configuration) GetTimeoutMessage() string {
  907. return c.TimeoutMessage
  908. }
  909. // GetDisablePathCorrection returns the DisablePathCorrection field.
  910. func (c *Configuration) GetDisablePathCorrection() bool {
  911. return c.DisablePathCorrection
  912. }
  913. // GetDisablePathCorrectionRedirection returns the DisablePathCorrectionRedirection field.
  914. func (c *Configuration) GetDisablePathCorrectionRedirection() bool {
  915. return c.DisablePathCorrectionRedirection
  916. }
  917. // GetEnablePathIntelligence returns the EnablePathIntelligence field.
  918. func (c *Configuration) GetEnablePathIntelligence() bool {
  919. return c.EnablePathIntelligence
  920. }
  921. // GetEnablePathEscape returns the EnablePathEscape field.
  922. func (c *Configuration) GetEnablePathEscape() bool {
  923. return c.EnablePathEscape
  924. }
  925. // GetForceLowercaseRouting returns the ForceLowercaseRouting field.
  926. func (c *Configuration) GetForceLowercaseRouting() bool {
  927. return c.ForceLowercaseRouting
  928. }
  929. // GetEnableDynamicHandler returns the EnableDynamicHandler field.
  930. func (c *Configuration) GetEnableDynamicHandler() bool {
  931. return c.EnableDynamicHandler
  932. }
  933. // GetFireMethodNotAllowed returns the FireMethodNotAllowed field.
  934. func (c *Configuration) GetFireMethodNotAllowed() bool {
  935. return c.FireMethodNotAllowed
  936. }
  937. // GetEnableOptimizations returns the EnableOptimizations.
  938. func (c *Configuration) GetEnableOptimizations() bool {
  939. return c.EnableOptimizations
  940. }
  941. // GetEnableProtoJSON returns the EnableProtoJSON field.
  942. func (c *Configuration) GetEnableProtoJSON() bool {
  943. return c.EnableProtoJSON
  944. }
  945. // GetEnableEasyJSON returns the EnableEasyJSON field.
  946. func (c *Configuration) GetEnableEasyJSON() bool {
  947. return c.EnableEasyJSON
  948. }
  949. // GetDisableBodyConsumptionOnUnmarshal returns the DisableBodyConsumptionOnUnmarshal field.
  950. func (c *Configuration) GetDisableBodyConsumptionOnUnmarshal() bool {
  951. return c.DisableBodyConsumptionOnUnmarshal
  952. }
  953. // GetFireEmptyFormError returns the DisableBodyConsumptionOnUnmarshal field.
  954. func (c *Configuration) GetFireEmptyFormError() bool {
  955. return c.FireEmptyFormError
  956. }
  957. // GetDisableAutoFireStatusCode returns the DisableAutoFireStatusCode field.
  958. func (c *Configuration) GetDisableAutoFireStatusCode() bool {
  959. return c.DisableAutoFireStatusCode
  960. }
  961. // GetResetOnFireErrorCode returns ResetOnFireErrorCode field.
  962. func (c *Configuration) GetResetOnFireErrorCode() bool {
  963. return c.ResetOnFireErrorCode
  964. }
  965. // GetURLParamSeparator returns URLParamSeparator field.
  966. func (c *Configuration) GetURLParamSeparator() *string {
  967. return c.URLParamSeparator
  968. }
  969. // GetTimeFormat returns the TimeFormat field.
  970. func (c *Configuration) GetTimeFormat() string {
  971. return c.TimeFormat
  972. }
  973. // GetCharset returns the Charset field.
  974. func (c *Configuration) GetCharset() string {
  975. return c.Charset
  976. }
  977. // GetPostMaxMemory returns the PostMaxMemory field.
  978. func (c *Configuration) GetPostMaxMemory() int64 {
  979. return c.PostMaxMemory
  980. }
  981. // GetLocaleContextKey returns the LocaleContextKey field.
  982. func (c *Configuration) GetLocaleContextKey() string {
  983. return c.LocaleContextKey
  984. }
  985. // GetLanguageContextKey returns the LanguageContextKey field.
  986. func (c *Configuration) GetLanguageContextKey() string {
  987. return c.LanguageContextKey
  988. }
  989. // GetLanguageInputContextKey returns the LanguageInputContextKey field.
  990. func (c *Configuration) GetLanguageInputContextKey() string {
  991. return c.LanguageInputContextKey
  992. }
  993. // GetVersionContextKey returns the VersionContextKey field.
  994. func (c *Configuration) GetVersionContextKey() string {
  995. return c.VersionContextKey
  996. }
  997. // GetVersionAliasesContextKey returns the VersionAliasesContextKey field.
  998. func (c *Configuration) GetVersionAliasesContextKey() string {
  999. return c.VersionAliasesContextKey
  1000. }
  1001. // GetViewEngineContextKey returns the ViewEngineContextKey field.
  1002. func (c *Configuration) GetViewEngineContextKey() string {
  1003. return c.ViewEngineContextKey
  1004. }
  1005. // GetViewLayoutContextKey returns the ViewLayoutContextKey field.
  1006. func (c *Configuration) GetViewLayoutContextKey() string {
  1007. return c.ViewLayoutContextKey
  1008. }
  1009. // GetViewDataContextKey returns the ViewDataContextKey field.
  1010. func (c *Configuration) GetViewDataContextKey() string {
  1011. return c.ViewDataContextKey
  1012. }
  1013. // GetFallbackViewContextKey returns the FallbackViewContextKey field.
  1014. func (c *Configuration) GetFallbackViewContextKey() string {
  1015. return c.FallbackViewContextKey
  1016. }
  1017. // GetRemoteAddrHeaders returns the RemoteAddrHeaders field.
  1018. func (c *Configuration) GetRemoteAddrHeaders() []string {
  1019. return c.RemoteAddrHeaders
  1020. }
  1021. // GetRemoteAddrHeadersForce returns RemoteAddrHeadersForce field.
  1022. func (c *Configuration) GetRemoteAddrHeadersForce() bool {
  1023. return c.RemoteAddrHeadersForce
  1024. }
  1025. // GetSSLProxyHeaders returns the SSLProxyHeaders field.
  1026. func (c *Configuration) GetSSLProxyHeaders() map[string]string {
  1027. return c.SSLProxyHeaders
  1028. }
  1029. // GetRemoteAddrPrivateSubnets returns the RemoteAddrPrivateSubnets field.
  1030. func (c *Configuration) GetRemoteAddrPrivateSubnets() []netutil.IPRange {
  1031. return c.RemoteAddrPrivateSubnets
  1032. }
  1033. // GetHostProxyHeaders returns the HostProxyHeaders field.
  1034. func (c *Configuration) GetHostProxyHeaders() map[string]bool {
  1035. return c.HostProxyHeaders
  1036. }
  1037. // GetOther returns the Other field.
  1038. func (c *Configuration) GetOther() map[string]interface{} {
  1039. return c.Other
  1040. }
  1041. // WithConfiguration sets the "c" values to the framework's configurations.
  1042. //
  1043. // Usage:
  1044. // app.Listen(":8080", iris.WithConfiguration(iris.Configuration{/* fields here */ }))
  1045. // or
  1046. // iris.WithConfiguration(iris.YAML("./cfg/iris.yml"))
  1047. // or
  1048. // iris.WithConfiguration(iris.TOML("./cfg/iris.tml"))
  1049. func WithConfiguration(c Configuration) Configurator {
  1050. return func(app *Application) {
  1051. main := app.config
  1052. if main == nil {
  1053. app.config = &c
  1054. return
  1055. }
  1056. if v := c.LogLevel; v != "" {
  1057. main.LogLevel = v
  1058. }
  1059. if v := c.SocketSharding; v {
  1060. main.SocketSharding = v
  1061. }
  1062. if v := c.KeepAlive; v > 0 {
  1063. main.KeepAlive = v
  1064. }
  1065. if v := c.Timeout; v > 0 {
  1066. main.Timeout = v
  1067. }
  1068. if v := c.TimeoutMessage; v != "" {
  1069. main.TimeoutMessage = v
  1070. }
  1071. if len(c.Tunneling.Tunnels) > 0 {
  1072. main.Tunneling = c.Tunneling
  1073. }
  1074. if v := c.IgnoreServerErrors; len(v) > 0 {
  1075. main.IgnoreServerErrors = append(main.IgnoreServerErrors, v...)
  1076. }
  1077. if v := c.DisableStartupLog; v {
  1078. main.DisableStartupLog = v
  1079. }
  1080. if v := c.DisableInterruptHandler; v {
  1081. main.DisableInterruptHandler = v
  1082. }
  1083. if v := c.DisablePathCorrection; v {
  1084. main.DisablePathCorrection = v
  1085. }
  1086. if v := c.DisablePathCorrectionRedirection; v {
  1087. main.DisablePathCorrectionRedirection = v
  1088. }
  1089. if v := c.EnablePathIntelligence; v {
  1090. main.EnablePathIntelligence = v
  1091. }
  1092. if v := c.EnablePathEscape; v {
  1093. main.EnablePathEscape = v
  1094. }
  1095. if v := c.ForceLowercaseRouting; v {
  1096. main.ForceLowercaseRouting = v
  1097. }
  1098. if v := c.EnableOptimizations; v {
  1099. main.EnableOptimizations = v
  1100. }
  1101. if v := c.EnableProtoJSON; v {
  1102. main.EnableProtoJSON = v
  1103. }
  1104. if v := c.EnableEasyJSON; v {
  1105. main.EnableEasyJSON = v
  1106. }
  1107. if v := c.FireMethodNotAllowed; v {
  1108. main.FireMethodNotAllowed = v
  1109. }
  1110. if v := c.DisableAutoFireStatusCode; v {
  1111. main.DisableAutoFireStatusCode = v
  1112. }
  1113. if v := c.ResetOnFireErrorCode; v {
  1114. main.ResetOnFireErrorCode = v
  1115. }
  1116. if v := c.URLParamSeparator; v != nil {
  1117. main.URLParamSeparator = v
  1118. }
  1119. if v := c.DisableBodyConsumptionOnUnmarshal; v {
  1120. main.DisableBodyConsumptionOnUnmarshal = v
  1121. }
  1122. if v := c.FireEmptyFormError; v {
  1123. main.FireEmptyFormError = v
  1124. }
  1125. if v := c.TimeFormat; v != "" {
  1126. main.TimeFormat = v
  1127. }
  1128. if v := c.Charset; v != "" {
  1129. main.Charset = v
  1130. }
  1131. if v := c.PostMaxMemory; v > 0 {
  1132. main.PostMaxMemory = v
  1133. }
  1134. if v := c.LocaleContextKey; v != "" {
  1135. main.LocaleContextKey = v
  1136. }
  1137. if v := c.LanguageContextKey; v != "" {
  1138. main.LanguageContextKey = v
  1139. }
  1140. if v := c.LanguageInputContextKey; v != "" {
  1141. main.LanguageInputContextKey = v
  1142. }
  1143. if v := c.VersionContextKey; v != "" {
  1144. main.VersionContextKey = v
  1145. }
  1146. if v := c.VersionAliasesContextKey; v != "" {
  1147. main.VersionAliasesContextKey = v
  1148. }
  1149. if v := c.ViewEngineContextKey; v != "" {
  1150. main.ViewEngineContextKey = v
  1151. }
  1152. if v := c.ViewLayoutContextKey; v != "" {
  1153. main.ViewLayoutContextKey = v
  1154. }
  1155. if v := c.ViewDataContextKey; v != "" {
  1156. main.ViewDataContextKey = v
  1157. }
  1158. if v := c.FallbackViewContextKey; v != "" {
  1159. main.FallbackViewContextKey = v
  1160. }
  1161. if v := c.RemoteAddrHeaders; len(v) > 0 {
  1162. main.RemoteAddrHeaders = v
  1163. }
  1164. if v := c.RemoteAddrHeadersForce; v {
  1165. main.RemoteAddrHeadersForce = v
  1166. }
  1167. if v := c.RemoteAddrPrivateSubnets; len(v) > 0 {
  1168. main.RemoteAddrPrivateSubnets = v
  1169. }
  1170. if v := c.SSLProxyHeaders; len(v) > 0 {
  1171. if main.SSLProxyHeaders == nil {
  1172. main.SSLProxyHeaders = make(map[string]string, len(v))
  1173. }
  1174. for key, value := range v {
  1175. main.SSLProxyHeaders[key] = value
  1176. }
  1177. }
  1178. if v := c.HostProxyHeaders; len(v) > 0 {
  1179. if main.HostProxyHeaders == nil {
  1180. main.HostProxyHeaders = make(map[string]bool, len(v))
  1181. }
  1182. for key, value := range v {
  1183. main.HostProxyHeaders[key] = value
  1184. }
  1185. }
  1186. if v := c.Other; len(v) > 0 {
  1187. if main.Other == nil {
  1188. main.Other = make(map[string]interface{}, len(v))
  1189. }
  1190. for key, value := range v {
  1191. main.Other[key] = value
  1192. }
  1193. }
  1194. }
  1195. }
  1196. // DefaultTimeoutMessage is the default timeout message which is rendered
  1197. // on expired handlers when timeout handler is registered (see Timeout configuration field).
  1198. var DefaultTimeoutMessage = `<html><head><title>Timeout</title></head><body><h1>Timeout</h1>Looks like the server is taking too long to respond, this can be caused by either poor connectivity or an error with our servers. Please try again in a while.</body></html>`
  1199. func toStringPtr(s string) *string {
  1200. return &s
  1201. }
  1202. // DefaultConfiguration returns the default configuration for an iris station, fills the main Configuration
  1203. func DefaultConfiguration() Configuration {
  1204. return Configuration{
  1205. LogLevel: "info",
  1206. SocketSharding: false,
  1207. KeepAlive: 0,
  1208. Timeout: 0,
  1209. TimeoutMessage: DefaultTimeoutMessage,
  1210. DisableStartupLog: false,
  1211. DisableInterruptHandler: false,
  1212. DisablePathCorrection: false,
  1213. EnablePathEscape: false,
  1214. ForceLowercaseRouting: false,
  1215. FireMethodNotAllowed: false,
  1216. DisableBodyConsumptionOnUnmarshal: false,
  1217. FireEmptyFormError: false,
  1218. DisableAutoFireStatusCode: false,
  1219. ResetOnFireErrorCode: false,
  1220. URLParamSeparator: toStringPtr(","),
  1221. TimeFormat: "Mon, 02 Jan 2006 15:04:05 GMT",
  1222. Charset: "utf-8",
  1223. // PostMaxMemory is for post body max memory.
  1224. //
  1225. // The request body the size limit
  1226. // can be set by the middleware `LimitRequestBodySize`
  1227. // or `context#SetMaxRequestBodySize`.
  1228. PostMaxMemory: 32 << 20, // 32MB
  1229. LocaleContextKey: "iris.locale",
  1230. LanguageContextKey: "iris.locale.language",
  1231. LanguageInputContextKey: "iris.locale.language.input",
  1232. VersionContextKey: "iris.api.version",
  1233. VersionAliasesContextKey: "iris.api.version.aliases",
  1234. ViewEngineContextKey: "iris.view.engine",
  1235. ViewLayoutContextKey: "iris.view.layout",
  1236. ViewDataContextKey: "iris.view.data",
  1237. FallbackViewContextKey: "iris.view.fallback",
  1238. RemoteAddrHeaders: nil,
  1239. RemoteAddrHeadersForce: false,
  1240. RemoteAddrPrivateSubnets: []netutil.IPRange{
  1241. {
  1242. Start: "10.0.0.0",
  1243. End: "10.255.255.255",
  1244. },
  1245. {
  1246. Start: "100.64.0.0",
  1247. End: "100.127.255.255",
  1248. },
  1249. {
  1250. Start: "172.16.0.0",
  1251. End: "172.31.255.255",
  1252. },
  1253. {
  1254. Start: "192.0.0.0",
  1255. End: "192.0.0.255",
  1256. },
  1257. {
  1258. Start: "192.168.0.0",
  1259. End: "192.168.255.255",
  1260. },
  1261. {
  1262. Start: "198.18.0.0",
  1263. End: "198.19.255.255",
  1264. },
  1265. },
  1266. SSLProxyHeaders: make(map[string]string),
  1267. HostProxyHeaders: make(map[string]bool),
  1268. EnableOptimizations: false,
  1269. EnableProtoJSON: false,
  1270. EnableEasyJSON: false,
  1271. Other: make(map[string]interface{}),
  1272. }
  1273. }