context.go 136 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664
  1. package context
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "encoding/xml"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "mime"
  10. "mime/multipart"
  11. "net"
  12. "net/http"
  13. "net/url"
  14. "os"
  15. "path"
  16. "path/filepath"
  17. "regexp"
  18. "strconv"
  19. "strings"
  20. "sync/atomic"
  21. "time"
  22. "github.com/kataras/iris/core/errors"
  23. "github.com/kataras/iris/core/memstore"
  24. "github.com/Shopify/goreferrer"
  25. "github.com/fatih/structs"
  26. formbinder "github.com/iris-contrib/formBinder"
  27. "github.com/json-iterator/go"
  28. "github.com/microcosm-cc/bluemonday"
  29. "gopkg.in/russross/blackfriday.v2"
  30. "gopkg.in/yaml.v2"
  31. )
  32. type (
  33. // BodyDecoder is an interface which any struct can implement in order to customize the decode action
  34. // from ReadJSON and ReadXML
  35. //
  36. // Trivial example of this could be:
  37. // type User struct { Username string }
  38. //
  39. // func (u *User) Decode(data []byte) error {
  40. // return json.Unmarshal(data, u)
  41. // }
  42. //
  43. // the 'context.ReadJSON/ReadXML(&User{})' will call the User's
  44. // Decode option to decode the request body
  45. //
  46. // Note: This is totally optionally, the default decoders
  47. // for ReadJSON is the encoding/json and for ReadXML is the encoding/xml.
  48. //
  49. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-per-type/main.go
  50. BodyDecoder interface {
  51. Decode(data []byte) error
  52. }
  53. // Unmarshaler is the interface implemented by types that can unmarshal any raw data.
  54. // TIP INFO: Any pointer to a value which implements the BodyDecoder can be override the unmarshaler.
  55. Unmarshaler interface {
  56. Unmarshal(data []byte, outPtr interface{}) error
  57. }
  58. // UnmarshalerFunc a shortcut for the Unmarshaler interface
  59. //
  60. // See 'Unmarshaler' and 'BodyDecoder' for more.
  61. //
  62. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
  63. UnmarshalerFunc func(data []byte, outPtr interface{}) error
  64. )
  65. // Unmarshal parses the X-encoded data and stores the result in the value pointed to by v.
  66. // Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps,
  67. // slices, and pointers as necessary.
  68. func (u UnmarshalerFunc) Unmarshal(data []byte, v interface{}) error {
  69. return u(data, v)
  70. }
  71. // RequestParams is a key string - value string storage which
  72. // context's request dynamic path params are being kept.
  73. // Empty if the route is static.
  74. type RequestParams struct {
  75. store memstore.Store
  76. }
  77. // Set adds a key-value pair to the path parameters values
  78. // it's being called internally so it shouldn't be used as a local storage by the user, use `ctx.Values()` instead.
  79. func (r *RequestParams) Set(key, value string) {
  80. r.store.Set(key, value)
  81. }
  82. // Visit accepts a visitor which will be filled
  83. // by the key-value params.
  84. func (r *RequestParams) Visit(visitor func(key string, value string)) {
  85. r.store.Visit(func(k string, v interface{}) {
  86. visitor(k, v.(string)) // always string here.
  87. })
  88. }
  89. var emptyEntry memstore.Entry
  90. // GetEntryAt returns the internal Entry of the memstore based on its index,
  91. // the stored index by the router.
  92. // If not found then it returns a zero Entry and false.
  93. func (r RequestParams) GetEntryAt(index int) (memstore.Entry, bool) {
  94. if len(r.store) > index {
  95. return r.store[index], true
  96. }
  97. return emptyEntry, false
  98. }
  99. // GetEntry returns the internal Entry of the memstore based on its "key".
  100. // If not found then it returns a zero Entry and false.
  101. func (r RequestParams) GetEntry(key string) (memstore.Entry, bool) {
  102. // we don't return the pointer here, we don't want to give the end-developer
  103. // the strength to change the entry that way.
  104. if e := r.store.GetEntry(key); e != nil {
  105. return *e, true
  106. }
  107. return emptyEntry, false
  108. }
  109. // Get returns a path parameter's value based on its route's dynamic path key.
  110. func (r RequestParams) Get(key string) string {
  111. return r.store.GetString(key)
  112. }
  113. // GetTrim returns a path parameter's value without trailing spaces based on its route's dynamic path key.
  114. func (r RequestParams) GetTrim(key string) string {
  115. return strings.TrimSpace(r.Get(key))
  116. }
  117. // GetEscape returns a path parameter's double-url-query-escaped value based on its route's dynamic path key.
  118. func (r RequestParams) GetEscape(key string) string {
  119. return DecodeQuery(DecodeQuery(r.Get(key)))
  120. }
  121. // GetDecoded returns a path parameter's double-url-query-escaped value based on its route's dynamic path key.
  122. // same as `GetEscape`.
  123. func (r RequestParams) GetDecoded(key string) string {
  124. return r.GetEscape(key)
  125. }
  126. // GetInt returns the path parameter's value as int, based on its key.
  127. // It checks for all available types of int, including int64, strings etc.
  128. // It will return -1 and a non-nil error if parameter wasn't found.
  129. func (r RequestParams) GetInt(key string) (int, error) {
  130. return r.store.GetInt(key)
  131. }
  132. // GetInt64 returns the path paramete's value as int64, based on its key.
  133. // It checks for all available types of int, including int, strings etc.
  134. // It will return -1 and a non-nil error if parameter wasn't found.
  135. func (r RequestParams) GetInt64(key string) (int64, error) {
  136. return r.store.GetInt64(key)
  137. }
  138. // GetFloat64 returns a path parameter's value based as float64 on its route's dynamic path key.
  139. // It checks for all available types of int, including float64, int, strings etc.
  140. // It will return -1 and a non-nil error if parameter wasn't found.
  141. func (r RequestParams) GetFloat64(key string) (float64, error) {
  142. return r.store.GetFloat64(key)
  143. }
  144. // GetUint64 returns the path paramete's value as uint64, based on its key.
  145. // It checks for all available types of int, including int, uint64, int64, strings etc.
  146. // It will return 0 and a non-nil error if parameter wasn't found.
  147. func (r RequestParams) GetUint64(key string) (uint64, error) {
  148. return r.store.GetUint64(key)
  149. }
  150. // GetBool returns the path parameter's value as bool, based on its key.
  151. // a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
  152. // or "0" or "f" or "F" or "FALSE" or "false" or "False".
  153. // Any other value returns an error.
  154. func (r RequestParams) GetBool(key string) (bool, error) {
  155. return r.store.GetBool(key)
  156. }
  157. // GetIntUnslashed same as Get but it removes the first slash if found.
  158. // Usage: Get an id from a wildcard path.
  159. //
  160. // Returns -1 with an error if the parameter couldn't be found.
  161. func (r RequestParams) GetIntUnslashed(key string) (int, error) {
  162. v := r.Get(key)
  163. if v != "" {
  164. if len(v) > 1 {
  165. if v[0] == '/' {
  166. v = v[1:]
  167. }
  168. }
  169. return strconv.Atoi(v)
  170. }
  171. return -1, fmt.Errorf("unable to find int for '%s'", key)
  172. }
  173. // Len returns the full length of the parameters.
  174. func (r RequestParams) Len() int {
  175. return r.store.Len()
  176. }
  177. // Context is the midle-man server's "object" for the clients.
  178. //
  179. // A New context is being acquired from a sync.Pool on each connection.
  180. // The Context is the most important thing on the iris's http flow.
  181. //
  182. // Developers send responses to the client's request through a Context.
  183. // Developers get request information from the client's request a Context.
  184. //
  185. // This context is an implementation of the context.Context sub-package.
  186. // context.Context is very extensible and developers can override
  187. // its methods if that is actually needed.
  188. type Context interface {
  189. // BeginRequest is executing once for each request
  190. // it should prepare the (new or acquired from pool) context's fields for the new request.
  191. //
  192. // To follow the iris' flow, developer should:
  193. // 1. reset handlers to nil
  194. // 2. reset values to empty
  195. // 3. reset sessions to nil
  196. // 4. reset response writer to the http.ResponseWriter
  197. // 5. reset request to the *http.Request
  198. // and any other optional steps, depends on dev's application type.
  199. BeginRequest(http.ResponseWriter, *http.Request)
  200. // EndRequest is executing once after a response to the request was sent and this context is useless or released.
  201. //
  202. // To follow the iris' flow, developer should:
  203. // 1. flush the response writer's result
  204. // 2. release the response writer
  205. // and any other optional steps, depends on dev's application type.
  206. EndRequest()
  207. // ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
  208. ResponseWriter() ResponseWriter
  209. // ResetResponseWriter should change or upgrade the Context's ResponseWriter.
  210. ResetResponseWriter(ResponseWriter)
  211. // Request returns the original *http.Request, as expected.
  212. Request() *http.Request
  213. // SetCurrentRouteName sets the route's name internally,
  214. // in order to be able to find the correct current "read-only" Route when
  215. // end-developer calls the `GetCurrentRoute()` function.
  216. // It's being initialized by the Router, if you change that name
  217. // manually nothing really happens except that you'll get other
  218. // route via `GetCurrentRoute()`.
  219. // Instead, to execute a different path
  220. // from this context you should use the `Exec` function
  221. // or change the handlers via `SetHandlers/AddHandler` functions.
  222. SetCurrentRouteName(currentRouteName string)
  223. // GetCurrentRoute returns the current registered "read-only" route that
  224. // was being registered to this request's path.
  225. GetCurrentRoute() RouteReadOnly
  226. // Do calls the SetHandlers(handlers)
  227. // and executes the first handler,
  228. // handlers should not be empty.
  229. //
  230. // It's used by the router, developers may use that
  231. // to replace and execute handlers immediately.
  232. Do(Handlers)
  233. // AddHandler can add handler(s)
  234. // to the current request in serve-time,
  235. // these handlers are not persistenced to the router.
  236. //
  237. // Router is calling this function to add the route's handler.
  238. // If AddHandler called then the handlers will be inserted
  239. // to the end of the already-defined route's handler.
  240. //
  241. AddHandler(...Handler)
  242. // SetHandlers replaces all handlers with the new.
  243. SetHandlers(Handlers)
  244. // Handlers keeps tracking of the current handlers.
  245. Handlers() Handlers
  246. // HandlerIndex sets the current index of the
  247. // current context's handlers chain.
  248. // If -1 passed then it just returns the
  249. // current handler index without change the current index.rns that index, useless return value.
  250. //
  251. // Look Handlers(), Next() and StopExecution() too.
  252. HandlerIndex(n int) (currentIndex int)
  253. // Proceed is an alternative way to check if a particular handler
  254. // has been executed and called the `ctx.Next` function inside it.
  255. // This is useful only when you run a handler inside
  256. // another handler. It justs checks for before index and the after index.
  257. //
  258. // A usecase example is when you want to execute a middleware
  259. // inside controller's `BeginRequest` that calls the `ctx.Next` inside it.
  260. // The Controller looks the whole flow (BeginRequest, method handler, EndRequest)
  261. // as one handler, so `ctx.Next` will not be reflected to the method handler
  262. // if called from the `BeginRequest`.
  263. //
  264. // Although `BeginRequest` should NOT be used to call other handlers,
  265. // the `BeginRequest` has been introduced to be able to set
  266. // common data to all method handlers before their execution.
  267. // Controllers can accept middleware(s) from the MVC's Application's Router as normally.
  268. //
  269. // That said let's see an example of `ctx.Proceed`:
  270. //
  271. // var authMiddleware = basicauth.New(basicauth.Config{
  272. // Users: map[string]string{
  273. // "admin": "password",
  274. // },
  275. // })
  276. //
  277. // func (c *UsersController) BeginRequest(ctx iris.Context) {
  278. // if !ctx.Proceed(authMiddleware) {
  279. // ctx.StopExecution()
  280. // }
  281. // }
  282. // This Get() will be executed in the same handler as `BeginRequest`,
  283. // internally controller checks for `ctx.StopExecution`.
  284. // So it will not be fired if BeginRequest called the `StopExecution`.
  285. // func(c *UsersController) Get() []models.User {
  286. // return c.Service.GetAll()
  287. //}
  288. // Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
  289. Proceed(Handler) bool
  290. // HandlerName returns the current handler's name, helpful for debugging.
  291. HandlerName() string
  292. // Next calls all the next handler from the handlers chain,
  293. // it should be used inside a middleware.
  294. //
  295. // Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
  296. Next()
  297. // NextOr checks if chain has a next handler, if so then it executes it
  298. // otherwise it sets a new chain assigned to this Context based on the given handler(s)
  299. // and executes its first handler.
  300. //
  301. // Returns true if next handler exists and executed, otherwise false.
  302. //
  303. // Note that if no next handler found and handlers are missing then
  304. // it sends a Status Not Found (404) to the client and it stops the execution.
  305. NextOr(handlers ...Handler) bool
  306. // NextOrNotFound checks if chain has a next handler, if so then it executes it
  307. // otherwise it sends a Status Not Found (404) to the client and stops the execution.
  308. //
  309. // Returns true if next handler exists and executed, otherwise false.
  310. NextOrNotFound() bool
  311. // NextHandler returns (it doesn't execute) the next handler from the handlers chain.
  312. //
  313. // Use .Skip() to skip this handler if needed to execute the next of this returning handler.
  314. NextHandler() Handler
  315. // Skip skips/ignores the next handler from the handlers chain,
  316. // it should be used inside a middleware.
  317. Skip()
  318. // StopExecution if called then the following .Next calls are ignored,
  319. // as a result the next handlers in the chain will not be fire.
  320. StopExecution()
  321. // IsStopped checks and returns true if the current position of the Context is 255,
  322. // means that the StopExecution() was called.
  323. IsStopped() bool
  324. // OnConnectionClose registers the "cb" function which will fire (on its own goroutine, no need to be registered goroutine by the end-dev)
  325. // when the underlying connection has gone away.
  326. //
  327. // This mechanism can be used to cancel long operations on the server
  328. // if the client has disconnected before the response is ready.
  329. //
  330. // It depends on the `http#CloseNotify`.
  331. // CloseNotify may wait to notify until Request.Body has been
  332. // fully read.
  333. //
  334. // After the main Handler has returned, there is no guarantee
  335. // that the channel receives a value.
  336. //
  337. // Finally, it reports whether the protocol supports pipelines (HTTP/1.1 with pipelines disabled is not supported).
  338. // The "cb" will not fire for sure if the output value is false.
  339. //
  340. // Note that you can register only one callback for the entire request handler chain/per route.
  341. //
  342. // Look the `ResponseWriter#CloseNotifier` for more.
  343. OnConnectionClose(fnGoroutine func()) bool
  344. // OnClose registers the callback function "cb" to the underline connection closing event using the `Context#OnConnectionClose`
  345. // and also in the end of the request handler using the `ResponseWriter#SetBeforeFlush`.
  346. // Note that you can register only one callback for the entire request handler chain/per route.
  347. //
  348. // Look the `Context#OnConnectionClose` and `ResponseWriter#SetBeforeFlush` for more.
  349. OnClose(cb func())
  350. // +------------------------------------------------------------+
  351. // | Current "user/request" storage |
  352. // | and share information between the handlers - Values(). |
  353. // | Save and get named path parameters - Params() |
  354. // +------------------------------------------------------------+
  355. // Params returns the current url's named parameters key-value storage.
  356. // Named path parameters are being saved here.
  357. // This storage, as the whole Context, is per-request lifetime.
  358. Params() *RequestParams
  359. // Values returns the current "user" storage.
  360. // Named path parameters and any optional data can be saved here.
  361. // This storage, as the whole Context, is per-request lifetime.
  362. //
  363. // You can use this function to Set and Get local values
  364. // that can be used to share information between handlers and middleware.
  365. Values() *memstore.Store
  366. // Translate is the i18n (localization) middleware's function,
  367. // it calls the Get("translate") to return the translated value.
  368. //
  369. // Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
  370. Translate(format string, args ...interface{}) string
  371. // +------------------------------------------------------------+
  372. // | Path, Host, Subdomain, IP, Headers etc... |
  373. // +------------------------------------------------------------+
  374. // Method returns the request.Method, the client's http method to the server.
  375. Method() string
  376. // Path returns the full request path,
  377. // escaped if EnablePathEscape config field is true.
  378. Path() string
  379. // RequestPath returns the full request path,
  380. // based on the 'escape'.
  381. RequestPath(escape bool) string
  382. // Host returns the host part of the current url.
  383. Host() string
  384. // Subdomain returns the subdomain of this request, if any.
  385. // Note that this is a fast method which does not cover all cases.
  386. Subdomain() (subdomain string)
  387. // IsWWW returns true if the current subdomain (if any) is www.
  388. IsWWW() bool
  389. // RemoteAddr tries to parse and return the real client's request IP.
  390. //
  391. // Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
  392. //
  393. // If parse based on these headers fail then it will return the Request's `RemoteAddr` field
  394. // which is filled by the server before the HTTP handler.
  395. //
  396. // Look `Configuration.RemoteAddrHeaders`,
  397. // `Configuration.WithRemoteAddrHeader(...)`,
  398. // `Configuration.WithoutRemoteAddrHeader(...)` for more.
  399. RemoteAddr() string
  400. // GetHeader returns the request header's value based on its name.
  401. GetHeader(name string) string
  402. // IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
  403. //
  404. // There is no a 100% way of knowing that a request was made via Ajax.
  405. // You should never trust data coming from the client, they can be easily overcome by spoofing.
  406. //
  407. // Note that "X-Requested-With" Header can be modified by any client(because of "X-"),
  408. // so don't rely on IsAjax for really serious stuff,
  409. // try to find another way of detecting the type(i.e, content type),
  410. // there are many blogs that describe these problems and provide different kind of solutions,
  411. // it's always depending on the application you're building,
  412. // this is the reason why this `IsAjax`` is simple enough for general purpose use.
  413. //
  414. // Read more at: https://developer.mozilla.org/en-US/docs/AJAX
  415. // and https://xhr.spec.whatwg.org/
  416. IsAjax() bool
  417. // IsMobile checks if client is using a mobile device(phone or tablet) to communicate with this server.
  418. // If the return value is true that means that the http client using a mobile
  419. // device to communicate with the server, otherwise false.
  420. //
  421. // Keep note that this checks the "User-Agent" request header.
  422. IsMobile() bool
  423. // GetReferrer extracts and returns the information from the "Referer" header as specified
  424. // in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  425. // or by the URL query parameter "referer".
  426. GetReferrer() Referrer
  427. // +------------------------------------------------------------+
  428. // | Headers helpers |
  429. // +------------------------------------------------------------+
  430. // Header adds a header to the response writer.
  431. Header(name string, value string)
  432. // ContentType sets the response writer's header key "Content-Type" to the 'cType'.
  433. ContentType(cType string)
  434. // GetContentType returns the response writer's header value of "Content-Type"
  435. // which may, setted before with the 'ContentType'.
  436. GetContentType() string
  437. // GetContentType returns the request's header value of "Content-Type".
  438. GetContentTypeRequested() string
  439. // GetContentLength returns the request's header value of "Content-Length".
  440. // Returns 0 if header was unable to be found or its value was not a valid number.
  441. GetContentLength() int64
  442. // StatusCode sets the status code header to the response.
  443. // Look .`GetStatusCode` too.
  444. StatusCode(statusCode int)
  445. // GetStatusCode returns the current status code of the response.
  446. // Look `StatusCode` too.
  447. GetStatusCode() int
  448. // Redirect sends a redirect response to the client
  449. // to a specific url or relative path.
  450. // accepts 2 parameters string and an optional int
  451. // first parameter is the url to redirect
  452. // second parameter is the http status should send,
  453. // default is 302 (StatusFound),
  454. // you can set it to 301 (Permant redirect)
  455. // or 303 (StatusSeeOther) if POST method,
  456. // or StatusTemporaryRedirect(307) if that's nessecery.
  457. Redirect(urlToRedirect string, statusHeader ...int)
  458. // +------------------------------------------------------------+
  459. // | Various Request and Post Data |
  460. // +------------------------------------------------------------+
  461. // URLParam returns true if the url parameter exists, otherwise false.
  462. URLParamExists(name string) bool
  463. // URLParamDefault returns the get parameter from a request,
  464. // if not found then "def" is returned.
  465. URLParamDefault(name string, def string) string
  466. // URLParam returns the get parameter from a request, if any.
  467. URLParam(name string) string
  468. // URLParamTrim returns the url query parameter with trailing white spaces removed from a request.
  469. URLParamTrim(name string) string
  470. // URLParamTrim returns the escaped url query parameter from a request.
  471. URLParamEscape(name string) string
  472. // URLParamInt returns the url query parameter as int value from a request,
  473. // returns -1 and an error if parse failed.
  474. URLParamInt(name string) (int, error)
  475. // URLParamIntDefault returns the url query parameter as int value from a request,
  476. // if not found or parse failed then "def" is returned.
  477. URLParamIntDefault(name string, def int) int
  478. // URLParamInt32Default returns the url query parameter as int32 value from a request,
  479. // if not found or parse failed then "def" is returned.
  480. URLParamInt32Default(name string, def int32) int32
  481. // URLParamInt64 returns the url query parameter as int64 value from a request,
  482. // returns -1 and an error if parse failed.
  483. URLParamInt64(name string) (int64, error)
  484. // URLParamInt64Default returns the url query parameter as int64 value from a request,
  485. // if not found or parse failed then "def" is returned.
  486. URLParamInt64Default(name string, def int64) int64
  487. // URLParamFloat64 returns the url query parameter as float64 value from a request,
  488. // returns -1 and an error if parse failed.
  489. URLParamFloat64(name string) (float64, error)
  490. // URLParamFloat64Default returns the url query parameter as float64 value from a request,
  491. // if not found or parse failed then "def" is returned.
  492. URLParamFloat64Default(name string, def float64) float64
  493. // URLParamBool returns the url query parameter as boolean value from a request,
  494. // returns an error if parse failed or not found.
  495. URLParamBool(name string) (bool, error)
  496. // URLParams returns a map of GET query parameters separated by comma if more than one
  497. // it returns an empty map if nothing found.
  498. URLParams() map[string]string
  499. // FormValueDefault returns a single parsed form value by its "name",
  500. // including both the URL field's query parameters and the POST or PUT form data.
  501. //
  502. // Returns the "def" if not found.
  503. FormValueDefault(name string, def string) string
  504. // FormValue returns a single parsed form value by its "name",
  505. // including both the URL field's query parameters and the POST or PUT form data.
  506. FormValue(name string) string
  507. // FormValues returns the parsed form data, including both the URL
  508. // field's query parameters and the POST or PUT form data.
  509. //
  510. // The default form's memory maximum size is 32MB, it can be changed by the
  511. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  512. //
  513. // NOTE: A check for nil is necessary.
  514. FormValues() map[string][]string
  515. // PostValueDefault returns the parsed form data from POST, PATCH,
  516. // or PUT body parameters based on a "name".
  517. //
  518. // If not found then "def" is returned instead.
  519. PostValueDefault(name string, def string) string
  520. // PostValue returns the parsed form data from POST, PATCH,
  521. // or PUT body parameters based on a "name"
  522. PostValue(name string) string
  523. // PostValueTrim returns the parsed form data from POST, PATCH,
  524. // or PUT body parameters based on a "name", without trailing spaces.
  525. PostValueTrim(name string) string
  526. // PostValueInt returns the parsed form data from POST, PATCH,
  527. // or PUT body parameters based on a "name", as int.
  528. //
  529. // If not found returns -1 and a non-nil error.
  530. PostValueInt(name string) (int, error)
  531. // PostValueIntDefault returns the parsed form data from POST, PATCH,
  532. // or PUT body parameters based on a "name", as int.
  533. //
  534. // If not found returns or parse errors the "def".
  535. PostValueIntDefault(name string, def int) int
  536. // PostValueInt64 returns the parsed form data from POST, PATCH,
  537. // or PUT body parameters based on a "name", as float64.
  538. //
  539. // If not found returns -1 and a no-nil error.
  540. PostValueInt64(name string) (int64, error)
  541. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  542. // or PUT body parameters based on a "name", as int64.
  543. //
  544. // If not found or parse errors returns the "def".
  545. PostValueInt64Default(name string, def int64) int64
  546. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  547. // or PUT body parameters based on a "name", as float64.
  548. //
  549. // If not found returns -1 and a non-nil error.
  550. PostValueFloat64(name string) (float64, error)
  551. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  552. // or PUT body parameters based on a "name", as float64.
  553. //
  554. // If not found or parse errors returns the "def".
  555. PostValueFloat64Default(name string, def float64) float64
  556. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  557. // or PUT body parameters based on a "name", as bool.
  558. //
  559. // If not found or value is false, then it returns false, otherwise true.
  560. PostValueBool(name string) (bool, error)
  561. // PostValues returns all the parsed form data from POST, PATCH,
  562. // or PUT body parameters based on a "name" as a string slice.
  563. //
  564. // The default form's memory maximum size is 32MB, it can be changed by the
  565. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  566. PostValues(name string) []string
  567. // FormFile returns the first uploaded file that received from the client.
  568. //
  569. // The default form's memory maximum size is 32MB, it can be changed by the
  570. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  571. //
  572. // Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-file
  573. FormFile(key string) (multipart.File, *multipart.FileHeader, error)
  574. // UploadFormFiles uploads any received file(s) from the client
  575. // to the system physical location "destDirectory".
  576. //
  577. // The second optional argument "before" gives caller the chance to
  578. // modify the *miltipart.FileHeader before saving to the disk,
  579. // it can be used to change a file's name based on the current request,
  580. // all FileHeader's options can be changed. You can ignore it if
  581. // you don't need to use this capability before saving a file to the disk.
  582. //
  583. // Note that it doesn't check if request body streamed.
  584. //
  585. // Returns the copied length as int64 and
  586. // a not nil error if at least one new file
  587. // can't be created due to the operating system's permissions or
  588. // http.ErrMissingFile if no file received.
  589. //
  590. // If you want to receive & accept files and manage them manually you can use the `context#FormFile`
  591. // instead and create a copy function that suits your needs, the below is for generic usage.
  592. //
  593. // The default form's memory maximum size is 32MB, it can be changed by the
  594. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  595. //
  596. // See `FormFile` to a more controlled to receive a file.
  597. //
  598. //
  599. // Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-files
  600. UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error)
  601. // +------------------------------------------------------------+
  602. // | Custom HTTP Errors |
  603. // +------------------------------------------------------------+
  604. // NotFound emits an error 404 to the client, using the specific custom error error handler.
  605. // Note that you may need to call ctx.StopExecution() if you don't want the next handlers
  606. // to be executed. Next handlers are being executed on iris because you can alt the
  607. // error code and change it to a more specific one, i.e
  608. // users := app.Party("/users")
  609. // users.Done(func(ctx context.Context){ if ctx.StatusCode() == 400 { /* custom error code for /users */ }})
  610. NotFound()
  611. // +------------------------------------------------------------+
  612. // | Body Readers |
  613. // +------------------------------------------------------------+
  614. // SetMaxRequestBodySize sets a limit to the request body size
  615. // should be called before reading the request body from the client.
  616. SetMaxRequestBodySize(limitOverBytes int64)
  617. // UnmarshalBody reads the request's body and binds it to a value or pointer of any type.
  618. // Examples of usage: context.ReadJSON, context.ReadXML.
  619. //
  620. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
  621. //
  622. // UnmarshalBody does not check about gzipped data.
  623. // Do not rely on compressed data incoming to your server. The main reason is: https://en.wikipedia.org/wiki/Zip_bomb
  624. // However you are still free to read the `ctx.Request().Body io.Reader` manually.
  625. UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error
  626. // ReadJSON reads JSON from request's body and binds it to a pointer of a value of any json-valid type.
  627. //
  628. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-json/main.go
  629. ReadJSON(jsonObjectPtr interface{}) error
  630. // ReadXML reads XML from request's body and binds it to a pointer of a value of any xml-valid type.
  631. //
  632. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-xml/main.go
  633. ReadXML(xmlObjectPtr interface{}) error
  634. // ReadForm binds the formObject with the form data
  635. // it supports any kind of struct.
  636. //
  637. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-form/main.go
  638. ReadForm(formObjectPtr interface{}) error
  639. // +------------------------------------------------------------+
  640. // | Body (raw) Writers |
  641. // +------------------------------------------------------------+
  642. // Write writes the data to the connection as part of an HTTP reply.
  643. //
  644. // If WriteHeader has not yet been called, Write calls
  645. // WriteHeader(http.StatusOK) before writing the data. If the Header
  646. // does not contain a Content-Type line, Write adds a Content-Type set
  647. // to the result of passing the initial 512 bytes of written data to
  648. // DetectContentType.
  649. //
  650. // Depending on the HTTP protocol version and the client, calling
  651. // Write or WriteHeader may prevent future reads on the
  652. // Request.Body. For HTTP/1.x requests, handlers should read any
  653. // needed request body data before writing the response. Once the
  654. // headers have been flushed (due to either an explicit Flusher.Flush
  655. // call or writing enough data to trigger a flush), the request body
  656. // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
  657. // handlers to continue to read the request body while concurrently
  658. // writing the response. However, such behavior may not be supported
  659. // by all HTTP/2 clients. Handlers should read before writing if
  660. // possible to maximize compatibility.
  661. Write(body []byte) (int, error)
  662. // Writef formats according to a format specifier and writes to the response.
  663. //
  664. // Returns the number of bytes written and any write error encountered.
  665. Writef(format string, args ...interface{}) (int, error)
  666. // WriteString writes a simple string to the response.
  667. //
  668. // Returns the number of bytes written and any write error encountered.
  669. WriteString(body string) (int, error)
  670. // SetLastModified sets the "Last-Modified" based on the "modtime" input.
  671. // If "modtime" is zero then it does nothing.
  672. //
  673. // It's mostly internally on core/router and context packages.
  674. //
  675. // Note that modtime.UTC() is being used instead of just modtime, so
  676. // you don't have to know the internals in order to make that works.
  677. SetLastModified(modtime time.Time)
  678. // CheckIfModifiedSince checks if the response is modified since the "modtime".
  679. // Note that it has nothing to do with server-side caching.
  680. // It does those checks by checking if the "If-Modified-Since" request header
  681. // sent by client or a previous server response header
  682. // (e.g with WriteWithExpiration or StaticEmbedded or Favicon etc.)
  683. // is a valid one and it's before the "modtime".
  684. //
  685. // A check for !modtime && err == nil is necessary to make sure that
  686. // it's not modified since, because it may return false but without even
  687. // had the chance to check the client-side (request) header due to some errors,
  688. // like the HTTP Method is not "GET" or "HEAD" or if the "modtime" is zero
  689. // or if parsing time from the header failed.
  690. //
  691. // It's mostly used internally, e.g. `context#WriteWithExpiration`.
  692. //
  693. // Note that modtime.UTC() is being used instead of just modtime, so
  694. // you don't have to know the internals in order to make that works.
  695. CheckIfModifiedSince(modtime time.Time) (bool, error)
  696. // WriteNotModified sends a 304 "Not Modified" status code to the client,
  697. // it makes sure that the content type, the content length headers
  698. // and any "ETag" are removed before the response sent.
  699. //
  700. // It's mostly used internally on core/router/fs.go and context methods.
  701. WriteNotModified()
  702. // WriteWithExpiration like Write but it sends with an expiration datetime
  703. // which is refreshed every package-level `StaticCacheDuration` field.
  704. WriteWithExpiration(body []byte, modtime time.Time) (int, error)
  705. // StreamWriter registers the given stream writer for populating
  706. // response body.
  707. //
  708. // Access to context's and/or its' members is forbidden from writer.
  709. //
  710. // This function may be used in the following cases:
  711. //
  712. // * if response body is too big (more than iris.LimitRequestBodySize(if setted)).
  713. // * if response body is streamed from slow external sources.
  714. // * if response body must be streamed to the client in chunks.
  715. // (aka `http server push`).
  716. //
  717. // receives a function which receives the response writer
  718. // and returns false when it should stop writing, otherwise true in order to continue
  719. StreamWriter(writer func(w io.Writer) bool)
  720. // +------------------------------------------------------------+
  721. // | Body Writers with compression |
  722. // +------------------------------------------------------------+
  723. // ClientSupportsGzip retruns true if the client supports gzip compression.
  724. ClientSupportsGzip() bool
  725. // WriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
  726. // returns the number of bytes written and an error ( if the client doesn' supports gzip compression)
  727. // You may re-use this function in the same handler
  728. // to write more data many times without any troubles.
  729. WriteGzip(b []byte) (int, error)
  730. // TryWriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
  731. // If client does not supprots gzip then the contents are written as they are, uncompressed.
  732. TryWriteGzip(b []byte) (int, error)
  733. // GzipResponseWriter converts the current response writer into a response writer
  734. // which when its .Write called it compress the data to gzip and writes them to the client.
  735. //
  736. // Can be also disabled with its .Disable and .ResetBody to rollback to the usual response writer.
  737. GzipResponseWriter() *GzipResponseWriter
  738. // Gzip enables or disables (if enabled before) the gzip response writer,if the client
  739. // supports gzip compression, so the following response data will
  740. // be sent as compressed gzip data to the client.
  741. Gzip(enable bool)
  742. // +------------------------------------------------------------+
  743. // | Rich Body Content Writers/Renderers |
  744. // +------------------------------------------------------------+
  745. // ViewLayout sets the "layout" option if and when .View
  746. // is being called afterwards, in the same request.
  747. // Useful when need to set or/and change a layout based on the previous handlers in the chain.
  748. //
  749. // Note that the 'layoutTmplFile' argument can be setted to iris.NoLayout || view.NoLayout
  750. // to disable the layout for a specific view render action,
  751. // it disables the engine's configuration's layout property.
  752. //
  753. // Look .ViewData and .View too.
  754. //
  755. // Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
  756. ViewLayout(layoutTmplFile string)
  757. // ViewData saves one or more key-value pair in order to be passed if and when .View
  758. // is being called afterwards, in the same request.
  759. // Useful when need to set or/and change template data from previous hanadlers in the chain.
  760. //
  761. // If .View's "binding" argument is not nil and it's not a type of map
  762. // then these data are being ignored, binding has the priority, so the main route's handler can still decide.
  763. // If binding is a map or context.Map then these data are being added to the view data
  764. // and passed to the template.
  765. //
  766. // After .View, the data are not destroyed, in order to be re-used if needed (again, in the same request as everything else),
  767. // to clear the view data, developers can call:
  768. // ctx.Set(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), nil)
  769. //
  770. // If 'key' is empty then the value is added as it's (struct or map) and developer is unable to add other value.
  771. //
  772. // Look .ViewLayout and .View too.
  773. //
  774. // Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
  775. ViewData(key string, value interface{})
  776. // GetViewData returns the values registered by `context#ViewData`.
  777. // The return value is `map[string]interface{}`, this means that
  778. // if a custom struct registered to ViewData then this function
  779. // will try to parse it to map, if failed then the return value is nil
  780. // A check for nil is always a good practise if different
  781. // kind of values or no data are registered via `ViewData`.
  782. //
  783. // Similarly to `viewData := ctx.Values().Get("iris.viewData")` or
  784. // `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`.
  785. GetViewData() map[string]interface{}
  786. // View renders a template based on the registered view engine(s).
  787. // First argument accepts the filename, relative to the view engine's Directory and Extension,
  788. // i.e: if directory is "./templates" and want to render the "./templates/users/index.html"
  789. // then you pass the "users/index.html" as the filename argument.
  790. //
  791. // The second optional argument can receive a single "view model"
  792. // that will be binded to the view template if it's not nil,
  793. // otherwise it will check for previous view data stored by the `ViewData`
  794. // even if stored at any previous handler(middleware) for the same request.
  795. //
  796. // Look .ViewData` and .ViewLayout too.
  797. //
  798. // Examples: https://github.com/kataras/iris/tree/master/_examples/view
  799. View(filename string, optionalViewModel ...interface{}) error
  800. // Binary writes out the raw bytes as binary data.
  801. Binary(data []byte) (int, error)
  802. // Text writes out a string as plain text.
  803. Text(text string) (int, error)
  804. // HTML writes out a string as text/html.
  805. HTML(htmlContents string) (int, error)
  806. // JSON marshals the given interface object and writes the JSON response.
  807. JSON(v interface{}, options ...JSON) (int, error)
  808. // JSONP marshals the given interface object and writes the JSON response.
  809. JSONP(v interface{}, options ...JSONP) (int, error)
  810. // XML marshals the given interface object and writes the XML response.
  811. XML(v interface{}, options ...XML) (int, error)
  812. // Markdown parses the markdown to html and renders its result to the client.
  813. Markdown(markdownB []byte, options ...Markdown) (int, error)
  814. // YAML parses the "v" using the yaml parser and renders its result to the client.
  815. YAML(v interface{}) (int, error)
  816. // +------------------------------------------------------------+
  817. // | Serve files |
  818. // +------------------------------------------------------------+
  819. // ServeContent serves content, headers are autoset
  820. // receives three parameters, it's low-level function, instead you can use .ServeFile(string,bool)/SendFile(string,string)
  821. //
  822. //
  823. // You can define your own "Content-Type" with `context#ContentType`, before this function call.
  824. //
  825. // This function doesn't support resuming (by range),
  826. // use ctx.SendFile or router's `StaticWeb` instead.
  827. ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error
  828. // ServeFile serves a file (to send a file, a zip for example to the client you should use the `SendFile` instead)
  829. // receives two parameters
  830. // filename/path (string)
  831. // gzipCompression (bool)
  832. //
  833. // You can define your own "Content-Type" with `context#ContentType`, before this function call.
  834. //
  835. // This function doesn't support resuming (by range),
  836. // use ctx.SendFile or router's `StaticWeb` instead.
  837. //
  838. // Use it when you want to serve dynamic files to the client.
  839. ServeFile(filename string, gzipCompression bool) error
  840. // SendFile sends file for force-download to the client
  841. //
  842. // Use this instead of ServeFile to 'force-download' bigger files to the client.
  843. SendFile(filename string, destinationName string) error
  844. // +------------------------------------------------------------+
  845. // | Cookies |
  846. // +------------------------------------------------------------+
  847. // SetCookie adds a cookie.
  848. // Use of the "options" is not required, they can be used to amend the "cookie".
  849. //
  850. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  851. SetCookie(cookie *http.Cookie, options ...CookieOption)
  852. // SetCookieKV adds a cookie, requires the name(string) and the value(string).
  853. //
  854. // By default it expires at 2 hours and it's added to the root path,
  855. // use the `CookieExpires` and `CookiePath` to modify them.
  856. // Alternatively: ctx.SetCookie(&http.Cookie{...})
  857. //
  858. // If you want to set custom the path:
  859. // ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))
  860. //
  861. // If you want to be visible only to current request path:
  862. // ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
  863. // More:
  864. // iris.CookieExpires(time.Duration)
  865. // iris.CookieHTTPOnly(false)
  866. //
  867. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  868. SetCookieKV(name, value string, options ...CookieOption)
  869. // GetCookie returns cookie's value by it's name
  870. // returns empty string if nothing was found.
  871. //
  872. // If you want more than the value then:
  873. // cookie, err := ctx.Request().Cookie("name")
  874. //
  875. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  876. GetCookie(name string, options ...CookieOption) string
  877. // RemoveCookie deletes a cookie by it's name and path = "/".
  878. // Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath)
  879. //
  880. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  881. RemoveCookie(name string, options ...CookieOption)
  882. // VisitAllCookies takes a visitor which loops
  883. // on each (request's) cookies' name and value.
  884. VisitAllCookies(visitor func(name string, value string))
  885. // MaxAge returns the "cache-control" request header's value
  886. // seconds as int64
  887. // if header not found or parse failed then it returns -1.
  888. MaxAge() int64
  889. // +------------------------------------------------------------+
  890. // | Advanced: Response Recorder and Transactions |
  891. // +------------------------------------------------------------+
  892. // Record transforms the context's basic and direct responseWriter to a ResponseRecorder
  893. // which can be used to reset the body, reset headers, get the body,
  894. // get & set the status code at any time and more.
  895. Record()
  896. // Recorder returns the context's ResponseRecorder
  897. // if not recording then it starts recording and returns the new context's ResponseRecorder
  898. Recorder() *ResponseRecorder
  899. // IsRecording returns the response recorder and a true value
  900. // when the response writer is recording the status code, body, headers and so on,
  901. // else returns nil and false.
  902. IsRecording() (*ResponseRecorder, bool)
  903. // BeginTransaction starts a scoped transaction.
  904. //
  905. // You can search third-party articles or books on how Business Transaction works (it's quite simple, especially here).
  906. //
  907. // Note that this is unique and new
  908. // (=I haver never seen any other examples or code in Golang on this subject, so far, as with the most of iris features...)
  909. // it's not covers all paths,
  910. // such as databases, this should be managed by the libraries you use to make your database connection,
  911. // this transaction scope is only for context's response.
  912. // Transactions have their own middleware ecosystem also, look iris.go:UseTransaction.
  913. //
  914. // See https://github.com/kataras/iris/tree/master/_examples/ for more
  915. BeginTransaction(pipe func(t *Transaction))
  916. // SkipTransactions if called then skip the rest of the transactions
  917. // or all of them if called before the first transaction
  918. SkipTransactions()
  919. // TransactionsSkipped returns true if the transactions skipped or canceled at all.
  920. TransactionsSkipped() bool
  921. // Exec calls the `context/Application#ServeCtx`
  922. // based on this context but with a changed method and path
  923. // like it was requested by the user, but it is not.
  924. //
  925. // Offline means that the route is registered to the iris and have all features that a normal route has
  926. // BUT it isn't available by browsing, its handlers executed only when other handler's context call them
  927. // it can validate paths, has sessions, path parameters and all.
  928. //
  929. // You can find the Route by app.GetRoute("theRouteName")
  930. // you can set a route name as: myRoute := app.Get("/mypath", handler)("theRouteName")
  931. // that will set a name to the route and returns its RouteInfo instance for further usage.
  932. //
  933. // It doesn't changes the global state, if a route was "offline" it remains offline.
  934. //
  935. // app.None(...) and app.GetRoutes().Offline(route)/.Online(route, method)
  936. //
  937. // Example: https://github.com/kataras/iris/tree/master/_examples/routing/route-state
  938. //
  939. // User can get the response by simple using rec := ctx.Recorder(); rec.Body()/rec.StatusCode()/rec.Header().
  940. //
  941. // Context's Values and the Session are kept in order to be able to communicate via the result route.
  942. //
  943. // It's for extreme use cases, 99% of the times will never be useful for you.
  944. Exec(method, path string)
  945. // RouteExists reports whether a particular route exists
  946. // It will search from the current subdomain of context's host, if not inside the root domain.
  947. RouteExists(method, path string) bool
  948. // Application returns the iris app instance which belongs to this context.
  949. // Worth to notice that this function returns an interface
  950. // of the Application, which contains methods that are safe
  951. // to be executed at serve-time. The full app's fields
  952. // and methods are not available here for the developer's safety.
  953. Application() Application
  954. // String returns the string representation of this request.
  955. // Each context has a unique string representation.
  956. // It can be used for simple debugging scenarios, i.e print context as string.
  957. //
  958. // What it returns? A number which declares the length of the
  959. // total `String` calls per executable application, followed
  960. // by the remote IP (the client) and finally the method:url.
  961. String() string
  962. }
  963. var _ Context = (*context)(nil)
  964. // Do calls the SetHandlers(handlers)
  965. // and executes the first handler,
  966. // handlers should not be empty.
  967. //
  968. // It's used by the router, developers may use that
  969. // to replace and execute handlers immediately.
  970. func Do(ctx Context, handlers Handlers) {
  971. if len(handlers) > 0 {
  972. ctx.SetHandlers(handlers)
  973. handlers[0](ctx)
  974. }
  975. }
  976. // LimitRequestBodySize is a middleware which sets a request body size limit
  977. // for all next handlers in the chain.
  978. var LimitRequestBodySize = func(maxRequestBodySizeBytes int64) Handler {
  979. return func(ctx Context) {
  980. ctx.SetMaxRequestBodySize(maxRequestBodySizeBytes)
  981. ctx.Next()
  982. }
  983. }
  984. // Gzip is a middleware which enables writing
  985. // using gzip compression, if client supports.
  986. var Gzip = func(ctx Context) {
  987. ctx.Gzip(true)
  988. ctx.Next()
  989. }
  990. // Map is just a shortcut of the map[string]interface{}.
  991. type Map map[string]interface{}
  992. // +------------------------------------------------------------+
  993. // | Context Implementation |
  994. // +------------------------------------------------------------+
  995. type context struct {
  996. // the unique id, it's zero until `String` function is called,
  997. // it's here to cache the random, unique context's id, although `String`
  998. // returns more than this.
  999. id uint64
  1000. // the http.ResponseWriter wrapped by custom writer.
  1001. writer ResponseWriter
  1002. // the original http.Request
  1003. request *http.Request
  1004. // the current route's name registered to this request path.
  1005. currentRouteName string
  1006. // the local key-value storage
  1007. params RequestParams // url named parameters.
  1008. values memstore.Store // generic storage, middleware communication.
  1009. // the underline application app.
  1010. app Application
  1011. // the route's handlers
  1012. handlers Handlers
  1013. // the current position of the handler's chain
  1014. currentHandlerIndex int
  1015. }
  1016. // NewContext returns the default, internal, context implementation.
  1017. // You may use this function to embed the default context implementation
  1018. // to a custom one.
  1019. //
  1020. // This context is received by the context pool.
  1021. func NewContext(app Application) Context {
  1022. return &context{app: app}
  1023. }
  1024. // BeginRequest is executing once for each request
  1025. // it should prepare the (new or acquired from pool) context's fields for the new request.
  1026. //
  1027. // To follow the iris' flow, developer should:
  1028. // 1. reset handlers to nil
  1029. // 2. reset store to empty
  1030. // 3. reset sessions to nil
  1031. // 4. reset response writer to the http.ResponseWriter
  1032. // 5. reset request to the *http.Request
  1033. // and any other optional steps, depends on dev's application type.
  1034. func (ctx *context) BeginRequest(w http.ResponseWriter, r *http.Request) {
  1035. ctx.handlers = nil // will be filled by router.Serve/HTTP
  1036. ctx.values = ctx.values[0:0] // >> >> by context.Values().Set
  1037. ctx.params.store = ctx.params.store[0:0]
  1038. ctx.request = r
  1039. ctx.currentHandlerIndex = 0
  1040. ctx.writer = AcquireResponseWriter()
  1041. ctx.writer.BeginResponse(w)
  1042. }
  1043. // StatusCodeNotSuccessful defines if a specific "statusCode" is not
  1044. // a valid status code for a successful response.
  1045. // It defaults to < 200 || >= 400
  1046. //
  1047. // Read more at `iris#DisableAutoFireStatusCode`, `iris/core/router#ErrorCodeHandler`
  1048. // and `iris/core/router#OnAnyErrorCode` for relative information.
  1049. //
  1050. // Do NOT change it.
  1051. //
  1052. // It's exported for extreme situations--special needs only, when the Iris server and the client
  1053. // is not following the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  1054. var StatusCodeNotSuccessful = func(statusCode int) bool {
  1055. return statusCode < 200 || statusCode >= 400
  1056. }
  1057. // EndRequest is executing once after a response to the request was sent and this context is useless or released.
  1058. //
  1059. // To follow the iris' flow, developer should:
  1060. // 1. flush the response writer's result
  1061. // 2. release the response writer
  1062. // and any other optional steps, depends on dev's application type.
  1063. func (ctx *context) EndRequest() {
  1064. if StatusCodeNotSuccessful(ctx.GetStatusCode()) &&
  1065. !ctx.Application().ConfigurationReadOnly().GetDisableAutoFireStatusCode() {
  1066. // author's note:
  1067. // if recording, the error handler can handle
  1068. // the rollback and remove any response written before,
  1069. // we don't have to do anything here, written is <=0 (-1 for default empty, even no status code)
  1070. // when Recording
  1071. // because we didn't flush the response yet
  1072. // if !recording then check if the previous handler didn't send something
  1073. // to the client.
  1074. if ctx.writer.Written() <= 0 {
  1075. // Author's notes:
  1076. // previously: == -1,
  1077. // <=0 means even if empty write called which has meaning;
  1078. // rel: core/router/status.go#Fire-else
  1079. // mvc/activator/funcmethod/func_result_dispatcher.go#DispatchCommon-write
  1080. // mvc/response.go#defaultFailureResponse - no text given but
  1081. // status code should be fired, but it couldn't because of the .Write
  1082. // action, the .Written() was 0 even on empty response, this 0 means that
  1083. // a status code given, the previous check of the "== -1" didn't make check for that,
  1084. // we do now.
  1085. ctx.Application().FireErrorCode(ctx)
  1086. }
  1087. }
  1088. ctx.writer.FlushResponse()
  1089. ctx.writer.EndResponse()
  1090. }
  1091. // ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
  1092. func (ctx *context) ResponseWriter() ResponseWriter {
  1093. return ctx.writer
  1094. }
  1095. // ResetResponseWriter should change or upgrade the context's ResponseWriter.
  1096. func (ctx *context) ResetResponseWriter(newResponseWriter ResponseWriter) {
  1097. ctx.writer = newResponseWriter
  1098. }
  1099. // Request returns the original *http.Request, as expected.
  1100. func (ctx *context) Request() *http.Request {
  1101. return ctx.request
  1102. }
  1103. // SetCurrentRouteName sets the route's name internally,
  1104. // in order to be able to find the correct current "read-only" Route when
  1105. // end-developer calls the `GetCurrentRoute()` function.
  1106. // It's being initialized by the Router, if you change that name
  1107. // manually nothing really happens except that you'll get other
  1108. // route via `GetCurrentRoute()`.
  1109. // Instead, to execute a different path
  1110. // from this context you should use the `Exec` function
  1111. // or change the handlers via `SetHandlers/AddHandler` functions.
  1112. func (ctx *context) SetCurrentRouteName(currentRouteName string) {
  1113. ctx.currentRouteName = currentRouteName
  1114. }
  1115. // GetCurrentRoute returns the current registered "read-only" route that
  1116. // was being registered to this request's path.
  1117. func (ctx *context) GetCurrentRoute() RouteReadOnly {
  1118. return ctx.app.GetRouteReadOnly(ctx.currentRouteName)
  1119. }
  1120. // Do calls the SetHandlers(handlers)
  1121. // and executes the first handler,
  1122. // handlers should not be empty.
  1123. //
  1124. // It's used by the router, developers may use that
  1125. // to replace and execute handlers immediately.
  1126. func (ctx *context) Do(handlers Handlers) {
  1127. Do(ctx, handlers)
  1128. }
  1129. // AddHandler can add handler(s)
  1130. // to the current request in serve-time,
  1131. // these handlers are not persistenced to the router.
  1132. //
  1133. // Router is calling this function to add the route's handler.
  1134. // If AddHandler called then the handlers will be inserted
  1135. // to the end of the already-defined route's handler.
  1136. //
  1137. func (ctx *context) AddHandler(handlers ...Handler) {
  1138. ctx.handlers = append(ctx.handlers, handlers...)
  1139. }
  1140. // SetHandlers replaces all handlers with the new.
  1141. func (ctx *context) SetHandlers(handlers Handlers) {
  1142. ctx.handlers = handlers
  1143. }
  1144. // Handlers keeps tracking of the current handlers.
  1145. func (ctx *context) Handlers() Handlers {
  1146. return ctx.handlers
  1147. }
  1148. // HandlerIndex sets the current index of the
  1149. // current context's handlers chain.
  1150. // If -1 passed then it just returns the
  1151. // current handler index without change the current index.rns that index, useless return value.
  1152. //
  1153. // Look Handlers(), Next() and StopExecution() too.
  1154. func (ctx *context) HandlerIndex(n int) (currentIndex int) {
  1155. if n < 0 || n > len(ctx.handlers)-1 {
  1156. return ctx.currentHandlerIndex
  1157. }
  1158. ctx.currentHandlerIndex = n
  1159. return n
  1160. }
  1161. // Proceed is an alternative way to check if a particular handler
  1162. // has been executed and called the `ctx.Next` function inside it.
  1163. // This is useful only when you run a handler inside
  1164. // another handler. It justs checks for before index and the after index.
  1165. //
  1166. // A usecase example is when you want to execute a middleware
  1167. // inside controller's `BeginRequest` that calls the `ctx.Next` inside it.
  1168. // The Controller looks the whole flow (BeginRequest, method handler, EndRequest)
  1169. // as one handler, so `ctx.Next` will not be reflected to the method handler
  1170. // if called from the `BeginRequest`.
  1171. //
  1172. // Although `BeginRequest` should NOT be used to call other handlers,
  1173. // the `BeginRequest` has been introduced to be able to set
  1174. // common data to all method handlers before their execution.
  1175. // Controllers can accept middleware(s) from the MVC's Application's Router as normally.
  1176. //
  1177. // That said let's see an example of `ctx.Proceed`:
  1178. //
  1179. // var authMiddleware = basicauth.New(basicauth.Config{
  1180. // Users: map[string]string{
  1181. // "admin": "password",
  1182. // },
  1183. // })
  1184. //
  1185. // func (c *UsersController) BeginRequest(ctx iris.Context) {
  1186. // if !ctx.Proceed(authMiddleware) {
  1187. // ctx.StopExecution()
  1188. // }
  1189. // }
  1190. // This Get() will be executed in the same handler as `BeginRequest`,
  1191. // internally controller checks for `ctx.StopExecution`.
  1192. // So it will not be fired if BeginRequest called the `StopExecution`.
  1193. // func(c *UsersController) Get() []models.User {
  1194. // return c.Service.GetAll()
  1195. //}
  1196. // Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
  1197. func (ctx *context) Proceed(h Handler) bool {
  1198. beforeIdx := ctx.currentHandlerIndex
  1199. h(ctx)
  1200. if ctx.currentHandlerIndex > beforeIdx && !ctx.IsStopped() {
  1201. return true
  1202. }
  1203. return false
  1204. }
  1205. // HandlerName returns the current handler's name, helpful for debugging.
  1206. func (ctx *context) HandlerName() string {
  1207. return HandlerName(ctx.handlers[ctx.currentHandlerIndex])
  1208. }
  1209. // Next is the function that executed when `ctx.Next()` is called.
  1210. // It can be changed to a customized one if needed (very advanced usage).
  1211. //
  1212. // See `DefaultNext` for more information about this and why it's exported like this.
  1213. var Next = DefaultNext
  1214. // DefaultNext is the default function that executed on each middleware if `ctx.Next()`
  1215. // is called.
  1216. //
  1217. // DefaultNext calls the next handler from the handlers chain by registration order,
  1218. // it should be used inside a middleware.
  1219. //
  1220. // It can be changed to a customized one if needed (very advanced usage).
  1221. //
  1222. // Developers are free to customize the whole or part of the Context's implementation
  1223. // by implementing a new `context.Context` (see https://github.com/kataras/iris/tree/master/_examples/routing/custom-context)
  1224. // or by just override the `context.Next` package-level field, `context.DefaultNext` is exported
  1225. // in order to be able for developers to merge your customized version one with the default behavior as well.
  1226. func DefaultNext(ctx Context) {
  1227. if ctx.IsStopped() {
  1228. return
  1229. }
  1230. if n, handlers := ctx.HandlerIndex(-1)+1, ctx.Handlers(); n < len(handlers) {
  1231. ctx.HandlerIndex(n)
  1232. handlers[n](ctx)
  1233. }
  1234. }
  1235. // Next calls all the next handler from the handlers chain,
  1236. // it should be used inside a middleware.
  1237. //
  1238. // Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
  1239. func (ctx *context) Next() { // or context.Next(ctx)
  1240. Next(ctx)
  1241. }
  1242. // NextOr checks if chain has a next handler, if so then it executes it
  1243. // otherwise it sets a new chain assigned to this Context based on the given handler(s)
  1244. // and executes its first handler.
  1245. //
  1246. // Returns true if next handler exists and executed, otherwise false.
  1247. //
  1248. // Note that if no next handler found and handlers are missing then
  1249. // it sends a Status Not Found (404) to the client and it stops the execution.
  1250. func (ctx *context) NextOr(handlers ...Handler) bool {
  1251. if next := ctx.NextHandler(); next != nil {
  1252. next(ctx)
  1253. ctx.Skip() // skip this handler from the chain.
  1254. return true
  1255. }
  1256. if len(handlers) == 0 {
  1257. ctx.NotFound()
  1258. ctx.StopExecution()
  1259. return false
  1260. }
  1261. ctx.Do(handlers)
  1262. return false
  1263. }
  1264. // NextOrNotFound checks if chain has a next handler, if so then it executes it
  1265. // otherwise it sends a Status Not Found (404) to the client and stops the execution.
  1266. //
  1267. // Returns true if next handler exists and executed, otherwise false.
  1268. func (ctx *context) NextOrNotFound() bool { return ctx.NextOr() }
  1269. // NextHandler returns (it doesn't execute) the next handler from the handlers chain.
  1270. //
  1271. // Use .Skip() to skip this handler if needed to execute the next of this returning handler.
  1272. func (ctx *context) NextHandler() Handler {
  1273. if ctx.IsStopped() {
  1274. return nil
  1275. }
  1276. nextIndex := ctx.currentHandlerIndex + 1
  1277. // check if it has a next middleware
  1278. if nextIndex < len(ctx.handlers) {
  1279. return ctx.handlers[nextIndex]
  1280. }
  1281. return nil
  1282. }
  1283. // Skip skips/ignores the next handler from the handlers chain,
  1284. // it should be used inside a middleware.
  1285. func (ctx *context) Skip() {
  1286. ctx.HandlerIndex(ctx.currentHandlerIndex + 1)
  1287. }
  1288. const stopExecutionIndex = -1 // I don't set to a max value because we want to be able to reuse the handlers even if stopped with .Skip
  1289. // StopExecution if called then the following .Next calls are ignored,
  1290. // as a result the next handlers in the chain will not be fire.
  1291. func (ctx *context) StopExecution() {
  1292. ctx.currentHandlerIndex = stopExecutionIndex
  1293. }
  1294. // IsStopped checks and returns true if the current position of the context is -1,
  1295. // means that the StopExecution() was called.
  1296. func (ctx *context) IsStopped() bool {
  1297. return ctx.currentHandlerIndex == stopExecutionIndex
  1298. }
  1299. // OnConnectionClose registers the "cb" function which will fire (on its own goroutine, no need to be registered goroutine by the end-dev)
  1300. // when the underlying connection has gone away.
  1301. //
  1302. // This mechanism can be used to cancel long operations on the server
  1303. // if the client has disconnected before the response is ready.
  1304. //
  1305. // It depends on the `http#CloseNotify`.
  1306. // CloseNotify may wait to notify until Request.Body has been
  1307. // fully read.
  1308. //
  1309. // After the main Handler has returned, there is no guarantee
  1310. // that the channel receives a value.
  1311. //
  1312. // Finally, it reports whether the protocol supports pipelines (HTTP/1.1 with pipelines disabled is not supported).
  1313. // The "cb" will not fire for sure if the output value is false.
  1314. //
  1315. // Note that you can register only one callback for the entire request handler chain/per route.
  1316. //
  1317. // Look the `ResponseWriter#CloseNotifier` for more.
  1318. func (ctx *context) OnConnectionClose(cb func()) bool {
  1319. // Note that `ctx.ResponseWriter().CloseNotify()` can already do the same
  1320. // but it returns a channel which will never fire if it the protocol version is not compatible,
  1321. // here we don't want to allocate an empty channel, just skip it.
  1322. notifier, ok := ctx.writer.CloseNotifier()
  1323. if !ok {
  1324. return false
  1325. }
  1326. notify := notifier.CloseNotify()
  1327. go func() {
  1328. <-notify
  1329. if cb != nil {
  1330. cb()
  1331. }
  1332. }()
  1333. return true
  1334. }
  1335. // OnClose registers the callback function "cb" to the underline connection closing event using the `Context#OnConnectionClose`
  1336. // and also in the end of the request handler using the `ResponseWriter#SetBeforeFlush`.
  1337. // Note that you can register only one callback for the entire request handler chain/per route.
  1338. //
  1339. // Look the `Context#OnConnectionClose` and `ResponseWriter#SetBeforeFlush` for more.
  1340. func (ctx *context) OnClose(cb func()) {
  1341. if cb == nil {
  1342. return
  1343. }
  1344. // Register the on underline connection close handler first.
  1345. ctx.OnConnectionClose(cb)
  1346. // Author's notes:
  1347. // This is fired on `ctx.ResponseWriter().FlushResponse()` which is fired by the framework automatically, internally, on the end of request handler(s),
  1348. // it is not fired on the underline streaming function of the writer: `ctx.ResponseWriter().Flush()` (which can be fired more than one if streaming is supported by the client).
  1349. // The `FlushResponse` is called only once, so add the "cb" here, no need to add done request handlers each time `OnClose` is called by the end-dev.
  1350. //
  1351. // Don't allow more than one because we don't allow that on `OnConnectionClose` too:
  1352. // old := ctx.writer.GetBeforeFlush()
  1353. // if old != nil {
  1354. // ctx.writer.SetBeforeFlush(func() {
  1355. // old()
  1356. // cb()
  1357. // })
  1358. // return
  1359. // }
  1360. ctx.writer.SetBeforeFlush(cb)
  1361. }
  1362. // +------------------------------------------------------------+
  1363. // | Current "user/request" storage |
  1364. // | and share information between the handlers - Values(). |
  1365. // | Save and get named path parameters - Params() |
  1366. // +------------------------------------------------------------+
  1367. // Params returns the current url's named parameters key-value storage.
  1368. // Named path parameters are being saved here.
  1369. // This storage, as the whole context, is per-request lifetime.
  1370. func (ctx *context) Params() *RequestParams {
  1371. return &ctx.params
  1372. }
  1373. // Values returns the current "user" storage.
  1374. // Named path parameters and any optional data can be saved here.
  1375. // This storage, as the whole context, is per-request lifetime.
  1376. //
  1377. // You can use this function to Set and Get local values
  1378. // that can be used to share information between handlers and middleware.
  1379. func (ctx *context) Values() *memstore.Store {
  1380. return &ctx.values
  1381. }
  1382. // Translate is the i18n (localization) middleware's function,
  1383. // it calls the Get("translate") to return the translated value.
  1384. //
  1385. // Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
  1386. func (ctx *context) Translate(format string, args ...interface{}) string {
  1387. if cb, ok := ctx.values.Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey()).(func(format string, args ...interface{}) string); ok {
  1388. return cb(format, args...)
  1389. }
  1390. return ""
  1391. }
  1392. // +------------------------------------------------------------+
  1393. // | Path, Host, Subdomain, IP, Headers etc... |
  1394. // +------------------------------------------------------------+
  1395. // Method returns the request.Method, the client's http method to the server.
  1396. func (ctx *context) Method() string {
  1397. return ctx.request.Method
  1398. }
  1399. // Path returns the full request path,
  1400. // escaped if EnablePathEscape config field is true.
  1401. func (ctx *context) Path() string {
  1402. return ctx.RequestPath(ctx.Application().ConfigurationReadOnly().GetEnablePathEscape())
  1403. }
  1404. // DecodeQuery returns the uri parameter as url (string)
  1405. // useful when you want to pass something to a database and be valid to retrieve it via context.Param
  1406. // use it only for special cases, when the default behavior doesn't suits you.
  1407. //
  1408. // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
  1409. // it uses just the url.QueryUnescape
  1410. func DecodeQuery(path string) string {
  1411. if path == "" {
  1412. return ""
  1413. }
  1414. encodedPath, err := url.QueryUnescape(path)
  1415. if err != nil {
  1416. return path
  1417. }
  1418. return encodedPath
  1419. }
  1420. // DecodeURL returns the decoded uri
  1421. // useful when you want to pass something to a database and be valid to retrieve it via context.Param
  1422. // use it only for special cases, when the default behavior doesn't suits you.
  1423. //
  1424. // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
  1425. // it uses just the url.Parse
  1426. func DecodeURL(uri string) string {
  1427. u, err := url.Parse(uri)
  1428. if err != nil {
  1429. return uri
  1430. }
  1431. return u.String()
  1432. }
  1433. // RequestPath returns the full request path,
  1434. // based on the 'escape'.
  1435. func (ctx *context) RequestPath(escape bool) string {
  1436. if escape {
  1437. return DecodeQuery(ctx.request.URL.EscapedPath())
  1438. }
  1439. return ctx.request.URL.Path // RawPath returns empty, requesturi can be used instead also.
  1440. }
  1441. // PathPrefixMap accepts a map of string and a handler.
  1442. // The key of "m" is the key, which is the prefix, regular expressions are not valid.
  1443. // The value of "m" is the handler that will be executed if HasPrefix(context.Path).
  1444. // func (ctx *context) PathPrefixMap(m map[string]context.Handler) bool {
  1445. // path := ctx.Path()
  1446. // for k, v := range m {
  1447. // if strings.HasPrefix(path, k) {
  1448. // v(ctx)
  1449. // return true
  1450. // }
  1451. // }
  1452. // return false
  1453. // } no, it will not work because map is a random peek data structure.
  1454. // Host returns the host part of the current URI.
  1455. func (ctx *context) Host() string {
  1456. return GetHost(ctx.request)
  1457. }
  1458. // GetHost returns the host part of the current URI.
  1459. func GetHost(r *http.Request) string {
  1460. h := r.URL.Host
  1461. if h == "" {
  1462. h = r.Host
  1463. }
  1464. return h
  1465. }
  1466. // Subdomain returns the subdomain of this request, if any.
  1467. // Note that this is a fast method which does not cover all cases.
  1468. func (ctx *context) Subdomain() (subdomain string) {
  1469. host := ctx.Host()
  1470. if index := strings.IndexByte(host, '.'); index > 0 {
  1471. subdomain = host[0:index]
  1472. }
  1473. // listening on mydomain.com:80
  1474. // subdomain = mydomain, but it's wrong, it should return ""
  1475. vhost := ctx.Application().ConfigurationReadOnly().GetVHost()
  1476. if strings.Contains(vhost, subdomain) { // then it's not subdomain
  1477. return ""
  1478. }
  1479. return
  1480. }
  1481. // IsWWW returns true if the current subdomain (if any) is www.
  1482. func (ctx *context) IsWWW() bool {
  1483. host := ctx.Host()
  1484. if index := strings.IndexByte(host, '.'); index > 0 {
  1485. // if it has a subdomain and it's www then return true.
  1486. if subdomain := host[0:index]; !strings.Contains(ctx.Application().ConfigurationReadOnly().GetVHost(), subdomain) {
  1487. return subdomain == "www"
  1488. }
  1489. }
  1490. return false
  1491. }
  1492. const xForwardedForHeaderKey = "X-Forwarded-For"
  1493. // RemoteAddr tries to parse and return the real client's request IP.
  1494. //
  1495. // Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
  1496. //
  1497. // If parse based on these headers fail then it will return the Request's `RemoteAddr` field
  1498. // which is filled by the server before the HTTP handler.
  1499. //
  1500. // Look `Configuration.RemoteAddrHeaders`,
  1501. // `Configuration.WithRemoteAddrHeader(...)`,
  1502. // `Configuration.WithoutRemoteAddrHeader(...)` for more.
  1503. func (ctx *context) RemoteAddr() string {
  1504. remoteHeaders := ctx.Application().ConfigurationReadOnly().GetRemoteAddrHeaders()
  1505. for headerName, enabled := range remoteHeaders {
  1506. if enabled {
  1507. headerValue := ctx.GetHeader(headerName)
  1508. // exception needed for 'X-Forwarded-For' only , if enabled.
  1509. if headerName == xForwardedForHeaderKey {
  1510. idx := strings.IndexByte(headerValue, ',')
  1511. if idx >= 0 {
  1512. headerValue = headerValue[0:idx]
  1513. }
  1514. }
  1515. realIP := strings.TrimSpace(headerValue)
  1516. if realIP != "" {
  1517. return realIP
  1518. }
  1519. }
  1520. }
  1521. addr := strings.TrimSpace(ctx.request.RemoteAddr)
  1522. if addr != "" {
  1523. // if addr has port use the net.SplitHostPort otherwise(error occurs) take as it is
  1524. if ip, _, err := net.SplitHostPort(addr); err == nil {
  1525. return ip
  1526. }
  1527. }
  1528. return addr
  1529. }
  1530. // GetHeader returns the request header's value based on its name.
  1531. func (ctx *context) GetHeader(name string) string {
  1532. return ctx.request.Header.Get(name)
  1533. }
  1534. // IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
  1535. //
  1536. // There is no a 100% way of knowing that a request was made via Ajax.
  1537. // You should never trust data coming from the client, they can be easily overcome by spoofing.
  1538. //
  1539. // Note that "X-Requested-With" Header can be modified by any client(because of "X-"),
  1540. // so don't rely on IsAjax for really serious stuff,
  1541. // try to find another way of detecting the type(i.e, content type),
  1542. // there are many blogs that describe these problems and provide different kind of solutions,
  1543. // it's always depending on the application you're building,
  1544. // this is the reason why this `IsAjax`` is simple enough for general purpose use.
  1545. //
  1546. // Read more at: https://developer.mozilla.org/en-US/docs/AJAX
  1547. // and https://xhr.spec.whatwg.org/
  1548. func (ctx *context) IsAjax() bool {
  1549. return ctx.GetHeader("X-Requested-With") == "XMLHttpRequest"
  1550. }
  1551. var isMobileRegex = regexp.MustCompile(`(?i)(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)`)
  1552. // IsMobile checks if client is using a mobile device(phone or tablet) to communicate with this server.
  1553. // If the return value is true that means that the http client using a mobile
  1554. // device to communicate with the server, otherwise false.
  1555. //
  1556. // Keep note that this checks the "User-Agent" request header.
  1557. func (ctx *context) IsMobile() bool {
  1558. s := ctx.GetHeader("User-Agent")
  1559. return isMobileRegex.MatchString(s)
  1560. }
  1561. type (
  1562. // Referrer contains the extracted information from the `GetReferrer`
  1563. //
  1564. // The structure contains struct tags for JSON, form, XML, YAML and TOML.
  1565. // Look the `GetReferrer() Referrer` and `goreferrer` external package.
  1566. Referrer struct {
  1567. Type ReferrerType `json:"type" form:"referrer_type" xml:"Type" yaml:"Type" toml:"Type"`
  1568. Label string `json:"label" form:"referrer_form" xml:"Label" yaml:"Label" toml:"Label"`
  1569. URL string `json:"url" form:"referrer_url" xml:"URL" yaml:"URL" toml:"URL"`
  1570. Subdomain string `json:"subdomain" form:"referrer_subdomain" xml:"Subdomain" yaml:"Subdomain" toml:"Subdomain"`
  1571. Domain string `json:"domain" form:"referrer_domain" xml:"Domain" yaml:"Domain" toml:"Domain"`
  1572. Tld string `json:"tld" form:"referrer_tld" xml:"Tld" yaml:"Tld" toml:"Tld"`
  1573. Path string `jsonn:"path" form:"referrer_path" xml:"Path" yaml:"Path" toml:"Path"`
  1574. Query string `json:"query" form:"referrer_query" xml:"Query" yaml:"Query" toml:"GoogleType"`
  1575. GoogleType ReferrerGoogleSearchType `json:"googleType" form:"referrer_google_type" xml:"GoogleType" yaml:"GoogleType" toml:"GoogleType"`
  1576. }
  1577. // ReferrerType is the goreferrer enum for a referrer type (indirect, direct, email, search, social).
  1578. ReferrerType int
  1579. // ReferrerGoogleSearchType is the goreferrer enum for a google search type (organic, adwords).
  1580. ReferrerGoogleSearchType int
  1581. )
  1582. // Contains the available values of the goreferrer enums.
  1583. const (
  1584. ReferrerInvalid ReferrerType = iota
  1585. ReferrerIndirect
  1586. ReferrerDirect
  1587. ReferrerEmail
  1588. ReferrerSearch
  1589. ReferrerSocial
  1590. ReferrerNotGoogleSearch ReferrerGoogleSearchType = iota
  1591. ReferrerGoogleOrganicSearch
  1592. ReferrerGoogleAdwords
  1593. )
  1594. func (gs ReferrerGoogleSearchType) String() string {
  1595. return goreferrer.GoogleSearchType(gs).String()
  1596. }
  1597. func (r ReferrerType) String() string {
  1598. return goreferrer.ReferrerType(r).String()
  1599. }
  1600. // unnecessary but good to know the default values upfront.
  1601. var emptyReferrer = Referrer{Type: ReferrerInvalid, GoogleType: ReferrerNotGoogleSearch}
  1602. // GetReferrer extracts and returns the information from the "Referer" header as specified
  1603. // in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  1604. // or by the URL query parameter "referer".
  1605. func (ctx *context) GetReferrer() Referrer {
  1606. // the underline net/http follows the https://tools.ietf.org/html/rfc7231#section-5.5.2,
  1607. // so there is nothing special left to do.
  1608. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  1609. refURL := ctx.GetHeader("Referer")
  1610. if refURL == "" {
  1611. refURL = ctx.URLParam("referer")
  1612. }
  1613. if ref := goreferrer.DefaultRules.Parse(refURL); ref.Type > goreferrer.Invalid {
  1614. return Referrer{
  1615. Type: ReferrerType(ref.Type),
  1616. Label: ref.Label,
  1617. URL: ref.URL,
  1618. Subdomain: ref.Subdomain,
  1619. Domain: ref.Domain,
  1620. Tld: ref.Tld,
  1621. Path: ref.Path,
  1622. Query: ref.Query,
  1623. GoogleType: ReferrerGoogleSearchType(ref.GoogleType),
  1624. }
  1625. }
  1626. return emptyReferrer
  1627. }
  1628. // +------------------------------------------------------------+
  1629. // | Response Headers helpers |
  1630. // +------------------------------------------------------------+
  1631. // Header adds a header to the response, if value is empty
  1632. // it removes the header by its name.
  1633. func (ctx *context) Header(name string, value string) {
  1634. if value == "" {
  1635. ctx.writer.Header().Del(name)
  1636. return
  1637. }
  1638. ctx.writer.Header().Add(name, value)
  1639. }
  1640. // ContentType sets the response writer's header key "Content-Type" to the 'cType'.
  1641. func (ctx *context) ContentType(cType string) {
  1642. if cType == "" {
  1643. return
  1644. }
  1645. // 1. if it's path or a filename or an extension,
  1646. // then take the content type from that
  1647. if strings.Contains(cType, ".") {
  1648. ext := filepath.Ext(cType)
  1649. cType = mime.TypeByExtension(ext)
  1650. }
  1651. // if doesn't contain a charset already then append it
  1652. if !strings.Contains(cType, "charset") {
  1653. if cType != ContentBinaryHeaderValue {
  1654. cType += "; charset=" + ctx.Application().ConfigurationReadOnly().GetCharset()
  1655. }
  1656. }
  1657. ctx.writer.Header().Set(ContentTypeHeaderKey, cType)
  1658. }
  1659. // GetContentType returns the response writer's header value of "Content-Type"
  1660. // which may, setted before with the 'ContentType'.
  1661. func (ctx *context) GetContentType() string {
  1662. return ctx.writer.Header().Get(ContentTypeHeaderKey)
  1663. }
  1664. // GetContentType returns the request's header value of "Content-Type".
  1665. func (ctx *context) GetContentTypeRequested() string {
  1666. return ctx.GetHeader(ContentTypeHeaderKey)
  1667. }
  1668. // GetContentLength returns the request's header value of "Content-Length".
  1669. // Returns 0 if header was unable to be found or its value was not a valid number.
  1670. func (ctx *context) GetContentLength() int64 {
  1671. if v := ctx.GetHeader(ContentLengthHeaderKey); v != "" {
  1672. n, _ := strconv.ParseInt(v, 10, 64)
  1673. return n
  1674. }
  1675. return 0
  1676. }
  1677. // StatusCode sets the status code header to the response.
  1678. // Look .GetStatusCode & .FireStatusCode too.
  1679. //
  1680. // Remember, the last one before .Write matters except recorder and transactions.
  1681. func (ctx *context) StatusCode(statusCode int) {
  1682. ctx.writer.WriteHeader(statusCode)
  1683. }
  1684. // NotFound emits an error 404 to the client, using the specific custom error error handler.
  1685. // Note that you may need to call ctx.StopExecution() if you don't want the next handlers
  1686. // to be executed. Next handlers are being executed on iris because you can alt the
  1687. // error code and change it to a more specific one, i.e
  1688. // users := app.Party("/users")
  1689. // users.Done(func(ctx context.Context){ if ctx.StatusCode() == 400 { /* custom error code for /users */ }})
  1690. func (ctx *context) NotFound() {
  1691. ctx.StatusCode(http.StatusNotFound)
  1692. }
  1693. // GetStatusCode returns the current status code of the response.
  1694. // Look StatusCode too.
  1695. func (ctx *context) GetStatusCode() int {
  1696. return ctx.writer.StatusCode()
  1697. }
  1698. // +------------------------------------------------------------+
  1699. // | Various Request and Post Data |
  1700. // +------------------------------------------------------------+
  1701. // URLParam returns true if the url parameter exists, otherwise false.
  1702. func (ctx *context) URLParamExists(name string) bool {
  1703. if q := ctx.request.URL.Query(); q != nil {
  1704. _, exists := q[name]
  1705. return exists
  1706. }
  1707. return false
  1708. }
  1709. // URLParamDefault returns the get parameter from a request, if not found then "def" is returned.
  1710. func (ctx *context) URLParamDefault(name string, def string) string {
  1711. if v := ctx.request.URL.Query().Get(name); v != "" {
  1712. return v
  1713. }
  1714. return def
  1715. }
  1716. // URLParam returns the get parameter from a request, if any.
  1717. func (ctx *context) URLParam(name string) string {
  1718. return ctx.URLParamDefault(name, "")
  1719. }
  1720. // URLParamTrim returns the url query parameter with trailing white spaces removed from a request.
  1721. func (ctx *context) URLParamTrim(name string) string {
  1722. return strings.TrimSpace(ctx.URLParam(name))
  1723. }
  1724. // URLParamTrim returns the escaped url query parameter from a request.
  1725. func (ctx *context) URLParamEscape(name string) string {
  1726. return DecodeQuery(ctx.URLParam(name))
  1727. }
  1728. var errURLParamNotFound = errors.New("url param '%s' does not exist")
  1729. // URLParamInt returns the url query parameter as int value from a request,
  1730. // returns -1 and an error if parse failed or not found.
  1731. func (ctx *context) URLParamInt(name string) (int, error) {
  1732. if v := ctx.URLParam(name); v != "" {
  1733. n, err := strconv.Atoi(v)
  1734. if err != nil {
  1735. return -1, err
  1736. }
  1737. return n, nil
  1738. }
  1739. return -1, errURLParamNotFound.Format(name)
  1740. }
  1741. // URLParamIntDefault returns the url query parameter as int value from a request,
  1742. // if not found or parse failed then "def" is returned.
  1743. func (ctx *context) URLParamIntDefault(name string, def int) int {
  1744. v, err := ctx.URLParamInt(name)
  1745. if err != nil {
  1746. return def
  1747. }
  1748. return v
  1749. }
  1750. // URLParamInt32Default returns the url query parameter as int32 value from a request,
  1751. // if not found or parse failed then "def" is returned.
  1752. func (ctx *context) URLParamInt32Default(name string, def int32) int32 {
  1753. if v := ctx.URLParam(name); v != "" {
  1754. n, err := strconv.ParseInt(v, 10, 32)
  1755. if err != nil {
  1756. return def
  1757. }
  1758. return int32(n)
  1759. }
  1760. return def
  1761. }
  1762. // URLParamInt64 returns the url query parameter as int64 value from a request,
  1763. // returns -1 and an error if parse failed or not found.
  1764. func (ctx *context) URLParamInt64(name string) (int64, error) {
  1765. if v := ctx.URLParam(name); v != "" {
  1766. n, err := strconv.ParseInt(v, 10, 64)
  1767. if err != nil {
  1768. return -1, err
  1769. }
  1770. return n, nil
  1771. }
  1772. return -1, errURLParamNotFound.Format(name)
  1773. }
  1774. // URLParamInt64Default returns the url query parameter as int64 value from a request,
  1775. // if not found or parse failed then "def" is returned.
  1776. func (ctx *context) URLParamInt64Default(name string, def int64) int64 {
  1777. v, err := ctx.URLParamInt64(name)
  1778. if err != nil {
  1779. return def
  1780. }
  1781. return v
  1782. }
  1783. // URLParamFloat64 returns the url query parameter as float64 value from a request,
  1784. // returns an error and -1 if parse failed.
  1785. func (ctx *context) URLParamFloat64(name string) (float64, error) {
  1786. if v := ctx.URLParam(name); v != "" {
  1787. n, err := strconv.ParseFloat(v, 64)
  1788. if err != nil {
  1789. return -1, err
  1790. }
  1791. return n, nil
  1792. }
  1793. return -1, errURLParamNotFound.Format(name)
  1794. }
  1795. // URLParamFloat64Default returns the url query parameter as float64 value from a request,
  1796. // if not found or parse failed then "def" is returned.
  1797. func (ctx *context) URLParamFloat64Default(name string, def float64) float64 {
  1798. v, err := ctx.URLParamFloat64(name)
  1799. if err != nil {
  1800. return def
  1801. }
  1802. return v
  1803. }
  1804. // URLParamBool returns the url query parameter as boolean value from a request,
  1805. // returns an error if parse failed.
  1806. func (ctx *context) URLParamBool(name string) (bool, error) {
  1807. return strconv.ParseBool(ctx.URLParam(name))
  1808. }
  1809. // URLParams returns a map of GET query parameters separated by comma if more than one
  1810. // it returns an empty map if nothing found.
  1811. func (ctx *context) URLParams() map[string]string {
  1812. values := map[string]string{}
  1813. q := ctx.request.URL.Query()
  1814. if q != nil {
  1815. for k, v := range q {
  1816. values[k] = strings.Join(v, ",")
  1817. }
  1818. }
  1819. return values
  1820. }
  1821. // No need anymore, net/http checks for the Form already.
  1822. // func (ctx *context) askParseForm() error {
  1823. // if ctx.request.Form == nil {
  1824. // if err := ctx.request.ParseForm(); err != nil {
  1825. // return err
  1826. // }
  1827. // }
  1828. // return nil
  1829. // }
  1830. // FormValueDefault returns a single parsed form value by its "name",
  1831. // including both the URL field's query parameters and the POST or PUT form data.
  1832. //
  1833. // Returns the "def" if not found.
  1834. func (ctx *context) FormValueDefault(name string, def string) string {
  1835. if form, has := ctx.form(); has {
  1836. if v := form[name]; len(v) > 0 {
  1837. return v[0]
  1838. }
  1839. }
  1840. return def
  1841. }
  1842. // FormValue returns a single parsed form value by its "name",
  1843. // including both the URL field's query parameters and the POST or PUT form data.
  1844. func (ctx *context) FormValue(name string) string {
  1845. return ctx.FormValueDefault(name, "")
  1846. }
  1847. // FormValues returns the parsed form data, including both the URL
  1848. // field's query parameters and the POST or PUT form data.
  1849. //
  1850. // The default form's memory maximum size is 32MB, it can be changed by the
  1851. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  1852. // NOTE: A check for nil is necessary.
  1853. func (ctx *context) FormValues() map[string][]string {
  1854. form, _ := ctx.form()
  1855. return form
  1856. }
  1857. // Form contains the parsed form data, including both the URL
  1858. // field's query parameters and the POST or PUT form data.
  1859. func (ctx *context) form() (form map[string][]string, found bool) {
  1860. /*
  1861. net/http/request.go#1219
  1862. for k, v := range f.Value {
  1863. r.Form[k] = append(r.Form[k], v...)
  1864. // r.PostForm should also be populated. See Issue 9305.
  1865. r.PostForm[k] = append(r.PostForm[k], v...)
  1866. }
  1867. */
  1868. // ParseMultipartForm calls `request.ParseForm` automatically
  1869. // therefore we don't need to call it here, although it doesn't hurt.
  1870. // After one call to ParseMultipartForm or ParseForm,
  1871. // subsequent calls have no effect, are idempotent.
  1872. ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
  1873. if form := ctx.request.Form; len(form) > 0 {
  1874. return form, true
  1875. }
  1876. if form := ctx.request.PostForm; len(form) > 0 {
  1877. return form, true
  1878. }
  1879. if m := ctx.request.MultipartForm; m != nil {
  1880. if len(m.Value) > 0 {
  1881. return m.Value, true
  1882. }
  1883. }
  1884. return nil, false
  1885. }
  1886. // PostValueDefault returns the parsed form data from POST, PATCH,
  1887. // or PUT body parameters based on a "name".
  1888. //
  1889. // If not found then "def" is returned instead.
  1890. func (ctx *context) PostValueDefault(name string, def string) string {
  1891. ctx.form()
  1892. if v := ctx.request.PostForm[name]; len(v) > 0 {
  1893. return v[0]
  1894. }
  1895. return def
  1896. }
  1897. // PostValue returns the parsed form data from POST, PATCH,
  1898. // or PUT body parameters based on a "name"
  1899. func (ctx *context) PostValue(name string) string {
  1900. return ctx.PostValueDefault(name, "")
  1901. }
  1902. // PostValueTrim returns the parsed form data from POST, PATCH,
  1903. // or PUT body parameters based on a "name", without trailing spaces.
  1904. func (ctx *context) PostValueTrim(name string) string {
  1905. return strings.TrimSpace(ctx.PostValue(name))
  1906. }
  1907. var errUnableToFindPostValue = errors.New("unable to find post value '%s'")
  1908. // PostValueInt returns the parsed form data from POST, PATCH,
  1909. // or PUT body parameters based on a "name", as int.
  1910. //
  1911. // If not found returns -1 and a non-nil error.
  1912. func (ctx *context) PostValueInt(name string) (int, error) {
  1913. v := ctx.PostValue(name)
  1914. if v == "" {
  1915. return -1, errUnableToFindPostValue.Format(name)
  1916. }
  1917. return strconv.Atoi(v)
  1918. }
  1919. // PostValueIntDefault returns the parsed form data from POST, PATCH,
  1920. // or PUT body parameters based on a "name", as int.
  1921. //
  1922. // If not found or parse errors returns the "def".
  1923. func (ctx *context) PostValueIntDefault(name string, def int) int {
  1924. if v, err := ctx.PostValueInt(name); err == nil {
  1925. return v
  1926. }
  1927. return def
  1928. }
  1929. // PostValueInt64 returns the parsed form data from POST, PATCH,
  1930. // or PUT body parameters based on a "name", as float64.
  1931. //
  1932. // If not found returns -1 and a non-nil error.
  1933. func (ctx *context) PostValueInt64(name string) (int64, error) {
  1934. v := ctx.PostValue(name)
  1935. if v == "" {
  1936. return -1, errUnableToFindPostValue.Format(name)
  1937. }
  1938. return strconv.ParseInt(v, 10, 64)
  1939. }
  1940. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  1941. // or PUT body parameters based on a "name", as int64.
  1942. //
  1943. // If not found or parse errors returns the "def".
  1944. func (ctx *context) PostValueInt64Default(name string, def int64) int64 {
  1945. if v, err := ctx.PostValueInt64(name); err == nil {
  1946. return v
  1947. }
  1948. return def
  1949. }
  1950. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  1951. // or PUT body parameters based on a "name", as float64.
  1952. //
  1953. // If not found returns -1 and a non-nil error.
  1954. func (ctx *context) PostValueFloat64(name string) (float64, error) {
  1955. v := ctx.PostValue(name)
  1956. if v == "" {
  1957. return -1, errUnableToFindPostValue.Format(name)
  1958. }
  1959. return strconv.ParseFloat(v, 64)
  1960. }
  1961. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  1962. // or PUT body parameters based on a "name", as float64.
  1963. //
  1964. // If not found or parse errors returns the "def".
  1965. func (ctx *context) PostValueFloat64Default(name string, def float64) float64 {
  1966. if v, err := ctx.PostValueFloat64(name); err == nil {
  1967. return v
  1968. }
  1969. return def
  1970. }
  1971. // PostValueInt64Default returns the parsed form data from POST, PATCH,
  1972. // or PUT body parameters based on a "name", as bool.
  1973. //
  1974. // If not found or value is false, then it returns false, otherwise true.
  1975. func (ctx *context) PostValueBool(name string) (bool, error) {
  1976. v := ctx.PostValue(name)
  1977. if v == "" {
  1978. return false, errUnableToFindPostValue.Format(name)
  1979. }
  1980. return strconv.ParseBool(v)
  1981. }
  1982. // PostValues returns all the parsed form data from POST, PATCH,
  1983. // or PUT body parameters based on a "name" as a string slice.
  1984. //
  1985. // The default form's memory maximum size is 32MB, it can be changed by the
  1986. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  1987. func (ctx *context) PostValues(name string) []string {
  1988. ctx.form()
  1989. return ctx.request.PostForm[name]
  1990. }
  1991. // FormFile returns the first uploaded file that received from the client.
  1992. //
  1993. //
  1994. // The default form's memory maximum size is 32MB, it can be changed by the
  1995. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  1996. //
  1997. // Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-file
  1998. func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
  1999. // we don't have access to see if the request is body stream
  2000. // and then the ParseMultipartForm can be useless
  2001. // here but do it in order to apply the post limit,
  2002. // the internal request.FormFile will not do it if that's filled
  2003. // and it's not a stream body.
  2004. if err := ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory()); err != nil {
  2005. return nil, nil, err
  2006. }
  2007. return ctx.request.FormFile(key)
  2008. }
  2009. // UploadFormFiles uploads any received file(s) from the client
  2010. // to the system physical location "destDirectory".
  2011. //
  2012. // The second optional argument "before" gives caller the chance to
  2013. // modify the *miltipart.FileHeader before saving to the disk,
  2014. // it can be used to change a file's name based on the current request,
  2015. // all FileHeader's options can be changed. You can ignore it if
  2016. // you don't need to use this capability before saving a file to the disk.
  2017. //
  2018. // Note that it doesn't check if request body streamed.
  2019. //
  2020. // Returns the copied length as int64 and
  2021. // a not nil error if at least one new file
  2022. // can't be created due to the operating system's permissions or
  2023. // http.ErrMissingFile if no file received.
  2024. //
  2025. // If you want to receive & accept files and manage them manually you can use the `context#FormFile`
  2026. // instead and create a copy function that suits your needs, the below is for generic usage.
  2027. //
  2028. // The default form's memory maximum size is 32MB, it can be changed by the
  2029. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  2030. //
  2031. // See `FormFile` to a more controlled to receive a file.
  2032. //
  2033. // Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-files
  2034. func (ctx *context) UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error) {
  2035. err = ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
  2036. if err != nil {
  2037. return 0, err
  2038. }
  2039. if ctx.request.MultipartForm != nil {
  2040. if fhs := ctx.request.MultipartForm.File; fhs != nil {
  2041. for _, files := range fhs {
  2042. for _, file := range files {
  2043. for _, b := range before {
  2044. b(ctx, file)
  2045. }
  2046. n0, err0 := uploadTo(file, destDirectory)
  2047. if err0 != nil {
  2048. return 0, err0
  2049. }
  2050. n += n0
  2051. }
  2052. }
  2053. return n, nil
  2054. }
  2055. }
  2056. return 0, http.ErrMissingFile
  2057. }
  2058. func uploadTo(fh *multipart.FileHeader, destDirectory string) (int64, error) {
  2059. src, err := fh.Open()
  2060. if err != nil {
  2061. return 0, err
  2062. }
  2063. defer src.Close()
  2064. out, err := os.OpenFile(filepath.Join(destDirectory, fh.Filename),
  2065. os.O_WRONLY|os.O_CREATE, os.FileMode(0666))
  2066. if err != nil {
  2067. return 0, err
  2068. }
  2069. defer out.Close()
  2070. return io.Copy(out, src)
  2071. }
  2072. // Redirect sends a redirect response to the client
  2073. // to a specific url or relative path.
  2074. // accepts 2 parameters string and an optional int
  2075. // first parameter is the url to redirect
  2076. // second parameter is the http status should send,
  2077. // default is 302 (StatusFound),
  2078. // you can set it to 301 (Permant redirect)
  2079. // or 303 (StatusSeeOther) if POST method,
  2080. // or StatusTemporaryRedirect(307) if that's nessecery.
  2081. func (ctx *context) Redirect(urlToRedirect string, statusHeader ...int) {
  2082. ctx.StopExecution()
  2083. // get the previous status code given by the end-developer.
  2084. status := ctx.GetStatusCode()
  2085. if status < 300 { // the previous is not a RCF-valid redirect status.
  2086. status = 0
  2087. }
  2088. if len(statusHeader) > 0 {
  2089. // check if status code is passed via receivers.
  2090. if s := statusHeader[0]; s > 0 {
  2091. status = s
  2092. }
  2093. }
  2094. if status == 0 {
  2095. // if status remains zero then default it.
  2096. // a 'temporary-redirect-like' which works better than for our purpose
  2097. status = http.StatusFound
  2098. }
  2099. http.Redirect(ctx.writer, ctx.request, urlToRedirect, status)
  2100. }
  2101. // +------------------------------------------------------------+
  2102. // | Body Readers |
  2103. // +------------------------------------------------------------+
  2104. // SetMaxRequestBodySize sets a limit to the request body size
  2105. // should be called before reading the request body from the client.
  2106. func (ctx *context) SetMaxRequestBodySize(limitOverBytes int64) {
  2107. ctx.request.Body = http.MaxBytesReader(ctx.writer, ctx.request.Body, limitOverBytes)
  2108. }
  2109. // UnmarshalBody reads the request's body and binds it to a value or pointer of any type
  2110. // Examples of usage: context.ReadJSON, context.ReadXML.
  2111. //
  2112. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
  2113. //
  2114. // UnmarshalBody does not check about gzipped data.
  2115. // Do not rely on compressed data incoming to your server. The main reason is: https://en.wikipedia.org/wiki/Zip_bomb
  2116. // However you are still free to read the `ctx.Request().Body io.Reader` manually.
  2117. func (ctx *context) UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error {
  2118. if ctx.request.Body == nil {
  2119. return errors.New("unmarshal: empty body")
  2120. }
  2121. rawData, err := ioutil.ReadAll(ctx.request.Body)
  2122. if err != nil {
  2123. return err
  2124. }
  2125. if ctx.Application().ConfigurationReadOnly().GetDisableBodyConsumptionOnUnmarshal() {
  2126. // * remember, Request.Body has no Bytes(), we have to consume them first
  2127. // and after re-set them to the body, this is the only solution.
  2128. ctx.request.Body = ioutil.NopCloser(bytes.NewBuffer(rawData))
  2129. }
  2130. // check if the v contains its own decode
  2131. // in this case the v should be a pointer also,
  2132. // but this is up to the user's custom Decode implementation*
  2133. //
  2134. // See 'BodyDecoder' for more.
  2135. if decoder, isDecoder := outPtr.(BodyDecoder); isDecoder {
  2136. return decoder.Decode(rawData)
  2137. }
  2138. // // check if v is already a pointer, if yes then pass as it's
  2139. // if reflect.TypeOf(v).Kind() == reflect.Ptr {
  2140. // return unmarshaler.Unmarshal(rawData, v)
  2141. // } <- no need for that, ReadJSON is documented enough to receive a pointer,
  2142. // we don't need to reduce the performance here by using the reflect.TypeOf method.
  2143. // f the v doesn't contains a self-body decoder use the custom unmarshaler to bind the body.
  2144. return unmarshaler.Unmarshal(rawData, outPtr)
  2145. }
  2146. func (ctx *context) shouldOptimize() bool {
  2147. return ctx.Application().ConfigurationReadOnly().GetEnableOptimizations()
  2148. }
  2149. // ReadJSON reads JSON from request's body and binds it to a value of any json-valid type.
  2150. //
  2151. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-json/main.go
  2152. func (ctx *context) ReadJSON(jsonObject interface{}) error {
  2153. var unmarshaler = json.Unmarshal
  2154. if ctx.shouldOptimize() {
  2155. unmarshaler = jsoniter.Unmarshal
  2156. }
  2157. return ctx.UnmarshalBody(jsonObject, UnmarshalerFunc(unmarshaler))
  2158. }
  2159. // ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
  2160. //
  2161. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-xml/main.go
  2162. func (ctx *context) ReadXML(xmlObject interface{}) error {
  2163. return ctx.UnmarshalBody(xmlObject, UnmarshalerFunc(xml.Unmarshal))
  2164. }
  2165. var (
  2166. errReadBody = errors.New("while trying to read %s from the request body. Trace %s")
  2167. )
  2168. // ReadForm binds the formObject with the form data
  2169. // it supports any kind of struct.
  2170. //
  2171. // Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-form/main.go
  2172. func (ctx *context) ReadForm(formObject interface{}) error {
  2173. values := ctx.FormValues()
  2174. if values == nil {
  2175. return errors.New("An empty form passed on ReadForm")
  2176. }
  2177. // or dec := formbinder.NewDecoder(&formbinder.DecoderOptions{TagName: "form"})
  2178. // somewhere at the app level. I did change the tagName to "form"
  2179. // inside its source code, so it's not needed for now.
  2180. return errReadBody.With(formbinder.Decode(values, formObject))
  2181. }
  2182. // +------------------------------------------------------------+
  2183. // | Body (raw) Writers |
  2184. // +------------------------------------------------------------+
  2185. // Write writes the data to the connection as part of an HTTP reply.
  2186. //
  2187. // If WriteHeader has not yet been called, Write calls
  2188. // WriteHeader(http.StatusOK) before writing the data. If the Header
  2189. // does not contain a Content-Type line, Write adds a Content-Type set
  2190. // to the result of passing the initial 512 bytes of written data to
  2191. // DetectContentType.
  2192. //
  2193. // Depending on the HTTP protocol version and the client, calling
  2194. // Write or WriteHeader may prevent future reads on the
  2195. // Request.Body. For HTTP/1.x requests, handlers should read any
  2196. // needed request body data before writing the response. Once the
  2197. // headers have been flushed (due to either an explicit Flusher.Flush
  2198. // call or writing enough data to trigger a flush), the request body
  2199. // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
  2200. // handlers to continue to read the request body while concurrently
  2201. // writing the response. However, such behavior may not be supported
  2202. // by all HTTP/2 clients. Handlers should read before writing if
  2203. // possible to maximize compatibility.
  2204. func (ctx *context) Write(rawBody []byte) (int, error) {
  2205. return ctx.writer.Write(rawBody)
  2206. }
  2207. // Writef formats according to a format specifier and writes to the response.
  2208. //
  2209. // Returns the number of bytes written and any write error encountered.
  2210. func (ctx *context) Writef(format string, a ...interface{}) (n int, err error) {
  2211. return ctx.writer.Writef(format, a...)
  2212. }
  2213. // WriteString writes a simple string to the response.
  2214. //
  2215. // Returns the number of bytes written and any write error encountered.
  2216. func (ctx *context) WriteString(body string) (n int, err error) {
  2217. return ctx.writer.WriteString(body)
  2218. }
  2219. const (
  2220. // ContentTypeHeaderKey is the header key of "Content-Type".
  2221. ContentTypeHeaderKey = "Content-Type"
  2222. // LastModifiedHeaderKey is the header key of "Last-Modified".
  2223. LastModifiedHeaderKey = "Last-Modified"
  2224. // IfModifiedSinceHeaderKey is the header key of "If-Modified-Since".
  2225. IfModifiedSinceHeaderKey = "If-Modified-Since"
  2226. // CacheControlHeaderKey is the header key of "Cache-Control".
  2227. CacheControlHeaderKey = "Cache-Control"
  2228. // ETagHeaderKey is the header key of "ETag".
  2229. ETagHeaderKey = "ETag"
  2230. // ContentDispositionHeaderKey is the header key of "Content-Disposition".
  2231. ContentDispositionHeaderKey = "Content-Disposition"
  2232. // ContentLengthHeaderKey is the header key of "Content-Length"
  2233. ContentLengthHeaderKey = "Content-Length"
  2234. // ContentEncodingHeaderKey is the header key of "Content-Encoding".
  2235. ContentEncodingHeaderKey = "Content-Encoding"
  2236. // GzipHeaderValue is the header value of "gzip".
  2237. GzipHeaderValue = "gzip"
  2238. // AcceptEncodingHeaderKey is the header key of "Accept-Encoding".
  2239. AcceptEncodingHeaderKey = "Accept-Encoding"
  2240. // VaryHeaderKey is the header key of "Vary".
  2241. VaryHeaderKey = "Vary"
  2242. )
  2243. var unixEpochTime = time.Unix(0, 0)
  2244. // IsZeroTime reports whether t is obviously unspecified (either zero or Unix()=0).
  2245. func IsZeroTime(t time.Time) bool {
  2246. return t.IsZero() || t.Equal(unixEpochTime)
  2247. }
  2248. // ParseTime parses a time header (such as the Date: header),
  2249. // trying each forth formats (or three if Application's configuration's TimeFormat is defaulted)
  2250. // that are allowed by HTTP/1.1:
  2251. // Application's configuration's TimeFormat or/and http.TimeFormat,
  2252. // time.RFC850, and time.ANSIC.
  2253. //
  2254. // Look `context#FormatTime` for the opossite operation (Time to string).
  2255. var ParseTime = func(ctx Context, text string) (t time.Time, err error) {
  2256. t, err = time.Parse(ctx.Application().ConfigurationReadOnly().GetTimeFormat(), text)
  2257. if err != nil {
  2258. return http.ParseTime(text)
  2259. }
  2260. return
  2261. }
  2262. // FormatTime returns a textual representation of the time value formatted
  2263. // according to the Application's configuration's TimeFormat field
  2264. // which defines the format.
  2265. //
  2266. // Look `context#ParseTime` for the opossite operation (string to Time).
  2267. var FormatTime = func(ctx Context, t time.Time) string {
  2268. return t.Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat())
  2269. }
  2270. // SetLastModified sets the "Last-Modified" based on the "modtime" input.
  2271. // If "modtime" is zero then it does nothing.
  2272. //
  2273. // It's mostly internally on core/router and context packages.
  2274. func (ctx *context) SetLastModified(modtime time.Time) {
  2275. if !IsZeroTime(modtime) {
  2276. ctx.Header(LastModifiedHeaderKey, FormatTime(ctx, modtime.UTC())) // or modtime.UTC()?
  2277. }
  2278. }
  2279. // CheckIfModifiedSince checks if the response is modified since the "modtime".
  2280. // Note that it has nothing to do with server-side caching.
  2281. // It does those checks by checking if the "If-Modified-Since" request header
  2282. // sent by client or a previous server response header
  2283. // (e.g with WriteWithExpiration or StaticEmbedded or Favicon etc.)
  2284. // is a valid one and it's before the "modtime".
  2285. //
  2286. // A check for !modtime && err == nil is necessary to make sure that
  2287. // it's not modified since, because it may return false but without even
  2288. // had the chance to check the client-side (request) header due to some errors,
  2289. // like the HTTP Method is not "GET" or "HEAD" or if the "modtime" is zero
  2290. // or if parsing time from the header failed.
  2291. //
  2292. // It's mostly used internally, e.g. `context#WriteWithExpiration`.
  2293. func (ctx *context) CheckIfModifiedSince(modtime time.Time) (bool, error) {
  2294. if method := ctx.Method(); method != http.MethodGet && method != http.MethodHead {
  2295. return false, errors.New("skip: method")
  2296. }
  2297. ims := ctx.GetHeader(IfModifiedSinceHeaderKey)
  2298. if ims == "" || IsZeroTime(modtime) {
  2299. return false, errors.New("skip: zero time")
  2300. }
  2301. t, err := ParseTime(ctx, ims)
  2302. if err != nil {
  2303. return false, errors.New("skip: " + err.Error())
  2304. }
  2305. // sub-second precision, so
  2306. // use mtime < t+1s instead of mtime <= t to check for unmodified.
  2307. if modtime.UTC().Before(t.Add(1 * time.Second)) {
  2308. return false, nil
  2309. }
  2310. return true, nil
  2311. }
  2312. // WriteNotModified sends a 304 "Not Modified" status code to the client,
  2313. // it makes sure that the content type, the content length headers
  2314. // and any "ETag" are removed before the response sent.
  2315. //
  2316. // It's mostly used internally on core/router/fs.go and context methods.
  2317. func (ctx *context) WriteNotModified() {
  2318. // RFC 7232 section 4.1:
  2319. // a sender SHOULD NOT generate representation metadata other than the
  2320. // above listed fields unless said metadata exists for the purpose of
  2321. // guiding cache updates (e.g.," Last-Modified" might be useful if the
  2322. // response does not have an ETag field).
  2323. h := ctx.ResponseWriter().Header()
  2324. delete(h, ContentTypeHeaderKey)
  2325. delete(h, ContentLengthHeaderKey)
  2326. if h.Get(ETagHeaderKey) != "" {
  2327. delete(h, LastModifiedHeaderKey)
  2328. }
  2329. ctx.StatusCode(http.StatusNotModified)
  2330. }
  2331. // WriteWithExpiration like Write but it sends with an expiration datetime
  2332. // which is refreshed every package-level `StaticCacheDuration` field.
  2333. func (ctx *context) WriteWithExpiration(body []byte, modtime time.Time) (int, error) {
  2334. if modified, err := ctx.CheckIfModifiedSince(modtime); !modified && err == nil {
  2335. ctx.WriteNotModified()
  2336. return 0, nil
  2337. }
  2338. ctx.SetLastModified(modtime)
  2339. return ctx.writer.Write(body)
  2340. }
  2341. // StreamWriter registers the given stream writer for populating
  2342. // response body.
  2343. //
  2344. // Access to context's and/or its' members is forbidden from writer.
  2345. //
  2346. // This function may be used in the following cases:
  2347. //
  2348. // * if response body is too big (more than iris.LimitRequestBodySize(if setted)).
  2349. // * if response body is streamed from slow external sources.
  2350. // * if response body must be streamed to the client in chunks.
  2351. // (aka `http server push`).
  2352. //
  2353. // receives a function which receives the response writer
  2354. // and returns false when it should stop writing, otherwise true in order to continue
  2355. func (ctx *context) StreamWriter(writer func(w io.Writer) bool) {
  2356. w := ctx.writer
  2357. notifyClosed := w.CloseNotify()
  2358. for {
  2359. select {
  2360. // response writer forced to close, exit.
  2361. case <-notifyClosed:
  2362. return
  2363. default:
  2364. shouldContinue := writer(w)
  2365. w.Flush()
  2366. if !shouldContinue {
  2367. return
  2368. }
  2369. }
  2370. }
  2371. }
  2372. // +------------------------------------------------------------+
  2373. // | Body Writers with compression |
  2374. // +------------------------------------------------------------+
  2375. // ClientSupportsGzip retruns true if the client supports gzip compression.
  2376. func (ctx *context) ClientSupportsGzip() bool {
  2377. if h := ctx.GetHeader(AcceptEncodingHeaderKey); h != "" {
  2378. for _, v := range strings.Split(h, ";") {
  2379. if strings.Contains(v, GzipHeaderValue) { // we do Contains because sometimes browsers has the q=, we don't use it atm. || strings.Contains(v,"deflate"){
  2380. return true
  2381. }
  2382. }
  2383. }
  2384. return false
  2385. }
  2386. var (
  2387. errClientDoesNotSupportGzip = errors.New("client doesn't supports gzip compression")
  2388. )
  2389. // WriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
  2390. // returns the number of bytes written and an error ( if the client doesn' supports gzip compression)
  2391. //
  2392. // You may re-use this function in the same handler
  2393. // to write more data many times without any troubles.
  2394. func (ctx *context) WriteGzip(b []byte) (int, error) {
  2395. if !ctx.ClientSupportsGzip() {
  2396. return 0, errClientDoesNotSupportGzip
  2397. }
  2398. return ctx.GzipResponseWriter().Write(b)
  2399. }
  2400. // TryWriteGzip accepts bytes, which are compressed to gzip format and sent to the client.
  2401. // If client does not supprots gzip then the contents are written as they are, uncompressed.
  2402. func (ctx *context) TryWriteGzip(b []byte) (int, error) {
  2403. n, err := ctx.WriteGzip(b)
  2404. if err != nil {
  2405. // check if the error came from gzip not allowed and not the writer itself
  2406. if _, ok := err.(*errors.Error); ok {
  2407. // client didn't supported gzip, write them uncompressed:
  2408. return ctx.writer.Write(b)
  2409. }
  2410. }
  2411. return n, err
  2412. }
  2413. // GzipResponseWriter converts the current response writer into a response writer
  2414. // which when its .Write called it compress the data to gzip and writes them to the client.
  2415. //
  2416. // Can be also disabled with its .Disable and .ResetBody to rollback to the usual response writer.
  2417. func (ctx *context) GzipResponseWriter() *GzipResponseWriter {
  2418. // if it's already a gzip response writer then just return it
  2419. if gzipResWriter, ok := ctx.writer.(*GzipResponseWriter); ok {
  2420. return gzipResWriter
  2421. }
  2422. // if it's not acquire a new from a pool
  2423. // and register that as the ctx.ResponseWriter.
  2424. gzipResWriter := AcquireGzipResponseWriter()
  2425. gzipResWriter.BeginGzipResponse(ctx.writer)
  2426. ctx.ResetResponseWriter(gzipResWriter)
  2427. return gzipResWriter
  2428. }
  2429. // Gzip enables or disables (if enabled before) the gzip response writer,if the client
  2430. // supports gzip compression, so the following response data will
  2431. // be sent as compressed gzip data to the client.
  2432. func (ctx *context) Gzip(enable bool) {
  2433. if enable {
  2434. if ctx.ClientSupportsGzip() {
  2435. _ = ctx.GzipResponseWriter()
  2436. }
  2437. } else {
  2438. if gzipResWriter, ok := ctx.writer.(*GzipResponseWriter); ok {
  2439. gzipResWriter.Disable()
  2440. }
  2441. }
  2442. }
  2443. // +------------------------------------------------------------+
  2444. // | Rich Body Content Writers/Renderers |
  2445. // +------------------------------------------------------------+
  2446. const (
  2447. // NoLayout to disable layout for a particular template file
  2448. NoLayout = "iris.nolayout"
  2449. )
  2450. // ViewLayout sets the "layout" option if and when .View
  2451. // is being called afterwards, in the same request.
  2452. // Useful when need to set or/and change a layout based on the previous handlers in the chain.
  2453. //
  2454. // Note that the 'layoutTmplFile' argument can be setted to iris.NoLayout || view.NoLayout || context.NoLayout
  2455. // to disable the layout for a specific view render action,
  2456. // it disables the engine's configuration's layout property.
  2457. //
  2458. // Look .ViewData and .View too.
  2459. //
  2460. // Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
  2461. func (ctx *context) ViewLayout(layoutTmplFile string) {
  2462. ctx.values.Set(ctx.Application().ConfigurationReadOnly().GetViewLayoutContextKey(), layoutTmplFile)
  2463. }
  2464. // ViewData saves one or more key-value pair in order to be passed if and when .View
  2465. // is being called afterwards, in the same request.
  2466. // Useful when need to set or/and change template data from previous hanadlers in the chain.
  2467. //
  2468. // If .View's "binding" argument is not nil and it's not a type of map
  2469. // then these data are being ignored, binding has the priority, so the main route's handler can still decide.
  2470. // If binding is a map or context.Map then these data are being added to the view data
  2471. // and passed to the template.
  2472. //
  2473. // After .View, the data are not destroyed, in order to be re-used if needed (again, in the same request as everything else),
  2474. // to clear the view data, developers can call:
  2475. // ctx.Set(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), nil)
  2476. //
  2477. // If 'key' is empty then the value is added as it's (struct or map) and developer is unable to add other value.
  2478. //
  2479. // Look .ViewLayout and .View too.
  2480. //
  2481. // Example: https://github.com/kataras/iris/tree/master/_examples/view/context-view-data/
  2482. func (ctx *context) ViewData(key string, value interface{}) {
  2483. viewDataContextKey := ctx.Application().ConfigurationReadOnly().GetViewDataContextKey()
  2484. if key == "" {
  2485. ctx.values.Set(viewDataContextKey, value)
  2486. return
  2487. }
  2488. v := ctx.values.Get(viewDataContextKey)
  2489. if v == nil {
  2490. ctx.values.Set(viewDataContextKey, Map{key: value})
  2491. return
  2492. }
  2493. if data, ok := v.(map[string]interface{}); ok {
  2494. data[key] = value
  2495. } else if data, ok := v.(Map); ok {
  2496. data[key] = value
  2497. }
  2498. }
  2499. // GetViewData returns the values registered by `context#ViewData`.
  2500. // The return value is `map[string]interface{}`, this means that
  2501. // if a custom struct registered to ViewData then this function
  2502. // will try to parse it to map, if failed then the return value is nil
  2503. // A check for nil is always a good practise if different
  2504. // kind of values or no data are registered via `ViewData`.
  2505. //
  2506. // Similarly to `viewData := ctx.Values().Get("iris.viewData")` or
  2507. // `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`.
  2508. func (ctx *context) GetViewData() map[string]interface{} {
  2509. viewDataContextKey := ctx.Application().ConfigurationReadOnly().GetViewDataContextKey()
  2510. v := ctx.Values().Get(viewDataContextKey)
  2511. // if no values found, then return nil
  2512. if v == nil {
  2513. return nil
  2514. }
  2515. // if struct, convert it to map[string]interface{}
  2516. if structs.IsStruct(v) {
  2517. return structs.Map(v)
  2518. }
  2519. // if pure map[string]interface{}
  2520. if viewData, ok := v.(map[string]interface{}); ok {
  2521. return viewData
  2522. }
  2523. // if context#Map
  2524. if viewData, ok := v.(Map); ok {
  2525. return viewData
  2526. }
  2527. // if failure, then return nil
  2528. return nil
  2529. }
  2530. // View renders a template based on the registered view engine(s).
  2531. // First argument accepts the filename, relative to the view engine's Directory and Extension,
  2532. // i.e: if directory is "./templates" and want to render the "./templates/users/index.html"
  2533. // then you pass the "users/index.html" as the filename argument.
  2534. //
  2535. // The second optional argument can receive a single "view model"
  2536. // that will be binded to the view template if it's not nil,
  2537. // otherwise it will check for previous view data stored by the `ViewData`
  2538. // even if stored at any previous handler(middleware) for the same request.
  2539. //
  2540. // Look .ViewData and .ViewLayout too.
  2541. //
  2542. // Examples: https://github.com/kataras/iris/tree/master/_examples/view
  2543. func (ctx *context) View(filename string, optionalViewModel ...interface{}) error {
  2544. ctx.ContentType(ContentHTMLHeaderValue)
  2545. cfg := ctx.Application().ConfigurationReadOnly()
  2546. layout := ctx.values.GetString(cfg.GetViewLayoutContextKey())
  2547. var bindingData interface{}
  2548. if len(optionalViewModel) > 0 {
  2549. // a nil can override the existing data or model sent by `ViewData`.
  2550. bindingData = optionalViewModel[0]
  2551. } else {
  2552. bindingData = ctx.values.Get(cfg.GetViewDataContextKey())
  2553. }
  2554. err := ctx.Application().View(ctx.writer, filename, layout, bindingData)
  2555. if err != nil {
  2556. ctx.StatusCode(http.StatusInternalServerError)
  2557. ctx.StopExecution()
  2558. }
  2559. return err
  2560. }
  2561. const (
  2562. // ContentBinaryHeaderValue header value for binary data.
  2563. ContentBinaryHeaderValue = "application/octet-stream"
  2564. // ContentHTMLHeaderValue is the string of text/html response header's content type value.
  2565. ContentHTMLHeaderValue = "text/html"
  2566. // ContentJSONHeaderValue header value for JSON data.
  2567. ContentJSONHeaderValue = "application/json"
  2568. // ContentJavascriptHeaderValue header value for JSONP & Javascript data.
  2569. ContentJavascriptHeaderValue = "application/javascript"
  2570. // ContentTextHeaderValue header value for Text data.
  2571. ContentTextHeaderValue = "text/plain"
  2572. // ContentXMLHeaderValue header value for XML data.
  2573. ContentXMLHeaderValue = "text/xml"
  2574. // ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
  2575. ContentMarkdownHeaderValue = "text/markdown"
  2576. // ContentYAMLHeaderValue header value for YAML data.
  2577. ContentYAMLHeaderValue = "application/x-yaml"
  2578. )
  2579. // Binary writes out the raw bytes as binary data.
  2580. func (ctx *context) Binary(data []byte) (int, error) {
  2581. ctx.ContentType(ContentBinaryHeaderValue)
  2582. return ctx.Write(data)
  2583. }
  2584. // Text writes out a string as plain text.
  2585. func (ctx *context) Text(text string) (int, error) {
  2586. ctx.ContentType(ContentTextHeaderValue)
  2587. return ctx.writer.WriteString(text)
  2588. }
  2589. // HTML writes out a string as text/html.
  2590. func (ctx *context) HTML(htmlContents string) (int, error) {
  2591. ctx.ContentType(ContentHTMLHeaderValue)
  2592. return ctx.writer.WriteString(htmlContents)
  2593. }
  2594. // JSON contains the options for the JSON (Context's) Renderer.
  2595. type JSON struct {
  2596. // http-specific
  2597. StreamingJSON bool
  2598. // content-specific
  2599. UnescapeHTML bool
  2600. Indent string
  2601. Prefix string
  2602. }
  2603. // JSONP contains the options for the JSONP (Context's) Renderer.
  2604. type JSONP struct {
  2605. // content-specific
  2606. Indent string
  2607. Callback string
  2608. }
  2609. // XML contains the options for the XML (Context's) Renderer.
  2610. type XML struct {
  2611. // content-specific
  2612. Indent string
  2613. Prefix string
  2614. }
  2615. // Markdown contains the options for the Markdown (Context's) Renderer.
  2616. type Markdown struct {
  2617. // content-specific
  2618. Sanitize bool
  2619. }
  2620. var (
  2621. newLineB = []byte("\n")
  2622. // the html codes for unescaping
  2623. ltHex = []byte("\\u003c")
  2624. lt = []byte("<")
  2625. gtHex = []byte("\\u003e")
  2626. gt = []byte(">")
  2627. andHex = []byte("\\u0026")
  2628. and = []byte("&")
  2629. )
  2630. // WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
  2631. // Ignores StatusCode, Gzip, StreamingJSON options.
  2632. func WriteJSON(writer io.Writer, v interface{}, options JSON, enableOptimization ...bool) (int, error) {
  2633. var (
  2634. result []byte
  2635. err error
  2636. optimize = len(enableOptimization) > 0 && enableOptimization[0]
  2637. )
  2638. if indent := options.Indent; indent != "" {
  2639. marshalIndent := json.MarshalIndent
  2640. if optimize {
  2641. marshalIndent = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent
  2642. }
  2643. result, err = marshalIndent(v, "", indent)
  2644. result = append(result, newLineB...)
  2645. } else {
  2646. marshal := json.Marshal
  2647. if optimize {
  2648. marshal = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal
  2649. }
  2650. result, err = marshal(v)
  2651. }
  2652. if err != nil {
  2653. return 0, err
  2654. }
  2655. if options.UnescapeHTML {
  2656. result = bytes.Replace(result, ltHex, lt, -1)
  2657. result = bytes.Replace(result, gtHex, gt, -1)
  2658. result = bytes.Replace(result, andHex, and, -1)
  2659. }
  2660. if prefix := options.Prefix; prefix != "" {
  2661. result = append([]byte(prefix), result...)
  2662. }
  2663. return writer.Write(result)
  2664. }
  2665. // DefaultJSONOptions is the optional settings that are being used
  2666. // inside `ctx.JSON`.
  2667. var DefaultJSONOptions = JSON{}
  2668. // JSON marshals the given interface object and writes the JSON response to the client.
  2669. func (ctx *context) JSON(v interface{}, opts ...JSON) (n int, err error) {
  2670. options := DefaultJSONOptions
  2671. if len(opts) > 0 {
  2672. options = opts[0]
  2673. }
  2674. optimize := ctx.shouldOptimize()
  2675. ctx.ContentType(ContentJSONHeaderValue)
  2676. if options.StreamingJSON {
  2677. if optimize {
  2678. var jsoniterConfig = jsoniter.Config{
  2679. EscapeHTML: !options.UnescapeHTML,
  2680. IndentionStep: 4,
  2681. }.Froze()
  2682. enc := jsoniterConfig.NewEncoder(ctx.writer)
  2683. err = enc.Encode(v)
  2684. } else {
  2685. enc := json.NewEncoder(ctx.writer)
  2686. enc.SetEscapeHTML(!options.UnescapeHTML)
  2687. enc.SetIndent(options.Prefix, options.Indent)
  2688. err = enc.Encode(v)
  2689. }
  2690. if err != nil {
  2691. ctx.StatusCode(http.StatusInternalServerError) // it handles the fallback to normal mode here which also removes the gzip headers.
  2692. return 0, err
  2693. }
  2694. return ctx.writer.Written(), err
  2695. }
  2696. n, err = WriteJSON(ctx.writer, v, options, optimize)
  2697. if err != nil {
  2698. ctx.StatusCode(http.StatusInternalServerError)
  2699. return 0, err
  2700. }
  2701. return n, err
  2702. }
  2703. var (
  2704. finishCallbackB = []byte(");")
  2705. )
  2706. // WriteJSONP marshals the given interface object and writes the JSON response to the writer.
  2707. func WriteJSONP(writer io.Writer, v interface{}, options JSONP, enableOptimization ...bool) (int, error) {
  2708. if callback := options.Callback; callback != "" {
  2709. writer.Write([]byte(callback + "("))
  2710. defer writer.Write(finishCallbackB)
  2711. }
  2712. optimize := len(enableOptimization) > 0 && enableOptimization[0]
  2713. if indent := options.Indent; indent != "" {
  2714. marshalIndent := json.MarshalIndent
  2715. if optimize {
  2716. marshalIndent = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent
  2717. }
  2718. result, err := marshalIndent(v, "", indent)
  2719. if err != nil {
  2720. return 0, err
  2721. }
  2722. result = append(result, newLineB...)
  2723. return writer.Write(result)
  2724. }
  2725. marshal := json.Marshal
  2726. if optimize {
  2727. marshal = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal
  2728. }
  2729. result, err := marshal(v)
  2730. if err != nil {
  2731. return 0, err
  2732. }
  2733. return writer.Write(result)
  2734. }
  2735. // DefaultJSONPOptions is the optional settings that are being used
  2736. // inside `ctx.JSONP`.
  2737. var DefaultJSONPOptions = JSONP{}
  2738. // JSONP marshals the given interface object and writes the JSON response to the client.
  2739. func (ctx *context) JSONP(v interface{}, opts ...JSONP) (int, error) {
  2740. options := DefaultJSONPOptions
  2741. if len(opts) > 0 {
  2742. options = opts[0]
  2743. }
  2744. ctx.ContentType(ContentJavascriptHeaderValue)
  2745. n, err := WriteJSONP(ctx.writer, v, options, ctx.shouldOptimize())
  2746. if err != nil {
  2747. ctx.StatusCode(http.StatusInternalServerError)
  2748. return 0, err
  2749. }
  2750. return n, err
  2751. }
  2752. // WriteXML marshals the given interface object and writes the XML response to the writer.
  2753. func WriteXML(writer io.Writer, v interface{}, options XML) (int, error) {
  2754. if prefix := options.Prefix; prefix != "" {
  2755. writer.Write([]byte(prefix))
  2756. }
  2757. if indent := options.Indent; indent != "" {
  2758. result, err := xml.MarshalIndent(v, "", indent)
  2759. if err != nil {
  2760. return 0, err
  2761. }
  2762. result = append(result, newLineB...)
  2763. return writer.Write(result)
  2764. }
  2765. result, err := xml.Marshal(v)
  2766. if err != nil {
  2767. return 0, err
  2768. }
  2769. return writer.Write(result)
  2770. }
  2771. // DefaultXMLOptions is the optional settings that are being used
  2772. // from `ctx.XML`.
  2773. var DefaultXMLOptions = XML{}
  2774. // XML marshals the given interface object and writes the XML response to the client.
  2775. func (ctx *context) XML(v interface{}, opts ...XML) (int, error) {
  2776. options := DefaultXMLOptions
  2777. if len(opts) > 0 {
  2778. options = opts[0]
  2779. }
  2780. ctx.ContentType(ContentXMLHeaderValue)
  2781. n, err := WriteXML(ctx.writer, v, options)
  2782. if err != nil {
  2783. ctx.StatusCode(http.StatusInternalServerError)
  2784. return 0, err
  2785. }
  2786. return n, err
  2787. }
  2788. // WriteMarkdown parses the markdown to html and writes these contents to the writer.
  2789. func WriteMarkdown(writer io.Writer, markdownB []byte, options Markdown) (int, error) {
  2790. buf := blackfriday.Run(markdownB)
  2791. if options.Sanitize {
  2792. buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
  2793. }
  2794. return writer.Write(buf)
  2795. }
  2796. // DefaultMarkdownOptions is the optional settings that are being used
  2797. // from `WriteMarkdown` and `ctx.Markdown`.
  2798. var DefaultMarkdownOptions = Markdown{}
  2799. // Markdown parses the markdown to html and renders its result to the client.
  2800. func (ctx *context) Markdown(markdownB []byte, opts ...Markdown) (int, error) {
  2801. options := DefaultMarkdownOptions
  2802. if len(opts) > 0 {
  2803. options = opts[0]
  2804. }
  2805. ctx.ContentType(ContentHTMLHeaderValue)
  2806. n, err := WriteMarkdown(ctx.writer, markdownB, options)
  2807. if err != nil {
  2808. ctx.StatusCode(http.StatusInternalServerError)
  2809. return 0, err
  2810. }
  2811. return n, err
  2812. }
  2813. // YAML marshals the "v" using the yaml marshaler and renders its result to the client.
  2814. func (ctx *context) YAML(v interface{}) (int, error) {
  2815. out, err := yaml.Marshal(v)
  2816. if err != nil {
  2817. ctx.StatusCode(http.StatusInternalServerError)
  2818. return 0, err
  2819. }
  2820. ctx.ContentType(ContentYAMLHeaderValue)
  2821. return ctx.Write(out)
  2822. }
  2823. // +------------------------------------------------------------+
  2824. // | Serve files |
  2825. // +------------------------------------------------------------+
  2826. var (
  2827. errServeContent = errors.New("while trying to serve content to the client. Trace %s")
  2828. )
  2829. // ServeContent serves content, headers are autoset
  2830. // receives three parameters, it's low-level function, instead you can use .ServeFile(string,bool)/SendFile(string,string)
  2831. //
  2832. // You can define your own "Content-Type" header also, after this function call
  2833. // Doesn't implements resuming (by range), use ctx.SendFile instead
  2834. func (ctx *context) ServeContent(content io.ReadSeeker, filename string, modtime time.Time, gzipCompression bool) error {
  2835. if modified, err := ctx.CheckIfModifiedSince(modtime); !modified && err == nil {
  2836. ctx.WriteNotModified()
  2837. return nil
  2838. }
  2839. ctx.ContentType(filename)
  2840. ctx.SetLastModified(modtime)
  2841. var out io.Writer
  2842. if gzipCompression && ctx.ClientSupportsGzip() {
  2843. AddGzipHeaders(ctx.writer)
  2844. gzipWriter := acquireGzipWriter(ctx.writer)
  2845. defer releaseGzipWriter(gzipWriter)
  2846. out = gzipWriter
  2847. } else {
  2848. out = ctx.writer
  2849. }
  2850. _, err := io.Copy(out, content)
  2851. return errServeContent.With(err) ///TODO: add an int64 as return value for the content length written like other writers or let it as it's in order to keep the stable api?
  2852. }
  2853. // ServeFile serves a view file, to send a file ( zip for example) to the client you should use the SendFile(serverfilename,clientfilename)
  2854. // receives two parameters
  2855. // filename/path (string)
  2856. // gzipCompression (bool)
  2857. //
  2858. // You can define your own "Content-Type" header also, after this function call
  2859. // This function doesn't implement resuming (by range), use ctx.SendFile instead
  2860. //
  2861. // Use it when you want to serve css/js/... files to the client, for bigger files and 'force-download' use the SendFile.
  2862. func (ctx *context) ServeFile(filename string, gzipCompression bool) error {
  2863. f, err := os.Open(filename)
  2864. if err != nil {
  2865. return fmt.Errorf("%d", 404)
  2866. }
  2867. defer f.Close()
  2868. fi, _ := f.Stat()
  2869. if fi.IsDir() {
  2870. return ctx.ServeFile(path.Join(filename, "index.html"), gzipCompression)
  2871. }
  2872. return ctx.ServeContent(f, fi.Name(), fi.ModTime(), gzipCompression)
  2873. }
  2874. // SendFile sends file for force-download to the client
  2875. //
  2876. // Use this instead of ServeFile to 'force-download' bigger files to the client.
  2877. func (ctx *context) SendFile(filename string, destinationName string) error {
  2878. ctx.writer.Header().Set(ContentDispositionHeaderKey, "attachment;filename="+destinationName)
  2879. return ctx.ServeFile(filename, false)
  2880. }
  2881. // +------------------------------------------------------------+
  2882. // | Cookies |
  2883. // +------------------------------------------------------------+
  2884. // CookieOption is the type of function that is accepted on
  2885. // context's methods like `SetCookieKV`, `RemoveCookie` and `SetCookie`
  2886. // as their (last) variadic input argument to amend the end cookie's form.
  2887. //
  2888. // Any custom or built'n `CookieOption` is valid,
  2889. // see `CookiePath`, `CookieCleanPath`, `CookieExpires` and `CookieHTTPOnly` for more.
  2890. type CookieOption func(*http.Cookie)
  2891. // CookiePath is a `CookieOption`.
  2892. // Use it to change the cookie's Path field.
  2893. func CookiePath(path string) CookieOption {
  2894. return func(c *http.Cookie) {
  2895. c.Path = path
  2896. }
  2897. }
  2898. // CookieCleanPath is a `CookieOption`.
  2899. // Use it to clear the cookie's Path field, exactly the same as `CookiePath("")`.
  2900. func CookieCleanPath(c *http.Cookie) {
  2901. c.Path = ""
  2902. }
  2903. // CookieExpires is a `CookieOption`.
  2904. // Use it to change the cookie's Expires and MaxAge fields by passing the lifetime of the cookie.
  2905. func CookieExpires(durFromNow time.Duration) CookieOption {
  2906. return func(c *http.Cookie) {
  2907. c.Expires = time.Now().Add(durFromNow)
  2908. c.MaxAge = int(durFromNow.Seconds())
  2909. }
  2910. }
  2911. // CookieHTTPOnly is a `CookieOption`.
  2912. // Use it to set the cookie's HttpOnly field to false or true.
  2913. // HttpOnly field defaults to true for `RemoveCookie` and `SetCookieKV`.
  2914. func CookieHTTPOnly(httpOnly bool) CookieOption {
  2915. return func(c *http.Cookie) {
  2916. c.HttpOnly = httpOnly
  2917. }
  2918. }
  2919. type (
  2920. // CookieEncoder should encode the cookie value.
  2921. // Should accept as first argument the cookie name
  2922. // and as second argument the cookie value ptr.
  2923. // Should return an encoded value or an empty one if encode operation failed.
  2924. // Should return an error if encode operation failed.
  2925. //
  2926. // Note: Errors are not printed, so you have to know what you're doing,
  2927. // and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
  2928. // You either need to provide exactly that amount or you derive the key from what you type in.
  2929. //
  2930. // See `CookieDecoder` too.
  2931. CookieEncoder func(cookieName string, value interface{}) (string, error)
  2932. // CookieDecoder should decode the cookie value.
  2933. // Should accept as first argument the cookie name,
  2934. // as second argument the encoded cookie value and as third argument the decoded value ptr.
  2935. // Should return a decoded value or an empty one if decode operation failed.
  2936. // Should return an error if decode operation failed.
  2937. //
  2938. // Note: Errors are not printed, so you have to know what you're doing,
  2939. // and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
  2940. // You either need to provide exactly that amount or you derive the key from what you type in.
  2941. //
  2942. // See `CookieEncoder` too.
  2943. CookieDecoder func(cookieName string, cookieValue string, v interface{}) error
  2944. )
  2945. // CookieEncode is a `CookieOption`.
  2946. // Provides encoding functionality when adding a cookie.
  2947. // Accepts a `CookieEncoder` and sets the cookie's value to the encoded value.
  2948. // Users of that is the `SetCookie` and `SetCookieKV`.
  2949. //
  2950. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
  2951. func CookieEncode(encode CookieEncoder) CookieOption {
  2952. return func(c *http.Cookie) {
  2953. newVal, err := encode(c.Name, c.Value)
  2954. if err != nil {
  2955. c.Value = ""
  2956. } else {
  2957. c.Value = newVal
  2958. }
  2959. }
  2960. }
  2961. // CookieDecode is a `CookieOption`.
  2962. // Provides decoding functionality when retrieving a cookie.
  2963. // Accepts a `CookieDecoder` and sets the cookie's value to the decoded value before return by the `GetCookie`.
  2964. // User of that is the `GetCookie`.
  2965. //
  2966. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
  2967. func CookieDecode(decode CookieDecoder) CookieOption {
  2968. return func(c *http.Cookie) {
  2969. if err := decode(c.Name, c.Value, &c.Value); err != nil {
  2970. c.Value = ""
  2971. }
  2972. }
  2973. }
  2974. // SetCookie adds a cookie.
  2975. // Use of the "options" is not required, they can be used to amend the "cookie".
  2976. //
  2977. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  2978. func (ctx *context) SetCookie(cookie *http.Cookie, options ...CookieOption) {
  2979. for _, opt := range options {
  2980. opt(cookie)
  2981. }
  2982. http.SetCookie(ctx.writer, cookie)
  2983. }
  2984. // SetCookieKV adds a cookie, requires the name(string) and the value(string).
  2985. //
  2986. // By default it expires at 2 hours and it's added to the root path,
  2987. // use the `CookieExpires` and `CookiePath` to modify them.
  2988. // Alternatively: ctx.SetCookie(&http.Cookie{...})
  2989. //
  2990. // If you want to set custom the path:
  2991. // ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))
  2992. //
  2993. // If you want to be visible only to current request path:
  2994. // (note that client should be responsible for that if server sent an empty cookie's path, all browsers are compatible)
  2995. // ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
  2996. // More:
  2997. // iris.CookieExpires(time.Duration)
  2998. // iris.CookieHTTPOnly(false)
  2999. //
  3000. // Examples: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  3001. func (ctx *context) SetCookieKV(name, value string, options ...CookieOption) {
  3002. c := &http.Cookie{}
  3003. c.Path = "/"
  3004. c.Name = name
  3005. c.Value = url.QueryEscape(value)
  3006. c.HttpOnly = true
  3007. c.Expires = time.Now().Add(SetCookieKVExpiration)
  3008. c.MaxAge = int(SetCookieKVExpiration.Seconds())
  3009. ctx.SetCookie(c, options...)
  3010. }
  3011. // GetCookie returns cookie's value by it's name
  3012. // returns empty string if nothing was found.
  3013. //
  3014. // If you want more than the value then:
  3015. // cookie, err := ctx.Request().Cookie("name")
  3016. //
  3017. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  3018. func (ctx *context) GetCookie(name string, options ...CookieOption) string {
  3019. cookie, err := ctx.request.Cookie(name)
  3020. if err != nil {
  3021. return ""
  3022. }
  3023. for _, opt := range options {
  3024. opt(cookie)
  3025. }
  3026. value, _ := url.QueryUnescape(cookie.Value)
  3027. return value
  3028. }
  3029. // SetCookieKVExpiration is 2 hours by-default
  3030. // you can change it or simple, use the SetCookie for more control.
  3031. //
  3032. // See `SetCookieKVExpiration` and `CookieExpires` for more.
  3033. var SetCookieKVExpiration = time.Duration(120) * time.Minute
  3034. // RemoveCookie deletes a cookie by it's name and path = "/".
  3035. // Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath)
  3036. //
  3037. // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
  3038. func (ctx *context) RemoveCookie(name string, options ...CookieOption) {
  3039. c := &http.Cookie{}
  3040. c.Name = name
  3041. c.Value = ""
  3042. c.Path = "/" // if user wants to change it, use of the CookieOption `CookiePath` is required if not `ctx.SetCookie`.
  3043. c.HttpOnly = true
  3044. // RFC says 1 second, but let's do it 1 to make sure is working
  3045. exp := time.Now().Add(-time.Duration(1) * time.Minute)
  3046. c.Expires = exp
  3047. c.MaxAge = -1
  3048. ctx.SetCookie(c, options...)
  3049. // delete request's cookie also, which is temporary available.
  3050. ctx.request.Header.Set("Cookie", "")
  3051. }
  3052. // VisitAllCookies takes a visitor which loops
  3053. // on each (request's) cookies' name and value.
  3054. func (ctx *context) VisitAllCookies(visitor func(name string, value string)) {
  3055. for _, cookie := range ctx.request.Cookies() {
  3056. visitor(cookie.Name, cookie.Value)
  3057. }
  3058. }
  3059. var maxAgeExp = regexp.MustCompile(`maxage=(\d+)`)
  3060. // MaxAge returns the "cache-control" request header's value
  3061. // seconds as int64
  3062. // if header not found or parse failed then it returns -1.
  3063. func (ctx *context) MaxAge() int64 {
  3064. header := ctx.GetHeader(CacheControlHeaderKey)
  3065. if header == "" {
  3066. return -1
  3067. }
  3068. m := maxAgeExp.FindStringSubmatch(header)
  3069. if len(m) == 2 {
  3070. if v, err := strconv.Atoi(m[1]); err == nil {
  3071. return int64(v)
  3072. }
  3073. }
  3074. return -1
  3075. }
  3076. // +------------------------------------------------------------+
  3077. // | Advanced: Response Recorder and Transactions |
  3078. // +------------------------------------------------------------+
  3079. // Record transforms the context's basic and direct responseWriter to a *ResponseRecorder
  3080. // which can be used to reset the body, reset headers, get the body,
  3081. // get & set the status code at any time and more.
  3082. func (ctx *context) Record() {
  3083. if w, ok := ctx.writer.(*responseWriter); ok {
  3084. recorder := AcquireResponseRecorder()
  3085. recorder.BeginRecord(w)
  3086. ctx.ResetResponseWriter(recorder)
  3087. }
  3088. }
  3089. // Recorder returns the context's ResponseRecorder
  3090. // if not recording then it starts recording and returns the new context's ResponseRecorder
  3091. func (ctx *context) Recorder() *ResponseRecorder {
  3092. ctx.Record()
  3093. return ctx.writer.(*ResponseRecorder)
  3094. }
  3095. // IsRecording returns the response recorder and a true value
  3096. // when the response writer is recording the status code, body, headers and so on,
  3097. // else returns nil and false.
  3098. func (ctx *context) IsRecording() (*ResponseRecorder, bool) {
  3099. //NOTE:
  3100. // two return values in order to minimize the if statement:
  3101. // if (Recording) then writer = Recorder()
  3102. // instead we do: recorder,ok = Recording()
  3103. rr, ok := ctx.writer.(*ResponseRecorder)
  3104. return rr, ok
  3105. }
  3106. // non-detailed error log for transacton unexpected panic
  3107. var errTransactionInterrupted = errors.New("transaction interrupted, recovery from panic:\n%s")
  3108. // BeginTransaction starts a scoped transaction.
  3109. //
  3110. // Can't say a lot here because it will take more than 200 lines to write about.
  3111. // You can search third-party articles or books on how Business Transaction works (it's quite simple, especially here).
  3112. //
  3113. // Note that this is unique and new
  3114. // (=I haver never seen any other examples or code in Golang on this subject, so far, as with the most of iris features...)
  3115. // it's not covers all paths,
  3116. // such as databases, this should be managed by the libraries you use to make your database connection,
  3117. // this transaction scope is only for context's response.
  3118. // Transactions have their own middleware ecosystem also.
  3119. //
  3120. // See https://github.com/kataras/iris/tree/master/_examples/ for more
  3121. func (ctx *context) BeginTransaction(pipe func(t *Transaction)) {
  3122. // do NOT begin a transaction when the previous transaction has been failed
  3123. // and it was requested scoped or SkipTransactions called manually.
  3124. if ctx.TransactionsSkipped() {
  3125. return
  3126. }
  3127. // start recording in order to be able to control the full response writer
  3128. ctx.Record()
  3129. t := newTransaction(ctx) // it calls this *context, so the overriding with a new pool's New of context.Context wil not work here.
  3130. defer func() {
  3131. if err := recover(); err != nil {
  3132. ctx.Application().Logger().Warn(errTransactionInterrupted.Format(err).Error())
  3133. // complete (again or not , doesn't matters) the scope without loud
  3134. t.Complete(nil)
  3135. // we continue as normal, no need to return here*
  3136. }
  3137. // write the temp contents to the original writer
  3138. t.Context().ResponseWriter().WriteTo(ctx.writer)
  3139. // give back to the transaction the original writer (SetBeforeFlush works this way and only this way)
  3140. // this is tricky but nessecery if we want ctx.FireStatusCode to work inside transactions
  3141. t.Context().ResetResponseWriter(ctx.writer)
  3142. }()
  3143. // run the worker with its context clone inside.
  3144. pipe(t)
  3145. }
  3146. // skipTransactionsContextKey set this to any value to stop executing next transactions
  3147. // it's a context-key in order to be used from anywhere, set it by calling the SkipTransactions()
  3148. const skipTransactionsContextKey = "@transictions_skipped"
  3149. // SkipTransactions if called then skip the rest of the transactions
  3150. // or all of them if called before the first transaction
  3151. func (ctx *context) SkipTransactions() {
  3152. ctx.values.Set(skipTransactionsContextKey, 1)
  3153. }
  3154. // TransactionsSkipped returns true if the transactions skipped or canceled at all.
  3155. func (ctx *context) TransactionsSkipped() bool {
  3156. if n, err := ctx.values.GetInt(skipTransactionsContextKey); err == nil && n == 1 {
  3157. return true
  3158. }
  3159. return false
  3160. }
  3161. // Exec calls the framewrok's ServeCtx
  3162. // based on this context but with a changed method and path
  3163. // like it was requested by the user, but it is not.
  3164. //
  3165. // Offline means that the route is registered to the iris and have all features that a normal route has
  3166. // BUT it isn't available by browsing, its handlers executed only when other handler's context call them
  3167. // it can validate paths, has sessions, path parameters and all.
  3168. //
  3169. // You can find the Route by app.GetRoute("theRouteName")
  3170. // you can set a route name as: myRoute := app.Get("/mypath", handler)("theRouteName")
  3171. // that will set a name to the route and returns its RouteInfo instance for further usage.
  3172. //
  3173. // It doesn't changes the global state, if a route was "offline" it remains offline.
  3174. //
  3175. // app.None(...) and app.GetRoutes().Offline(route)/.Online(route, method)
  3176. //
  3177. // Example: https://github.com/kataras/iris/tree/master/_examples/routing/route-state
  3178. //
  3179. // User can get the response by simple using rec := ctx.Recorder(); rec.Body()/rec.StatusCode()/rec.Header().
  3180. //
  3181. // context's Values and the Session are kept in order to be able to communicate via the result route.
  3182. //
  3183. // It's for extreme use cases, 99% of the times will never be useful for you.
  3184. func (ctx *context) Exec(method string, path string) {
  3185. if path == "" {
  3186. return
  3187. }
  3188. if method == "" {
  3189. method = "GET"
  3190. }
  3191. // backup the handlers
  3192. backupHandlers := ctx.Handlers()[0:]
  3193. backupPos := ctx.HandlerIndex(-1)
  3194. // backup the request path information
  3195. backupPath := ctx.Path()
  3196. backupMethod := ctx.Method()
  3197. // don't backupValues := ctx.Values().ReadOnly()
  3198. // [values stays]
  3199. // reset handlers
  3200. ctx.SetHandlers(nil)
  3201. req := ctx.Request()
  3202. // set the request to be align with the 'againstRequestPath'
  3203. req.RequestURI = path
  3204. req.URL.Path = path
  3205. req.Method = method
  3206. // execute the route from the (internal) context router
  3207. // this way we keep the sessions and the values
  3208. ctx.Application().ServeHTTPC(ctx)
  3209. // set back the old handlers and the last known index
  3210. ctx.SetHandlers(backupHandlers)
  3211. ctx.HandlerIndex(backupPos)
  3212. // set the request back to its previous state
  3213. req.RequestURI = backupPath
  3214. req.URL.Path = backupPath
  3215. req.Method = backupMethod
  3216. // don't fill the values in order to be able to communicate from and to.
  3217. // // fill the values as they were before
  3218. // backupValues.Visit(func(key string, value interface{}) {
  3219. // ctx.Values().Set(key, value)
  3220. // })
  3221. }
  3222. // RouteExists reports whether a particular route exists
  3223. // It will search from the current subdomain of context's host, if not inside the root domain.
  3224. func (ctx *context) RouteExists(method, path string) bool {
  3225. return ctx.Application().RouteExists(ctx, method, path)
  3226. }
  3227. // Application returns the iris app instance which belongs to this context.
  3228. // Worth to notice that this function returns an interface
  3229. // of the Application, which contains methods that are safe
  3230. // to be executed at serve-time. The full app's fields
  3231. // and methods are not available here for the developer's safety.
  3232. func (ctx *context) Application() Application {
  3233. return ctx.app
  3234. }
  3235. var lastCapturedContextID uint64
  3236. // LastCapturedContextID returns the total number of `context#String` calls.
  3237. func LastCapturedContextID() uint64 {
  3238. return atomic.LoadUint64(&lastCapturedContextID)
  3239. }
  3240. // String returns the string representation of this request.
  3241. // Each context has a unique string representation.
  3242. // It can be used for simple debugging scenarios, i.e print context as string.
  3243. //
  3244. // What it returns? A number which declares the length of the
  3245. // total `String` calls per executable application, followed
  3246. // by the remote IP (the client) and finally the method:url.
  3247. func (ctx *context) String() string {
  3248. if ctx.id == 0 {
  3249. // set the id here.
  3250. forward := atomic.AddUint64(&lastCapturedContextID, 1)
  3251. ctx.id = forward
  3252. }
  3253. return fmt.Sprintf("[%d] %s ▶ %s:%s",
  3254. ctx.id, ctx.RemoteAddr(), ctx.Method(), ctx.Request().RequestURI)
  3255. }