context.go 207 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632
  1. package context
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "encoding/xml"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "mime"
  11. "mime/multipart"
  12. "net"
  13. "net/http"
  14. "net/url"
  15. "os"
  16. "path"
  17. "path/filepath"
  18. "reflect"
  19. "regexp"
  20. "sort"
  21. "strconv"
  22. "strings"
  23. "sync/atomic"
  24. "time"
  25. "unsafe"
  26. "github.com/kataras/iris/v12/core/memstore"
  27. "github.com/kataras/iris/v12/core/netutil"
  28. "github.com/Shopify/goreferrer"
  29. "github.com/fatih/structs"
  30. "github.com/gomarkdown/markdown"
  31. "github.com/gomarkdown/markdown/html"
  32. "github.com/iris-contrib/schema"
  33. "github.com/mailru/easyjson"
  34. "github.com/mailru/easyjson/jwriter"
  35. "github.com/microcosm-cc/bluemonday"
  36. "github.com/vmihailenco/msgpack/v5"
  37. "golang.org/x/net/publicsuffix"
  38. "golang.org/x/time/rate"
  39. "google.golang.org/protobuf/encoding/protojson"
  40. "google.golang.org/protobuf/proto"
  41. "gopkg.in/yaml.v3"
  42. )
  43. var (
  44. // BuildRevision holds the vcs commit id information of the program's build.
  45. // Available at go version 1.18+
  46. BuildRevision string
  47. // BuildTime holds the vcs commit time information of the program's build.
  48. // Available at go version 1.18+
  49. BuildTime string
  50. )
  51. type (
  52. // BodyDecoder is an interface which any struct can implement in order to customize the decode action
  53. // from ReadJSON and ReadXML
  54. //
  55. // Trivial example of this could be:
  56. // type User struct { Username string }
  57. //
  58. // func (u *User) Decode(data []byte) error {
  59. // return json.Unmarshal(data, u)
  60. // }
  61. //
  62. // the 'Context.ReadJSON/ReadXML(&User{})' will call the User's
  63. // Decode option to decode the request body
  64. //
  65. // Note: This is totally optionally, the default decoders
  66. // for ReadJSON is the encoding/json and for ReadXML is the encoding/xml.
  67. //
  68. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-custom-per-type/main.go
  69. BodyDecoder interface {
  70. Decode(data []byte) error
  71. }
  72. // BodyDecoderWithContext same as BodyDecoder but it can accept a standard context,
  73. // which is binded to the HTTP request's context.
  74. BodyDecoderWithContext interface {
  75. DecodeContext(ctx context.Context, data []byte) error
  76. }
  77. // Unmarshaler is the interface implemented by types that can unmarshal any raw data.
  78. // TIP INFO: Any pointer to a value which implements the BodyDecoder can be override the unmarshaler.
  79. Unmarshaler interface {
  80. Unmarshal(data []byte, outPtr interface{}) error
  81. }
  82. // UnmarshalerFunc a shortcut for the Unmarshaler interface
  83. //
  84. // See 'Unmarshaler' and 'BodyDecoder' for more.
  85. //
  86. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-custom-via-unmarshaler/main.go
  87. UnmarshalerFunc func(data []byte, outPtr interface{}) error
  88. // DecodeFunc is a generic type of decoder function.
  89. // When the returned error is not nil the decode operation
  90. // is terminated and the error is received by the ReadJSONStream method,
  91. // otherwise it continues to read the next available object.
  92. // Look the `Context.ReadJSONStream` method.
  93. DecodeFunc func(outPtr interface{}) error
  94. )
  95. // Unmarshal parses the X-encoded data and stores the result in the value pointed to by v.
  96. // Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps,
  97. // slices, and pointers as necessary.
  98. func (u UnmarshalerFunc) Unmarshal(data []byte, v interface{}) error {
  99. return u(data, v)
  100. }
  101. // LimitRequestBodySize is a middleware which sets a request body size limit
  102. // for all next handlers in the chain.
  103. var LimitRequestBodySize = func(maxRequestBodySizeBytes int64) Handler {
  104. return func(ctx *Context) {
  105. ctx.SetMaxRequestBodySize(maxRequestBodySizeBytes)
  106. ctx.Next()
  107. }
  108. }
  109. // Map is just a type alias of the map[string]interface{} type.
  110. type Map = map[string]interface{}
  111. // Context is the midle-man server's "object" dealing with incoming requests.
  112. //
  113. // A New context is being acquired from a sync.Pool on each connection.
  114. // The Context is the most important thing on the iris's http flow.
  115. //
  116. // Developers send responses to the client's request through a Context.
  117. // Developers get request information from the client's request a Context.
  118. type Context struct {
  119. // the http.ResponseWriter wrapped by custom writer.
  120. writer ResponseWriter
  121. // the original http.Request
  122. request *http.Request
  123. // the current route registered to this request path.
  124. currentRoute RouteReadOnly
  125. // the local key-value storage
  126. params RequestParams // url named parameters.
  127. values memstore.Store // generic storage, middleware communication.
  128. query url.Values // GET url query temp cache, useful on many URLParamXXX calls.
  129. // the underline application app.
  130. app Application
  131. // the route's handlers
  132. handlers Handlers
  133. // the current position of the handler's chain
  134. currentHandlerIndex int
  135. // proceeded reports whether `Proceed` method
  136. // called before a `Next`. It is a flash field and it is set
  137. // to true on `Next` call when its called on the last handler in the chain.
  138. // Reports whether a `Next` is called,
  139. // even if the handler index remains the same (last handler).
  140. //
  141. // Also it's responsible to keep the old value of the last known handler index
  142. // before StopExecution. See ResumeExecution.
  143. proceeded int
  144. // if true, caller is responsible to release the context (put the context to the pool).
  145. manualRelease bool
  146. }
  147. // NewContext returns a new Context instance.
  148. func NewContext(app Application) *Context {
  149. return &Context{app: app}
  150. }
  151. /* Not required, unless requested.
  152. // SetApplication sets an Iris Application on-fly.
  153. // Do NOT use it after ServeHTTPC is fired.
  154. func (ctx *Context) SetApplication(app Application) {
  155. ctx.app = app
  156. }
  157. */
  158. // Clone returns a copy of the context that
  159. // can be safely used outside the request's scope.
  160. // Note that if the request-response lifecycle terminated
  161. // or request canceled by the client (can be checked by `ctx.IsCanceled()`)
  162. // then the response writer is totally useless.
  163. // The http.Request pointer value is shared.
  164. func (ctx *Context) Clone() *Context {
  165. valuesCopy := make(memstore.Store, len(ctx.values))
  166. copy(valuesCopy, ctx.values)
  167. paramsCopy := make(memstore.Store, len(ctx.params.Store))
  168. copy(paramsCopy, ctx.params.Store)
  169. queryCopy := make(url.Values, len(ctx.query))
  170. for k, v := range ctx.query {
  171. queryCopy[k] = v
  172. }
  173. req := ctx.request.Clone(ctx.request.Context())
  174. return &Context{
  175. app: ctx.app,
  176. values: valuesCopy,
  177. params: RequestParams{Store: paramsCopy},
  178. query: queryCopy,
  179. writer: ctx.writer.Clone(),
  180. request: req,
  181. currentHandlerIndex: stopExecutionIndex,
  182. proceeded: ctx.proceeded,
  183. manualRelease: ctx.manualRelease,
  184. currentRoute: ctx.currentRoute,
  185. }
  186. }
  187. // BeginRequest is executing once for each request
  188. // it should prepare the (new or acquired from pool) context's fields for the new request.
  189. // Do NOT call it manually. Framework calls it automatically.
  190. //
  191. // Resets
  192. // 1. handlers to nil.
  193. // 2. values to empty.
  194. // 3. the defer function.
  195. // 4. response writer to the http.ResponseWriter.
  196. // 5. request to the *http.Request.
  197. func (ctx *Context) BeginRequest(w http.ResponseWriter, r *http.Request) {
  198. ctx.currentRoute = nil
  199. ctx.handlers = nil // will be filled by router.Serve/HTTP
  200. ctx.values = ctx.values[0:0] // >> >> by context.Values().Set
  201. ctx.params.Store = ctx.params.Store[0:0]
  202. ctx.query = nil
  203. ctx.request = r
  204. ctx.currentHandlerIndex = 0
  205. ctx.proceeded = 0
  206. ctx.manualRelease = false
  207. ctx.writer = AcquireResponseWriter()
  208. ctx.writer.BeginResponse(w)
  209. }
  210. // EndRequest is executing once after a response to the request was sent and this context is useless or released.
  211. // Do NOT call it manually. Framework calls it automatically.
  212. //
  213. // 1. executes the OnClose function (if any).
  214. // 2. flushes the response writer's result or fire any error handler.
  215. // 3. releases the response writer.
  216. func (ctx *Context) EndRequest() {
  217. if !ctx.app.ConfigurationReadOnly().GetDisableAutoFireStatusCode() &&
  218. StatusCodeNotSuccessful(ctx.GetStatusCode()) {
  219. ctx.app.FireErrorCode(ctx)
  220. }
  221. ctx.writer.FlushResponse()
  222. ctx.writer.EndResponse()
  223. }
  224. // DisablePoolRelease disables the auto context pool Put call.
  225. // Do NOT use it, unless you know what you are doing.
  226. func (ctx *Context) DisablePoolRelease() {
  227. ctx.manualRelease = true
  228. }
  229. // IsCanceled reports whether the client canceled the request
  230. // or the underlying connection has gone.
  231. // Note that it will always return true
  232. // when called from a goroutine after the request-response lifecycle.
  233. func (ctx *Context) IsCanceled() bool {
  234. var err error
  235. if reqCtx := ctx.request.Context(); reqCtx != nil {
  236. err = reqCtx.Err()
  237. } else {
  238. err = ctx.GetErr()
  239. }
  240. return IsErrCanceled(err)
  241. }
  242. // IsErrCanceled reports whether the "err" is caused by a cancellation or timeout.
  243. func IsErrCanceled(err error) bool {
  244. if err == nil {
  245. return false
  246. }
  247. var netErr net.Error
  248. return (errors.As(err, &netErr) && netErr.Timeout()) ||
  249. errors.Is(err, context.Canceled) ||
  250. errors.Is(err, context.DeadlineExceeded) ||
  251. errors.Is(err, http.ErrHandlerTimeout) ||
  252. err.Error() == "closed pool"
  253. }
  254. // OnConnectionClose registers the "cb" Handler
  255. // which will be fired on its on goroutine on a cloned Context
  256. // when the underlying connection has gone away.
  257. //
  258. // The code inside the given callback is running on its own routine,
  259. // as explained above, therefore the callback should NOT
  260. // try to access to handler's Context response writer.
  261. //
  262. // This mechanism can be used to cancel long operations on the server
  263. // if the client has disconnected before the response is ready.
  264. //
  265. // It depends on the Request's Context.Done() channel.
  266. //
  267. // Finally, it reports whether the protocol supports pipelines (HTTP/1.1 with pipelines disabled is not supported).
  268. // The "cb" will not fire for sure if the output value is false.
  269. //
  270. // Note that you can register only one callback per route.
  271. //
  272. // See `OnClose` too.
  273. func (ctx *Context) OnConnectionClose(cb Handler) bool {
  274. if cb == nil {
  275. return false
  276. }
  277. reqCtx := ctx.Request().Context()
  278. if reqCtx == nil {
  279. return false
  280. }
  281. notifyClose := reqCtx.Done()
  282. if notifyClose == nil {
  283. return false
  284. }
  285. go func() {
  286. <-notifyClose
  287. // Note(@kataras): No need to clone if not canceled,
  288. // EndRequest will be called on the end of the handler chain,
  289. // no matter the cancelation.
  290. // therefore the context will still be there.
  291. cb(ctx.Clone())
  292. }()
  293. return true
  294. }
  295. // OnConnectionCloseErr same as `OnConnectionClose` but instead it
  296. // receives a function which returns an error.
  297. // If error is not nil, it will be logged as a debug message.
  298. func (ctx *Context) OnConnectionCloseErr(cb func() error) bool {
  299. if cb == nil {
  300. return false
  301. }
  302. reqCtx := ctx.Request().Context()
  303. if reqCtx == nil {
  304. return false
  305. }
  306. notifyClose := reqCtx.Done()
  307. if notifyClose == nil {
  308. return false
  309. }
  310. go func() {
  311. <-notifyClose
  312. if err := cb(); err != nil {
  313. // Can be ignored.
  314. ctx.app.Logger().Debugf("OnConnectionCloseErr: received error: %v", err)
  315. }
  316. }()
  317. return true
  318. }
  319. // OnClose registers a callback which
  320. // will be fired when the underlying connection has gone away(request canceled)
  321. // on its own goroutine or in the end of the request-response lifecylce
  322. // on the handler's routine itself (Context access).
  323. //
  324. // See `OnConnectionClose` too.
  325. func (ctx *Context) OnClose(cb Handler) {
  326. if cb == nil {
  327. return
  328. }
  329. // Note(@kataras):
  330. // - on normal request-response lifecycle
  331. // the `SetBeforeFlush` will be called first
  332. // and then `OnConnectionClose`,
  333. // - when request was canceled before handler finish its job
  334. // then the `OnConnectionClose` will be called first instead,
  335. // and when the handler function completed then `SetBeforeFlush` is fired.
  336. // These are synchronized, they cannot be executed the same exact time,
  337. // below we just make sure the "cb" is executed once
  338. // by simple boolean check or an atomic one.
  339. var executed uint32
  340. callback := func(ctx *Context) {
  341. if atomic.CompareAndSwapUint32(&executed, 0, 1) {
  342. cb(ctx)
  343. }
  344. }
  345. ctx.OnConnectionClose(callback)
  346. onFlush := func() {
  347. callback(ctx)
  348. }
  349. ctx.writer.SetBeforeFlush(onFlush)
  350. }
  351. // OnCloseErr same as `OnClose` but instead it
  352. // receives a function which returns an error.
  353. // If error is not nil, it will be logged as a debug message.
  354. func (ctx *Context) OnCloseErr(cb func() error) {
  355. if cb == nil {
  356. return
  357. }
  358. var executed uint32
  359. callback := func() error {
  360. if atomic.CompareAndSwapUint32(&executed, 0, 1) {
  361. return cb()
  362. }
  363. return nil
  364. }
  365. ctx.OnConnectionCloseErr(callback)
  366. onFlush := func() {
  367. if err := callback(); err != nil {
  368. // Can be ignored.
  369. ctx.app.Logger().Debugf("OnClose: SetBeforeFlush: received error: %v", err)
  370. }
  371. }
  372. ctx.writer.SetBeforeFlush(onFlush)
  373. }
  374. /* Note(@kataras): just leave end-developer decide.
  375. const goroutinesContextKey = "iris.goroutines"
  376. type goroutines struct {
  377. wg *sync.WaitGroup
  378. length int
  379. mu sync.RWMutex
  380. }
  381. var acquireGoroutines = func() interface{} {
  382. return &goroutines{wg: new(sync.WaitGroup)}
  383. }
  384. func (ctx *Context) Go(fn func(cancelCtx context.Context)) (running int) {
  385. g := ctx.values.GetOrSet(goroutinesContextKey, acquireGoroutines).(*goroutines)
  386. if fn != nil {
  387. g.wg.Add(1)
  388. g.mu.Lock()
  389. g.length++
  390. g.mu.Unlock()
  391. ctx.waitFunc = g.wg.Wait
  392. go func(reqCtx context.Context) {
  393. fn(reqCtx)
  394. g.wg.Done()
  395. g.mu.Lock()
  396. g.length--
  397. g.mu.Unlock()
  398. }(ctx.request.Context())
  399. }
  400. g.mu.RLock()
  401. running = g.length
  402. g.mu.RUnlock()
  403. return
  404. }
  405. */
  406. // ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
  407. func (ctx *Context) ResponseWriter() ResponseWriter {
  408. return ctx.writer
  409. }
  410. // ResetResponseWriter sets a new ResponseWriter implementation
  411. // to this Context to use as its writer.
  412. // Note, to change the underline http.ResponseWriter use
  413. // ctx.ResponseWriter().SetWriter(http.ResponseWriter) instead.
  414. func (ctx *Context) ResetResponseWriter(newResponseWriter ResponseWriter) {
  415. if rec, ok := ctx.IsRecording(); ok {
  416. releaseResponseRecorder(rec)
  417. }
  418. ctx.writer = newResponseWriter
  419. }
  420. // Request returns the original *http.Request, as expected.
  421. func (ctx *Context) Request() *http.Request {
  422. return ctx.request
  423. }
  424. // ResetRequest sets the Context's Request,
  425. // It is useful to store the new request created by a std *http.Request#WithContext() into Iris' Context.
  426. // Use `ResetRequest` when for some reason you want to make a full
  427. // override of the *http.Request.
  428. // Note that: when you just want to change one of each fields you can use the Request() which returns a pointer to Request,
  429. // so the changes will have affect without a full override.
  430. // Usage: you use a native http handler which uses the standard "context" package
  431. // to get values instead of the Iris' Context#Values():
  432. // r := ctx.Request()
  433. // stdCtx := context.WithValue(r.Context(), key, val)
  434. // ctx.ResetRequest(r.WithContext(stdCtx)).
  435. func (ctx *Context) ResetRequest(r *http.Request) {
  436. ctx.request = r
  437. }
  438. // SetCurrentRoute sets the route internally,
  439. // See `GetCurrentRoute()` method too.
  440. // It's being initialized by the Router.
  441. // See `Exec` or `SetHandlers/AddHandler` methods to simulate a request.
  442. func (ctx *Context) SetCurrentRoute(route RouteReadOnly) {
  443. ctx.currentRoute = route
  444. }
  445. // GetCurrentRoute returns the current "read-only" route that
  446. // was registered to this request's path.
  447. func (ctx *Context) GetCurrentRoute() RouteReadOnly {
  448. return ctx.currentRoute
  449. }
  450. // Do sets the "handlers" as the chain
  451. // and executes the first handler,
  452. // handlers should not be empty.
  453. //
  454. // It's used by the router, developers may use that
  455. // to replace and execute handlers immediately.
  456. func (ctx *Context) Do(handlers Handlers) {
  457. if len(handlers) == 0 {
  458. return
  459. }
  460. ctx.handlers = handlers
  461. handlers[0](ctx)
  462. }
  463. // AddHandler can add handler(s)
  464. // to the current request in serve-time,
  465. // these handlers are not persistenced to the router.
  466. //
  467. // Router is calling this function to add the route's handler.
  468. // If AddHandler called then the handlers will be inserted
  469. // to the end of the already-defined route's handler.
  470. func (ctx *Context) AddHandler(handlers ...Handler) {
  471. ctx.handlers = append(ctx.handlers, handlers...)
  472. }
  473. // SetHandlers replaces all handlers with the new.
  474. func (ctx *Context) SetHandlers(handlers Handlers) {
  475. ctx.handlers = handlers
  476. }
  477. // Handlers keeps tracking of the current handlers.
  478. func (ctx *Context) Handlers() Handlers {
  479. return ctx.handlers
  480. }
  481. // HandlerIndex sets the current index of the
  482. // current context's handlers chain.
  483. // If n < 0 or the current handlers length is 0 then it just returns the
  484. // current handler index without change the current index.
  485. //
  486. // Look Handlers(), Next() and StopExecution() too.
  487. func (ctx *Context) HandlerIndex(n int) (currentIndex int) {
  488. if n < 0 || n > len(ctx.handlers)-1 {
  489. return ctx.currentHandlerIndex
  490. }
  491. ctx.currentHandlerIndex = n
  492. return n
  493. }
  494. // Proceed is an alternative way to check if a particular handler
  495. // has been executed.
  496. // The given "h" Handler can report a failure with `StopXXX` methods
  497. // or ignore calling a `Next` (see `iris.ExecutionRules` too).
  498. //
  499. // This is useful only when you run a handler inside
  500. // another handler. It justs checks for before index and the after index.
  501. //
  502. // A usecase example is when you want to execute a middleware
  503. // inside controller's `BeginRequest` that calls the `ctx.Next` inside it.
  504. // The Controller looks the whole flow (BeginRequest, method handler, EndRequest)
  505. // as one handler, so `ctx.Next` will not be reflected to the method handler
  506. // if called from the `BeginRequest`.
  507. //
  508. // Although `BeginRequest` should NOT be used to call other handlers,
  509. // the `BeginRequest` has been introduced to be able to set
  510. // common data to all method handlers before their execution.
  511. // Controllers can accept middleware(s) from the MVC's Application's Router as normally.
  512. //
  513. // That said let's see an example of `ctx.Proceed`:
  514. //
  515. // var authMiddleware = basicauth.New(basicauth.Config{
  516. // Users: map[string]string{
  517. // "admin": "password",
  518. // },
  519. // })
  520. //
  521. // func (c *UsersController) BeginRequest(ctx iris.Context) {
  522. // if !ctx.Proceed(authMiddleware) {
  523. // ctx.StopExecution()
  524. // }
  525. // }
  526. //
  527. // This Get() will be executed in the same handler as `BeginRequest`,
  528. // internally controller checks for `ctx.StopExecution`.
  529. // So it will not be fired if BeginRequest called the `StopExecution`.
  530. //
  531. // func(c *UsersController) Get() []models.User {
  532. // return c.Service.GetAll()
  533. // }
  534. //
  535. // Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
  536. func (ctx *Context) Proceed(h Handler) bool {
  537. _, ok := ctx.ProceedAndReportIfStopped(h)
  538. return ok
  539. }
  540. // ProceedAndReportIfStopped same as "Proceed" method
  541. // but the first output parameter reports whether the "h"
  542. // called "StopExecution" manually.
  543. func (ctx *Context) ProceedAndReportIfStopped(h Handler) (bool, bool) {
  544. ctx.proceeded = internalPauseExecutionIndex
  545. // Store the current index.
  546. beforeIdx := ctx.currentHandlerIndex
  547. h(ctx)
  548. // Retrieve the next one, if Next is called this is beforeIdx + 1 and so on.
  549. afterIdx := ctx.currentHandlerIndex
  550. // Restore prev index, no matter what.
  551. ctx.currentHandlerIndex = beforeIdx
  552. proceededByNext := ctx.proceeded == internalProceededHandlerIndex
  553. ctx.proceeded = beforeIdx
  554. // Stop called, return false but keep the handlers index.
  555. if afterIdx == stopExecutionIndex {
  556. return true, false
  557. }
  558. if proceededByNext {
  559. return false, true
  560. }
  561. // Next called or not.
  562. return false, afterIdx > beforeIdx
  563. }
  564. // HandlerName returns the current handler's name, helpful for debugging.
  565. func (ctx *Context) HandlerName() string {
  566. return HandlerName(ctx.handlers[ctx.currentHandlerIndex])
  567. }
  568. // HandlerFileLine returns the current running handler's function source file and line information.
  569. // Useful mostly when debugging.
  570. func (ctx *Context) HandlerFileLine() (file string, line int) {
  571. return HandlerFileLine(ctx.handlers[ctx.currentHandlerIndex])
  572. }
  573. // RouteName returns the route name that this handler is running on.
  574. // Note that it may return empty on not found handlers.
  575. func (ctx *Context) RouteName() string {
  576. if ctx.currentRoute == nil {
  577. return ""
  578. }
  579. return ctx.currentRoute.Name()
  580. }
  581. // Next calls the next handler from the handlers chain,
  582. // it should be used inside a middleware.
  583. func (ctx *Context) Next() {
  584. if ctx.IsStopped() {
  585. return
  586. }
  587. if ctx.proceeded <= internalPauseExecutionIndex /* pause and proceeded */ {
  588. ctx.proceeded = internalProceededHandlerIndex
  589. return
  590. }
  591. nextIndex, n := ctx.currentHandlerIndex+1, len(ctx.handlers)
  592. if nextIndex < n {
  593. ctx.currentHandlerIndex = nextIndex
  594. ctx.handlers[nextIndex](ctx)
  595. }
  596. }
  597. // NextOr checks if chain has a next handler, if so then it executes it
  598. // otherwise it sets a new chain assigned to this Context based on the given handler(s)
  599. // and executes its first handler.
  600. //
  601. // Returns true if next handler exists and executed, otherwise false.
  602. //
  603. // Note that if no next handler found and handlers are missing then
  604. // it sends a Status Not Found (404) to the client and it stops the execution.
  605. func (ctx *Context) NextOr(handlers ...Handler) bool {
  606. if next := ctx.NextHandler(); next != nil {
  607. ctx.Skip() // skip this handler from the chain.
  608. next(ctx)
  609. return true
  610. }
  611. if len(handlers) == 0 {
  612. ctx.NotFound()
  613. ctx.StopExecution()
  614. return false
  615. }
  616. ctx.Do(handlers)
  617. return false
  618. }
  619. // NextOrNotFound checks if chain has a next handler, if so then it executes it
  620. // otherwise it sends a Status Not Found (404) to the client and stops the execution.
  621. //
  622. // Returns true if next handler exists and executed, otherwise false.
  623. func (ctx *Context) NextOrNotFound() bool { return ctx.NextOr() }
  624. // NextHandler returns (it doesn't execute) the next handler from the handlers chain.
  625. //
  626. // Use .Skip() to skip this handler if needed to execute the next of this returning handler.
  627. func (ctx *Context) NextHandler() Handler {
  628. if ctx.IsStopped() {
  629. return nil
  630. }
  631. nextIndex := ctx.currentHandlerIndex + 1
  632. // check if it has a next middleware
  633. if nextIndex < len(ctx.handlers) {
  634. return ctx.handlers[nextIndex]
  635. }
  636. return nil
  637. }
  638. // Skip skips/ignores the next handler from the handlers chain,
  639. // it should be used inside a middleware.
  640. func (ctx *Context) Skip() {
  641. ctx.HandlerIndex(ctx.currentHandlerIndex + 1)
  642. }
  643. const (
  644. stopExecutionIndex = -1
  645. internalPauseExecutionIndex = -2
  646. internalProceededHandlerIndex = -3
  647. )
  648. // StopExecution stops the handlers chain of this request.
  649. // Meaning that any following `Next` calls are ignored,
  650. // as a result the next handlers in the chain will not be fire.
  651. //
  652. // See ResumeExecution too.
  653. func (ctx *Context) StopExecution() {
  654. if curIdx := ctx.currentHandlerIndex; curIdx != stopExecutionIndex {
  655. // Protect against multiple calls of StopExecution.
  656. // Resume should set the last proceeded handler index.
  657. // Store the current index.
  658. ctx.proceeded = curIdx
  659. // And stop.
  660. ctx.currentHandlerIndex = stopExecutionIndex
  661. }
  662. }
  663. // IsStopped reports whether the current position of the context's handlers is -1,
  664. // means that the StopExecution() was called at least once.
  665. func (ctx *Context) IsStopped() bool {
  666. return ctx.currentHandlerIndex == stopExecutionIndex
  667. }
  668. // ResumeExecution sets the current handler index to the last
  669. // index of the executed handler before StopExecution method was fired.
  670. //
  671. // Reports whether it's restored after a StopExecution call.
  672. func (ctx *Context) ResumeExecution() bool {
  673. if ctx.IsStopped() {
  674. ctx.currentHandlerIndex = ctx.proceeded
  675. return true
  676. }
  677. return false
  678. }
  679. // StopWithStatus stops the handlers chain and writes the "statusCode".
  680. //
  681. // If the status code is a failure one then
  682. // it will also fire the specified error code handler.
  683. func (ctx *Context) StopWithStatus(statusCode int) {
  684. ctx.StopExecution()
  685. ctx.StatusCode(statusCode)
  686. }
  687. // StopWithText stops the handlers chain and writes the "statusCode"
  688. // among with a fmt-style text of "format" and optional arguments.
  689. //
  690. // If the status code is a failure one then
  691. // it will also fire the specified error code handler.
  692. func (ctx *Context) StopWithText(statusCode int, format string, args ...interface{}) {
  693. ctx.StopWithStatus(statusCode)
  694. ctx.WriteString(fmt.Sprintf(format, args...))
  695. }
  696. // StopWithError stops the handlers chain and writes the "statusCode"
  697. // among with the error "err".
  698. // It Calls the `SetErr` method so error handlers can access the given error.
  699. //
  700. // If the status code is a failure one then
  701. // it will also fire the specified error code handler.
  702. //
  703. // If the given "err" is private then the
  704. // status code's text is rendered instead (unless a registered error handler overrides it).
  705. func (ctx *Context) StopWithError(statusCode int, err error) {
  706. if err == nil {
  707. return
  708. }
  709. ctx.SetErr(err)
  710. if _, ok := err.(ErrPrivate); ok {
  711. // error is private, we SHOULD not render it,
  712. // leave the error handler alone to
  713. // render the code's text instead.
  714. ctx.StopWithStatus(statusCode)
  715. return
  716. }
  717. ctx.StopWithText(statusCode, err.Error())
  718. }
  719. // StopWithPlainError like `StopWithError` but it does NOT
  720. // write anything to the response writer, it stores the error
  721. // so any error handler matching the given "statusCode" can handle it by its own.
  722. func (ctx *Context) StopWithPlainError(statusCode int, err error) {
  723. if err == nil {
  724. return
  725. }
  726. ctx.SetErr(err)
  727. ctx.StopWithStatus(statusCode)
  728. }
  729. // StopWithJSON stops the handlers chain, writes the status code
  730. // and sends a JSON response.
  731. //
  732. // If the status code is a failure one then
  733. // it will also fire the specified error code handler.
  734. func (ctx *Context) StopWithJSON(statusCode int, jsonObject interface{}) error {
  735. ctx.StopWithStatus(statusCode)
  736. return ctx.writeJSON(jsonObject, &DefaultJSONOptions) // do not modify - see errors.DefaultContextErrorHandler.
  737. }
  738. // StopWithProblem stops the handlers chain, writes the status code
  739. // and sends an application/problem+json response.
  740. // See `iris.NewProblem` to build a "problem" value correctly.
  741. //
  742. // If the status code is a failure one then
  743. // it will also fire the specified error code handler.
  744. func (ctx *Context) StopWithProblem(statusCode int, problem Problem) error {
  745. ctx.StopWithStatus(statusCode)
  746. problem.Status(statusCode)
  747. return ctx.Problem(problem)
  748. }
  749. // +------------------------------------------------------------+
  750. // | Current "user/request" storage |
  751. // | and share information between the handlers - Values(). |
  752. // | Save and get named path parameters - Params() |
  753. // +------------------------------------------------------------+
  754. // Params returns the current url's named parameters key-value storage.
  755. // Named path parameters are being saved here.
  756. // This storage, as the whole context, is per-request lifetime.
  757. func (ctx *Context) Params() *RequestParams {
  758. return &ctx.params
  759. }
  760. // Values returns the current "user" storage.
  761. // Named path parameters and any optional data can be saved here.
  762. // This storage, as the whole context, is per-request lifetime.
  763. //
  764. // You can use this function to Set and Get local values
  765. // that can be used to share information between handlers and middleware.
  766. func (ctx *Context) Values() *memstore.Store {
  767. return &ctx.values
  768. }
  769. // +------------------------------------------------------------+
  770. // | Path, Host, Subdomain, IP, Headers etc... |
  771. // +------------------------------------------------------------+
  772. // Method returns the request.Method, the client's http method to the server.
  773. func (ctx *Context) Method() string {
  774. return ctx.request.Method
  775. }
  776. // Path returns the full request path,
  777. // escaped if EnablePathEscape config field is true.
  778. func (ctx *Context) Path() string {
  779. return ctx.RequestPath(ctx.app.ConfigurationReadOnly().GetEnablePathEscape())
  780. }
  781. // DecodeQuery returns the uri parameter as url (string)
  782. // useful when you want to pass something to a database and be valid to retrieve it via context.Param
  783. // use it only for special cases, when the default behavior doesn't suits you.
  784. //
  785. // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
  786. // it uses just the url.QueryUnescape
  787. func DecodeQuery(path string) string {
  788. if path == "" {
  789. return ""
  790. }
  791. encodedPath, err := url.QueryUnescape(path)
  792. if err != nil {
  793. return path
  794. }
  795. return encodedPath
  796. }
  797. // DecodeURL returns the decoded uri
  798. // useful when you want to pass something to a database and be valid to retrieve it via context.Param
  799. // use it only for special cases, when the default behavior doesn't suits you.
  800. //
  801. // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
  802. // it uses just the url.Parse
  803. func DecodeURL(uri string) string {
  804. u, err := url.Parse(uri)
  805. if err != nil {
  806. return uri
  807. }
  808. return u.String()
  809. }
  810. // RequestPath returns the full request path,
  811. // based on the 'escape'.
  812. func (ctx *Context) RequestPath(escape bool) string {
  813. if escape {
  814. return ctx.request.URL.EscapedPath() // DecodeQuery(ctx.request.URL.EscapedPath())
  815. }
  816. return ctx.request.URL.Path // RawPath returns empty, requesturi can be used instead also.
  817. }
  818. const sufscheme = "://"
  819. // GetScheme returns the full scheme of the request URL (https://, http:// or ws:// and e.t.c.).
  820. func GetScheme(r *http.Request) string {
  821. scheme := r.URL.Scheme
  822. if scheme == "" {
  823. if r.TLS != nil {
  824. scheme = netutil.SchemeHTTPS
  825. } else {
  826. scheme = netutil.SchemeHTTP
  827. }
  828. }
  829. return scheme + sufscheme
  830. }
  831. // Scheme returns the full scheme of the request (including :// suffix).
  832. func (ctx *Context) Scheme() string {
  833. return GetScheme(ctx.Request())
  834. }
  835. // PathPrefixMap accepts a map of string and a handler.
  836. // The key of "m" is the key, which is the prefix, regular expressions are not valid.
  837. // The value of "m" is the handler that will be executed if HasPrefix(context.Path).
  838. // func (ctx *Context) PathPrefixMap(m map[string]context.Handler) bool {
  839. // path := ctx.Path()
  840. // for k, v := range m {
  841. // if strings.HasPrefix(path, k) {
  842. // v(ctx)
  843. // return true
  844. // }
  845. // }
  846. // return false
  847. // } no, it will not work because map is a random peek data structure.
  848. // GetHost returns the host part of the current URI.
  849. func GetHost(r *http.Request) string {
  850. // contains subdomain.
  851. if host := r.URL.Host; host != "" {
  852. return host
  853. }
  854. return r.Host
  855. }
  856. // Host returns the host:port part of the request URI, calls the `Request().Host`.
  857. // To get the subdomain part as well use the `Request().URL.Host` method instead.
  858. // To get the subdomain only use the `Subdomain` method instead.
  859. // This method makes use of the `Configuration.HostProxyHeaders` field too.
  860. func (ctx *Context) Host() string {
  861. for header, ok := range ctx.app.ConfigurationReadOnly().GetHostProxyHeaders() {
  862. if !ok {
  863. continue
  864. }
  865. if host := ctx.GetHeader(header); host != "" {
  866. return host
  867. }
  868. }
  869. return GetHost(ctx.request)
  870. }
  871. // GetDomain resolves and returns the server's domain.
  872. // To customize its behavior, developers can modify this package-level function at initialization.
  873. var GetDomain = func(hostport string) string {
  874. host := hostport
  875. if tmp, _, err := net.SplitHostPort(hostport); err == nil {
  876. host = tmp
  877. }
  878. switch host {
  879. // We could use the netutil.LoopbackRegex but leave it as it's for now, it's faster.
  880. case "localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]", "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0:1":
  881. // loopback.
  882. return "localhost"
  883. default:
  884. if net.ParseIP(host) != nil { // if it's an IP, see #1945.
  885. return host
  886. }
  887. if domain, err := publicsuffix.EffectiveTLDPlusOne(host); err == nil {
  888. host = domain
  889. }
  890. return host
  891. }
  892. }
  893. // Domain returns the root level domain.
  894. func (ctx *Context) Domain() string {
  895. return GetDomain(ctx.Host())
  896. }
  897. // GetSubdomainFull returns the full subdomain level, e.g.
  898. // [test.user.]mydomain.com.
  899. func GetSubdomainFull(r *http.Request) string {
  900. host := GetHost(r) // host:port
  901. rootDomain := GetDomain(host) // mydomain.com
  902. rootDomainIdx := strings.Index(host, rootDomain)
  903. if rootDomainIdx == -1 {
  904. return ""
  905. }
  906. return host[0:rootDomainIdx]
  907. }
  908. // SubdomainFull returns the full subdomain level, e.g.
  909. // [test.user.]mydomain.com.
  910. // Note that HostProxyHeaders are being respected here.
  911. func (ctx *Context) SubdomainFull() string {
  912. host := ctx.Host() // host:port
  913. rootDomain := GetDomain(host) // mydomain.com
  914. rootDomainIdx := strings.Index(host, rootDomain)
  915. if rootDomainIdx == -1 {
  916. return ""
  917. }
  918. return host[0:rootDomainIdx]
  919. }
  920. // Subdomain returns the first subdomain of this request,
  921. // e.g. [user.]mydomain.com.
  922. // See `SubdomainFull` too.
  923. func (ctx *Context) Subdomain() (subdomain string) {
  924. host := ctx.Host()
  925. if index := strings.IndexByte(host, '.'); index > 0 {
  926. subdomain = host[0:index]
  927. }
  928. // listening on mydomain.com:80
  929. // subdomain = mydomain, but it's wrong, it should return ""
  930. vhost := ctx.app.ConfigurationReadOnly().GetVHost()
  931. if strings.Contains(vhost, subdomain) { // then it's not subdomain
  932. return ""
  933. }
  934. return
  935. }
  936. // FindClosest returns a list of "n" paths close to
  937. // this request based on subdomain and request path.
  938. //
  939. // Order may change.
  940. // Example: https://github.com/kataras/iris/tree/main/_examples/routing/intelligence/manual
  941. func (ctx *Context) FindClosest(n int) []string {
  942. return ctx.app.FindClosestPaths(ctx.Subdomain(), ctx.Path(), n)
  943. }
  944. // IsWWW returns true if the current subdomain (if any) is www.
  945. func (ctx *Context) IsWWW() bool {
  946. host := ctx.Host()
  947. if index := strings.IndexByte(host, '.'); index > 0 {
  948. // if it has a subdomain and it's www then return true.
  949. if subdomain := host[0:index]; !strings.Contains(ctx.app.ConfigurationReadOnly().GetVHost(), subdomain) {
  950. return subdomain == "www"
  951. }
  952. }
  953. return false
  954. }
  955. // FullRequestURI returns the full URI,
  956. // including the scheme, the host and the relative requested path/resource.
  957. func (ctx *Context) FullRequestURI() string {
  958. return ctx.AbsoluteURI(ctx.Path())
  959. }
  960. // RemoteAddr tries to parse and return the real client's request IP.
  961. //
  962. // Based on allowed headers names that can be modified from Configuration.RemoteAddrHeaders.
  963. //
  964. // If parse based on these headers fail then it will return the Request's `RemoteAddr` field
  965. // which is filled by the server before the HTTP handler,
  966. // unless the Configuration.RemoteAddrHeadersForce was set to true
  967. // which will force this method to return the first IP from RemoteAddrHeaders
  968. // even if it's part of a private network.
  969. //
  970. // Look `Configuration.RemoteAddrHeaders`,
  971. //
  972. // Configuration.RemoteAddrHeadersForce,
  973. // Configuration.WithRemoteAddrHeader(...),
  974. // Configuration.WithoutRemoteAddrHeader(...) and
  975. // Configuration.RemoteAddrPrivateSubnetsW for more.
  976. func (ctx *Context) RemoteAddr() string {
  977. if remoteHeaders := ctx.app.ConfigurationReadOnly().GetRemoteAddrHeaders(); len(remoteHeaders) > 0 {
  978. privateSubnets := ctx.app.ConfigurationReadOnly().GetRemoteAddrPrivateSubnets()
  979. for _, headerName := range remoteHeaders {
  980. ipAddresses := strings.Split(ctx.GetHeader(headerName), ",")
  981. if ip, ok := netutil.GetIPAddress(ipAddresses, privateSubnets); ok {
  982. return ip
  983. }
  984. }
  985. if ctx.app.ConfigurationReadOnly().GetRemoteAddrHeadersForce() {
  986. for _, headerName := range remoteHeaders {
  987. // return the first valid IP,
  988. // even if it's a part of a private network.
  989. ipAddresses := strings.Split(ctx.GetHeader(headerName), ",")
  990. for _, addr := range ipAddresses {
  991. if ip, _, err := net.SplitHostPort(addr); err == nil {
  992. return ip
  993. }
  994. }
  995. }
  996. }
  997. }
  998. addr := strings.TrimSpace(ctx.request.RemoteAddr)
  999. if addr != "" {
  1000. // if addr has port use the net.SplitHostPort otherwise(error occurs) take as it is
  1001. if ip, _, err := net.SplitHostPort(addr); err == nil {
  1002. return ip
  1003. }
  1004. }
  1005. return addr
  1006. }
  1007. // TrimHeaderValue returns the "v[0:first space or semicolon]".
  1008. func TrimHeaderValue(v string) string {
  1009. for i, char := range v {
  1010. if char == ' ' || char == ';' {
  1011. return v[:i]
  1012. }
  1013. }
  1014. return v
  1015. }
  1016. // GetHeader returns the request header's value based on its name.
  1017. func (ctx *Context) GetHeader(name string) string {
  1018. return ctx.request.Header.Get(name)
  1019. }
  1020. // IsAjax returns true if this request is an 'ajax request'( XMLHttpRequest)
  1021. //
  1022. // There is no a 100% way of knowing that a request was made via Ajax.
  1023. // You should never trust data coming from the client, they can be easily overcome by spoofing.
  1024. //
  1025. // Note that "X-Requested-With" Header can be modified by any client(because of "X-"),
  1026. // so don't rely on IsAjax for really serious stuff,
  1027. // try to find another way of detecting the type(i.e, content type),
  1028. // there are many blogs that describe these problems and provide different kind of solutions,
  1029. // it's always depending on the application you're building,
  1030. // this is the reason why this `IsAjax` is simple enough for general purpose use.
  1031. //
  1032. // Read more at: https://developer.mozilla.org/en-US/docs/AJAX
  1033. // and https://xhr.spec.whatwg.org/
  1034. func (ctx *Context) IsAjax() bool {
  1035. return ctx.GetHeader("X-Requested-With") == "XMLHttpRequest"
  1036. }
  1037. var isMobileRegex = regexp.MustCompile("(?:hpw|i|web)os|alamofire|alcatel|amoi|android|avantgo|blackberry|blazer|cell|cfnetwork|darwin|dolfin|dolphin|fennec|htc|ip(?:hone|od|ad)|ipaq|j2me|kindle|midp|minimo|mobi|motorola|nec-|netfront|nokia|opera m(ob|in)i|palm|phone|pocket|portable|psp|silk-accelerated|skyfire|sony|ucbrowser|up.browser|up.link|windows ce|xda|zte|zune")
  1038. // IsMobile checks if client is using a mobile device(phone or tablet) to communicate with this server.
  1039. // If the return value is true that means that the http client using a mobile
  1040. // device to communicate with the server, otherwise false.
  1041. //
  1042. // Keep note that this checks the "User-Agent" request header.
  1043. func (ctx *Context) IsMobile() bool {
  1044. s := strings.ToLower(ctx.GetHeader("User-Agent"))
  1045. return isMobileRegex.MatchString(s)
  1046. }
  1047. var isScriptRegex = regexp.MustCompile("curl|wget|collectd|python|urllib|java|jakarta|httpclient|phpcrawl|libwww|perl|go-http|okhttp|lua-resty|winhttp|awesomium")
  1048. // IsScript reports whether a client is a script.
  1049. func (ctx *Context) IsScript() bool {
  1050. s := strings.ToLower(ctx.GetHeader("User-Agent"))
  1051. return isScriptRegex.MatchString(s)
  1052. }
  1053. // IsSSL reports whether the client is running under HTTPS SSL.
  1054. //
  1055. // See `IsHTTP2` too.
  1056. func (ctx *Context) IsSSL() bool {
  1057. ssl := strings.EqualFold(ctx.request.URL.Scheme, "https") || ctx.request.TLS != nil
  1058. if !ssl {
  1059. for k, v := range ctx.app.ConfigurationReadOnly().GetSSLProxyHeaders() {
  1060. if ctx.GetHeader(k) == v {
  1061. ssl = true
  1062. break
  1063. }
  1064. }
  1065. }
  1066. return ssl
  1067. }
  1068. // IsHTTP2 reports whether the protocol version for incoming request was HTTP/2.
  1069. // The client code always uses either HTTP/1.1 or HTTP/2.
  1070. //
  1071. // See `IsSSL` too.
  1072. func (ctx *Context) IsHTTP2() bool {
  1073. return ctx.request.ProtoMajor == 2
  1074. }
  1075. // IsGRPC reports whether the request came from a gRPC client.
  1076. func (ctx *Context) IsGRPC() bool {
  1077. return ctx.IsHTTP2() && strings.Contains(ctx.GetContentTypeRequested(), ContentGRPCHeaderValue)
  1078. }
  1079. type (
  1080. // Referrer contains the extracted information from the `GetReferrer`
  1081. //
  1082. // The structure contains struct tags for JSON, form, XML, YAML and TOML.
  1083. // Look the `GetReferrer() Referrer` and `goreferrer` external package.
  1084. Referrer struct {
  1085. // The raw refer(r)er URL.
  1086. Raw string `json:"raw" form:"raw" xml:"Raw" yaml:"Raw" toml:"Raw"`
  1087. Type ReferrerType `json:"type" form:"referrer_type" xml:"Type" yaml:"Type" toml:"Type"`
  1088. Label string `json:"label" form:"referrer_form" xml:"Label" yaml:"Label" toml:"Label"`
  1089. URL string `json:"url" form:"referrer_url" xml:"URL" yaml:"URL" toml:"URL"`
  1090. Subdomain string `json:"subdomain" form:"referrer_subdomain" xml:"Subdomain" yaml:"Subdomain" toml:"Subdomain"`
  1091. Domain string `json:"domain" form:"referrer_domain" xml:"Domain" yaml:"Domain" toml:"Domain"`
  1092. Tld string `json:"tld" form:"referrer_tld" xml:"Tld" yaml:"Tld" toml:"Tld"`
  1093. Path string `json:"path" form:"referrer_path" xml:"Path" yaml:"Path" toml:"Path"`
  1094. Query string `json:"query" form:"referrer_query" xml:"Query" yaml:"Query" toml:"GoogleType"`
  1095. GoogleType ReferrerGoogleSearchType `json:"googleType" form:"referrer_google_type" xml:"GoogleType" yaml:"GoogleType" toml:"GoogleType"`
  1096. }
  1097. // ReferrerType is the goreferrer enum for a referrer type (indirect, direct, email, search, social).
  1098. ReferrerType = goreferrer.ReferrerType
  1099. // ReferrerGoogleSearchType is the goreferrer enum for a google search type (organic, adwords).
  1100. ReferrerGoogleSearchType = goreferrer.GoogleSearchType
  1101. )
  1102. // String returns the raw ref url.
  1103. func (ref Referrer) String() string {
  1104. return ref.Raw
  1105. }
  1106. // Contains the available values of the goreferrer enums.
  1107. const (
  1108. ReferrerInvalid ReferrerType = iota
  1109. ReferrerIndirect
  1110. ReferrerDirect
  1111. ReferrerEmail
  1112. ReferrerSearch
  1113. ReferrerSocial
  1114. ReferrerNotGoogleSearch ReferrerGoogleSearchType = iota
  1115. ReferrerGoogleOrganicSearch
  1116. ReferrerGoogleAdwords
  1117. )
  1118. // unnecessary but good to know the default values upfront.
  1119. var emptyReferrer = Referrer{Type: ReferrerInvalid, GoogleType: ReferrerNotGoogleSearch}
  1120. // GetReferrer extracts and returns the information from the "Referer" (or "Referrer") header
  1121. // and url query parameter as specified in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy.
  1122. func (ctx *Context) GetReferrer() Referrer {
  1123. // the underline net/http follows the https://tools.ietf.org/html/rfc7231#section-5.5.2,
  1124. // so there is nothing special left to do.
  1125. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  1126. refURL := ctx.GetHeader("Referer")
  1127. if refURL == "" {
  1128. refURL = ctx.GetHeader("Referrer")
  1129. if refURL == "" {
  1130. refURL = ctx.URLParam("referer")
  1131. if refURL == "" {
  1132. refURL = ctx.URLParam("referrer")
  1133. }
  1134. }
  1135. }
  1136. if refURL == "" {
  1137. return emptyReferrer
  1138. }
  1139. if ref := goreferrer.DefaultRules.Parse(refURL); ref.Type > goreferrer.Invalid {
  1140. return Referrer{
  1141. Raw: refURL,
  1142. Type: ReferrerType(ref.Type),
  1143. Label: ref.Label,
  1144. URL: ref.URL,
  1145. Subdomain: ref.Subdomain,
  1146. Domain: ref.Domain,
  1147. Tld: ref.Tld,
  1148. Path: ref.Path,
  1149. Query: ref.Query,
  1150. GoogleType: ReferrerGoogleSearchType(ref.GoogleType),
  1151. }
  1152. }
  1153. return emptyReferrer
  1154. }
  1155. // SetLanguage force-sets the language for i18n, can be used inside a middleare.
  1156. // It has the highest priority over the rest and if it is empty then it is ignored,
  1157. // if it set to a static string of "default" or to the default language's code
  1158. // then the rest of the language extractors will not be called at all and
  1159. // the default language will be set instead.
  1160. //
  1161. // See `i18n.ExtractFunc` for a more organised way of the same feature.
  1162. func (ctx *Context) SetLanguage(langCode string) {
  1163. ctx.values.Set(ctx.app.ConfigurationReadOnly().GetLanguageContextKey(), langCode)
  1164. }
  1165. // GetLocale returns the current request's `Locale` found by i18n middleware.
  1166. // It always fallbacks to the default one.
  1167. // See `Tr` too.
  1168. func (ctx *Context) GetLocale() Locale {
  1169. // Cache the Locale itself for multiple calls of `Tr` method.
  1170. contextKey := ctx.app.ConfigurationReadOnly().GetLocaleContextKey()
  1171. if v := ctx.values.Get(contextKey); v != nil {
  1172. if locale, ok := v.(Locale); ok {
  1173. return locale
  1174. }
  1175. }
  1176. if locale := ctx.app.I18nReadOnly().GetLocale(ctx); locale != nil {
  1177. ctx.values.Set(contextKey, locale)
  1178. return locale
  1179. }
  1180. return nil
  1181. }
  1182. // Tr returns a i18n localized message based on format with optional arguments.
  1183. // See `GetLocale` too.
  1184. //
  1185. // Example: https://github.com/kataras/iris/tree/main/_examples/i18n
  1186. func (ctx *Context) Tr(key string, args ...interface{}) string {
  1187. return ctx.app.I18nReadOnly().TrContext(ctx, key, args...)
  1188. }
  1189. // +------------------------------------------------------------+
  1190. // | Response Headers helpers |
  1191. // +------------------------------------------------------------+
  1192. // Header adds a header to the response, if value is empty
  1193. // it removes the header by its name.
  1194. func (ctx *Context) Header(name string, value string) {
  1195. if value == "" {
  1196. ctx.writer.Header().Del(name)
  1197. return
  1198. }
  1199. ctx.writer.Header().Add(name, value)
  1200. }
  1201. const contentTypeContextKey = "iris.content_type"
  1202. func shouldAppendCharset(cType string) bool {
  1203. if idx := strings.IndexRune(cType, '/'); idx > 1 && len(cType) > idx+1 {
  1204. typ := cType[0:idx]
  1205. if typ == "application" {
  1206. switch cType[idx+1:] {
  1207. case "json", "xml", "yaml", "problem+json", "problem+xml":
  1208. return true
  1209. default:
  1210. return false
  1211. }
  1212. }
  1213. }
  1214. return true
  1215. }
  1216. func (ctx *Context) contentTypeOnce(cType string, charset string) {
  1217. if charset == "" {
  1218. charset = ctx.app.ConfigurationReadOnly().GetCharset()
  1219. }
  1220. if shouldAppendCharset(cType) {
  1221. cType += "; charset=" + charset
  1222. }
  1223. ctx.values.Set(contentTypeContextKey, cType)
  1224. ctx.writer.Header().Set(ContentTypeHeaderKey, cType)
  1225. }
  1226. // ContentType sets the response writer's
  1227. // header "Content-Type" to the 'cType'.
  1228. func (ctx *Context) ContentType(cType string) {
  1229. if cType == "" {
  1230. return
  1231. }
  1232. if _, wroteOnce := ctx.values.GetEntry(contentTypeContextKey); wroteOnce {
  1233. return
  1234. }
  1235. // 1. if it's path or a filename or an extension,
  1236. // then take the content type from that,
  1237. // ^ No, it's not always a file,e .g. vnd.$type
  1238. // if strings.Contains(cType, ".") {
  1239. // ext := filepath.Ext(cType)
  1240. // cType = mime.TypeByExtension(ext)
  1241. // }
  1242. // if doesn't contain a charset already then append it
  1243. if shouldAppendCharset(cType) {
  1244. if !strings.Contains(cType, "charset") {
  1245. cType += "; charset=" + ctx.app.ConfigurationReadOnly().GetCharset()
  1246. }
  1247. }
  1248. ctx.writer.Header().Set(ContentTypeHeaderKey, cType)
  1249. }
  1250. // GetContentType returns the response writer's
  1251. // header value of "Content-Type".
  1252. func (ctx *Context) GetContentType() string {
  1253. return ctx.writer.Header().Get(ContentTypeHeaderKey)
  1254. }
  1255. // GetContentTypeRequested returns the request's
  1256. // trim-ed(without the charset and priority values)
  1257. // header value of "Content-Type".
  1258. func (ctx *Context) GetContentTypeRequested() string {
  1259. // could use mime.ParseMediaType too.
  1260. return TrimHeaderValue(ctx.GetHeader(ContentTypeHeaderKey))
  1261. }
  1262. // GetContentLength returns the request's
  1263. // header value of "Content-Length".
  1264. func (ctx *Context) GetContentLength() int64 {
  1265. if v := ctx.GetHeader(ContentLengthHeaderKey); v != "" {
  1266. n, _ := strconv.ParseInt(v, 10, 64)
  1267. return n
  1268. }
  1269. return 0
  1270. }
  1271. // StatusCode sets the status code header to the response.
  1272. // Look .GetStatusCode & .FireStatusCode too.
  1273. //
  1274. // Note that you must set status code before write response body (except when recorder is used).
  1275. func (ctx *Context) StatusCode(statusCode int) {
  1276. ctx.writer.WriteHeader(statusCode)
  1277. }
  1278. // NotFound emits an error 404 to the client, using the specific custom error error handler.
  1279. // Note that you may need to call ctx.StopExecution() if you don't want the next handlers
  1280. // to be executed. Next handlers are being executed on iris because you can alt the
  1281. // error code and change it to a more specific one, i.e
  1282. // users := app.Party("/users")
  1283. // users.Done(func(ctx iris.Context){ if ctx.GetStatusCode() == 400 { /* custom error code for /users */ }})
  1284. func (ctx *Context) NotFound() {
  1285. ctx.StatusCode(http.StatusNotFound)
  1286. }
  1287. // GetStatusCode returns the current status code of the response.
  1288. // Look StatusCode too.
  1289. func (ctx *Context) GetStatusCode() int {
  1290. return ctx.writer.StatusCode()
  1291. }
  1292. // +------------------------------------------------------------+
  1293. // | Various Request and Post Data |
  1294. // +------------------------------------------------------------+
  1295. func (ctx *Context) getQuery() url.Values {
  1296. if ctx.query == nil {
  1297. ctx.query = ctx.request.URL.Query()
  1298. }
  1299. return ctx.query
  1300. }
  1301. // URLParamExists returns true if the url parameter exists, otherwise false.
  1302. func (ctx *Context) URLParamExists(name string) bool {
  1303. _, exists := ctx.getQuery()[name]
  1304. return exists
  1305. }
  1306. // URLParamDefault returns the get parameter from a request, if not found then "def" is returned.
  1307. func (ctx *Context) URLParamDefault(name string, def string) string {
  1308. if v := ctx.getQuery().Get(name); v != "" {
  1309. return v
  1310. }
  1311. return def
  1312. }
  1313. // URLParam returns the get parameter from a request, if any.
  1314. func (ctx *Context) URLParam(name string) string {
  1315. return ctx.URLParamDefault(name, "")
  1316. }
  1317. // URLParamSlice a shortcut of ctx.Request().URL.Query()[name].
  1318. // Like `URLParam` but it returns all values instead of a single string separated by commas.
  1319. // Returns the values of a url query of the given "name" as string slice, e.g.
  1320. // ?names=john&names=doe&names=kataras and ?names=john,doe,kataras will return [ john doe kataras].
  1321. //
  1322. // Note that, this method skips any empty entries.
  1323. //
  1324. // See `URLParamsSorted` for sorted values.
  1325. func (ctx *Context) URLParamSlice(name string) []string {
  1326. values := ctx.getQuery()[name]
  1327. n := len(values)
  1328. if n == 0 {
  1329. return values
  1330. }
  1331. var sep string
  1332. if sepPtr := ctx.app.ConfigurationReadOnly().GetURLParamSeparator(); sepPtr != nil {
  1333. sep = *sepPtr
  1334. }
  1335. normalizedValues := make([]string, 0, n)
  1336. for _, v := range values {
  1337. if v == "" {
  1338. continue
  1339. }
  1340. if sep != "" {
  1341. values := strings.Split(v, sep)
  1342. normalizedValues = append(normalizedValues, values...)
  1343. continue
  1344. }
  1345. normalizedValues = append(normalizedValues, v)
  1346. }
  1347. return normalizedValues
  1348. }
  1349. // URLParamTrim returns the url query parameter with trailing white spaces removed from a request.
  1350. func (ctx *Context) URLParamTrim(name string) string {
  1351. return strings.TrimSpace(ctx.URLParam(name))
  1352. }
  1353. // URLParamEscape returns the escaped url query parameter from a request.
  1354. func (ctx *Context) URLParamEscape(name string) string {
  1355. return DecodeQuery(ctx.URLParam(name))
  1356. }
  1357. // ErrNotFound is the type error which API users can make use of
  1358. // to check if a `Context` action of a `Handler` is type of Not Found,
  1359. // e.g. URL Query Parameters.
  1360. // Example:
  1361. //
  1362. // n, err := context.URLParamInt("url_query_param_name")
  1363. //
  1364. // if errors.Is(err, context.ErrNotFound) {
  1365. // // [handle error...]
  1366. // }
  1367. //
  1368. // Another usage would be `err == context.ErrNotFound`
  1369. // HOWEVER prefer use the new `errors.Is` as API details may change in the future.
  1370. var ErrNotFound = errors.New("not found")
  1371. // URLParamInt returns the url query parameter as int value from a request,
  1372. // returns -1 and an error if parse failed or not found.
  1373. func (ctx *Context) URLParamInt(name string) (int, error) {
  1374. if v := ctx.URLParam(name); v != "" {
  1375. n, err := strconv.Atoi(v)
  1376. if err != nil {
  1377. return -1, err
  1378. }
  1379. return n, nil
  1380. }
  1381. return -1, ErrNotFound
  1382. }
  1383. // URLParamIntDefault returns the url query parameter as int value from a request,
  1384. // if not found or parse failed then "def" is returned.
  1385. func (ctx *Context) URLParamIntDefault(name string, def int) int {
  1386. v, err := ctx.URLParamInt(name)
  1387. if err != nil {
  1388. return def
  1389. }
  1390. return v
  1391. }
  1392. // URLParamInt32Default returns the url query parameter as int32 value from a request,
  1393. // if not found or parse failed then "def" is returned.
  1394. func (ctx *Context) URLParamInt32Default(name string, def int32) int32 {
  1395. if v := ctx.URLParam(name); v != "" {
  1396. n, err := strconv.ParseInt(v, 10, 32)
  1397. if err != nil {
  1398. return def
  1399. }
  1400. return int32(n)
  1401. }
  1402. return def
  1403. }
  1404. // URLParamInt64 returns the url query parameter as int64 value from a request,
  1405. // returns -1 and an error if parse failed or not found.
  1406. func (ctx *Context) URLParamInt64(name string) (int64, error) {
  1407. if v := ctx.URLParam(name); v != "" {
  1408. n, err := strconv.ParseInt(v, 10, 64)
  1409. if err != nil {
  1410. return -1, err
  1411. }
  1412. return n, nil
  1413. }
  1414. return -1, ErrNotFound
  1415. }
  1416. // URLParamInt64Default returns the url query parameter as int64 value from a request,
  1417. // if not found or parse failed then "def" is returned.
  1418. func (ctx *Context) URLParamInt64Default(name string, def int64) int64 {
  1419. v, err := ctx.URLParamInt64(name)
  1420. if err != nil {
  1421. return def
  1422. }
  1423. return v
  1424. }
  1425. // URLParamUint64 returns the url query parameter as uint64 value from a request.
  1426. // Returns 0 on parse errors or when the URL parameter does not exist in the Query.
  1427. func (ctx *Context) URLParamUint64(name string) uint64 {
  1428. if v := ctx.URLParam(name); v != "" {
  1429. n, err := strconv.ParseUint(v, 10, 64)
  1430. if err != nil {
  1431. return 0
  1432. }
  1433. return n
  1434. }
  1435. return 0
  1436. }
  1437. // URLParamFloat64 returns the url query parameter as float64 value from a request,
  1438. // returns an error and -1 if parse failed.
  1439. func (ctx *Context) URLParamFloat64(name string) (float64, error) {
  1440. if v := ctx.URLParam(name); v != "" {
  1441. n, err := strconv.ParseFloat(v, 64)
  1442. if err != nil {
  1443. return -1, err
  1444. }
  1445. return n, nil
  1446. }
  1447. return -1, ErrNotFound
  1448. }
  1449. // URLParamFloat64Default returns the url query parameter as float64 value from a request,
  1450. // if not found or parse failed then "def" is returned.
  1451. func (ctx *Context) URLParamFloat64Default(name string, def float64) float64 {
  1452. v, err := ctx.URLParamFloat64(name)
  1453. if err != nil {
  1454. return def
  1455. }
  1456. return v
  1457. }
  1458. // URLParamBool returns the url query parameter as boolean value from a request,
  1459. // returns an error if parse failed.
  1460. func (ctx *Context) URLParamBool(name string) (bool, error) {
  1461. return strconv.ParseBool(ctx.URLParam(name))
  1462. }
  1463. // URLParamBoolDefault returns the url query parameter as boolean value from a request,
  1464. // if not found or parse failed then "def" is returned.
  1465. func (ctx *Context) URLParamBoolDefault(name string, def bool) bool {
  1466. v, err := ctx.URLParamBool(name)
  1467. if err != nil {
  1468. return def
  1469. }
  1470. return v
  1471. }
  1472. // URLParams returns a map of URL Query parameters.
  1473. // If the value of a URL parameter is a slice,
  1474. // then it is joined as one separated by comma.
  1475. // It returns an empty map on empty URL query.
  1476. //
  1477. // See URLParamsSorted too.
  1478. func (ctx *Context) URLParams() map[string]string {
  1479. q := ctx.getQuery()
  1480. values := make(map[string]string, len(q))
  1481. for k, v := range q {
  1482. values[k] = strings.Join(v, ",")
  1483. }
  1484. return values
  1485. }
  1486. // URLParamsSorted returns a sorted (by key) slice
  1487. // of key-value entries of the URL Query parameters.
  1488. func (ctx *Context) URLParamsSorted() []memstore.StringEntry {
  1489. q := ctx.getQuery()
  1490. n := len(q)
  1491. if n == 0 {
  1492. return nil
  1493. }
  1494. keys := make([]string, 0, n)
  1495. for key := range q {
  1496. keys = append(keys, key)
  1497. }
  1498. sort.Strings(keys)
  1499. entries := make([]memstore.StringEntry, 0, n)
  1500. for _, key := range keys {
  1501. value := q[key]
  1502. entries = append(entries, memstore.StringEntry{
  1503. Key: key,
  1504. Value: strings.Join(value, ","),
  1505. })
  1506. }
  1507. return entries
  1508. }
  1509. // ResetQuery clears the GET URL Query request, temporary, cache.
  1510. // Any new URLParamXXX calls will receive the new parsed values.
  1511. func (ctx *Context) ResetQuery() {
  1512. ctx.query = nil
  1513. }
  1514. // No need anymore, net/http checks for the Form already.
  1515. // func (ctx *Context) askParseForm() error {
  1516. // if ctx.request.Form == nil {
  1517. // if err := ctx.request.ParseForm(); err != nil {
  1518. // return err
  1519. // }
  1520. // }
  1521. // return nil
  1522. // }
  1523. // FormValueDefault returns a single parsed form value by its "name",
  1524. // including both the URL field's query parameters and the POST or PUT form data.
  1525. //
  1526. // Returns the "def" if not found.
  1527. func (ctx *Context) FormValueDefault(name string, def string) string {
  1528. if form, has := ctx.form(); has {
  1529. if v := form[name]; len(v) > 0 {
  1530. return v[0]
  1531. }
  1532. }
  1533. return def
  1534. }
  1535. // FormValueDefault retruns a single parsed form value.
  1536. func FormValueDefault(r *http.Request, name string, def string, postMaxMemory int64, resetBody bool) string {
  1537. if form, has := GetForm(r, postMaxMemory, resetBody); has {
  1538. if v := form[name]; len(v) > 0 {
  1539. return v[0]
  1540. }
  1541. }
  1542. return def
  1543. }
  1544. // FormValue returns a single parsed form value by its "name",
  1545. // including both the URL field's query parameters and the POST or PUT form data.
  1546. func (ctx *Context) FormValue(name string) string {
  1547. return ctx.FormValueDefault(name, "")
  1548. }
  1549. // FormValues returns the parsed form data, including both the URL
  1550. // field's query parameters and the POST or PUT form data.
  1551. //
  1552. // The default form's memory maximum size is 32MB, it can be changed by the
  1553. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  1554. // NOTE: A check for nil is necessary.
  1555. func (ctx *Context) FormValues() map[string][]string {
  1556. form, _ := ctx.form()
  1557. return form
  1558. }
  1559. // Form contains the parsed form data, including both the URL
  1560. // field's query parameters and the POST or PUT form data.
  1561. func (ctx *Context) form() (form map[string][]string, found bool) {
  1562. return GetForm(ctx.request, ctx.app.ConfigurationReadOnly().GetPostMaxMemory(), ctx.app.ConfigurationReadOnly().GetDisableBodyConsumptionOnUnmarshal())
  1563. }
  1564. // GetForm returns the request form (url queries, post or multipart) values.
  1565. func GetForm(r *http.Request, postMaxMemory int64, resetBody bool) (form map[string][]string, found bool) {
  1566. /*
  1567. net/http/request.go#1219
  1568. for k, v := range f.Value {
  1569. r.Form[k] = append(r.Form[k], v...)
  1570. // r.PostForm should also be populated. See Issue 9305.
  1571. r.PostForm[k] = append(r.PostForm[k], v...)
  1572. }
  1573. */
  1574. if form := r.Form; len(form) > 0 {
  1575. return form, true
  1576. }
  1577. if form := r.PostForm; len(form) > 0 {
  1578. return form, true
  1579. }
  1580. if m := r.MultipartForm; m != nil {
  1581. if len(m.Value) > 0 {
  1582. return m.Value, true
  1583. }
  1584. }
  1585. if resetBody {
  1586. // on POST, PUT and PATCH it will read the form values from request body otherwise from URL queries.
  1587. if m := r.Method; m == "POST" || m == "PUT" || m == "PATCH" {
  1588. body, restoreBody, err := GetBody(r, resetBody)
  1589. if err != nil {
  1590. return nil, false
  1591. }
  1592. setBody(r, body) // so the ctx.request.Body works
  1593. defer restoreBody() // so the next GetForm calls work.
  1594. // r.Body = io.NopCloser(io.TeeReader(r.Body, buf))
  1595. } else {
  1596. resetBody = false
  1597. }
  1598. }
  1599. // ParseMultipartForm calls `request.ParseForm` automatically
  1600. // therefore we don't need to call it here, although it doesn't hurt.
  1601. // After one call to ParseMultipartForm or ParseForm,
  1602. // subsequent calls have no effect, are idempotent.
  1603. err := r.ParseMultipartForm(postMaxMemory)
  1604. // if resetBody {
  1605. // r.Body = io.NopCloser(bytes.NewBuffer(bodyCopy))
  1606. // }
  1607. if err != nil && err != http.ErrNotMultipart {
  1608. return nil, false
  1609. }
  1610. if form := r.Form; len(form) > 0 {
  1611. return form, true
  1612. }
  1613. if form := r.PostForm; len(form) > 0 {
  1614. return form, true
  1615. }
  1616. if m := r.MultipartForm; m != nil {
  1617. if len(m.Value) > 0 {
  1618. return m.Value, true
  1619. }
  1620. }
  1621. return nil, false
  1622. }
  1623. // PostValues returns all the parsed form data from POST, PATCH,
  1624. // or PUT body parameters based on a "name" as a string slice.
  1625. //
  1626. // The default form's memory maximum size is 32MB, it can be changed by the
  1627. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  1628. //
  1629. // In addition, it reports whether the form was empty
  1630. // or when the "name" does not exist
  1631. // or whether the available values are empty.
  1632. // It strips any empty key-values from the slice before return.
  1633. //
  1634. // Look ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1635. // See `PostValueMany` method too.
  1636. func (ctx *Context) PostValues(name string) ([]string, error) {
  1637. _, ok := ctx.form()
  1638. if !ok {
  1639. if !ctx.app.ConfigurationReadOnly().GetFireEmptyFormError() {
  1640. return nil, nil
  1641. }
  1642. return nil, ErrEmptyForm // empty form.
  1643. }
  1644. values, ok := ctx.request.PostForm[name]
  1645. if !ok {
  1646. return nil, ErrNotFound // field does not exist
  1647. }
  1648. if len(values) == 0 ||
  1649. // Fast check for its first empty value (see below).
  1650. strings.TrimSpace(values[0]) == "" {
  1651. return nil, fmt.Errorf("%w: %s", ErrEmptyFormField, name)
  1652. }
  1653. for _, value := range values {
  1654. if value == "" { // if at least one empty value, then perform the strip from the beginning.
  1655. result := make([]string, 0, len(values))
  1656. for _, value := range values {
  1657. if strings.TrimSpace(value) != "" {
  1658. result = append(result, value) // we store the value as it is, not space-trimmed.
  1659. }
  1660. }
  1661. if len(result) == 0 {
  1662. return nil, fmt.Errorf("%w: %s", ErrEmptyFormField, name)
  1663. }
  1664. return result, nil
  1665. }
  1666. }
  1667. return values, nil
  1668. }
  1669. // PostValueMany is like `PostValues` method, it returns the post data of a given key.
  1670. // In addition to `PostValues` though, the returned value is a single string
  1671. // separated by commas on multiple values.
  1672. //
  1673. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1674. func (ctx *Context) PostValueMany(name string) (string, error) {
  1675. values, err := ctx.PostValues(name)
  1676. if err != nil || len(values) == 0 {
  1677. return "", err
  1678. }
  1679. return strings.Join(values, ","), nil
  1680. }
  1681. // PostValueDefault returns the last parsed form data from POST, PATCH,
  1682. // or PUT body parameters based on a "name".
  1683. //
  1684. // If not found then "def" is returned instead.
  1685. func (ctx *Context) PostValueDefault(name string, def string) string {
  1686. values, err := ctx.PostValues(name)
  1687. if err != nil || len(values) == 0 {
  1688. return def // it returns "def" even if it's empty here.
  1689. }
  1690. return values[len(values)-1]
  1691. }
  1692. // PostValueString same as `PostValue` method but it reports
  1693. // an error if the value with key equals to "name" does not exist.
  1694. func (ctx *Context) PostValueString(name string) (string, error) {
  1695. values, err := ctx.PostValues(name)
  1696. if err != nil {
  1697. return "", err
  1698. }
  1699. if len(values) == 0 { // just in case.
  1700. return "", ErrEmptyForm
  1701. }
  1702. return values[len(values)-1], nil
  1703. }
  1704. // PostValue returns the last parsed form data from POST, PATCH,
  1705. // or PUT body parameters based on a "name".
  1706. //
  1707. // See `PostValueMany` too.
  1708. func (ctx *Context) PostValue(name string) string {
  1709. return ctx.PostValueDefault(name, "")
  1710. }
  1711. // PostValueTrim returns the last parsed form data from POST, PATCH,
  1712. // or PUT body parameters based on a "name", without trailing spaces.
  1713. func (ctx *Context) PostValueTrim(name string) string {
  1714. return strings.TrimSpace(ctx.PostValue(name))
  1715. }
  1716. // PostValueUint returns the last parsed form data matches the given "name" key
  1717. // from POST, PATCH, or PUT body request parameters as unassigned number.
  1718. //
  1719. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1720. func (ctx *Context) PostValueUint(name string) (uint, error) {
  1721. value, err := ctx.PostValueString(name)
  1722. if err != nil {
  1723. return 0, err
  1724. }
  1725. return strParseUint(value)
  1726. }
  1727. // PostValueUint returns the last parsed form data matches the given "name" key
  1728. // from POST, PATCH, or PUT body request parameters as unassigned number.
  1729. //
  1730. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1731. func (ctx *Context) PostValueUint8(name string) (uint8, error) {
  1732. value, err := ctx.PostValueString(name)
  1733. if err != nil {
  1734. return 0, err
  1735. }
  1736. return strParseUint8(value)
  1737. }
  1738. // PostValueUint returns the last parsed form data matches the given "name" key
  1739. // from POST, PATCH, or PUT body request parameters as unassigned number.
  1740. //
  1741. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1742. func (ctx *Context) PostValueUint16(name string) (uint16, error) {
  1743. value, err := ctx.PostValueString(name)
  1744. if err != nil {
  1745. return 0, err
  1746. }
  1747. return strParseUint16(value)
  1748. }
  1749. // PostValueUint returns the last parsed form data matches the given "name" key
  1750. // from POST, PATCH, or PUT body request parameters as unassigned number.
  1751. //
  1752. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1753. func (ctx *Context) PostValueUint32(name string) (uint32, error) {
  1754. value, err := ctx.PostValueString(name)
  1755. if err != nil {
  1756. return 0, err
  1757. }
  1758. return strParseUint32(value)
  1759. }
  1760. // PostValueUint returns the last parsed form data matches the given "name" key
  1761. // from POST, PATCH, or PUT body request parameters as unassigned number.
  1762. //
  1763. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1764. func (ctx *Context) PostValueUint64(name string) (uint64, error) {
  1765. value, err := ctx.PostValueString(name)
  1766. if err != nil {
  1767. return 0, err
  1768. }
  1769. return strParseUint64(value)
  1770. }
  1771. // PostValueInt returns the last parsed form data matches the given "name" key
  1772. // from POST, PATCH, or PUT body request parameters as signed number.
  1773. //
  1774. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1775. func (ctx *Context) PostValueInt(name string) (int, error) {
  1776. value, err := ctx.PostValueString(name)
  1777. if err != nil {
  1778. return 0, err
  1779. }
  1780. return strParseInt(value)
  1781. }
  1782. // PostValueIntDefault same as PostValueInt but if errored it returns
  1783. // the given "def" default value.
  1784. func (ctx *Context) PostValueIntDefault(name string, def int) int {
  1785. value, err := ctx.PostValueInt(name)
  1786. if err != nil {
  1787. return def
  1788. }
  1789. return value
  1790. }
  1791. // PostValueInt8 returns the last parsed form data matches the given "name" key
  1792. // from POST, PATCH, or PUT body request parameters as int8.
  1793. //
  1794. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1795. func (ctx *Context) PostValueInt8(name string) (int8, error) {
  1796. value, err := ctx.PostValueString(name)
  1797. if err != nil {
  1798. return 0, err
  1799. }
  1800. return strParseInt8(value)
  1801. }
  1802. // PostValueInt8Default same as PostValueInt8 but if errored it returns
  1803. // the given "def" default value.
  1804. func (ctx *Context) PostValueInt8Default(name string, def int8) int8 {
  1805. value, err := ctx.PostValueInt8(name)
  1806. if err != nil {
  1807. return def
  1808. }
  1809. return value
  1810. }
  1811. // PostValueInt16 returns the last parsed form data matches the given "name" key
  1812. // from POST, PATCH, or PUT body request parameters as int16.
  1813. //
  1814. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1815. func (ctx *Context) PostValueInt16(name string) (int16, error) {
  1816. value, err := ctx.PostValueString(name)
  1817. if err != nil {
  1818. return 0, err
  1819. }
  1820. return strParseInt16(value)
  1821. }
  1822. // PostValueInt16Default same as PostValueInt16 but if errored it returns
  1823. // the given "def" default value.
  1824. func (ctx *Context) PostValueInt16Default(name string, def int16) int16 {
  1825. value, err := ctx.PostValueInt16(name)
  1826. if err != nil {
  1827. return def
  1828. }
  1829. return value
  1830. }
  1831. // PostValueInt32 returns the last parsed form data matches the given "name" key
  1832. // from POST, PATCH, or PUT body request parameters as int32.
  1833. //
  1834. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1835. func (ctx *Context) PostValueInt32(name string) (int32, error) {
  1836. value, err := ctx.PostValueString(name)
  1837. if err != nil {
  1838. return 0, err
  1839. }
  1840. return strParseInt32(value)
  1841. }
  1842. // PostValueInt32Default same as PostValueInt32 but if errored it returns
  1843. // the given "def" default value.
  1844. func (ctx *Context) PostValueInt32Default(name string, def int32) int32 {
  1845. value, err := ctx.PostValueInt32(name)
  1846. if err != nil {
  1847. return def
  1848. }
  1849. return value
  1850. }
  1851. // PostValueInt64 returns the last parsed form data matches the given "name" key
  1852. // from POST, PATCH, or PUT body request parameters as int64.
  1853. //
  1854. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1855. func (ctx *Context) PostValueInt64(name string) (int64, error) {
  1856. value, err := ctx.PostValueString(name)
  1857. if err != nil {
  1858. return 0, err
  1859. }
  1860. return strParseInt64(value)
  1861. }
  1862. // PostValueInt64Default same as PostValueInt64 but if errored it returns
  1863. // the given "def" default value.
  1864. func (ctx *Context) PostValueInt64Default(name string, def int64) int64 {
  1865. value, err := ctx.PostValueInt64(name)
  1866. if err != nil {
  1867. return def
  1868. }
  1869. return value
  1870. }
  1871. // PostValueFloat32 returns the last parsed form data matches the given "name" key
  1872. // from POST, PATCH, or PUT body request parameters as float32.
  1873. //
  1874. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1875. func (ctx *Context) PostValueFloat32(name string) (float32, error) {
  1876. value, err := ctx.PostValueString(name)
  1877. if err != nil {
  1878. return 0, err
  1879. }
  1880. return strParseFloat32(value)
  1881. }
  1882. // PostValueFloat32Default same as PostValueFloat32 but if errored it returns
  1883. // the given "def" default value.
  1884. func (ctx *Context) PostValueFloat32Default(name string, def float32) float32 {
  1885. value, err := ctx.PostValueFloat32(name)
  1886. if err != nil {
  1887. return def
  1888. }
  1889. return value
  1890. }
  1891. // PostValueFloat64 returns the last parsed form data matches the given "name" key
  1892. // from POST, PATCH, or PUT body request parameters as float64.
  1893. //
  1894. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1895. func (ctx *Context) PostValueFloat64(name string) (float64, error) {
  1896. value, err := ctx.PostValueString(name)
  1897. if err != nil {
  1898. return 0, err
  1899. }
  1900. return strParseFloat64(value)
  1901. }
  1902. // PostValueFloat64Default same as PostValueFloat64 but if errored it returns
  1903. // the given "def" default value.
  1904. func (ctx *Context) PostValueFloat64Default(name string, def float64) float64 {
  1905. value, err := ctx.PostValueFloat64(name)
  1906. if err != nil {
  1907. return def
  1908. }
  1909. return value
  1910. }
  1911. // PostValueComplex64 returns the last parsed form data matches the given "name" key
  1912. // from POST, PATCH, or PUT body request parameters as complex64.
  1913. //
  1914. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1915. func (ctx *Context) PostValueComplex64(name string) (complex64, error) {
  1916. value, err := ctx.PostValueString(name)
  1917. if err != nil {
  1918. return 0, err
  1919. }
  1920. return strParseComplex64(value)
  1921. }
  1922. // PostValueComplex64Default same as PostValueComplex64 but if errored it returns
  1923. // the given "def" default value.
  1924. func (ctx *Context) PostValueComplex64Default(name string, def complex64) complex64 {
  1925. value, err := ctx.PostValueComplex64(name)
  1926. if err != nil {
  1927. return def
  1928. }
  1929. return value
  1930. }
  1931. // PostValueComplex128 returns the last parsed form data matches the given "name" key
  1932. // from POST, PATCH, or PUT body request parameters as complex128.
  1933. //
  1934. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1935. func (ctx *Context) PostValueComplex128(name string) (complex128, error) {
  1936. value, err := ctx.PostValueString(name)
  1937. if err != nil {
  1938. return 0, err
  1939. }
  1940. return strParseComplex128(value)
  1941. }
  1942. // PostValueComplex128Default same as PostValueComplex128 but if errored it returns
  1943. // the given "def" default value.
  1944. func (ctx *Context) PostValueComplex128Default(name string, def complex128) complex128 {
  1945. value, err := ctx.PostValueComplex128(name)
  1946. if err != nil {
  1947. return def
  1948. }
  1949. return value
  1950. }
  1951. // PostValueBool returns the last parsed form data matches the given "name" key
  1952. // from POST, PATCH, or PUT body request parameters as bool.
  1953. //
  1954. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1955. func (ctx *Context) PostValueBool(name string) (bool, error) {
  1956. value, err := ctx.PostValueString(name)
  1957. if err != nil {
  1958. return false, err
  1959. }
  1960. return strParseBool(value)
  1961. }
  1962. // PostValueWeekday returns the last parsed form data matches the given "name" key
  1963. // from POST, PATCH, or PUT body request parameters as time.Weekday.
  1964. //
  1965. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1966. func (ctx *Context) PostValueWeekday(name string) (time.Weekday, error) {
  1967. value, err := ctx.PostValueString(name)
  1968. if err != nil {
  1969. return 0, err
  1970. }
  1971. return strParseWeekday(value)
  1972. }
  1973. // PostValueTime returns the last parsed form data matches the given "name" key
  1974. // from POST, PATCH, or PUT body request parameters as time.Time with the given "layout".
  1975. //
  1976. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1977. func (ctx *Context) PostValueTime(layout, name string) (time.Time, error) {
  1978. value, err := ctx.PostValueString(name)
  1979. if err != nil {
  1980. return time.Time{}, err
  1981. }
  1982. return strParseTime(layout, value)
  1983. }
  1984. // PostValueSimpleDate returns the last parsed form data matches the given "name" key
  1985. // from POST, PATCH, or PUT body request parameters as time.Time with "2006/01/02"
  1986. // or "2006-01-02" time layout.
  1987. //
  1988. // See ErrEmptyForm, ErrNotFound and ErrEmptyFormField respectfully.
  1989. func (ctx *Context) PostValueSimpleDate(name string) (time.Time, error) {
  1990. value, err := ctx.PostValueString(name)
  1991. if err != nil {
  1992. return time.Time{}, err
  1993. }
  1994. return strParseSimpleDate(value)
  1995. }
  1996. // FormFile returns the first uploaded file that received from the client.
  1997. //
  1998. // The default form's memory maximum size is 32MB, it can be changed by the
  1999. // `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
  2000. //
  2001. // Example: https://github.com/kataras/iris/tree/main/_examples/file-server/upload-file
  2002. func (ctx *Context) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
  2003. // we don't have access to see if the request is body stream
  2004. // and then the ParseMultipartForm can be useless
  2005. // here but do it in order to apply the post limit,
  2006. // the internal request.FormFile will not do it if that's filled
  2007. // and it's not a stream body.
  2008. if err := ctx.request.ParseMultipartForm(ctx.app.ConfigurationReadOnly().GetPostMaxMemory()); err != nil {
  2009. return nil, nil, err
  2010. }
  2011. return ctx.request.FormFile(key)
  2012. }
  2013. // FormFiles same as FormFile but may return multiple file inputs based on a key, e.g. "files[]".
  2014. func (ctx *Context) FormFiles(key string, before ...func(*Context, *multipart.FileHeader) bool) (files []multipart.File, headers []*multipart.FileHeader, err error) {
  2015. err = ctx.request.ParseMultipartForm(ctx.app.ConfigurationReadOnly().GetPostMaxMemory())
  2016. if err != nil {
  2017. return
  2018. }
  2019. if ctx.request.MultipartForm != nil {
  2020. fhs := ctx.request.MultipartForm.File
  2021. if n := len(fhs); n > 0 {
  2022. files = make([]multipart.File, 0, n)
  2023. headers = make([]*multipart.FileHeader, 0, n)
  2024. innerLoop:
  2025. for _, header := range fhs[key] {
  2026. header.Filename = filepath.Base(header.Filename)
  2027. for _, b := range before {
  2028. if !b(ctx, header) {
  2029. continue innerLoop
  2030. }
  2031. }
  2032. file, fErr := header.Open()
  2033. if fErr != nil { // exit on first error but return the succeed.
  2034. return files, headers, fErr
  2035. }
  2036. files = append(files, file)
  2037. headers = append(headers, header)
  2038. }
  2039. }
  2040. return
  2041. }
  2042. return nil, nil, http.ErrMissingFile
  2043. }
  2044. var (
  2045. // ValidFileNameRegexp is used to validate the user input by using a regular expression.
  2046. // See `Context.UploadFormFiles` method.
  2047. ValidFilenameRegexp = regexp.MustCompile(`^[a-zA-Z0-9_\-\.]+$`)
  2048. // ValidExtensionRegexp acts as an allowlist of valid extensions. It's optional. Defaults to nil (all file extensions are allowed to be uploaded).
  2049. // See `Context.UploadFormFiles` method.
  2050. ValidExtensionRegexp *regexp.Regexp
  2051. )
  2052. // UploadFormFiles uploads any received file(s) from the client
  2053. // to the system physical location "destDirectory".
  2054. //
  2055. // The second optional argument "before" gives caller the chance to
  2056. // modify or cancel the *miltipart.FileHeader before saving to the disk,
  2057. // it can be used to change a file's name based on the current request,
  2058. // all FileHeader's options can be changed. You can ignore it if
  2059. // you don't need to use this capability before saving a file to the disk.
  2060. //
  2061. // Note that it doesn't check if request body streamed.
  2062. //
  2063. // Returns the copied length as int64 and
  2064. // a not nil error if at least one new file
  2065. // can't be created due to the operating system's permissions or
  2066. // http.ErrMissingFile if no file received.
  2067. //
  2068. // If you want to receive & accept files and manage them manually you can use the `context#FormFile`
  2069. // instead and create a copy function that suits your needs or use the `SaveFormFile` method,
  2070. // the below is for generic usage.
  2071. //
  2072. // The default form's memory maximum size is 32MB, it can be changed by
  2073. // the `WithPostMaxMemory` configurator or by `SetMaxRequestBodySize` or
  2074. // by the `LimitRequestBodySize` middleware (depends the use case).
  2075. //
  2076. // See `FormFile` and `FormFiles` to a more controlled way to receive a file.
  2077. //
  2078. // Example: https://github.com/kataras/iris/tree/main/_examples/file-server/upload-files
  2079. func (ctx *Context) UploadFormFiles(destDirectory string, before ...func(*Context, *multipart.FileHeader) bool) (uploaded []*multipart.FileHeader, n int64, err error) {
  2080. err = ctx.request.ParseMultipartForm(ctx.app.ConfigurationReadOnly().GetPostMaxMemory())
  2081. if err != nil {
  2082. return nil, 0, err
  2083. }
  2084. if ctx.request.MultipartForm != nil {
  2085. if fhs := ctx.request.MultipartForm.File; fhs != nil {
  2086. for _, files := range fhs {
  2087. innerLoop:
  2088. for _, file := range files {
  2089. for _, b := range before {
  2090. if !b(ctx, file) {
  2091. continue innerLoop
  2092. }
  2093. }
  2094. // Security fix for go < 1.17.5:
  2095. // Reported by Kirill Efimov (snyk.io) through security reports.
  2096. filename := filepath.Base(filepath.ToSlash(file.Filename))
  2097. // CWE-99.
  2098. // Sanitize the user input by using a regular expression
  2099. // and an allowlist of valid extensions
  2100. isValidFilename := ValidFilenameRegexp.MatchString(filename)
  2101. if !isValidFilename {
  2102. // Reject the input as it is invalid or unsafe.
  2103. continue innerLoop
  2104. }
  2105. if ValidExtensionRegexp != nil && !ValidExtensionRegexp.MatchString(filename) {
  2106. // Reject the input as it is invalid or unsafe.
  2107. continue innerLoop
  2108. }
  2109. // Join the sanitized input with the destination directory.
  2110. destPath := filepath.Join(destDirectory, filename)
  2111. // Get the canonical path of the destination
  2112. // canonicalDestPath, err := filepath.EvalSymlinks(destPath)
  2113. // if err != nil {
  2114. // return nil, 0, fmt.Errorf("dest path: %s: eval symlinks: %w", destPath, err)
  2115. // }
  2116. // ^ No, it will try to find the file before uploaded.
  2117. // Get the canonical path of the destination directory.
  2118. canonicalDestDir, err := filepath.EvalSymlinks(destDirectory) // the destDirectory should exists.
  2119. if err != nil {
  2120. return nil, 0, fmt.Errorf("dest directory: %s: eval symlinks: %w", destDirectory, err)
  2121. }
  2122. // Check if the destination path is within the destination directory.
  2123. if !strings.HasPrefix(destPath, canonicalDestDir) {
  2124. // Reject the input as it is a path traversal attempt.
  2125. continue innerLoop
  2126. }
  2127. file.Filename = filename
  2128. n0, err0 := ctx.SaveFormFile(file, destPath)
  2129. if err0 != nil {
  2130. return nil, 0, err0
  2131. }
  2132. n += n0
  2133. uploaded = append(uploaded, file)
  2134. }
  2135. }
  2136. return uploaded, n, nil
  2137. }
  2138. }
  2139. return nil, 0, http.ErrMissingFile
  2140. }
  2141. // SaveFormFile saves a result of `FormFile` to the "dest" disk full path (directory + filename).
  2142. // See `FormFile` and `UploadFormFiles` too.
  2143. func (ctx *Context) SaveFormFile(fh *multipart.FileHeader, dest string) (int64, error) {
  2144. src, err := fh.Open()
  2145. if err != nil {
  2146. return 0, err
  2147. }
  2148. defer src.Close()
  2149. out, err := os.Create(dest)
  2150. if err != nil {
  2151. return 0, err
  2152. }
  2153. defer out.Close()
  2154. return io.Copy(out, src)
  2155. }
  2156. // AbsoluteURI parses the "s" and returns its absolute URI form.
  2157. func (ctx *Context) AbsoluteURI(s string) string {
  2158. if s == "" {
  2159. return ""
  2160. }
  2161. userInfo := ""
  2162. if s[0] == '@' {
  2163. endUserInfoIdx := strings.IndexByte(s, '/')
  2164. if endUserInfoIdx > 0 && len(s) > endUserInfoIdx {
  2165. userInfo = s[1:endUserInfoIdx] + "@"
  2166. s = s[endUserInfoIdx:]
  2167. }
  2168. }
  2169. if s[0] == '/' {
  2170. scheme := ctx.request.URL.Scheme
  2171. if scheme == "" {
  2172. if ctx.request.TLS != nil {
  2173. scheme = "https:"
  2174. } else {
  2175. scheme = "http:"
  2176. }
  2177. }
  2178. host := ctx.Host()
  2179. return scheme + "//" + userInfo + host + path.Clean(s)
  2180. }
  2181. if u, err := url.Parse(s); err == nil {
  2182. r := ctx.request
  2183. if u.Scheme == "" && u.Host == "" {
  2184. oldpath := r.URL.Path
  2185. if oldpath == "" {
  2186. oldpath = "/"
  2187. }
  2188. if s == "" || s[0] != '/' {
  2189. olddir, _ := path.Split(oldpath)
  2190. s = olddir + s
  2191. }
  2192. var query string
  2193. if i := strings.Index(s, "?"); i != -1 {
  2194. s, query = s[:i], s[i:]
  2195. }
  2196. // clean up but preserve trailing slash
  2197. trailing := strings.HasSuffix(s, "/")
  2198. s = path.Clean(s)
  2199. if trailing && !strings.HasSuffix(s, "/") {
  2200. s += "/"
  2201. }
  2202. s += query
  2203. }
  2204. }
  2205. return s
  2206. }
  2207. // Redirect sends a redirect response to the client
  2208. // of an absolute or relative target URL.
  2209. // It accepts 2 input arguments, a string and an optional integer.
  2210. // The first parameter is the target url to redirect.
  2211. // The second one is the HTTP status code should be sent
  2212. // among redirection response,
  2213. // If the second parameter is missing, then it defaults to 302 (StatusFound).
  2214. // It can be set to 301 (Permant redirect), StatusTemporaryRedirect(307)
  2215. // or 303 (StatusSeeOther) if POST method.
  2216. func (ctx *Context) Redirect(urlToRedirect string, statusHeader ...int) {
  2217. ctx.StopExecution()
  2218. // get the previous status code given by the end-developer.
  2219. status := ctx.GetStatusCode()
  2220. if status < 300 { // the previous is not a RCF-valid redirect status.
  2221. status = 0
  2222. }
  2223. if len(statusHeader) > 0 {
  2224. // check if status code is passed via receivers.
  2225. if s := statusHeader[0]; s > 0 {
  2226. status = s
  2227. }
  2228. }
  2229. if status == 0 {
  2230. // if status remains zero then default it.
  2231. // a 'temporary-redirect-like' which works better than for our purpose
  2232. status = http.StatusFound
  2233. }
  2234. http.Redirect(ctx.writer, ctx.request, urlToRedirect, status)
  2235. }
  2236. // +------------------------------------------------------------+
  2237. // | Body Readers |
  2238. // +------------------------------------------------------------+
  2239. // SetMaxRequestBodySize sets a limit to the request body size
  2240. // should be called before reading the request body from the client.
  2241. func (ctx *Context) SetMaxRequestBodySize(limitOverBytes int64) {
  2242. ctx.request.Body = http.MaxBytesReader(ctx.writer, ctx.request.Body, limitOverBytes)
  2243. }
  2244. var emptyFunc = func() {}
  2245. // GetBody reads and returns the request body.
  2246. func GetBody(r *http.Request, resetBody bool) ([]byte, func(), error) {
  2247. data, err := io.ReadAll(r.Body)
  2248. if err != nil {
  2249. return nil, nil, err
  2250. }
  2251. if resetBody {
  2252. // * remember, Request.Body has no Bytes(), we have to consume them first
  2253. // and after re-set them to the body, this is the only solution.
  2254. return data, func() {
  2255. setBody(r, data)
  2256. }, nil
  2257. }
  2258. return data, emptyFunc, nil
  2259. }
  2260. func setBody(r *http.Request, data []byte) {
  2261. r.Body = io.NopCloser(bytes.NewBuffer(data))
  2262. }
  2263. const disableRequestBodyConsumptionContextKey = "iris.request.body.record"
  2264. // RecordRequestBody same as the Application's DisableBodyConsumptionOnUnmarshal
  2265. // configuration field but acts only for the current request.
  2266. // It makes the request body readable more than once.
  2267. func (ctx *Context) RecordRequestBody(b bool) {
  2268. ctx.values.Set(disableRequestBodyConsumptionContextKey, b)
  2269. }
  2270. // IsRecordingBody reports whether the request body can be readen multiple times.
  2271. func (ctx *Context) IsRecordingBody() bool {
  2272. if ctx.app.ConfigurationReadOnly().GetDisableBodyConsumptionOnUnmarshal() {
  2273. return true
  2274. }
  2275. value, _ := ctx.values.GetBool(disableRequestBodyConsumptionContextKey)
  2276. return value
  2277. }
  2278. // GetBody reads and returns the request body.
  2279. // The default behavior for the http request reader is to consume the data readen
  2280. // but you can change that behavior by passing the `WithoutBodyConsumptionOnUnmarshal` Iris option
  2281. // or by calling the `RecordRequestBody` method.
  2282. //
  2283. // However, whenever you can use the `ctx.Request().Body` instead.
  2284. func (ctx *Context) GetBody() ([]byte, error) {
  2285. body, release, err := GetBody(ctx.request, ctx.IsRecordingBody())
  2286. if err != nil {
  2287. return nil, err
  2288. }
  2289. release()
  2290. return body, nil
  2291. }
  2292. // Validator is the validator for request body on Context methods such as
  2293. // ReadJSON, ReadMsgPack, ReadXML, ReadYAML, ReadForm, ReadQuery, ReadBody and e.t.c.
  2294. type Validator interface {
  2295. Struct(interface{}) error
  2296. // If community asks for more than a struct validation on JSON, XML, MsgPack, Form, Query and e.t.c
  2297. // then we should add more methods here, alternative approach would be to have a
  2298. // `Validator:Validate(interface{}) error` and a map[reflect.Kind]Validator instead.
  2299. }
  2300. // UnmarshalBody reads the request's body and binds it to a value or pointer of any type
  2301. // Examples of usage: context.ReadJSON, context.ReadXML.
  2302. //
  2303. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-custom-via-unmarshaler/main.go
  2304. func (ctx *Context) UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error {
  2305. if ctx.request.Body == nil {
  2306. return fmt.Errorf("unmarshal: empty body: %w", ErrNotFound)
  2307. }
  2308. rawData, err := ctx.GetBody()
  2309. if err != nil {
  2310. return err
  2311. }
  2312. if decoderWithCtx, ok := outPtr.(BodyDecoderWithContext); ok {
  2313. return decoderWithCtx.DecodeContext(ctx.request.Context(), rawData)
  2314. }
  2315. // check if the v contains its own decode
  2316. // in this case the v should be a pointer also,
  2317. // but this is up to the user's custom Decode implementation*
  2318. //
  2319. // See 'BodyDecoder' for more.
  2320. if decoder, isDecoder := outPtr.(BodyDecoder); isDecoder {
  2321. return decoder.Decode(rawData)
  2322. }
  2323. // // check if v is already a pointer, if yes then pass as it's
  2324. // if reflect.TypeOf(v).Kind() == reflect.Ptr {
  2325. // return unmarshaler.Unmarshal(rawData, v)
  2326. // } <- no need for that, ReadJSON is documented enough to receive a pointer,
  2327. // we don't need to reduce the performance here by using the reflect.TypeOf method.
  2328. // f the v doesn't contains a self-body decoder use the custom unmarshaler to bind the body.
  2329. err = unmarshaler.Unmarshal(rawData, outPtr)
  2330. if err != nil {
  2331. return err
  2332. }
  2333. return ctx.app.Validate(outPtr)
  2334. }
  2335. // JSONReader holds the JSON decode options of the `Context.ReadJSON, ReadBody` methods.
  2336. type JSONReader struct { // Note(@kataras): struct instead of optional funcs to keep consistently with the encoder options.
  2337. // DisallowUnknownFields causes the json decoder to return an error when the destination
  2338. // is a struct and the input contains object keys which do not match any
  2339. // non-ignored, exported fields in the destination.
  2340. DisallowUnknownFields bool
  2341. // If set to true then a bit faster json decoder is used instead,
  2342. // note that if this is true then it overrides
  2343. // the Application's EnableOptimizations configuration field.
  2344. Optimize bool
  2345. // This field only applies to the ReadJSONStream.
  2346. // The Optimize field has no effect when this is true.
  2347. // If set to true the request body stream MUST start with a `[`
  2348. // and end with `]` literals, example:
  2349. // [
  2350. // {"username":"john"},
  2351. // {"username": "makis"},
  2352. // {"username": "george"}
  2353. // ]
  2354. // Defaults to false: decodes a json object one by one, example:
  2355. // {"username":"john"}
  2356. // {"username": "makis"}
  2357. // {"username": "george"}
  2358. ArrayStream bool
  2359. }
  2360. var ReadJSON = func(ctx *Context, outPtr interface{}, opts ...JSONReader) error {
  2361. var body io.Reader
  2362. if ctx.IsRecordingBody() {
  2363. data, err := io.ReadAll(ctx.request.Body)
  2364. if err != nil {
  2365. return err
  2366. }
  2367. setBody(ctx.request, data)
  2368. body = bytes.NewReader(data)
  2369. } else {
  2370. body = ctx.request.Body
  2371. }
  2372. decoder := json.NewDecoder(body)
  2373. // decoder := gojson.NewDecoder(ctx.Request().Body)
  2374. if len(opts) > 0 {
  2375. options := opts[0]
  2376. if options.DisallowUnknownFields {
  2377. decoder.DisallowUnknownFields()
  2378. }
  2379. }
  2380. if err := decoder.Decode(&outPtr); err != nil {
  2381. return err
  2382. }
  2383. return ctx.app.Validate(outPtr)
  2384. }
  2385. // ReadJSON reads JSON from request's body and binds it to a value of any json-valid type.
  2386. //
  2387. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-json/main.go
  2388. func (ctx *Context) ReadJSON(outPtr interface{}, opts ...JSONReader) error {
  2389. return ReadJSON(ctx, outPtr, opts...)
  2390. }
  2391. // ReadJSONStream is an alternative of ReadJSON which can reduce the memory load
  2392. // by reading only one json object every time.
  2393. // It buffers just the content required for a single json object instead of the entire string,
  2394. // and discards that once it reaches an end of value that can be decoded into the provided struct
  2395. // inside the onDecode's DecodeFunc.
  2396. //
  2397. // It accepts a function which accepts the json Decode function and returns an error.
  2398. // The second variadic argument is optional and can be used to customize the decoder even further.
  2399. //
  2400. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-json-stream/main.go
  2401. func (ctx *Context) ReadJSONStream(onDecode func(DecodeFunc) error, opts ...JSONReader) error {
  2402. decoder := json.NewDecoder(ctx.request.Body)
  2403. if len(opts) > 0 && opts[0].ArrayStream {
  2404. _, err := decoder.Token() // read open bracket.
  2405. if err != nil {
  2406. return err
  2407. }
  2408. for decoder.More() { // hile the array contains values.
  2409. if err = onDecode(decoder.Decode); err != nil {
  2410. return err
  2411. }
  2412. }
  2413. _, err = decoder.Token() // read closing bracket.
  2414. return err
  2415. }
  2416. // while the array contains values
  2417. for decoder.More() {
  2418. if err := onDecode(decoder.Decode); err != nil {
  2419. return err
  2420. }
  2421. }
  2422. return nil
  2423. }
  2424. // ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
  2425. //
  2426. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-xml/main.go
  2427. func (ctx *Context) ReadXML(outPtr interface{}) error {
  2428. return ctx.UnmarshalBody(outPtr, UnmarshalerFunc(xml.Unmarshal))
  2429. }
  2430. // ReadYAML reads YAML from request's body and binds it to the "outPtr" value.
  2431. //
  2432. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-yaml/main.go
  2433. func (ctx *Context) ReadYAML(outPtr interface{}) error {
  2434. return ctx.UnmarshalBody(outPtr, UnmarshalerFunc(yaml.Unmarshal))
  2435. }
  2436. var (
  2437. // IsErrEmptyJSON reports whether the given "err" is caused by a
  2438. // Client.ReadJSON call when the request body was empty or
  2439. // didn't start with { or [.
  2440. IsErrEmptyJSON = func(err error) bool {
  2441. if err == nil {
  2442. return false
  2443. }
  2444. if errors.Is(err, io.EOF) {
  2445. return true
  2446. }
  2447. if v, ok := err.(*json.SyntaxError); ok {
  2448. // standard go json encoder error.
  2449. return v.Offset == 0 && v.Error() == "unexpected end of JSON input"
  2450. }
  2451. errMsg := err.Error()
  2452. // 3rd party pacakges:
  2453. return strings.Contains(errMsg, "readObjectStart: expect {") || strings.Contains(errMsg, "readArrayStart: expect [")
  2454. }
  2455. // IsErrPath can be used at `context#ReadForm` and `context#ReadQuery`.
  2456. // It reports whether the incoming error
  2457. // can be ignored when server allows unknown post values to be sent by the client.
  2458. //
  2459. // A shortcut for the `schema#IsErrPath`.
  2460. IsErrPath = schema.IsErrPath
  2461. // IsErrPathCRSFToken reports whether the given "err" is caused
  2462. // by unknown key error on "csrf.token". See `context#ReadForm` for more.
  2463. IsErrPathCRSFToken = func(err error) bool {
  2464. if err == nil || CSRFTokenFormKey == "" {
  2465. return false
  2466. }
  2467. if m, ok := err.(schema.MultiError); ok {
  2468. if csrfErr, hasCSRFToken := m[CSRFTokenFormKey]; hasCSRFToken {
  2469. _, is := csrfErr.(schema.UnknownKeyError)
  2470. return is
  2471. }
  2472. }
  2473. return false
  2474. }
  2475. // ErrEmptyForm is returned by
  2476. // - `context#ReadForm`
  2477. // - `context#ReadQuery`
  2478. // - `context#ReadBody`
  2479. // when the request data (form, query and body respectfully) is empty.
  2480. ErrEmptyForm = errors.New("empty form")
  2481. // ErrEmptyFormField reports whether a specific field exists but it's empty.
  2482. // Usage: errors.Is(err, ErrEmptyFormField)
  2483. // See postValue method. It's only returned on parsed post value methods.
  2484. ErrEmptyFormField = errors.New("empty form field")
  2485. // ConnectionCloseErrorSubstr if at least one of the given
  2486. // substrings are found in a net.OpError:os.SyscallError error type
  2487. // on `IsErrConnectionReset` then the function will report true.
  2488. ConnectionCloseErrorSubstr = []string{
  2489. "broken pipe",
  2490. "connection reset by peer",
  2491. }
  2492. // IsErrConnectionClosed reports whether the given "err"
  2493. // is caused because of a broken connection.
  2494. IsErrConnectionClosed = func(err error) bool {
  2495. if err == nil {
  2496. return false
  2497. }
  2498. if opErr, ok := err.(*net.OpError); ok {
  2499. if syscallErr, ok := opErr.Err.(*os.SyscallError); ok {
  2500. errStr := strings.ToLower(syscallErr.Error())
  2501. for _, s := range ConnectionCloseErrorSubstr {
  2502. if strings.Contains(errStr, s) {
  2503. return true
  2504. }
  2505. }
  2506. }
  2507. }
  2508. return false
  2509. }
  2510. )
  2511. // CSRFTokenFormKey the CSRF token key of the form data.
  2512. //
  2513. // See ReadForm method for more.
  2514. const CSRFTokenFormKey = "csrf.token"
  2515. // ReadForm binds the request body of a form to the "formObject".
  2516. // It supports any kind of type, including custom structs.
  2517. // It will return nothing if request data are empty.
  2518. // The struct field tag is "form".
  2519. // Note that it will return nil error on empty form data if `Configuration.FireEmptyFormError`
  2520. // is false (as defaulted) in this case the caller should check the pointer to
  2521. // see if something was actually binded.
  2522. //
  2523. // If a client sent an unknown field, this method will return an error,
  2524. // in order to ignore that error use the `err != nil && !iris.IsErrPath(err)`.
  2525. //
  2526. // As of 15 Aug 2022, ReadForm does not return an error over unknown CSRF token form key,
  2527. // to change this behavior globally, set the `context.CSRFTokenFormKey` to an empty value.
  2528. //
  2529. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-form/main.go
  2530. func (ctx *Context) ReadForm(formObject interface{}) error {
  2531. values := ctx.FormValues()
  2532. if len(values) == 0 {
  2533. if ctx.app.ConfigurationReadOnly().GetFireEmptyFormError() {
  2534. return ErrEmptyForm
  2535. }
  2536. return nil
  2537. }
  2538. err := schema.DecodeForm(values, formObject)
  2539. if err != nil && !IsErrPathCRSFToken(err) {
  2540. return err
  2541. }
  2542. return ctx.app.Validate(formObject)
  2543. }
  2544. type (
  2545. // MultipartRelated is the result of the context.ReadMultipartRelated method.
  2546. MultipartRelated struct {
  2547. // ContentIDs keeps an ordered list of all the
  2548. // content-ids of the multipart related request.
  2549. ContentIDs []string
  2550. // Contents keeps each part's information by Content-ID.
  2551. // Contents holds each of the multipart/related part's data.
  2552. Contents map[string]MultipartRelatedContent
  2553. }
  2554. // MultipartRelatedContent holds a multipart/related part's id, header and body.
  2555. MultipartRelatedContent struct {
  2556. // ID holds the Content-ID.
  2557. ID string
  2558. // Headers holds the part's request headers.
  2559. Headers map[string][]string
  2560. // Body holds the part's body.
  2561. Body []byte
  2562. }
  2563. )
  2564. // ReadMultipartRelated returns a structure which contain
  2565. // information about each part (id, headers, body).
  2566. //
  2567. // Read more at: https://www.ietf.org/rfc/rfc2387.txt.
  2568. //
  2569. // Example request (2387/5.2 Text/X-Okie):
  2570. // Content-Type: Multipart/Related; boundary=example-2;
  2571. // start="<950118.AEBH@XIson.com>"
  2572. // type="Text/x-Okie"
  2573. //
  2574. // --example-2
  2575. // Content-Type: Text/x-Okie; charset=iso-8859-1;
  2576. // declaration="<950118.AEB0@XIson.com>"
  2577. // Content-ID: <950118.AEBH@XIson.com>
  2578. // Content-Description: Document
  2579. //
  2580. // {doc}
  2581. // This picture was taken by an automatic camera mounted ...
  2582. // {image file=cid:950118.AECB@XIson.com}
  2583. // {para}
  2584. // Now this is an enlargement of the area ...
  2585. // {image file=cid:950118:AFDH@XIson.com}
  2586. // {/doc}
  2587. // --example-2
  2588. // Content-Type: image/jpeg
  2589. // Content-ID: <950118.AFDH@XIson.com>
  2590. // Content-Transfer-Encoding: BASE64
  2591. // Content-Description: Picture A
  2592. //
  2593. // [encoded jpeg image]
  2594. // --example-2
  2595. // Content-Type: image/jpeg
  2596. // Content-ID: <950118.AECB@XIson.com>
  2597. // Content-Transfer-Encoding: BASE64
  2598. // Content-Description: Picture B
  2599. //
  2600. // [encoded jpeg image]
  2601. // --example-2--
  2602. func (ctx *Context) ReadMultipartRelated() (MultipartRelated, error) {
  2603. contentType, params, err := mime.ParseMediaType(ctx.GetHeader(ContentTypeHeaderKey))
  2604. if err != nil {
  2605. return MultipartRelated{}, err
  2606. }
  2607. if !strings.HasPrefix(contentType, ContentMultipartRelatedHeaderValue) {
  2608. return MultipartRelated{}, ErrEmptyForm
  2609. }
  2610. var (
  2611. contentIDs []string
  2612. contents = make(map[string]MultipartRelatedContent)
  2613. )
  2614. if ctx.IsRecordingBody() {
  2615. // * remember, Request.Body has no Bytes(), we have to consume them first
  2616. // and after re-set them to the body, this is the only solution.
  2617. body, restoreBody, err := GetBody(ctx.request, true)
  2618. if err != nil {
  2619. return MultipartRelated{}, fmt.Errorf("multipart related: body copy because of iris.Configuration.DisableBodyConsumptionOnUnmarshal: %w", err)
  2620. }
  2621. setBody(ctx.request, body) // so the ctx.request.Body works
  2622. defer restoreBody() // so the next ctx.GetBody calls work.
  2623. }
  2624. multipartReader := multipart.NewReader(ctx.request.Body, params["boundary"])
  2625. for {
  2626. part, err := multipartReader.NextPart()
  2627. if err != nil {
  2628. if err == io.EOF {
  2629. break
  2630. }
  2631. return MultipartRelated{}, fmt.Errorf("multipart related: next part: %w", err)
  2632. }
  2633. defer part.Close()
  2634. b, err := io.ReadAll(part)
  2635. if err != nil {
  2636. return MultipartRelated{}, fmt.Errorf("multipart related: next part: read: %w", err)
  2637. }
  2638. contentID := part.Header.Get("Content-ID")
  2639. contentIDs = append(contentIDs, contentID)
  2640. contents[contentID] = MultipartRelatedContent{ // replace if same Content-ID appears, which it shouldn't.
  2641. ID: contentID,
  2642. Headers: http.Header(part.Header),
  2643. Body: b,
  2644. }
  2645. }
  2646. if len(contents) != len(contentIDs) {
  2647. contentIDs = distinctStrings(contentIDs)
  2648. }
  2649. result := MultipartRelated{
  2650. ContentIDs: contentIDs,
  2651. Contents: contents,
  2652. }
  2653. return result, nil
  2654. }
  2655. func distinctStrings(values []string) []string {
  2656. seen := make(map[string]struct{}, len(values))
  2657. result := make([]string, 0, len(values))
  2658. for _, val := range values {
  2659. if _, ok := seen[val]; !ok {
  2660. seen[val] = struct{}{}
  2661. result = append(result, val)
  2662. }
  2663. }
  2664. return result
  2665. }
  2666. // ReadQuery binds URL Query to "ptr". The struct field tag is "url".
  2667. //
  2668. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-query/main.go
  2669. func (ctx *Context) ReadQuery(ptr interface{}) error {
  2670. values := ctx.getQuery()
  2671. if len(values) == 0 {
  2672. if ctx.app.ConfigurationReadOnly().GetFireEmptyFormError() {
  2673. return ErrEmptyForm
  2674. }
  2675. return nil
  2676. }
  2677. err := schema.DecodeQuery(values, ptr)
  2678. if err != nil {
  2679. return err
  2680. }
  2681. return ctx.app.Validate(ptr)
  2682. }
  2683. // ReadHeaders binds request headers to "ptr". The struct field tag is "header".
  2684. //
  2685. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-headers/main.go
  2686. func (ctx *Context) ReadHeaders(ptr interface{}) error {
  2687. err := schema.DecodeHeaders(ctx.request.Header, ptr)
  2688. if err != nil {
  2689. return err
  2690. }
  2691. return ctx.app.Validate(ptr)
  2692. }
  2693. // ReadParams binds URI Dynamic Path Parameters to "ptr". The struct field tag is "param".
  2694. //
  2695. // Example: https://github.com/kataras/iris/blob/main/_examples/request-body/read-params/main.go
  2696. func (ctx *Context) ReadParams(ptr interface{}) error {
  2697. n := ctx.params.Len()
  2698. if n == 0 {
  2699. return nil
  2700. }
  2701. values := make(map[string][]string, n)
  2702. ctx.params.Visit(func(key string, value string) {
  2703. // []string on path parameter, e.g.
  2704. // /.../{tail:path}
  2705. // Tail []string `param:"tail"`
  2706. values[key] = strings.Split(value, "/")
  2707. })
  2708. err := schema.DecodeParams(values, ptr)
  2709. if err != nil {
  2710. return err
  2711. }
  2712. return ctx.app.Validate(ptr)
  2713. }
  2714. // ReadURL is a shortcut of ReadParams and ReadQuery.
  2715. // It binds dynamic path parameters and URL query parameters
  2716. // to the "ptr" pointer struct value.
  2717. // The struct fields may contain "url" or "param" binding tags.
  2718. // If a validator exists then it validates the result too.
  2719. func (ctx *Context) ReadURL(ptr interface{}) error {
  2720. values := make(map[string][]string, ctx.params.Len())
  2721. ctx.params.Visit(func(key string, value string) {
  2722. values[key] = strings.Split(value, "/")
  2723. })
  2724. for k, v := range ctx.getQuery() {
  2725. values[k] = append(values[k], v...)
  2726. }
  2727. // Decode using all available binding tags (url, header, param).
  2728. err := schema.Decode(values, ptr)
  2729. if err != nil {
  2730. return err
  2731. }
  2732. return ctx.app.Validate(ptr)
  2733. }
  2734. // ReadProtobuf binds the body to the "ptr" of a proto Message and returns any error.
  2735. // Look `ReadJSONProtobuf` too.
  2736. func (ctx *Context) ReadProtobuf(ptr proto.Message) error {
  2737. rawData, err := ctx.GetBody()
  2738. if err != nil {
  2739. return err
  2740. }
  2741. return proto.Unmarshal(rawData, ptr)
  2742. }
  2743. // ProtoUnmarshalOptions is a type alias for protojson.UnmarshalOptions.
  2744. type ProtoUnmarshalOptions = protojson.UnmarshalOptions
  2745. var defaultProtobufUnmarshalOptions ProtoUnmarshalOptions
  2746. // ReadJSONProtobuf reads a JSON body request into the given "ptr" proto.Message.
  2747. // Look `ReadProtobuf` too.
  2748. func (ctx *Context) ReadJSONProtobuf(ptr proto.Message, opts ...ProtoUnmarshalOptions) error {
  2749. rawData, err := ctx.GetBody()
  2750. if err != nil {
  2751. return err
  2752. }
  2753. opt := defaultProtobufUnmarshalOptions
  2754. if len(opts) > 0 {
  2755. opt = opts[0]
  2756. }
  2757. return opt.Unmarshal(rawData, ptr)
  2758. }
  2759. // ReadMsgPack binds the request body of msgpack format to the "ptr" and returns any error.
  2760. func (ctx *Context) ReadMsgPack(ptr interface{}) error {
  2761. rawData, err := ctx.GetBody()
  2762. if err != nil {
  2763. return err
  2764. }
  2765. err = msgpack.Unmarshal(rawData, ptr)
  2766. if err != nil {
  2767. return err
  2768. }
  2769. return ctx.app.Validate(ptr)
  2770. }
  2771. // ReadBody binds the request body to the "ptr" depending on the HTTP Method and the Request's Content-Type.
  2772. // If a GET method request then it reads from a form (or URL Query), otherwise
  2773. // it tries to match (depending on the request content-type) the data format e.g.
  2774. // JSON, Protobuf, MsgPack, XML, YAML, MultipartForm and binds the result to the "ptr".
  2775. // As a special case if the "ptr" was a pointer to string or []byte
  2776. // then it will bind it to the request body as it is.
  2777. func (ctx *Context) ReadBody(ptr interface{}) error {
  2778. // If the ptr is string or byte, read the body as it's.
  2779. switch v := ptr.(type) {
  2780. case *string:
  2781. b, err := ctx.GetBody()
  2782. if err != nil {
  2783. return err
  2784. }
  2785. *v = string(b)
  2786. case *[]byte:
  2787. b, err := ctx.GetBody()
  2788. if err != nil {
  2789. return err
  2790. }
  2791. copy(*v, b)
  2792. }
  2793. if ctx.Method() == http.MethodGet {
  2794. if ctx.Request().URL.RawQuery != "" {
  2795. // try read from query.
  2796. return ctx.ReadQuery(ptr)
  2797. }
  2798. // otherwise use the ReadForm,
  2799. // it's actually the same except
  2800. // ReadQuery will not fire errors on:
  2801. // 1. unknown or empty url query parameters
  2802. // 2. empty query or form (if FireEmptyFormError is enabled).
  2803. return ctx.ReadForm(ptr)
  2804. }
  2805. switch ctx.GetContentTypeRequested() {
  2806. case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
  2807. return ctx.ReadXML(ptr)
  2808. // "%v reflect.Indirect(reflect.ValueOf(ptr)).Interface())
  2809. case ContentYAMLHeaderValue, ContentYAMLTextHeaderValue:
  2810. return ctx.ReadYAML(ptr)
  2811. case ContentFormHeaderValue, ContentFormMultipartHeaderValue:
  2812. return ctx.ReadForm(ptr)
  2813. case ContentMultipartRelatedHeaderValue:
  2814. return fmt.Errorf("context: read body: cannot bind multipart/related: use ReadMultipartRelated instead")
  2815. case ContentJSONHeaderValue:
  2816. return ctx.ReadJSON(ptr)
  2817. case ContentProtobufHeaderValue:
  2818. msg, ok := ptr.(proto.Message)
  2819. if !ok {
  2820. return ErrContentNotSupported
  2821. }
  2822. return ctx.ReadProtobuf(msg)
  2823. case ContentMsgPackHeaderValue, ContentMsgPack2HeaderValue:
  2824. return ctx.ReadMsgPack(ptr)
  2825. default:
  2826. if ctx.Request().URL.RawQuery != "" {
  2827. // try read from query.
  2828. return ctx.ReadQuery(ptr)
  2829. }
  2830. // otherwise default to JSON.
  2831. return ctx.ReadJSON(ptr)
  2832. }
  2833. }
  2834. // +------------------------------------------------------------+
  2835. // | Body (raw) Writers |
  2836. // +------------------------------------------------------------+
  2837. // Write writes the data to the connection as part of an HTTP reply.
  2838. //
  2839. // If WriteHeader has not yet been called, Write calls
  2840. // WriteHeader(http.StatusOK) before writing the data. If the Header
  2841. // does not contain a Content-Type line, Write adds a Content-Type set
  2842. // to the result of passing the initial 512 bytes of written data to
  2843. // DetectContentType.
  2844. //
  2845. // Depending on the HTTP protocol version and the client, calling
  2846. // Write or WriteHeader may prevent future reads on the
  2847. // Request.Body. For HTTP/1.x requests, handlers should read any
  2848. // needed request body data before writing the response. Once the
  2849. // headers have been flushed (due to either an explicit Flusher.Flush
  2850. // call or writing enough data to trigger a flush), the request body
  2851. // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
  2852. // handlers to continue to read the request body while concurrently
  2853. // writing the response. However, such behavior may not be supported
  2854. // by all HTTP/2 clients. Handlers should read before writing if
  2855. // possible to maximize compatibility.
  2856. //
  2857. // It reports any write errors back to the caller, Application.SetContentErrorHandler does NOT apply here
  2858. // as this is a lower-level method which must be remain as it is.
  2859. func (ctx *Context) Write(rawBody []byte) (int, error) {
  2860. return ctx.writer.Write(rawBody)
  2861. }
  2862. // Writef formats according to a format specifier and writes to the response.
  2863. //
  2864. // Returns the number of bytes written and any write error encountered.
  2865. func (ctx *Context) Writef(format string, a ...interface{}) (n int, err error) {
  2866. /* if len(a) == 0 {
  2867. return ctx.WriteString(format)
  2868. } ^ No, let it complain about arguments, because go test will do even if the app is running.
  2869. Users should use WriteString instead of (format, args)
  2870. when format may contain go-sprintf reserved chars (e.g. %).*/
  2871. return fmt.Fprintf(ctx.writer, format, a...)
  2872. }
  2873. // WriteString writes a simple string to the response.
  2874. //
  2875. // Returns the number of bytes written and any write error encountered.
  2876. func (ctx *Context) WriteString(body string) (n int, err error) {
  2877. return io.WriteString(ctx.writer, body)
  2878. }
  2879. const (
  2880. // ContentTypeHeaderKey is the header key of "Content-Type".
  2881. ContentTypeHeaderKey = "Content-Type"
  2882. // LastModifiedHeaderKey is the header key of "Last-Modified".
  2883. LastModifiedHeaderKey = "Last-Modified"
  2884. // IfModifiedSinceHeaderKey is the header key of "If-Modified-Since".
  2885. IfModifiedSinceHeaderKey = "If-Modified-Since"
  2886. // CacheControlHeaderKey is the header key of "Cache-Control".
  2887. CacheControlHeaderKey = "Cache-Control"
  2888. // ETagHeaderKey is the header key of "ETag".
  2889. ETagHeaderKey = "ETag"
  2890. // ContentDispositionHeaderKey is the header key of "Content-Disposition".
  2891. ContentDispositionHeaderKey = "Content-Disposition"
  2892. // ContentLengthHeaderKey is the header key of "Content-Length"
  2893. ContentLengthHeaderKey = "Content-Length"
  2894. // ContentEncodingHeaderKey is the header key of "Content-Encoding".
  2895. ContentEncodingHeaderKey = "Content-Encoding"
  2896. // GzipHeaderValue is the header value of "gzip".
  2897. GzipHeaderValue = "gzip"
  2898. // AcceptEncodingHeaderKey is the header key of "Accept-Encoding".
  2899. AcceptEncodingHeaderKey = "Accept-Encoding"
  2900. // VaryHeaderKey is the header key of "Vary".
  2901. VaryHeaderKey = "Vary"
  2902. )
  2903. var unixEpochTime = time.Unix(0, 0)
  2904. // IsZeroTime reports whether t is obviously unspecified (either zero or Unix()=0).
  2905. func IsZeroTime(t time.Time) bool {
  2906. return t.IsZero() || t.Equal(unixEpochTime)
  2907. }
  2908. // ParseTime parses a time header (such as the Date: header),
  2909. // trying each forth formats (or three if Application's configuration's TimeFormat is defaulted)
  2910. // that are allowed by HTTP/1.1:
  2911. // Application's configuration's TimeFormat or/and http.TimeFormat,
  2912. // time.RFC850, and time.ANSIC.
  2913. //
  2914. // Look `context#FormatTime` for the opossite operation (Time to string).
  2915. var ParseTime = func(ctx *Context, text string) (t time.Time, err error) {
  2916. t, err = time.Parse(ctx.Application().ConfigurationReadOnly().GetTimeFormat(), text)
  2917. if err != nil {
  2918. return http.ParseTime(text)
  2919. }
  2920. return
  2921. }
  2922. // FormatTime returns a textual representation of the time value formatted
  2923. // according to the Application's configuration's TimeFormat field
  2924. // which defines the format.
  2925. //
  2926. // Look `context#ParseTime` for the opossite operation (string to Time).
  2927. var FormatTime = func(ctx *Context, t time.Time) string {
  2928. return t.Format(ctx.Application().ConfigurationReadOnly().GetTimeFormat())
  2929. }
  2930. // SetLastModified sets the "Last-Modified" based on the "modtime" input.
  2931. // If "modtime" is zero then it does nothing.
  2932. //
  2933. // It's mostly internally on core/router and context packages.
  2934. func (ctx *Context) SetLastModified(modtime time.Time) {
  2935. if !IsZeroTime(modtime) {
  2936. ctx.Header(LastModifiedHeaderKey, FormatTime(ctx, modtime.UTC())) // or modtime.UTC()?
  2937. }
  2938. }
  2939. // ErrPreconditionFailed may be returned from `Context` methods
  2940. // that has to perform one or more client side preconditions before the actual check, e.g. `CheckIfModifiedSince`.
  2941. // Usage:
  2942. // ok, err := context.CheckIfModifiedSince(modTime)
  2943. //
  2944. // if err != nil {
  2945. // if errors.Is(err, context.ErrPreconditionFailed) {
  2946. // [handle missing client conditions,such as not valid request method...]
  2947. // }else {
  2948. // [the error is probably a time parse error...]
  2949. // }
  2950. // }
  2951. var ErrPreconditionFailed = errors.New("precondition failed")
  2952. // CheckIfModifiedSince checks if the response is modified since the "modtime".
  2953. // Note that it has nothing to do with server-side caching.
  2954. // It does those checks by checking if the "If-Modified-Since" request header
  2955. // sent by client or a previous server response header
  2956. // (e.g with WriteWithExpiration or HandleDir or Favicon etc.)
  2957. // is a valid one and it's before the "modtime".
  2958. //
  2959. // A check for !modtime && err == nil is necessary to make sure that
  2960. // it's not modified since, because it may return false but without even
  2961. // had the chance to check the client-side (request) header due to some errors,
  2962. // like the HTTP Method is not "GET" or "HEAD" or if the "modtime" is zero
  2963. // or if parsing time from the header failed. See `ErrPreconditionFailed` too.
  2964. //
  2965. // It's mostly used internally, e.g. `context#WriteWithExpiration`.
  2966. func (ctx *Context) CheckIfModifiedSince(modtime time.Time) (bool, error) {
  2967. if method := ctx.Method(); method != http.MethodGet && method != http.MethodHead {
  2968. return false, fmt.Errorf("method: %w", ErrPreconditionFailed)
  2969. }
  2970. ims := ctx.GetHeader(IfModifiedSinceHeaderKey)
  2971. if ims == "" || IsZeroTime(modtime) {
  2972. return false, fmt.Errorf("zero time: %w", ErrPreconditionFailed)
  2973. }
  2974. t, err := ParseTime(ctx, ims)
  2975. if err != nil {
  2976. return false, err
  2977. }
  2978. // sub-second precision, so
  2979. // use mtime < t+1s instead of mtime <= t to check for unmodified.
  2980. if modtime.UTC().Before(t.Add(1 * time.Second)) {
  2981. return false, nil
  2982. }
  2983. return true, nil
  2984. }
  2985. // WriteNotModified sends a 304 "Not Modified" status code to the client,
  2986. // it makes sure that the content type, the content length headers
  2987. // and any "ETag" are removed before the response sent.
  2988. //
  2989. // It's mostly used internally on core/router/fs.go and context methods.
  2990. func (ctx *Context) WriteNotModified() {
  2991. // RFC 7232 section 4.1:
  2992. // a sender SHOULD NOT generate representation metadata other than the
  2993. // above listed fields unless said metadata exists for the purpose of
  2994. // guiding cache updates (e.g.," Last-Modified" might be useful if the
  2995. // response does not have an ETag field).
  2996. h := ctx.ResponseWriter().Header()
  2997. delete(h, ContentTypeHeaderKey)
  2998. delete(h, ContentLengthHeaderKey)
  2999. if h.Get(ETagHeaderKey) != "" {
  3000. delete(h, LastModifiedHeaderKey)
  3001. }
  3002. ctx.StatusCode(http.StatusNotModified)
  3003. }
  3004. // WriteWithExpiration works like `Write` but it will check if a resource is modified,
  3005. // based on the "modtime" input argument,
  3006. // otherwise sends a 304 status code in order to let the client-side render the cached content.
  3007. func (ctx *Context) WriteWithExpiration(body []byte, modtime time.Time) (int, error) {
  3008. if modified, err := ctx.CheckIfModifiedSince(modtime); !modified && err == nil {
  3009. ctx.WriteNotModified()
  3010. return 0, nil
  3011. }
  3012. ctx.SetLastModified(modtime)
  3013. return ctx.writer.Write(body)
  3014. }
  3015. // StreamWriter registers the given stream writer for populating
  3016. // response body.
  3017. //
  3018. // Access to context's and/or its' members is forbidden from writer.
  3019. //
  3020. // This function may be used in the following cases:
  3021. //
  3022. // - if response body is too big (more than iris.LimitRequestBodySize(if set)).
  3023. // - if response body is streamed from slow external sources.
  3024. // - if response body must be streamed to the client in chunks.
  3025. // (aka `http server push`).
  3026. func (ctx *Context) StreamWriter(writer func(w io.Writer) error) error {
  3027. cancelCtx := ctx.Request().Context()
  3028. notifyClosed := cancelCtx.Done()
  3029. for {
  3030. select {
  3031. // response writer forced to close, exit.
  3032. case <-notifyClosed:
  3033. return cancelCtx.Err()
  3034. default:
  3035. if err := writer(ctx.writer); err != nil {
  3036. return err
  3037. }
  3038. ctx.writer.Flush()
  3039. }
  3040. }
  3041. }
  3042. // +------------------------------------------------------------+
  3043. // | Body Writers with compression |
  3044. // +------------------------------------------------------------+
  3045. // ClientSupportsEncoding reports whether the
  3046. // client expects one of the given "encodings" compression.
  3047. //
  3048. // Note, this method just reports back the first valid encoding it sees,
  3049. // meaning that request accept-encoding offers don't matter here.
  3050. // See `CompressWriter` too.
  3051. func (ctx *Context) ClientSupportsEncoding(encodings ...string) bool {
  3052. if len(encodings) == 0 {
  3053. return false
  3054. }
  3055. if h := ctx.GetHeader(AcceptEncodingHeaderKey); h != "" {
  3056. for _, v := range strings.Split(h, ",") {
  3057. for _, encoding := range encodings {
  3058. if strings.Contains(v, encoding) {
  3059. return true
  3060. }
  3061. }
  3062. }
  3063. }
  3064. return false
  3065. }
  3066. // CompressWriter enables or disables the compress response writer.
  3067. // if the client expects a valid compression algorithm then this
  3068. // will change the response writer to a compress writer instead.
  3069. // All future write and rich write methods will respect this option.
  3070. // Usage:
  3071. //
  3072. // app.Use(func(ctx iris.Context){
  3073. // err := ctx.CompressWriter(true)
  3074. // ctx.Next()
  3075. // })
  3076. //
  3077. // The recommendation is to compress data as much as possible and therefore to use this field,
  3078. // but some types of resources, such as jpeg images, are already compressed.
  3079. // Sometimes, using additional compression doesn't reduce payload size and
  3080. // can even make the payload longer.
  3081. func (ctx *Context) CompressWriter(enable bool) error {
  3082. switch w := ctx.writer.(type) {
  3083. case *CompressResponseWriter:
  3084. if enable {
  3085. return nil
  3086. }
  3087. w.Disabled = true
  3088. case *ResponseRecorder:
  3089. if enable {
  3090. // If it's a recorder which already wraps the compress, exit.
  3091. if _, ok := w.ResponseWriter.(*CompressResponseWriter); ok {
  3092. return nil
  3093. }
  3094. // Keep the Recorder as ctx.writer.
  3095. // Wrap the existing net/http response writer
  3096. // with the compressed writer and
  3097. // replace the recorder's response writer
  3098. // reference with that compressed one.
  3099. // Fixes an issue when Record is called before CompressWriter.
  3100. cw, err := AcquireCompressResponseWriter(w.ResponseWriter, ctx.request, -1)
  3101. if err != nil {
  3102. return err
  3103. }
  3104. w.ResponseWriter = cw
  3105. } else {
  3106. cw, ok := w.ResponseWriter.(*CompressResponseWriter)
  3107. if ok {
  3108. cw.Disabled = true
  3109. }
  3110. }
  3111. default:
  3112. if !enable {
  3113. return nil
  3114. }
  3115. cw, err := AcquireCompressResponseWriter(w, ctx.request, -1)
  3116. if err != nil {
  3117. return err
  3118. }
  3119. ctx.writer = cw
  3120. }
  3121. return nil
  3122. }
  3123. // CompressReader accepts a boolean, which, if set to true
  3124. // it wraps the request body reader with a reader which decompresses request data before read.
  3125. // If the "enable" input argument is false then the request body will reset to the default one.
  3126. //
  3127. // Useful when incoming request data are compressed.
  3128. // All future calls of `ctx.GetBody/ReadXXX/UnmarshalBody` methods will respect this option.
  3129. //
  3130. // Usage:
  3131. //
  3132. // app.Use(func(ctx iris.Context){
  3133. // err := ctx.CompressReader(true)
  3134. // ctx.Next()
  3135. // })
  3136. //
  3137. // More:
  3138. //
  3139. // if cr, ok := ctx.Request().Body.(*CompressReader); ok {
  3140. // cr.Src // the original request body
  3141. // cr.Encoding // the compression algorithm.
  3142. // }
  3143. //
  3144. // It returns `ErrRequestNotCompressed` if client's request data are not compressed
  3145. // (or empty)
  3146. // or `ErrNotSupportedCompression` if server missing the decompression algorithm.
  3147. func (ctx *Context) CompressReader(enable bool) error {
  3148. cr, ok := ctx.request.Body.(*CompressReader)
  3149. if enable {
  3150. if ok {
  3151. // already called.
  3152. return nil
  3153. }
  3154. encoding := ctx.GetHeader(ContentEncodingHeaderKey)
  3155. if encoding == IDENTITY {
  3156. // no transformation whatsoever, return nil error and
  3157. // don't wrap the body reader.
  3158. return nil
  3159. }
  3160. r, err := NewCompressReader(ctx.request.Body, encoding)
  3161. if err != nil {
  3162. return err
  3163. }
  3164. ctx.request.Body = r
  3165. } else if ok {
  3166. ctx.request.Body = cr.Src
  3167. }
  3168. return nil
  3169. }
  3170. // +------------------------------------------------------------+
  3171. // | Rich Body Content Writers/Renderers |
  3172. // +------------------------------------------------------------+
  3173. // ViewEngine registers a view engine for the current chain of handlers.
  3174. // It overrides any previously registered engines, including the application's root ones.
  3175. // Note that, because performance is everything,
  3176. // the "engine" MUST be already ready-to-use,
  3177. // meaning that its `Load` method should be called once before this method call.
  3178. //
  3179. // To register a view engine per-group of groups too see `Party.RegisterView` instead.
  3180. func (ctx *Context) ViewEngine(engine ViewEngine) {
  3181. ctx.values.Set(ctx.app.ConfigurationReadOnly().GetViewEngineContextKey(), engine)
  3182. }
  3183. // ViewLayout sets the "layout" option if and when .View
  3184. // is being called afterwards, in the same request.
  3185. // Useful when need to set or/and change a layout based on the previous handlers in the chain.
  3186. //
  3187. // Note that the 'layoutTmplFile' argument can be set to iris.NoLayout
  3188. // to disable the layout for a specific view render action,
  3189. // it disables the engine's configuration's layout property.
  3190. //
  3191. // Look .ViewData and .View too.
  3192. //
  3193. // Example: https://github.com/kataras/iris/tree/main/_examples/view/context-view-data/
  3194. func (ctx *Context) ViewLayout(layoutTmplFile string) {
  3195. ctx.values.Set(ctx.app.ConfigurationReadOnly().GetViewLayoutContextKey(), layoutTmplFile)
  3196. }
  3197. // ViewData saves one or more key-value pair in order to be passed if and when .View
  3198. // is being called afterwards, in the same request.
  3199. // Useful when need to set or/and change template data from previous hanadlers in the chain.
  3200. //
  3201. // If .View's "binding" argument is not nil and it's not a type of map
  3202. // then these data are being ignored, binding has the priority, so the main route's handler can still decide.
  3203. // If binding is a map or iris.Map then these data are being added to the view data
  3204. // and passed to the template.
  3205. //
  3206. // After .View, the data are not destroyed, in order to be re-used if needed (again, in the same request as everything else),
  3207. // to clear the view data, developers can call:
  3208. // ctx.Set(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey(), nil)
  3209. //
  3210. // If 'key' is empty then the value is added as it's (struct or map) and developer is unable to add other value.
  3211. //
  3212. // Look .ViewLayout and .View too.
  3213. //
  3214. // Example: https://github.com/kataras/iris/tree/main/_examples/view/context-view-data/
  3215. func (ctx *Context) ViewData(key string, value interface{}) {
  3216. viewDataContextKey := ctx.app.ConfigurationReadOnly().GetViewDataContextKey()
  3217. if key == "" {
  3218. ctx.values.Set(viewDataContextKey, value)
  3219. return
  3220. }
  3221. v := ctx.values.Get(viewDataContextKey)
  3222. if v == nil {
  3223. ctx.values.Set(viewDataContextKey, Map{key: value})
  3224. return
  3225. }
  3226. if data, ok := v.(Map); ok {
  3227. data[key] = value
  3228. }
  3229. }
  3230. // GetViewData returns the values registered by `context#ViewData`.
  3231. // The return value is `map[string]interface{}`, this means that
  3232. // if a custom struct registered to ViewData then this function
  3233. // will try to parse it to map, if failed then the return value is nil
  3234. // A check for nil is always a good practise if different
  3235. // kind of values or no data are registered via `ViewData`.
  3236. //
  3237. // Similarly to `viewData := ctx.Values().Get("iris.view.data")` or
  3238. // `viewData := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetViewDataContextKey())`.
  3239. func (ctx *Context) GetViewData() map[string]interface{} {
  3240. if v := ctx.values.Get(ctx.app.ConfigurationReadOnly().GetViewDataContextKey()); v != nil {
  3241. // if pure map[string]interface{}
  3242. if viewData, ok := v.(Map); ok {
  3243. return viewData
  3244. }
  3245. // if struct, convert it to map[string]interface{}
  3246. if structs.IsStruct(v) {
  3247. return structs.Map(v)
  3248. }
  3249. }
  3250. // if no values found, then return nil
  3251. return nil
  3252. }
  3253. // FallbackViewProvider is an interface which can be registered to the `Party.FallbackView`
  3254. // or `Context.FallbackView` methods to handle fallback views.
  3255. // See FallbackView, FallbackViewLayout and FallbackViewFunc.
  3256. type FallbackViewProvider interface {
  3257. FallbackView(ctx *Context, err ErrViewNotExist) error
  3258. } /* Notes(@kataras): If ever requested, this fallback logic (of ctx, error) can go to all necessary methods.
  3259. I've designed with a bit more complexity here instead of a simple filename fallback in order to give
  3260. the freedom to the developer to do whatever he/she wants with that template/layout not exists error,
  3261. e.g. have a list of fallbacks views to loop through until succeed or fire a different error than the default.
  3262. We also provide some helpers for common fallback actions (FallbackView, FallbackViewLayout).
  3263. This naming was chosen in order to be easy to follow up with the previous view-relative context features.
  3264. Also note that here we catch a specific error, we want the developer
  3265. to be aware of the rest template errors (e.g. when a template having parsing issues).
  3266. */
  3267. // FallbackViewFunc is a function that can be registered
  3268. // to handle view fallbacks. It accepts the Context and
  3269. // a special error which contains information about the previous template error.
  3270. // It implements the FallbackViewProvider interface.
  3271. //
  3272. // See `Context.View` method.
  3273. type FallbackViewFunc func(ctx *Context, err ErrViewNotExist) error
  3274. // FallbackView completes the FallbackViewProvider interface.
  3275. func (fn FallbackViewFunc) FallbackView(ctx *Context, err ErrViewNotExist) error {
  3276. return fn(ctx, err)
  3277. }
  3278. var (
  3279. _ FallbackViewProvider = FallbackView("")
  3280. _ FallbackViewProvider = FallbackViewLayout("")
  3281. )
  3282. // FallbackView is a helper to register a single template filename as a fallback
  3283. // when the provided tempate filename was not found.
  3284. type FallbackView string
  3285. // FallbackView completes the FallbackViewProvider interface.
  3286. func (f FallbackView) FallbackView(ctx *Context, err ErrViewNotExist) error {
  3287. if err.IsLayout { // Not responsible to render layouts.
  3288. return err
  3289. }
  3290. // ctx.StatusCode(200) // Let's keep the previous status code here, developer can change it anyways.
  3291. return ctx.View(string(f), err.Data)
  3292. }
  3293. // FallbackViewLayout is a helper to register a single template filename as a fallback
  3294. // layout when the provided layout filename was not found.
  3295. type FallbackViewLayout string
  3296. // FallbackView completes the FallbackViewProvider interface.
  3297. func (f FallbackViewLayout) FallbackView(ctx *Context, err ErrViewNotExist) error {
  3298. if !err.IsLayout {
  3299. // Responsible to render layouts only.
  3300. return err
  3301. }
  3302. ctx.ViewLayout(string(f))
  3303. return ctx.View(err.Name, err.Data)
  3304. }
  3305. const fallbackViewOnce = "iris.fallback.view.once"
  3306. func (ctx *Context) fireFallbackViewOnce(err ErrViewNotExist) error {
  3307. // Note(@kataras): this is our way to keep the same View method for
  3308. // both fallback and normal views, remember, we export the whole
  3309. // Context functionality to the end-developer through the fallback view provider.
  3310. if ctx.values.Get(fallbackViewOnce) != nil {
  3311. return err
  3312. }
  3313. v := ctx.values.Get(ctx.app.ConfigurationReadOnly().GetFallbackViewContextKey())
  3314. if v == nil {
  3315. return err
  3316. }
  3317. providers, ok := v.([]FallbackViewProvider)
  3318. if !ok {
  3319. return err
  3320. }
  3321. ctx.values.Set(fallbackViewOnce, struct{}{})
  3322. var pErr error
  3323. for _, provider := range providers {
  3324. pErr = provider.FallbackView(ctx, err)
  3325. if pErr != nil {
  3326. if vErr, ok := pErr.(ErrViewNotExist); ok {
  3327. // This fallback view does not exist or it's not responsible to handle,
  3328. // try the next.
  3329. pErr = vErr
  3330. continue
  3331. }
  3332. }
  3333. // If OK then we found the correct fallback.
  3334. // If the error was a parse error and not a template not found
  3335. // then exit and report the pErr error.
  3336. break
  3337. }
  3338. return pErr
  3339. }
  3340. // FallbackView registers one or more fallback views for a template or a template layout.
  3341. // When View cannot find the given filename to execute then this "provider"
  3342. // is responsible to handle the error or render a different view.
  3343. //
  3344. // Usage:
  3345. //
  3346. // FallbackView(iris.FallbackView("fallback.html"))
  3347. // FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
  3348. // OR
  3349. // FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
  3350. // err.Name is the previous template name.
  3351. // err.IsLayout reports whether the failure came from the layout template.
  3352. // err.Data is the template data provided to the previous View call.
  3353. // [...custom logic e.g. ctx.View("fallback", err.Data)]
  3354. // })
  3355. func (ctx *Context) FallbackView(providers ...FallbackViewProvider) {
  3356. key := ctx.app.ConfigurationReadOnly().GetFallbackViewContextKey()
  3357. if key == "" {
  3358. return
  3359. }
  3360. v := ctx.values.Get(key)
  3361. if v == nil {
  3362. ctx.values.Set(key, providers)
  3363. return
  3364. }
  3365. // Can register more than one.
  3366. storedProviders, ok := v.([]FallbackViewProvider)
  3367. if !ok {
  3368. return
  3369. }
  3370. storedProviders = append(storedProviders, providers...)
  3371. ctx.values.Set(key, storedProviders)
  3372. }
  3373. // View renders a template based on the registered view engine(s).
  3374. // First argument accepts the filename, relative to the view engine's Directory and Extension,
  3375. // i.e: if directory is "./templates" and want to render the "./templates/users/index.html"
  3376. // then you pass the "users/index.html" as the filename argument.
  3377. //
  3378. // The second optional argument can receive a single "view model".
  3379. // If "optionalViewModel" exists, even if it's nil, overrides any previous `ViewData` calls.
  3380. // If second argument is missing then binds the data through previous `ViewData` calls (e.g. middleware).
  3381. //
  3382. // Look .ViewData and .ViewLayout too.
  3383. //
  3384. // Examples: https://github.com/kataras/iris/tree/main/_examples/view
  3385. func (ctx *Context) View(filename string, optionalViewModel ...interface{}) error {
  3386. ctx.ContentType(ContentHTMLHeaderValue)
  3387. err := ctx.renderView(filename, optionalViewModel...)
  3388. if err != nil {
  3389. if errNotExists, ok := err.(ErrViewNotExist); ok {
  3390. err = ctx.fireFallbackViewOnce(errNotExists)
  3391. }
  3392. }
  3393. if err != nil {
  3394. if ctx.IsDebug() {
  3395. // send the error back to the client, when debug mode.
  3396. ctx.StopWithError(http.StatusInternalServerError, err)
  3397. } else {
  3398. ctx.SetErrPrivate(err)
  3399. ctx.StopWithStatus(http.StatusInternalServerError)
  3400. }
  3401. }
  3402. return err
  3403. }
  3404. func (ctx *Context) renderView(filename string, optionalViewModel ...interface{}) error {
  3405. cfg := ctx.app.ConfigurationReadOnly()
  3406. layout := ctx.values.GetString(cfg.GetViewLayoutContextKey())
  3407. var bindingData interface{}
  3408. if len(optionalViewModel) > 0 /* Don't do it: can break a lot of servers: && optionalViewModel[0] != nil */ {
  3409. // a nil can override the existing data or model sent by `ViewData`.
  3410. bindingData = optionalViewModel[0]
  3411. } else {
  3412. bindingData = ctx.values.Get(cfg.GetViewDataContextKey())
  3413. }
  3414. if key := cfg.GetViewEngineContextKey(); key != "" {
  3415. if engineV := ctx.values.Get(key); engineV != nil {
  3416. if engine, ok := engineV.(ViewEngine); ok {
  3417. return engine.ExecuteWriter(ctx, filename, layout, bindingData)
  3418. }
  3419. }
  3420. }
  3421. return ctx.app.View(ctx, filename, layout, bindingData)
  3422. }
  3423. const (
  3424. // ContentBinaryHeaderValue header value for binary data.
  3425. ContentBinaryHeaderValue = "application/octet-stream"
  3426. // ContentWebassemblyHeaderValue header value for web assembly files.
  3427. ContentWebassemblyHeaderValue = "application/wasm"
  3428. // ContentHTMLHeaderValue is the string of text/html response header's content type value.
  3429. ContentHTMLHeaderValue = "text/html"
  3430. // ContentJSONHeaderValue header value for JSON data.
  3431. ContentJSONHeaderValue = "application/json"
  3432. // ContentJSONProblemHeaderValue header value for JSON API problem error.
  3433. // Read more at: https://tools.ietf.org/html/rfc7807
  3434. ContentJSONProblemHeaderValue = "application/problem+json"
  3435. // ContentXMLProblemHeaderValue header value for XML API problem error.
  3436. // Read more at: https://tools.ietf.org/html/rfc7807
  3437. ContentXMLProblemHeaderValue = "application/problem+xml"
  3438. // ContentJavascriptHeaderValue header value for JSONP & Javascript data.
  3439. ContentJavascriptHeaderValue = "text/javascript"
  3440. // ContentTextHeaderValue header value for Text data.
  3441. ContentTextHeaderValue = "text/plain"
  3442. // ContentXMLHeaderValue header value for XML data.
  3443. ContentXMLHeaderValue = "text/xml"
  3444. // ContentXMLUnreadableHeaderValue obselete header value for XML.
  3445. ContentXMLUnreadableHeaderValue = "application/xml"
  3446. // ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
  3447. ContentMarkdownHeaderValue = "text/markdown"
  3448. // ContentYAMLHeaderValue header value for YAML data.
  3449. ContentYAMLHeaderValue = "application/x-yaml"
  3450. // ContentYAMLTextHeaderValue header value for YAML plain text.
  3451. ContentYAMLTextHeaderValue = "text/yaml"
  3452. // ContentProtobufHeaderValue header value for Protobuf messages data.
  3453. ContentProtobufHeaderValue = "application/x-protobuf"
  3454. // ContentMsgPackHeaderValue header value for MsgPack data.
  3455. ContentMsgPackHeaderValue = "application/msgpack"
  3456. // ContentMsgPack2HeaderValue alternative header value for MsgPack data.
  3457. ContentMsgPack2HeaderValue = "application/x-msgpack"
  3458. // ContentFormHeaderValue header value for post form data.
  3459. ContentFormHeaderValue = "application/x-www-form-urlencoded"
  3460. // ContentFormMultipartHeaderValue header value for post multipart form data.
  3461. ContentFormMultipartHeaderValue = "multipart/form-data"
  3462. // ContentMultipartRelatedHeaderValue header value for multipart related data.
  3463. ContentMultipartRelatedHeaderValue = "multipart/related"
  3464. // ContentGRPCHeaderValue Content-Type header value for gRPC.
  3465. ContentGRPCHeaderValue = "application/grpc"
  3466. )
  3467. // Binary writes out the raw bytes as binary data.
  3468. func (ctx *Context) Binary(data []byte) (int, error) {
  3469. ctx.ContentType(ContentBinaryHeaderValue)
  3470. return ctx.Write(data)
  3471. }
  3472. // Text writes out a string as plain text.
  3473. func (ctx *Context) Text(format string, args ...interface{}) (int, error) {
  3474. ctx.ContentType(ContentTextHeaderValue)
  3475. return ctx.Writef(format, args...)
  3476. }
  3477. // HTML writes out a string as text/html.
  3478. func (ctx *Context) HTML(format string, args ...interface{}) (int, error) {
  3479. ctx.ContentType(ContentHTMLHeaderValue)
  3480. return ctx.Writef(format, args...)
  3481. }
  3482. // ProtoMarshalOptions is a type alias for protojson.MarshalOptions.
  3483. type ProtoMarshalOptions = protojson.MarshalOptions
  3484. // JSON contains the options for the JSON (Context's) Renderer.
  3485. type JSON struct {
  3486. // content-specific
  3487. UnescapeHTML bool `yaml:"UnescapeHTML"`
  3488. Indent string `yaml:"Indent"`
  3489. Prefix string `yaml:"Prefix"`
  3490. ASCII bool `yaml:"ASCII"` // if true writes with unicode to ASCII content.
  3491. Secure bool `yaml:"Secure"` // if true then it prepends a "while(1);" when Go slice (to JSON Array) value.
  3492. // proto.Message specific marshal options.
  3493. Proto ProtoMarshalOptions `yaml:"ProtoMarshalOptions"`
  3494. // If true and json writing failed then the error handler is skipped
  3495. // and it just returns to the caller.
  3496. //
  3497. // See StopWithJSON and x/errors package.
  3498. OmitErrorHandler bool `yaml:"OmitErrorHandler"`
  3499. }
  3500. // DefaultJSONOptions is the optional settings that are being used
  3501. // inside `Context.JSON`.
  3502. var DefaultJSONOptions = JSON{}
  3503. // IsDefault reports whether this JSON options structure holds the default values.
  3504. func (j *JSON) IsDefault() bool {
  3505. return j.UnescapeHTML == DefaultJSONOptions.UnescapeHTML &&
  3506. j.Indent == DefaultJSONOptions.Indent &&
  3507. j.Prefix == DefaultJSONOptions.Prefix &&
  3508. j.ASCII == DefaultJSONOptions.ASCII &&
  3509. j.Secure == DefaultJSONOptions.Secure &&
  3510. j.Proto == DefaultJSONOptions.Proto
  3511. }
  3512. // JSONP contains the options for the JSONP (Context's) Renderer.
  3513. type JSONP struct {
  3514. // content-specific
  3515. Indent string
  3516. Callback string
  3517. OmitErrorHandler bool // See JSON.OmitErrorHandler.
  3518. }
  3519. // XML contains the options for the XML (Context's) Renderer.
  3520. type XML struct {
  3521. // content-specific
  3522. Indent string
  3523. Prefix string
  3524. OmitErrorHandler bool // See JSON.OmitErrorHandler.
  3525. }
  3526. // Markdown contains the options for the Markdown (Context's) Renderer.
  3527. type Markdown struct {
  3528. // content-specific
  3529. Sanitize bool
  3530. OmitErrorHandler bool // See JSON.OmitErrorHandler.
  3531. //
  3532. // Library-specific.
  3533. // E.g. Flags: html.CommonFlags | html.HrefTargetBlank
  3534. RenderOptions html.RendererOptions
  3535. }
  3536. var (
  3537. newLineB = []byte("\n")
  3538. // the html codes for unescaping.
  3539. ltHex = []byte("\\u003c")
  3540. lt = []byte("<")
  3541. gtHex = []byte("\\u003e")
  3542. gt = []byte(">")
  3543. andHex = []byte("\\u0026")
  3544. and = []byte("&")
  3545. // secure JSON.
  3546. jsonArrayPrefix = []byte("[")
  3547. jsonArraySuffix = []byte("]")
  3548. secureJSONPrefix = []byte("while(1);")
  3549. )
  3550. func (ctx *Context) handleSpecialJSONResponseValue(v interface{}, options *JSON) (bool, int, error) {
  3551. if ctx.app.ConfigurationReadOnly().GetEnableProtoJSON() {
  3552. if m, ok := v.(proto.Message); ok {
  3553. protoJSON := ProtoMarshalOptions{}
  3554. if options != nil {
  3555. protoJSON = options.Proto
  3556. }
  3557. result, err := protoJSON.Marshal(m)
  3558. if err != nil {
  3559. return true, 0, err
  3560. }
  3561. n, err := ctx.writer.Write(result)
  3562. return true, n, err
  3563. }
  3564. }
  3565. if ctx.app.ConfigurationReadOnly().GetEnableEasyJSON() {
  3566. if easyObject, ok := v.(easyjson.Marshaler); ok {
  3567. noEscapeHTML := false
  3568. if options != nil {
  3569. noEscapeHTML = !options.UnescapeHTML
  3570. }
  3571. jw := jwriter.Writer{NoEscapeHTML: noEscapeHTML}
  3572. easyObject.MarshalEasyJSON(&jw)
  3573. n, err := jw.DumpTo(ctx.writer)
  3574. return true, n, err
  3575. }
  3576. }
  3577. return false, 0, nil
  3578. }
  3579. // WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
  3580. var WriteJSON = func(ctx *Context, v interface{}, options *JSON) error {
  3581. if !options.Secure && !options.ASCII && options.Prefix == "" {
  3582. // jsoniterConfig := jsoniter.Config{
  3583. // EscapeHTML: !options.UnescapeHTML,
  3584. // IndentionStep: 4,
  3585. // }.Froze()
  3586. // enc := jsoniterConfig.NewEncoder(ctx.writer)
  3587. // err = enc.Encode(v)
  3588. //
  3589. // enc := gojson.NewEncoder(ctx.writer)
  3590. // enc.SetEscapeHTML(!options.UnescapeHTML)
  3591. // enc.SetIndent(options.Prefix, options.Indent)
  3592. // err = enc.EncodeContext(ctx, v)
  3593. enc := json.NewEncoder(ctx.writer)
  3594. enc.SetEscapeHTML(!options.UnescapeHTML)
  3595. enc.SetIndent(options.Prefix, options.Indent)
  3596. return enc.Encode(v)
  3597. }
  3598. var (
  3599. result []byte
  3600. err error
  3601. )
  3602. if indent := options.Indent; indent != "" {
  3603. result, err = json.MarshalIndent(v, "", indent)
  3604. result = append(result, newLineB...)
  3605. } else {
  3606. result, err = json.Marshal(v)
  3607. }
  3608. if err != nil {
  3609. return err
  3610. }
  3611. prependSecure := false
  3612. if options.Secure {
  3613. if bytes.HasPrefix(result, jsonArrayPrefix) {
  3614. if options.Indent == "" {
  3615. prependSecure = bytes.HasSuffix(result, jsonArraySuffix)
  3616. } else {
  3617. prependSecure = bytes.HasSuffix(bytes.TrimRightFunc(result, func(r rune) bool {
  3618. return r == '\n' || r == '\r'
  3619. }), jsonArraySuffix)
  3620. }
  3621. }
  3622. }
  3623. if options.UnescapeHTML {
  3624. result = bytes.ReplaceAll(result, ltHex, lt)
  3625. result = bytes.ReplaceAll(result, gtHex, gt)
  3626. result = bytes.ReplaceAll(result, andHex, and)
  3627. }
  3628. if prependSecure {
  3629. result = append(secureJSONPrefix, result...)
  3630. }
  3631. if options.ASCII {
  3632. if len(result) > 0 {
  3633. buf := new(bytes.Buffer)
  3634. for _, s := range string(result) {
  3635. char := string(s)
  3636. if s >= 128 {
  3637. char = fmt.Sprintf("\\u%04x", int64(s))
  3638. }
  3639. buf.WriteString(char)
  3640. }
  3641. result = buf.Bytes()
  3642. }
  3643. }
  3644. if prefix := options.Prefix; prefix != "" {
  3645. result = append(stringToBytes(prefix), result...)
  3646. }
  3647. _, err = ctx.Write(result)
  3648. return err
  3649. }
  3650. // See https://golang.org/src/strings/builder.go#L45
  3651. // func bytesToString(b []byte) string {
  3652. // return unsafe.String(unsafe.SliceData(b), len(b))
  3653. // }
  3654. func stringToBytes(s string) []byte {
  3655. return unsafe.Slice(unsafe.StringData(s), len(s))
  3656. }
  3657. type (
  3658. // ErrorHandler describes a context error handler which applies on
  3659. // JSON, JSONP, Protobuf, MsgPack, XML, YAML and Markdown write errors.
  3660. //
  3661. // It does NOT modify or handle the result of Context.GetErr at all,
  3662. // use a custom middleware instead if you want to handle the handler-provided custom errors (Context.SetErr)
  3663. //
  3664. // An ErrorHandler can be registered once via Application.SetErrorHandler method to override the default behavior.
  3665. // The default behavior is to simply send status internal code error
  3666. // without a body back to the client.
  3667. //
  3668. // See Application.SetContextErrorHandler for more.
  3669. ErrorHandler interface {
  3670. HandleContextError(ctx *Context, err error)
  3671. }
  3672. // ErrorHandlerFunc a function shortcut for ErrorHandler interface.
  3673. ErrorHandlerFunc func(ctx *Context, err error)
  3674. )
  3675. // HandleContextError completes the ErrorHandler interface.
  3676. func (h ErrorHandlerFunc) HandleContextError(ctx *Context, err error) {
  3677. h(ctx, err)
  3678. }
  3679. func (ctx *Context) handleContextError(err error) {
  3680. if err == nil {
  3681. return
  3682. }
  3683. if errHandler := ctx.app.GetContextErrorHandler(); errHandler != nil {
  3684. errHandler.HandleContextError(ctx, err)
  3685. } else {
  3686. if ctx.IsDebug() {
  3687. ctx.app.Logger().Error(err)
  3688. }
  3689. ctx.StatusCode(http.StatusInternalServerError)
  3690. }
  3691. // keep the error non nil so the caller has control over further actions.
  3692. }
  3693. // Render writes the response headers and calls the given renderer "r" to render data.
  3694. // This method can be used while migrating from other frameworks.
  3695. func (ctx *Context) Render(statusCode int, r interface {
  3696. // Render should push data with custom content type to the client.
  3697. Render(http.ResponseWriter) error
  3698. // WriteContentType writes custom content type to the response.
  3699. WriteContentType(w http.ResponseWriter)
  3700. }) {
  3701. ctx.StatusCode(statusCode)
  3702. if statusCode >= 100 && statusCode <= 199 || statusCode == http.StatusNoContent || statusCode == http.StatusNotModified {
  3703. r.WriteContentType(ctx.writer)
  3704. return
  3705. }
  3706. if err := r.Render(ctx.writer); err != nil {
  3707. ctx.StopWithError(http.StatusInternalServerError, err)
  3708. }
  3709. }
  3710. // Component is the interface which all components must implement.
  3711. // A component is a struct which can be rendered to a writer.
  3712. // It's being used by the `Context.RenderComponent` method.
  3713. // An example of compatible Component is a templ.Component.
  3714. type Component interface {
  3715. Render(context.Context, io.Writer) error
  3716. }
  3717. // RenderComponent renders a component to the client.
  3718. // It sets the "Content-Type" header to "text/html; charset=utf-8".
  3719. // It reports any component render errors back to the caller.
  3720. // Look the Application.SetContextErrorHandler to override the
  3721. // default status code 500 with a custom error response.
  3722. func (ctx *Context) RenderComponent(component Component) error {
  3723. ctx.ContentType("text/html; charset=utf-8")
  3724. err := component.Render(ctx.Request().Context(), ctx.ResponseWriter())
  3725. if err != nil {
  3726. ctx.handleContextError(err)
  3727. }
  3728. return err
  3729. }
  3730. // JSON marshals the given "v" value to JSON and writes the response to the client.
  3731. // Look the Configuration.EnableProtoJSON and EnableEasyJSON too.
  3732. //
  3733. // It reports any JSON parser or write errors back to the caller.
  3734. // Look the Application.SetContextErrorHandler to override the
  3735. // default status code 500 with a custom error response.
  3736. //
  3737. // Customize the behavior of every `Context.JSON“ can be achieved
  3738. // by modifying the package-level `WriteJSON` function on program initilization.
  3739. func (ctx *Context) JSON(v interface{}, opts ...JSON) (err error) {
  3740. var options *JSON
  3741. if len(opts) > 0 {
  3742. options = &opts[0]
  3743. } else {
  3744. // If no options are given safely read the already-initialized value.
  3745. options = &DefaultJSONOptions
  3746. }
  3747. if err = ctx.writeJSON(v, options); err != nil {
  3748. // if no options are given or OmitErrorHandler is false
  3749. // then call the error handler (which may lead to a cycle if the error handler fails to write JSON too).
  3750. if !options.OmitErrorHandler {
  3751. ctx.handleContextError(err)
  3752. }
  3753. }
  3754. return
  3755. }
  3756. func (ctx *Context) writeJSON(v interface{}, options *JSON) error {
  3757. ctx.ContentType(ContentJSONHeaderValue)
  3758. // After content type given and before everything else, try handle proto or easyjson, no matter the performance mode.
  3759. if handled, _, err := ctx.handleSpecialJSONResponseValue(v, options); handled {
  3760. return err
  3761. }
  3762. return WriteJSON(ctx, v, options)
  3763. }
  3764. var finishCallbackB = []byte(");")
  3765. // WriteJSONP marshals the given interface object and writes the JSONP response to the writer.
  3766. var WriteJSONP = func(ctx *Context, v interface{}, options *JSONP) (err error) {
  3767. if callback := options.Callback; callback != "" {
  3768. _, err = ctx.Write(stringToBytes(callback + "("))
  3769. if err != nil {
  3770. return err
  3771. }
  3772. defer func() {
  3773. if err == nil {
  3774. ctx.Write(finishCallbackB)
  3775. }
  3776. }()
  3777. }
  3778. err = WriteJSON(ctx, v, &JSON{
  3779. Indent: options.Indent,
  3780. OmitErrorHandler: options.OmitErrorHandler,
  3781. })
  3782. return err
  3783. }
  3784. // DefaultJSONPOptions is the optional settings that are being used
  3785. // inside `ctx.JSONP`.
  3786. var DefaultJSONPOptions = JSONP{}
  3787. // JSONP marshals the given "v" value to JSON and sends the response to the client.
  3788. //
  3789. // It reports any JSON parser or write errors back to the caller.
  3790. // Look the Application.SetContextErrorHandler to override the
  3791. // default status code 500 with a custom error response.
  3792. func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (err error) {
  3793. var options *JSONP
  3794. if len(opts) > 0 {
  3795. options = &opts[0]
  3796. } else {
  3797. options = &DefaultJSONPOptions
  3798. }
  3799. ctx.ContentType(ContentJavascriptHeaderValue)
  3800. if err = WriteJSONP(ctx, v, options); err != nil {
  3801. if !options.OmitErrorHandler {
  3802. ctx.handleContextError(err)
  3803. }
  3804. }
  3805. return
  3806. }
  3807. type xmlMapEntry struct {
  3808. XMLName xml.Name
  3809. Value interface{} `xml:",chardata"`
  3810. }
  3811. // XMLMap wraps a map[string]interface{} to compatible xml marshaler,
  3812. // in order to be able to render maps as XML on the `Context.XML` method.
  3813. //
  3814. // Example: `Context.XML(XMLMap("Root", map[string]interface{}{...})`.
  3815. func XMLMap(elementName string, v Map) xml.Marshaler {
  3816. return xmlMap{
  3817. entries: v,
  3818. elementName: elementName,
  3819. }
  3820. }
  3821. type xmlMap struct {
  3822. entries Map
  3823. elementName string
  3824. }
  3825. // MarshalXML marshals a map to XML.
  3826. func (m xmlMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  3827. if len(m.entries) == 0 {
  3828. return nil
  3829. }
  3830. start.Name = xml.Name{Local: m.elementName}
  3831. err := e.EncodeToken(start)
  3832. if err != nil {
  3833. return err
  3834. }
  3835. for k, v := range m.entries {
  3836. err = e.Encode(xmlMapEntry{XMLName: xml.Name{Local: k}, Value: v})
  3837. if err != nil {
  3838. return err
  3839. }
  3840. }
  3841. return e.EncodeToken(start.End())
  3842. }
  3843. // WriteXML marshals the given interface object and writes the XML response to the writer.
  3844. var WriteXML = func(ctx *Context, v interface{}, options *XML) error {
  3845. if prefix := options.Prefix; prefix != "" {
  3846. _, err := ctx.Write(stringToBytes(prefix))
  3847. if err != nil {
  3848. return err
  3849. }
  3850. }
  3851. encoder := xml.NewEncoder(ctx.writer)
  3852. encoder.Indent("", options.Indent)
  3853. if err := encoder.Encode(v); err != nil {
  3854. return err
  3855. }
  3856. return encoder.Flush()
  3857. }
  3858. // DefaultXMLOptions is the optional settings that are being used
  3859. // from `ctx.XML`.
  3860. var DefaultXMLOptions = XML{}
  3861. // XML marshals the given interface object and writes the XML response to the client.
  3862. // To render maps as XML see the `XMLMap` package-level function.
  3863. //
  3864. // It reports any XML parser or write errors back to the caller.
  3865. // Look the Application.SetContextErrorHandler to override the
  3866. // default status code 500 with a custom error response.
  3867. func (ctx *Context) XML(v interface{}, opts ...XML) (err error) {
  3868. var options *XML
  3869. if len(opts) > 0 {
  3870. options = &opts[0]
  3871. } else {
  3872. options = &DefaultXMLOptions
  3873. }
  3874. ctx.ContentType(ContentXMLHeaderValue)
  3875. if err = WriteXML(ctx, v, options); err != nil {
  3876. if !options.OmitErrorHandler {
  3877. ctx.handleContextError(err)
  3878. }
  3879. }
  3880. return
  3881. }
  3882. // Problem writes a JSON or XML problem response.
  3883. // Order of Problem fields are not always rendered the same.
  3884. //
  3885. // Behaves exactly like the `Context.JSON` method
  3886. // but with default ProblemOptions.JSON indent of " " and
  3887. // a response content type of "application/problem+json" instead.
  3888. //
  3889. // Use the options.RenderXML and XML fields to change this behavior and
  3890. // send a response of content type "application/problem+xml" instead.
  3891. //
  3892. // Read more at: https://github.com/kataras/iris/blob/main/_examples/routing/http-errors.
  3893. func (ctx *Context) Problem(v interface{}, opts ...ProblemOptions) error {
  3894. options := DefaultProblemOptions
  3895. if len(opts) > 0 {
  3896. options = opts[0]
  3897. // Currently apply only if custom options passsed, otherwise,
  3898. // with the current settings, it's not required.
  3899. // This may change in the future though.
  3900. options.Apply(ctx)
  3901. }
  3902. if p, ok := v.(Problem); ok {
  3903. // if !p.Validate() {
  3904. // ctx.StatusCode(http.StatusInternalServerError)
  3905. // return ErrNotValidProblem
  3906. // }
  3907. p.updateURIsToAbs(ctx)
  3908. code, _ := p.getStatus()
  3909. if code == 0 { // get the current status code and set it to the problem.
  3910. code = ctx.GetStatusCode()
  3911. ctx.StatusCode(code)
  3912. } else {
  3913. // send the problem's status code
  3914. ctx.StatusCode(code)
  3915. }
  3916. if options.RenderXML {
  3917. ctx.contentTypeOnce(ContentXMLProblemHeaderValue, "")
  3918. // Problem is an xml Marshaler already, don't use `XMLMap`.
  3919. return ctx.XML(v, options.XML)
  3920. }
  3921. }
  3922. ctx.contentTypeOnce(ContentJSONProblemHeaderValue, "")
  3923. return ctx.writeJSON(v, &options.JSON)
  3924. }
  3925. var sanitizer = bluemonday.UGCPolicy()
  3926. // WriteMarkdown parses the markdown to html and writes these contents to the writer.
  3927. var WriteMarkdown = func(ctx *Context, markdownB []byte, options *Markdown) error {
  3928. out := markdown.NormalizeNewlines(markdownB)
  3929. renderer := html.NewRenderer(options.RenderOptions)
  3930. doc := markdown.Parse(out, nil)
  3931. out = markdown.Render(doc, renderer)
  3932. if options.Sanitize {
  3933. out = sanitizer.SanitizeBytes(out)
  3934. }
  3935. _, err := ctx.Write(out)
  3936. return err
  3937. }
  3938. // DefaultMarkdownOptions is the optional settings that are being used
  3939. // from `WriteMarkdown` and `ctx.Markdown`.
  3940. var DefaultMarkdownOptions = Markdown{}
  3941. // Markdown parses the markdown to html and renders its result to the client.
  3942. //
  3943. // It reports any Markdown parser or write errors back to the caller.
  3944. // Look the Application.SetContextErrorHandler to override the
  3945. // default status code 500 with a custom error response.
  3946. func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (err error) {
  3947. var options *Markdown
  3948. if len(opts) > 0 {
  3949. options = &opts[0]
  3950. } else {
  3951. options = &DefaultMarkdownOptions
  3952. }
  3953. ctx.ContentType(ContentHTMLHeaderValue)
  3954. if err = WriteMarkdown(ctx, markdownB, options); err != nil {
  3955. if !options.OmitErrorHandler {
  3956. ctx.handleContextError(err)
  3957. }
  3958. }
  3959. return
  3960. }
  3961. // WriteYAML sends YAML response to the client.
  3962. var WriteYAML = func(ctx *Context, v interface{}, indentSpace int) error {
  3963. encoder := yaml.NewEncoder(ctx.writer)
  3964. encoder.SetIndent(indentSpace)
  3965. if err := encoder.Encode(v); err != nil {
  3966. return err
  3967. }
  3968. return encoder.Close()
  3969. }
  3970. // YAML marshals the given "v" value using the yaml marshaler and writes the result to the client.
  3971. //
  3972. // It reports any YAML parser or write errors back to the caller.
  3973. // Look the Application.SetContextErrorHandler to override the
  3974. // default status code 500 with a custom error response.
  3975. func (ctx *Context) YAML(v interface{}) error {
  3976. ctx.ContentType(ContentYAMLHeaderValue)
  3977. err := WriteYAML(ctx, v, 0)
  3978. if err != nil {
  3979. ctx.handleContextError(err)
  3980. return err
  3981. }
  3982. return nil
  3983. }
  3984. // TextYAML calls the Context.YAML method but with the text/yaml content type instead.
  3985. func (ctx *Context) TextYAML(v interface{}) error {
  3986. ctx.ContentType(ContentYAMLTextHeaderValue)
  3987. err := WriteYAML(ctx, v, 4)
  3988. if err != nil {
  3989. ctx.handleContextError(err)
  3990. return err
  3991. }
  3992. return nil
  3993. }
  3994. // Protobuf marshals the given "v" value of proto Message and writes its result to the client.
  3995. //
  3996. // It reports any protobuf parser or write errors back to the caller.
  3997. // Look the Application.SetContextErrorHandler to override the
  3998. // default status code 500 with a custom error response.
  3999. func (ctx *Context) Protobuf(v proto.Message) (int, error) {
  4000. out, err := proto.Marshal(v)
  4001. if err != nil {
  4002. ctx.handleContextError(err)
  4003. return 0, err
  4004. }
  4005. ctx.ContentType(ContentProtobufHeaderValue)
  4006. n, err := ctx.Write(out)
  4007. if err != nil {
  4008. ctx.handleContextError(err)
  4009. }
  4010. return n, err
  4011. }
  4012. // MsgPack marshals the given "v" value of msgpack format and writes its result to the client.
  4013. //
  4014. // It reports any message pack or write errors back to the caller.
  4015. // Look the Application.SetContextErrorHandler to override the
  4016. // default status code 500 with a custom error response.
  4017. func (ctx *Context) MsgPack(v interface{}) (int, error) {
  4018. out, err := msgpack.Marshal(v)
  4019. if err != nil {
  4020. ctx.handleContextError(err)
  4021. }
  4022. ctx.ContentType(ContentMsgPackHeaderValue)
  4023. n, err := ctx.Write(out)
  4024. if err != nil {
  4025. ctx.handleContextError(err)
  4026. }
  4027. return n, err
  4028. }
  4029. // +-----------------------------------------------------------------------+
  4030. // | Content Νegotiation |
  4031. // | https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation | |
  4032. // +-----------------------------------------------------------------------+
  4033. // ErrContentNotSupported returns from the `Negotiate` method
  4034. // when server responds with 406.
  4035. var ErrContentNotSupported = errors.New("unsupported content")
  4036. // ContentSelector is the interface which structs can implement
  4037. // to manually choose a content based on the negotiated mime (content type).
  4038. // It can be passed to the `Context.Negotiate` method.
  4039. //
  4040. // See the `N` struct too.
  4041. type ContentSelector interface {
  4042. SelectContent(mime string) interface{}
  4043. }
  4044. // ContentNegotiator is the interface which structs can implement
  4045. // to override the `Context.Negotiate` default implementation and
  4046. // manually respond to the client based on a manuall call of `Context.Negotiation().Build()`
  4047. // to get the final negotiated mime and charset.
  4048. // It can be passed to the `Context.Negotiate` method.
  4049. type ContentNegotiator interface {
  4050. // mime and charset can be retrieved by:
  4051. // mime, charset := Context.Negotiation().Build()
  4052. // Pass this method to `Context.Negotiate` method
  4053. // to write custom content.
  4054. // Overriding the existing behavior of Context.Negotiate for selecting values based on
  4055. // content types, although it can accept any custom mime type with []byte.
  4056. // Content type is already set.
  4057. // Use it with caution, 99.9% you don't need this but it's here for extreme cases.
  4058. Negotiate(ctx *Context) (int, error)
  4059. }
  4060. // N is a struct which can be passed on the `Context.Negotiate` method.
  4061. // It contains fields which should be filled based on the `Context.Negotiation()`
  4062. // server side values. If no matched mime then its "Other" field will be sent,
  4063. // which should be a string or []byte.
  4064. // It completes the `ContentSelector` interface.
  4065. type N struct {
  4066. Text, HTML string
  4067. Markdown []byte
  4068. Binary []byte
  4069. JSON interface{}
  4070. Problem Problem
  4071. JSONP interface{}
  4072. XML interface{}
  4073. YAML interface{}
  4074. Protobuf interface{}
  4075. MsgPack interface{}
  4076. Other []byte // custom content types.
  4077. }
  4078. var _ ContentSelector = N{}
  4079. // SelectContent returns a content based on the matched negotiated "mime".
  4080. func (n N) SelectContent(mime string) interface{} {
  4081. switch mime {
  4082. case ContentTextHeaderValue:
  4083. return n.Text
  4084. case ContentHTMLHeaderValue:
  4085. return n.HTML
  4086. case ContentMarkdownHeaderValue:
  4087. return n.Markdown
  4088. case ContentBinaryHeaderValue:
  4089. return n.Binary
  4090. case ContentJSONHeaderValue:
  4091. return n.JSON
  4092. case ContentJSONProblemHeaderValue:
  4093. return n.Problem
  4094. case ContentJavascriptHeaderValue:
  4095. return n.JSONP
  4096. case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
  4097. return n.XML
  4098. case ContentYAMLHeaderValue:
  4099. return n.YAML
  4100. case ContentProtobufHeaderValue:
  4101. return n.Protobuf
  4102. case ContentMsgPackHeaderValue, ContentMsgPack2HeaderValue:
  4103. return n.MsgPack
  4104. default:
  4105. return n.Other
  4106. }
  4107. }
  4108. const negotiationContextKey = "iris.negotiation_builder"
  4109. // Negotiation creates once and returns the negotiation builder
  4110. // to build server-side available prioritized content
  4111. // for specific content type(s), charset(s) and encoding algorithm(s).
  4112. //
  4113. // See `Negotiate` method too.
  4114. func (ctx *Context) Negotiation() *NegotiationBuilder {
  4115. if n := ctx.values.Get(negotiationContextKey); n != nil {
  4116. return n.(*NegotiationBuilder)
  4117. }
  4118. acceptBuilder := NegotiationAcceptBuilder{}
  4119. acceptBuilder.accept = parseHeader(ctx.GetHeader("Accept"))
  4120. acceptBuilder.charset = parseHeader(ctx.GetHeader("Accept-Charset"))
  4121. n := &NegotiationBuilder{Accept: acceptBuilder}
  4122. ctx.values.Set(negotiationContextKey, n)
  4123. return n
  4124. }
  4125. func parseHeader(headerValue string) []string {
  4126. in := strings.Split(headerValue, ",")
  4127. out := make([]string, 0, len(in))
  4128. for _, value := range in {
  4129. // remove any spaces and quality values such as ;q=0.8.
  4130. v := strings.TrimSpace(strings.Split(value, ";")[0])
  4131. if v != "" {
  4132. out = append(out, v)
  4133. }
  4134. }
  4135. return out
  4136. }
  4137. // Negotiate used for serving different representations of a resource at the same URI.
  4138. //
  4139. // The "v" can be a single `N` struct value.
  4140. // The "v" can be any value completes the `ContentSelector` interface.
  4141. // The "v" can be any value completes the `ContentNegotiator` interface.
  4142. // The "v" can be any value of struct(JSON, JSONP, XML, YAML, Protobuf, MsgPack) or
  4143. // string(TEXT, HTML) or []byte(Markdown, Binary) or []byte with any matched mime type.
  4144. //
  4145. // If the "v" is nil, the `Context.Negotitation()` builder's
  4146. // content will be used instead, otherwise "v" overrides builder's content
  4147. // (server mime types are still retrieved by its registered, supported, mime list)
  4148. //
  4149. // Set mime type priorities by `Negotiation().JSON().XML().HTML()...`.
  4150. // Set charset priorities by `Negotiation().Charset(...)`.
  4151. // Set encoding algorithm priorities by `Negotiation().Encoding(...)`.
  4152. // Modify the accepted by
  4153. // `Negotiation().Accept./Override()/.XML().JSON().Charset(...).Encoding(...)...`.
  4154. //
  4155. // It returns `ErrContentNotSupported` when not matched mime type(s).
  4156. //
  4157. // Resources:
  4158. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation
  4159. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
  4160. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset
  4161. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
  4162. //
  4163. // Supports the above without quality values.
  4164. //
  4165. // Read more at: https://github.com/kataras/iris/tree/main/_examples/response-writer/content-negotiation
  4166. func (ctx *Context) Negotiate(v interface{}) (int, error) {
  4167. contentType, charset, encoding, content := ctx.Negotiation().Build()
  4168. if v == nil {
  4169. v = content
  4170. }
  4171. if contentType == "" {
  4172. // If the server cannot serve any matching set,
  4173. // it SHOULD send back a 406 (Not Acceptable) error code.
  4174. ctx.StatusCode(http.StatusNotAcceptable)
  4175. return -1, ErrContentNotSupported
  4176. }
  4177. if charset == "" {
  4178. charset = ctx.app.ConfigurationReadOnly().GetCharset()
  4179. }
  4180. if encoding != "" {
  4181. ctx.CompressWriter(true)
  4182. }
  4183. ctx.contentTypeOnce(contentType, charset)
  4184. if n, ok := v.(ContentNegotiator); ok {
  4185. return n.Negotiate(ctx)
  4186. }
  4187. if s, ok := v.(ContentSelector); ok {
  4188. v = s.SelectContent(contentType)
  4189. }
  4190. // switch v := value.(type) {
  4191. // case []byte:
  4192. // if contentType == ContentMarkdownHeaderValue {
  4193. // return ctx.Markdown(v)
  4194. // }
  4195. // return ctx.Write(v)
  4196. // case string:
  4197. // return ctx.WriteString(v)
  4198. // default:
  4199. // make it switch by content-type only, but we lose custom mime types capability that way:
  4200. // ^ solved with []byte on default case and
  4201. // ^ N.Other and
  4202. // ^ ContentSelector and ContentNegotiator interfaces.
  4203. switch contentType {
  4204. case ContentTextHeaderValue, ContentHTMLHeaderValue:
  4205. return ctx.WriteString(v.(string))
  4206. case ContentMarkdownHeaderValue:
  4207. err := ctx.Markdown(v.([]byte))
  4208. if err != nil {
  4209. return 0, err
  4210. }
  4211. return ctx.writer.Written(), nil
  4212. case ContentJSONHeaderValue:
  4213. err := ctx.JSON(v)
  4214. if err != nil {
  4215. return 0, err
  4216. }
  4217. return ctx.writer.Written(), nil
  4218. case ContentJSONProblemHeaderValue, ContentXMLProblemHeaderValue:
  4219. err := ctx.Problem(v)
  4220. if err != nil {
  4221. return 0, err
  4222. }
  4223. return ctx.writer.Written(), nil
  4224. case ContentJavascriptHeaderValue:
  4225. err := ctx.JSONP(v)
  4226. if err != nil {
  4227. return 0, err
  4228. }
  4229. return ctx.writer.Written(), nil
  4230. case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
  4231. err := ctx.XML(v)
  4232. if err != nil {
  4233. return 0, err
  4234. }
  4235. return ctx.writer.Written(), nil
  4236. case ContentYAMLHeaderValue:
  4237. err := ctx.YAML(v)
  4238. if err != nil {
  4239. return 0, err
  4240. }
  4241. return ctx.writer.Written(), nil
  4242. case ContentYAMLTextHeaderValue:
  4243. err := ctx.TextYAML(v)
  4244. if err != nil {
  4245. return 0, err
  4246. }
  4247. return ctx.writer.Written(), nil
  4248. case ContentProtobufHeaderValue:
  4249. msg, ok := v.(proto.Message)
  4250. if !ok {
  4251. return -1, ErrContentNotSupported
  4252. }
  4253. return ctx.Protobuf(msg)
  4254. case ContentMsgPackHeaderValue, ContentMsgPack2HeaderValue:
  4255. return ctx.MsgPack(v)
  4256. default:
  4257. // maybe "Other" or v is []byte or string but not a built-in framework mime,
  4258. // for custom content types,
  4259. // panic if not correct usage.
  4260. switch vv := v.(type) {
  4261. case []byte:
  4262. return ctx.Write(vv)
  4263. case string:
  4264. return ctx.WriteString(vv)
  4265. default:
  4266. ctx.StatusCode(http.StatusNotAcceptable)
  4267. return -1, ErrContentNotSupported
  4268. }
  4269. }
  4270. }
  4271. // NegotiationBuilder returns from the `Context.Negotitation`
  4272. // and can be used inside chain of handlers to build server-side
  4273. // mime type(s), charset(s) and encoding algorithm(s)
  4274. // that should match with the client's
  4275. // Accept, Accept-Charset and Accept-Encoding headers (by-default).
  4276. // To modify the client's accept use its "Accept" field
  4277. // which it's the `NegotitationAcceptBuilder`.
  4278. //
  4279. // See the `Negotiate` method too.
  4280. type NegotiationBuilder struct {
  4281. Accept NegotiationAcceptBuilder
  4282. mime []string // we need order.
  4283. contents map[string]interface{} // map to the "mime" and content should be rendered if that mime requested.
  4284. charset []string
  4285. encoding []string
  4286. }
  4287. // MIME registers a mime type and optionally the value that should be rendered
  4288. // through `Context.Negotiate` when this mime type is accepted by client.
  4289. //
  4290. // Returns itself for recursive calls.
  4291. func (n *NegotiationBuilder) MIME(mime string, content interface{}) *NegotiationBuilder {
  4292. mimes := parseHeader(mime) // if contains more than one sep by commas ",".
  4293. if content == nil {
  4294. n.mime = append(n.mime, mimes...)
  4295. return n
  4296. }
  4297. if n.contents == nil {
  4298. n.contents = make(map[string]interface{})
  4299. }
  4300. for _, m := range mimes {
  4301. n.mime = append(n.mime, m)
  4302. n.contents[m] = content
  4303. }
  4304. return n
  4305. }
  4306. // Text registers the "text/plain" content type and, optionally,
  4307. // a value that `Context.Negotiate` will render
  4308. // when a client accepts the "text/plain" content type.
  4309. //
  4310. // Returns itself for recursive calls.
  4311. func (n *NegotiationBuilder) Text(v ...string) *NegotiationBuilder {
  4312. var content interface{}
  4313. if len(v) > 0 {
  4314. content = v[0]
  4315. }
  4316. return n.MIME(ContentTextHeaderValue, content)
  4317. }
  4318. // HTML registers the "text/html" content type and, optionally,
  4319. // a value that `Context.Negotiate` will render
  4320. // when a client accepts the "text/html" content type.
  4321. //
  4322. // Returns itself for recursive calls.
  4323. func (n *NegotiationBuilder) HTML(v ...string) *NegotiationBuilder {
  4324. var content interface{}
  4325. if len(v) > 0 {
  4326. content = v[0]
  4327. }
  4328. return n.MIME(ContentHTMLHeaderValue, content)
  4329. }
  4330. // Markdown registers the "text/markdown" content type and, optionally,
  4331. // a value that `Context.Negotiate` will render
  4332. // when a client accepts the "text/markdown" content type.
  4333. //
  4334. // Returns itself for recursive calls.
  4335. func (n *NegotiationBuilder) Markdown(v ...[]byte) *NegotiationBuilder {
  4336. var content interface{}
  4337. if len(v) > 0 {
  4338. content = v
  4339. }
  4340. return n.MIME(ContentMarkdownHeaderValue, content)
  4341. }
  4342. // Binary registers the "application/octet-stream" content type and, optionally,
  4343. // a value that `Context.Negotiate` will render
  4344. // when a client accepts the "application/octet-stream" content type.
  4345. //
  4346. // Returns itself for recursive calls.
  4347. func (n *NegotiationBuilder) Binary(v ...[]byte) *NegotiationBuilder {
  4348. var content interface{}
  4349. if len(v) > 0 {
  4350. content = v[0]
  4351. }
  4352. return n.MIME(ContentBinaryHeaderValue, content)
  4353. }
  4354. // JSON registers the "application/json" content type and, optionally,
  4355. // a value that `Context.Negotiate` will render
  4356. // when a client accepts the "application/json" content type.
  4357. //
  4358. // Returns itself for recursive calls.
  4359. func (n *NegotiationBuilder) JSON(v ...interface{}) *NegotiationBuilder {
  4360. var content interface{}
  4361. if len(v) > 0 {
  4362. content = v[0]
  4363. }
  4364. return n.MIME(ContentJSONHeaderValue, content)
  4365. }
  4366. // Problem registers the "application/problem+json" or "application/problem+xml" content type and, optionally,
  4367. // a value that `Context.Negotiate` will render
  4368. // when a client accepts the "application/problem+json" or the "application/problem+xml" content type.
  4369. //
  4370. // Returns itself for recursive calls.
  4371. func (n *NegotiationBuilder) Problem(v ...interface{}) *NegotiationBuilder {
  4372. var content interface{}
  4373. if len(v) > 0 {
  4374. content = v[0]
  4375. }
  4376. return n.MIME(ContentJSONProblemHeaderValue+","+ContentXMLProblemHeaderValue, content)
  4377. }
  4378. // JSONP registers the "text/javascript" content type and, optionally,
  4379. // a value that `Context.Negotiate` will render
  4380. // when a client accepts the "javascript/javascript" content type.
  4381. //
  4382. // Returns itself for recursive calls.
  4383. func (n *NegotiationBuilder) JSONP(v ...interface{}) *NegotiationBuilder {
  4384. var content interface{}
  4385. if len(v) > 0 {
  4386. content = v[0]
  4387. }
  4388. return n.MIME(ContentJavascriptHeaderValue, content)
  4389. }
  4390. // XML registers the "text/xml" and "application/xml" content types and, optionally,
  4391. // a value that `Context.Negotiate` will render
  4392. // when a client accepts one of the "text/xml" or "application/xml" content types.
  4393. //
  4394. // Returns itself for recursive calls.
  4395. func (n *NegotiationBuilder) XML(v ...interface{}) *NegotiationBuilder {
  4396. var content interface{}
  4397. if len(v) > 0 {
  4398. content = v[0]
  4399. }
  4400. return n.MIME(ContentXMLHeaderValue+","+ContentXMLUnreadableHeaderValue, content)
  4401. }
  4402. // YAML registers the "application/x-yaml" content type and, optionally,
  4403. // a value that `Context.Negotiate` will render
  4404. // when a client accepts the "application/x-yaml" content type.
  4405. //
  4406. // Returns itself for recursive calls.
  4407. func (n *NegotiationBuilder) YAML(v ...interface{}) *NegotiationBuilder {
  4408. var content interface{}
  4409. if len(v) > 0 {
  4410. content = v[0]
  4411. }
  4412. return n.MIME(ContentYAMLHeaderValue, content)
  4413. }
  4414. // TextYAML registers the "text/yaml" content type and, optionally,
  4415. // a value that `Context.Negotiate` will render
  4416. // when a client accepts the "application/x-yaml" content type.
  4417. //
  4418. // Returns itself for recursive calls.
  4419. func (n *NegotiationBuilder) TextYAML(v ...interface{}) *NegotiationBuilder {
  4420. var content interface{}
  4421. if len(v) > 0 {
  4422. content = v[0]
  4423. }
  4424. return n.MIME(ContentYAMLTextHeaderValue, content)
  4425. }
  4426. // Protobuf registers the "application/x-protobuf" content type and, optionally,
  4427. // a value that `Context.Negotiate` will render
  4428. // when a client accepts the "application/x-protobuf" content type.
  4429. //
  4430. // Returns itself for recursive calls.
  4431. func (n *NegotiationBuilder) Protobuf(v ...interface{}) *NegotiationBuilder {
  4432. var content interface{}
  4433. if len(v) > 0 {
  4434. content = v[0]
  4435. }
  4436. return n.MIME(ContentProtobufHeaderValue, content)
  4437. }
  4438. // MsgPack registers the "application/x-msgpack" and "application/msgpack" content types and, optionally,
  4439. // a value that `Context.Negotiate` will render
  4440. // when a client accepts one of the "application/x-msgpack" or "application/msgpack" content types.
  4441. //
  4442. // Returns itself for recursive calls.
  4443. func (n *NegotiationBuilder) MsgPack(v ...interface{}) *NegotiationBuilder {
  4444. var content interface{}
  4445. if len(v) > 0 {
  4446. content = v[0]
  4447. }
  4448. return n.MIME(ContentMsgPackHeaderValue+","+ContentMsgPack2HeaderValue, content)
  4449. }
  4450. // Any registers a wildcard that can match any client's accept content type.
  4451. //
  4452. // Returns itself for recursive calls.
  4453. func (n *NegotiationBuilder) Any(v ...interface{}) *NegotiationBuilder {
  4454. var content interface{}
  4455. if len(v) > 0 {
  4456. content = v[0]
  4457. }
  4458. return n.MIME("*", content)
  4459. }
  4460. // Charset overrides the application's config's charset (which defaults to "utf-8")
  4461. // that a client should match for
  4462. // (through Accept-Charset header or custom through `NegotitationBuilder.Accept.Override().Charset(...)` call).
  4463. // Do not set it if you don't know what you're doing.
  4464. //
  4465. // Returns itself for recursive calls.
  4466. func (n *NegotiationBuilder) Charset(charset ...string) *NegotiationBuilder {
  4467. n.charset = append(n.charset, charset...)
  4468. return n
  4469. }
  4470. // Encoding registers one or more encoding algorithms by name, i.e gzip, deflate, br, snappy, s2.
  4471. // that a client should match for (through Accept-Encoding header).
  4472. //
  4473. // Returns itself for recursive calls.
  4474. func (n *NegotiationBuilder) Encoding(encoding ...string) *NegotiationBuilder {
  4475. n.encoding = append(n.encoding, encoding...)
  4476. return n
  4477. }
  4478. // EncodingGzip registers the "gzip" encoding algorithm
  4479. // that a client should match for (through Accept-Encoding header or call of Accept.Encoding(enc)).
  4480. //
  4481. // It will make resources to served by "gzip" if Accept-Encoding contains the "gzip" as well.
  4482. //
  4483. // Returns itself for recursive calls.
  4484. func (n *NegotiationBuilder) EncodingGzip() *NegotiationBuilder {
  4485. return n.Encoding(GzipHeaderValue)
  4486. }
  4487. // Build calculates the client's and server's mime type(s), charset(s) and encoding
  4488. // and returns the final content type, charset and encoding that server should render
  4489. // to the client. It does not clear the fields, use the `Clear` method if neeeded.
  4490. //
  4491. // The returned "content" can be nil if the matched "contentType" does not provide any value,
  4492. // in that case the `Context.Negotiate(v)` must be called with a non-nil value.
  4493. func (n *NegotiationBuilder) Build() (contentType, charset, encoding string, content interface{}) {
  4494. contentType = negotiationMatch(n.Accept.accept, n.mime)
  4495. charset = negotiationMatch(n.Accept.charset, n.charset)
  4496. encoding = negotiationMatch(n.Accept.encoding, n.encoding)
  4497. if n.contents != nil {
  4498. if data, ok := n.contents[contentType]; ok {
  4499. content = data
  4500. }
  4501. }
  4502. return
  4503. }
  4504. // Clear clears the prioritized mime type(s), charset(s) and any contents
  4505. // relative to those mime type(s).
  4506. // The "Accept" field is stay as it is, use its `Override` method
  4507. // to clear out the client's accepted mime type(s) and charset(s).
  4508. func (n *NegotiationBuilder) Clear() *NegotiationBuilder {
  4509. n.mime = n.mime[0:0]
  4510. n.contents = nil
  4511. n.charset = n.charset[0:0]
  4512. return n
  4513. }
  4514. // NegotiationAcceptBuilder builds the accepted mime types and charset
  4515. //
  4516. // and "Accept-Charset" headers respectfully.
  4517. // The default values are set by the client side, server can append or override those.
  4518. // The end result will be challenged with runtime preffered set of content types and charsets.
  4519. //
  4520. // See the `Negotiate` method too.
  4521. type NegotiationAcceptBuilder struct {
  4522. // initialized with "Accept" request header values.
  4523. accept []string
  4524. // initialized with "Accept-Charset" request header. and if was empty then the
  4525. // application's default (which defaults to utf-8).
  4526. charset []string
  4527. // initialized with "Accept-Encoding" request header values.
  4528. encoding []string
  4529. // To support override in request life cycle.
  4530. // We need slice when data is the same format
  4531. // for one or more mime types,
  4532. // i.e text/xml and obselete application/xml.
  4533. lastAccept []string
  4534. lastCharset []string
  4535. lastEncoding []string
  4536. }
  4537. // Override clears the default values for accept and accept charset.
  4538. // Returns itself.
  4539. func (n *NegotiationAcceptBuilder) Override() *NegotiationAcceptBuilder {
  4540. // when called first.
  4541. n.accept = n.accept[0:0]
  4542. n.charset = n.charset[0:0]
  4543. n.encoding = n.encoding[0:0]
  4544. // when called after.
  4545. if len(n.lastAccept) > 0 {
  4546. n.accept = append(n.accept, n.lastAccept...)
  4547. n.lastAccept = n.lastAccept[0:0]
  4548. }
  4549. if len(n.lastCharset) > 0 {
  4550. n.charset = append(n.charset, n.lastCharset...)
  4551. n.lastCharset = n.lastCharset[0:0]
  4552. }
  4553. if len(n.lastEncoding) > 0 {
  4554. n.encoding = append(n.encoding, n.lastEncoding...)
  4555. n.lastEncoding = n.lastEncoding[0:0]
  4556. }
  4557. return n
  4558. }
  4559. // MIME adds accepted client's mime type(s).
  4560. // Returns itself.
  4561. func (n *NegotiationAcceptBuilder) MIME(mimeType ...string) *NegotiationAcceptBuilder {
  4562. n.lastAccept = mimeType
  4563. n.accept = append(n.accept, mimeType...)
  4564. return n
  4565. }
  4566. // Text adds the "text/plain" as accepted client content type.
  4567. // Returns itself.
  4568. func (n *NegotiationAcceptBuilder) Text() *NegotiationAcceptBuilder {
  4569. return n.MIME(ContentTextHeaderValue)
  4570. }
  4571. // HTML adds the "text/html" as accepted client content type.
  4572. // Returns itself.
  4573. func (n *NegotiationAcceptBuilder) HTML() *NegotiationAcceptBuilder {
  4574. return n.MIME(ContentHTMLHeaderValue)
  4575. }
  4576. // Markdown adds the "text/markdown" as accepted client content type.
  4577. // Returns itself.
  4578. func (n *NegotiationAcceptBuilder) Markdown() *NegotiationAcceptBuilder {
  4579. return n.MIME(ContentMarkdownHeaderValue)
  4580. }
  4581. // Binary adds the "application/octet-stream" as accepted client content type.
  4582. // Returns itself.
  4583. func (n *NegotiationAcceptBuilder) Binary() *NegotiationAcceptBuilder {
  4584. return n.MIME(ContentBinaryHeaderValue)
  4585. }
  4586. // JSON adds the "application/json" as accepted client content type.
  4587. // Returns itself.
  4588. func (n *NegotiationAcceptBuilder) JSON() *NegotiationAcceptBuilder {
  4589. return n.MIME(ContentJSONHeaderValue)
  4590. }
  4591. // Problem adds the "application/problem+json" and "application/problem-xml"
  4592. // as accepted client content types.
  4593. // Returns itself.
  4594. func (n *NegotiationAcceptBuilder) Problem() *NegotiationAcceptBuilder {
  4595. return n.MIME(ContentJSONProblemHeaderValue, ContentXMLProblemHeaderValue)
  4596. }
  4597. // JSONP adds the "text/javascript" as accepted client content type.
  4598. // Returns itself.
  4599. func (n *NegotiationAcceptBuilder) JSONP() *NegotiationAcceptBuilder {
  4600. return n.MIME(ContentJavascriptHeaderValue)
  4601. }
  4602. // XML adds the "text/xml" and "application/xml" as accepted client content types.
  4603. // Returns itself.
  4604. func (n *NegotiationAcceptBuilder) XML() *NegotiationAcceptBuilder {
  4605. return n.MIME(ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue)
  4606. }
  4607. // YAML adds the "application/x-yaml" as accepted client content type.
  4608. // Returns itself.
  4609. func (n *NegotiationAcceptBuilder) YAML() *NegotiationAcceptBuilder {
  4610. return n.MIME(ContentYAMLHeaderValue)
  4611. }
  4612. // TextYAML adds the "text/yaml" as accepted client content type.
  4613. // Returns itself.
  4614. func (n *NegotiationAcceptBuilder) TextYAML() *NegotiationAcceptBuilder {
  4615. return n.MIME(ContentYAMLTextHeaderValue)
  4616. }
  4617. // Protobuf adds the "application/x-protobuf" as accepted client content type.
  4618. // Returns itself.
  4619. func (n *NegotiationAcceptBuilder) Protobuf() *NegotiationAcceptBuilder {
  4620. return n.MIME(ContentYAMLHeaderValue)
  4621. }
  4622. // MsgPack adds the "application/msgpack" and "application/x-msgpack" as accepted client content types.
  4623. // Returns itself.
  4624. func (n *NegotiationAcceptBuilder) MsgPack() *NegotiationAcceptBuilder {
  4625. return n.MIME(ContentYAMLHeaderValue)
  4626. }
  4627. // Charset adds one or more client accepted charsets.
  4628. // Returns itself.
  4629. func (n *NegotiationAcceptBuilder) Charset(charset ...string) *NegotiationAcceptBuilder {
  4630. n.lastCharset = charset
  4631. n.charset = append(n.charset, charset...)
  4632. return n
  4633. }
  4634. // Encoding adds one or more client accepted encoding algorithms.
  4635. // Returns itself.
  4636. func (n *NegotiationAcceptBuilder) Encoding(encoding ...string) *NegotiationAcceptBuilder {
  4637. n.lastEncoding = encoding
  4638. n.encoding = append(n.encoding, encoding...)
  4639. return n
  4640. }
  4641. // EncodingGzip adds the "gzip" as accepted encoding.
  4642. // Returns itself.
  4643. func (n *NegotiationAcceptBuilder) EncodingGzip() *NegotiationAcceptBuilder {
  4644. return n.Encoding(GzipHeaderValue)
  4645. }
  4646. // +------------------------------------------------------------+
  4647. // | Serve files |
  4648. // +------------------------------------------------------------+
  4649. // ServeContent replies to the request using the content in the
  4650. // provided ReadSeeker. The main benefit of ServeContent over io.Copy
  4651. // is that it handles Range requests properly, sets the MIME type, and
  4652. // handles If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since,
  4653. // and If-Range requests.
  4654. //
  4655. // If the response's Content-Type header is not set, ServeContent
  4656. // first tries to deduce the type from name's file extension.
  4657. //
  4658. // The name is otherwise unused; in particular it can be empty and is
  4659. // never sent in the response.
  4660. //
  4661. // If modtime is not the zero time or Unix epoch, ServeContent
  4662. // includes it in a Last-Modified header in the response. If the
  4663. // request includes an If-Modified-Since header, ServeContent uses
  4664. // modtime to decide whether the content needs to be sent at all.
  4665. //
  4666. // The content's Seek method must work: ServeContent uses
  4667. // a seek to the end of the content to determine its size.
  4668. //
  4669. // If the caller has set w's ETag header formatted per RFC 7232, section 2.3,
  4670. // ServeContent uses it to handle requests using If-Match, If-None-Match, or If-Range.
  4671. //
  4672. // Note that *os.File implements the io.ReadSeeker interface.
  4673. // Note that compression can be registered
  4674. // through `ctx.CompressWriter(true)` or `app.Use(iris.Compression)`.
  4675. func (ctx *Context) ServeContent(content io.ReadSeeker, filename string, modtime time.Time) {
  4676. ctx.ServeContentWithRate(content, filename, modtime, 0, 0)
  4677. }
  4678. // rateReadSeeker is a io.ReadSeeker that is rate limited by
  4679. // the given token bucket. Each token in the bucket
  4680. // represents one byte. See "golang.org/x/time/rate" package.
  4681. type rateReadSeeker struct {
  4682. io.ReadSeeker
  4683. ctx context.Context
  4684. limiter *rate.Limiter
  4685. }
  4686. func (rs *rateReadSeeker) Read(buf []byte) (int, error) {
  4687. n, err := rs.ReadSeeker.Read(buf)
  4688. if n <= 0 {
  4689. return n, err
  4690. }
  4691. err = rs.limiter.WaitN(rs.ctx, n)
  4692. return n, err
  4693. }
  4694. // ServeContentWithRate same as `ServeContent` but it can throttle the speed of reading
  4695. // and though writing the "content" to the client.
  4696. func (ctx *Context) ServeContentWithRate(content io.ReadSeeker, filename string, modtime time.Time, limit float64, burst int) {
  4697. if limit > 0 {
  4698. content = &rateReadSeeker{
  4699. ReadSeeker: content,
  4700. ctx: ctx.request.Context(),
  4701. limiter: rate.NewLimiter(rate.Limit(limit), burst),
  4702. }
  4703. }
  4704. http.ServeContent(ctx.writer, ctx.request, filename, modtime, content)
  4705. }
  4706. // ServeFile replies to the request with the contents of the named
  4707. // file or directory.
  4708. //
  4709. // If the provided file or directory name is a relative path, it is
  4710. // interpreted relative to the current directory and may ascend to
  4711. // parent directories. If the provided name is constructed from user
  4712. // input, it should be sanitized before calling `ServeFile`.
  4713. //
  4714. // Use it when you want to serve assets like css and javascript files.
  4715. // If client should confirm and save the file use the `SendFile` instead.
  4716. // Note that compression can be registered
  4717. // through `ctx.CompressWriter(true)` or `app.Use(iris.Compression)`.
  4718. func (ctx *Context) ServeFile(filename string) error {
  4719. return ctx.ServeFileWithRate(filename, 0, 0)
  4720. }
  4721. // ServeFileWithRate same as `ServeFile` but it can throttle the speed of reading
  4722. // and though writing the file to the client.
  4723. func (ctx *Context) ServeFileWithRate(filename string, limit float64, burst int) error {
  4724. f, err := os.Open(filename)
  4725. if err != nil {
  4726. ctx.StatusCode(http.StatusNotFound)
  4727. return err
  4728. }
  4729. defer f.Close()
  4730. st, err := f.Stat()
  4731. if err != nil {
  4732. code := http.StatusInternalServerError
  4733. if os.IsNotExist(err) {
  4734. code = http.StatusNotFound
  4735. }
  4736. if os.IsPermission(err) {
  4737. code = http.StatusForbidden
  4738. }
  4739. ctx.StatusCode(code)
  4740. return err
  4741. }
  4742. if st.IsDir() {
  4743. return ctx.ServeFile(path.Join(filename, "index.html"))
  4744. }
  4745. ctx.ServeContentWithRate(f, st.Name(), st.ModTime(), limit, burst)
  4746. return nil
  4747. }
  4748. // SendFile sends a file as an attachment, that is downloaded and saved locally from client.
  4749. // Note that compression can be registered
  4750. // through `ctx.CompressWriter(true)` or `app.Use(iris.Compression)`.
  4751. // Use `ServeFile` if a file should be served as a page asset instead.
  4752. func (ctx *Context) SendFile(src string, destName string) error {
  4753. return ctx.SendFileWithRate(src, destName, 0, 0)
  4754. }
  4755. // SendFileWithRate same as `SendFile` but it can throttle the speed of reading
  4756. // and though writing the file to the client.
  4757. func (ctx *Context) SendFileWithRate(src, destName string, limit float64, burst int) error {
  4758. if destName == "" {
  4759. destName = filepath.Base(src)
  4760. }
  4761. ctx.writer.Header().Set(ContentDispositionHeaderKey, MakeDisposition(destName))
  4762. return ctx.ServeFileWithRate(src, limit, burst)
  4763. }
  4764. // MakeDisposition generates an HTTP Content-Disposition field-value.
  4765. // Similar solution followed by: Spring(Java), Symfony(PHP) and Ruby on Rails frameworks too.
  4766. //
  4767. // Fixes CVE-2020-5398. Reported by motoyasu-saburi.
  4768. func MakeDisposition(filename string) string {
  4769. return `attachment; filename*=UTF-8''` + url.QueryEscape(filename)
  4770. } /*
  4771. // Found at: https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters
  4772. // A faster (better, more idiomatic) version, which avoids unnecessary rune conversions.
  4773. func isASCII(s string) bool {
  4774. for i := 0; i < len(s); i++ {
  4775. if s[i] > unicode.MaxASCII {
  4776. return false
  4777. }
  4778. }
  4779. return true
  4780. }
  4781. func isRFC5987AttrChar(c rune) bool {
  4782. return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
  4783. c == '!' || c == '#' || c == '$' || c == '&' || c == '+' || c == '-' ||
  4784. c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~'
  4785. }
  4786. */
  4787. // +------------------------------------------------------------+
  4788. // | Cookies |
  4789. // +------------------------------------------------------------+
  4790. // Set of Cookie actions for `CookieOption`.
  4791. const (
  4792. OpCookieGet uint8 = iota
  4793. OpCookieSet
  4794. OpCookieDel
  4795. )
  4796. // CookieOption is the type of function that is accepted on
  4797. // context's methods like `SetCookieKV`, `RemoveCookie` and `SetCookie`
  4798. // as their (last) variadic input argument to amend the to-be-sent cookie.
  4799. //
  4800. // The "op" is the operation code, 0 is GET, 1 is SET and 2 is REMOVE.
  4801. type CookieOption func(ctx *Context, c *http.Cookie, op uint8)
  4802. // CookieIncluded reports whether the "cookie.Name" is in the list of "cookieNames".
  4803. // Notes:
  4804. // If "cookieNames" slice is empty then it returns true,
  4805. // If "cookie.Name" is empty then it returns false.
  4806. func CookieIncluded(cookie *http.Cookie, cookieNames []string) bool {
  4807. if cookie.Name == "" {
  4808. return false
  4809. }
  4810. if len(cookieNames) > 0 {
  4811. for _, name := range cookieNames {
  4812. if cookie.Name == name {
  4813. return true
  4814. }
  4815. }
  4816. return false
  4817. }
  4818. return true
  4819. }
  4820. // var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
  4821. //
  4822. // func sanitizeCookieName(n string) string {
  4823. // return cookieNameSanitizer.Replace(n)
  4824. // }
  4825. // CookieOverride is a CookieOption which overrides the cookie explicitly to the given "cookie".
  4826. //
  4827. // Usage:
  4828. // ctx.RemoveCookie("the_cookie_name", iris.CookieOverride(&http.Cookie{Domain: "example.com"}))
  4829. func CookieOverride(cookie *http.Cookie) CookieOption { // The "Cookie" word method name is reserved as it's used as an alias.
  4830. return func(_ *Context, c *http.Cookie, op uint8) {
  4831. if op == OpCookieGet {
  4832. return
  4833. }
  4834. *cookie = *c
  4835. }
  4836. }
  4837. // CookieDomain is a CookieOption which sets the cookie's Domain field.
  4838. // If empty then the current domain is used.
  4839. //
  4840. // Usage:
  4841. // ctx.RemoveCookie("the_cookie_name", iris.CookieDomain("example.com"))
  4842. func CookieDomain(domain string) CookieOption {
  4843. return func(_ *Context, c *http.Cookie, op uint8) {
  4844. if op == OpCookieGet {
  4845. return
  4846. }
  4847. c.Domain = domain
  4848. }
  4849. }
  4850. // CookieAllowReclaim accepts the Context itself.
  4851. // If set it will add the cookie to (on `CookieSet`, `CookieSetKV`, `CookieUpsert`)
  4852. // or remove the cookie from (on `CookieRemove`) the Request object too.
  4853. func CookieAllowReclaim(cookieNames ...string) CookieOption {
  4854. return func(ctx *Context, c *http.Cookie, op uint8) {
  4855. if op == OpCookieGet {
  4856. return
  4857. }
  4858. if !CookieIncluded(c, cookieNames) {
  4859. return
  4860. }
  4861. switch op {
  4862. case OpCookieSet:
  4863. // perform upsert on request cookies or is it too much and not worth the cost?
  4864. ctx.Request().AddCookie(c)
  4865. case OpCookieDel:
  4866. cookies := ctx.Request().Cookies()
  4867. ctx.Request().Header.Del("Cookie")
  4868. for i, v := range cookies {
  4869. if v.Name != c.Name {
  4870. ctx.Request().AddCookie(cookies[i])
  4871. }
  4872. }
  4873. }
  4874. }
  4875. }
  4876. // CookieAllowSubdomains set to the Cookie Options
  4877. // in order to allow subdomains to have access to the cookies.
  4878. // It sets the cookie's Domain field (if was empty) and
  4879. // it also sets the cookie's SameSite to lax mode too.
  4880. func CookieAllowSubdomains(cookieNames ...string) CookieOption {
  4881. return func(ctx *Context, c *http.Cookie, _ uint8) {
  4882. if c.Domain != "" {
  4883. return // already set.
  4884. }
  4885. if !CookieIncluded(c, cookieNames) {
  4886. return
  4887. }
  4888. c.Domain = ctx.Domain()
  4889. c.SameSite = http.SameSiteLaxMode // allow subdomain sharing.
  4890. }
  4891. }
  4892. // CookieSameSite sets a same-site rule for cookies to set.
  4893. // SameSite allows a server to define a cookie attribute making it impossible for
  4894. // the browser to send this cookie along with cross-site requests. The main
  4895. // goal is to mitigate the risk of cross-origin information leakage, and provide
  4896. // some protection against cross-site request forgery attacks.
  4897. //
  4898. // See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
  4899. func CookieSameSite(sameSite http.SameSite) CookieOption {
  4900. return func(_ *Context, c *http.Cookie, op uint8) {
  4901. if op == OpCookieSet {
  4902. c.SameSite = sameSite
  4903. }
  4904. }
  4905. }
  4906. // CookieSecure sets the cookie's Secure option if the current request's
  4907. // connection is using TLS. See `CookieHTTPOnly` too.
  4908. func CookieSecure(ctx *Context, c *http.Cookie, op uint8) {
  4909. if op == OpCookieSet {
  4910. if ctx.Request().TLS != nil {
  4911. c.Secure = true
  4912. }
  4913. }
  4914. }
  4915. // CookieHTTPOnly is a `CookieOption`.
  4916. // Use it to set the cookie's HttpOnly field to false or true.
  4917. // HttpOnly field defaults to true for `RemoveCookie` and `SetCookieKV`.
  4918. // See `CookieSecure` too.
  4919. func CookieHTTPOnly(httpOnly bool) CookieOption {
  4920. return func(_ *Context, c *http.Cookie, op uint8) {
  4921. if op == OpCookieSet {
  4922. c.HttpOnly = httpOnly
  4923. }
  4924. }
  4925. }
  4926. // CookiePath is a `CookieOption`.
  4927. // Use it to change the cookie's Path field.
  4928. func CookiePath(path string) CookieOption {
  4929. return func(_ *Context, c *http.Cookie, op uint8) {
  4930. if op > OpCookieGet { // on set and remove.
  4931. c.Path = path
  4932. }
  4933. }
  4934. }
  4935. // CookieCleanPath is a `CookieOption`.
  4936. // Use it to clear the cookie's Path field, exactly the same as `CookiePath("")`.
  4937. func CookieCleanPath(_ *Context, c *http.Cookie, op uint8) {
  4938. if op > OpCookieGet {
  4939. c.Path = ""
  4940. }
  4941. }
  4942. // CookieExpires is a `CookieOption`.
  4943. // Use it to change the cookie's Expires and MaxAge fields by passing the lifetime of the cookie.
  4944. func CookieExpires(durFromNow time.Duration) CookieOption {
  4945. return func(_ *Context, c *http.Cookie, op uint8) {
  4946. if op == OpCookieSet {
  4947. c.Expires = time.Now().Add(durFromNow)
  4948. c.MaxAge = int(durFromNow.Seconds())
  4949. }
  4950. }
  4951. }
  4952. // SecureCookie should encodes and decodes
  4953. // authenticated and optionally encrypted cookie values.
  4954. // See `CookieEncoding` package-level function.
  4955. type SecureCookie interface {
  4956. // Encode should encode the cookie value.
  4957. // Should accept the cookie's name as its first argument
  4958. // and as second argument the cookie value ptr.
  4959. // Should return an encoded value or an empty one if encode operation failed.
  4960. // Should return an error if encode operation failed.
  4961. //
  4962. // Note: Errors are not printed, so you have to know what you're doing,
  4963. // and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
  4964. // You either need to provide exactly that amount or you derive the key from what you type in.
  4965. //
  4966. // See `Decode` too.
  4967. Encode(cookieName string, cookieValue interface{}) (string, error)
  4968. // Decode should decode the cookie value.
  4969. // Should accept the cookie's name as its first argument,
  4970. // as second argument the encoded cookie value and as third argument the decoded value ptr.
  4971. // Should return a decoded value or an empty one if decode operation failed.
  4972. // Should return an error if decode operation failed.
  4973. //
  4974. // Note: Errors are not printed, so you have to know what you're doing,
  4975. // and remember: if you use AES it only supports key sizes of 16, 24 or 32 bytes.
  4976. // You either need to provide exactly that amount or you derive the key from what you type in.
  4977. //
  4978. // See `Encode` too.
  4979. Decode(cookieName string, cookieValue string, cookieValuePtr interface{}) error
  4980. }
  4981. // CookieEncoding accepts a value which implements `Encode` and `Decode` methods.
  4982. // It calls its `Encode` on `Context.SetCookie, UpsertCookie, and SetCookieKV` methods.
  4983. // And on `Context.GetCookie` method it calls its `Decode`.
  4984. // If "cookieNames" slice is not empty then only cookies
  4985. // with that `Name` will be encoded on set and decoded on get, that way you can encrypt
  4986. // specific cookie names (like the session id) and let the rest of the cookies "insecure".
  4987. //
  4988. // Example: https://github.com/kataras/iris/tree/main/_examples/cookies/securecookie
  4989. func CookieEncoding(encoding SecureCookie, cookieNames ...string) CookieOption {
  4990. if encoding == nil {
  4991. return func(_ *Context, _ *http.Cookie, _ uint8) {}
  4992. }
  4993. return func(ctx *Context, c *http.Cookie, op uint8) {
  4994. if op == OpCookieDel {
  4995. return
  4996. }
  4997. if !CookieIncluded(c, cookieNames) {
  4998. return
  4999. }
  5000. switch op {
  5001. case OpCookieSet:
  5002. // Should encode, it's a write to the client operation.
  5003. newVal, err := encoding.Encode(c.Name, c.Value)
  5004. if err != nil {
  5005. ctx.Application().Logger().Error(err)
  5006. c.Value = ""
  5007. } else {
  5008. c.Value = newVal
  5009. }
  5010. return
  5011. case OpCookieGet:
  5012. // Should decode, it's a read from the client operation.
  5013. if err := encoding.Decode(c.Name, c.Value, &c.Value); err != nil {
  5014. c.Value = ""
  5015. }
  5016. }
  5017. }
  5018. }
  5019. const cookieOptionsContextKey = "iris.cookie.options"
  5020. // AddCookieOptions adds cookie options for `SetCookie`,
  5021. // `SetCookieKV, UpsertCookie` and `RemoveCookie` methods
  5022. // for the current request. It can be called from a middleware before
  5023. // cookies sent or received from the next Handler in the chain.
  5024. //
  5025. // Available builtin Cookie options are:
  5026. // - CookieOverride
  5027. // - CookieDomain
  5028. // - CookieAllowReclaim
  5029. // - CookieAllowSubdomains
  5030. // - CookieSecure
  5031. // - CookieHTTPOnly
  5032. // - CookieSameSite
  5033. // - CookiePath
  5034. // - CookieCleanPath
  5035. // - CookieExpires
  5036. // - CookieEncoding
  5037. //
  5038. // Example at: https://github.com/kataras/iris/tree/main/_examples/cookies/securecookie
  5039. func (ctx *Context) AddCookieOptions(options ...CookieOption) {
  5040. if len(options) == 0 {
  5041. return
  5042. }
  5043. if v := ctx.values.Get(cookieOptionsContextKey); v != nil {
  5044. if opts, ok := v.([]CookieOption); ok {
  5045. options = append(opts, options...)
  5046. }
  5047. }
  5048. ctx.values.Set(cookieOptionsContextKey, options)
  5049. }
  5050. func (ctx *Context) applyCookieOptions(c *http.Cookie, op uint8, override []CookieOption) {
  5051. if v := ctx.values.Get(cookieOptionsContextKey); v != nil {
  5052. if options, ok := v.([]CookieOption); ok {
  5053. for _, opt := range options {
  5054. opt(ctx, c, op)
  5055. }
  5056. }
  5057. }
  5058. // The function's ones should be called last, so they can override
  5059. // the stored ones (i.e by a prior middleware).
  5060. for _, opt := range override {
  5061. opt(ctx, c, op)
  5062. }
  5063. }
  5064. // ClearCookieOptions clears any previously registered cookie options.
  5065. // See `AddCookieOptions` too.
  5066. func (ctx *Context) ClearCookieOptions() {
  5067. ctx.values.Remove(cookieOptionsContextKey)
  5068. }
  5069. // SetCookie adds a cookie.
  5070. // Use of the "options" is not required, they can be used to amend the "cookie".
  5071. //
  5072. // Example: https://github.com/kataras/iris/tree/main/_examples/cookies/basic
  5073. func (ctx *Context) SetCookie(cookie *http.Cookie, options ...CookieOption) {
  5074. ctx.applyCookieOptions(cookie, OpCookieSet, options)
  5075. http.SetCookie(ctx.writer, cookie)
  5076. }
  5077. const setCookieHeaderKey = "Set-Cookie"
  5078. // UpsertCookie adds a cookie to the response like `SetCookie` does
  5079. // but it will also perform a replacement of the cookie
  5080. // if already set by a previous `SetCookie` call.
  5081. // It reports whether the cookie is new (true) or an existing one was updated (false).
  5082. func (ctx *Context) UpsertCookie(cookie *http.Cookie, options ...CookieOption) bool {
  5083. ctx.applyCookieOptions(cookie, OpCookieSet, options)
  5084. header := ctx.ResponseWriter().Header()
  5085. if cookies := header[setCookieHeaderKey]; len(cookies) > 0 {
  5086. s := cookie.Name + "=" // name=?value
  5087. existingUpdated := false
  5088. for i, c := range cookies {
  5089. if strings.HasPrefix(c, s) {
  5090. if existingUpdated { // fixes #1877
  5091. // remove any duplicated.
  5092. cookies[i] = ""
  5093. header[setCookieHeaderKey] = cookies
  5094. continue
  5095. }
  5096. // We need to update the Set-Cookie (to update the expiration or any other cookie's properties).
  5097. // Probably the cookie is set and then updated in the first session creation
  5098. // (e.g. UpdateExpiration, see https://github.com/kataras/iris/issues/1485).
  5099. cookies[i] = cookie.String()
  5100. header[setCookieHeaderKey] = cookies
  5101. existingUpdated = true
  5102. }
  5103. }
  5104. if existingUpdated {
  5105. return false // existing one updated.
  5106. }
  5107. }
  5108. header.Add(setCookieHeaderKey, cookie.String())
  5109. return true
  5110. }
  5111. // SetCookieKVExpiration is 365 days by-default
  5112. // you can change it or simple, use the SetCookie for more control.
  5113. //
  5114. // See `CookieExpires` and `AddCookieOptions` for more.
  5115. var SetCookieKVExpiration = 8760 * time.Hour
  5116. // SetCookieKV adds a cookie, requires the name(string) and the value(string).
  5117. //
  5118. // By default it expires after 365 days and it is added to the root URL path,
  5119. // use the `CookieExpires` and `CookiePath` to modify them.
  5120. // Alternatively: ctx.SetCookie(&http.Cookie{...}) or ctx.AddCookieOptions(...)
  5121. //
  5122. // If you want to set custom the path:
  5123. // ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))
  5124. //
  5125. // If you want to be visible only to current request path:
  5126. // (note that client should be responsible for that if server sent an empty cookie's path, all browsers are compatible)
  5127. // ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
  5128. // More:
  5129. //
  5130. // iris.CookieExpires(time.Duration)
  5131. // iris.CookieHTTPOnly(false)
  5132. //
  5133. // Examples: https://github.com/kataras/iris/tree/main/_examples/cookies/basic
  5134. func (ctx *Context) SetCookieKV(name, value string, options ...CookieOption) {
  5135. c := &http.Cookie{}
  5136. c.Path = "/"
  5137. c.Name = name
  5138. c.Value = url.QueryEscape(value)
  5139. c.HttpOnly = true
  5140. // MaxAge=0 means no 'Max-Age' attribute specified.
  5141. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
  5142. // MaxAge>0 means Max-Age attribute present and given in seconds
  5143. c.Expires = time.Now().Add(SetCookieKVExpiration)
  5144. c.MaxAge = int(time.Until(c.Expires).Seconds())
  5145. ctx.SetCookie(c, options...)
  5146. }
  5147. // GetCookie returns cookie's value by its name
  5148. // returns empty string if nothing was found.
  5149. //
  5150. // If you want more than the value then:
  5151. // cookie, err := ctx.GetRequestCookie("name")
  5152. //
  5153. // Example: https://github.com/kataras/iris/tree/main/_examples/cookies/basic
  5154. func (ctx *Context) GetCookie(name string, options ...CookieOption) string {
  5155. c, err := ctx.GetRequestCookie(name, options...)
  5156. if err != nil {
  5157. return ""
  5158. }
  5159. value, _ := url.QueryUnescape(c.Value)
  5160. return value
  5161. }
  5162. // GetRequestCookie returns the request cookie including any context's cookie options (stored or given by this method).
  5163. func (ctx *Context) GetRequestCookie(name string, options ...CookieOption) (*http.Cookie, error) {
  5164. c, err := ctx.request.Cookie(name)
  5165. if err != nil {
  5166. return nil, err
  5167. }
  5168. ctx.applyCookieOptions(c, OpCookieGet, options)
  5169. return c, nil
  5170. }
  5171. var (
  5172. // CookieExpireDelete may be set on Cookie.Expire for expiring the given cookie.
  5173. CookieExpireDelete = memstore.ExpireDelete
  5174. // CookieExpireUnlimited indicates that does expires after 24 years.
  5175. CookieExpireUnlimited = time.Now().AddDate(24, 10, 10)
  5176. )
  5177. // RemoveCookie deletes a cookie by its name and path = "/".
  5178. // Tip: change the cookie's path to the current one by: RemoveCookie("the_cookie_name", iris.CookieCleanPath)
  5179. //
  5180. // If you intend to remove a cookie with a specific domain and value, please ensure to pass these values explicitly:
  5181. //
  5182. // ctx.RemoveCookie("the_cookie_name", iris.CookieDomain("example.com"), iris.CookiePath("/"))
  5183. //
  5184. // OR use a Cookie value instead:
  5185. //
  5186. // ctx.RemoveCookie("the_cookie_name", iris.CookieOverride(&http.Cookie{Domain: "example.com", Path: "/"}))
  5187. //
  5188. // Example: https://github.com/kataras/iris/tree/main/_examples/cookies/basic
  5189. func (ctx *Context) RemoveCookie(name string, options ...CookieOption) {
  5190. c := &http.Cookie{Path: "/"}
  5191. // Send the cookie back to the client
  5192. ctx.applyCookieOptions(c, OpCookieDel, options)
  5193. c.Name = name
  5194. c.Value = ""
  5195. c.HttpOnly = true
  5196. // Set the cookie expiration date to a past time
  5197. c.Expires = CookieExpireDelete
  5198. c.MaxAge = -1 // RFC says 1 second, but let's do it -1 to make sure is working.
  5199. http.SetCookie(ctx.writer, c)
  5200. }
  5201. // VisitAllCookies takes a visitor function which is called
  5202. // on each (request's) cookies' name and value.
  5203. func (ctx *Context) VisitAllCookies(visitor func(name string, value string)) {
  5204. for _, cookie := range ctx.request.Cookies() {
  5205. visitor(cookie.Name, cookie.Value)
  5206. }
  5207. }
  5208. var maxAgeExp = regexp.MustCompile(`maxage=(\d+)`)
  5209. // MaxAge returns the "cache-control" request header's value
  5210. // seconds as int64
  5211. // if header not found or parse failed then it returns -1.
  5212. func (ctx *Context) MaxAge() int64 {
  5213. header := ctx.GetHeader(CacheControlHeaderKey)
  5214. if header == "" {
  5215. return -1
  5216. }
  5217. m := maxAgeExp.FindStringSubmatch(header)
  5218. if len(m) == 2 {
  5219. if v, err := strconv.Atoi(m[1]); err == nil {
  5220. return int64(v)
  5221. }
  5222. }
  5223. return -1
  5224. }
  5225. // +------------------------------------------------------------+
  5226. // | Advanced: Response Recorder |
  5227. // +------------------------------------------------------------+
  5228. // Record transforms the context's basic and direct responseWriter to a *ResponseRecorder
  5229. // which can be used to reset the body, reset headers, get the body,
  5230. // get & set the status code at any time and more.
  5231. func (ctx *Context) Record() {
  5232. switch w := ctx.writer.(type) {
  5233. case *ResponseRecorder:
  5234. default:
  5235. recorder := AcquireResponseRecorder()
  5236. recorder.BeginRecord(w)
  5237. ctx.ResetResponseWriter(recorder)
  5238. }
  5239. }
  5240. // Recorder returns the context's ResponseRecorder
  5241. // if not recording then it starts recording and returns the new context's ResponseRecorder
  5242. func (ctx *Context) Recorder() *ResponseRecorder {
  5243. ctx.Record()
  5244. return ctx.writer.(*ResponseRecorder)
  5245. }
  5246. // IsRecording returns the response recorder and a true value
  5247. // when the response writer is recording the status code, body, headers and so on,
  5248. // else returns nil and false.
  5249. func (ctx *Context) IsRecording() (*ResponseRecorder, bool) {
  5250. // NOTE:
  5251. // two return values in order to minimize the if statement:
  5252. // if (Recording) then writer = Recorder()
  5253. // instead we do: recorder,ok = Recording()
  5254. rr, ok := ctx.writer.(*ResponseRecorder)
  5255. return rr, ok
  5256. }
  5257. // Exec calls the framewrok's ServeHTTPC
  5258. // based on this context but with a changed method and path
  5259. // like it was requested by the user, but it is not.
  5260. //
  5261. // Offline means that the route is registered to the iris and have all features that a normal route has
  5262. // BUT it isn't available by browsing, its handlers executed only when other handler's context call them
  5263. // it can validate paths, has sessions, path parameters and all.
  5264. //
  5265. // You can find the Route by app.GetRoute("theRouteName")
  5266. // you can set a route name as: myRoute := app.Get("/mypath", handler)("theRouteName")
  5267. // that will set a name to the route and returns its RouteInfo instance for further usage.
  5268. //
  5269. // It doesn't changes the global state, if a route was "offline" it remains offline.
  5270. //
  5271. // app.None(...) and app.GetRoutes().Offline(route)/.Online(route, method)
  5272. //
  5273. // Example: https://github.com/kataras/iris/tree/main/_examples/routing/route-state
  5274. //
  5275. // User can get the response by simple using rec := ctx.Recorder(); rec.Body()/rec.StatusCode()/rec.Header().
  5276. //
  5277. // context's Values and the Session are kept in order to be able to communicate via the result route.
  5278. //
  5279. // It's for extreme use cases, 99% of the times will never be useful for you.
  5280. func (ctx *Context) Exec(method string, path string) {
  5281. if path == "" {
  5282. return
  5283. }
  5284. if method == "" {
  5285. method = "GET"
  5286. }
  5287. // backup the handlers
  5288. backupHandlers := ctx.handlers[0:]
  5289. backupPos := ctx.currentHandlerIndex
  5290. req := ctx.request
  5291. // backup the request path information
  5292. backupPath := req.URL.Path
  5293. backupMethod := req.Method
  5294. // don't backupValues := ctx.values.ReadOnly()
  5295. // set the request to be align with the 'againstRequestPath'
  5296. req.RequestURI = path
  5297. req.URL.Path = path
  5298. req.Method = method
  5299. // [values stays]
  5300. // reset handlers
  5301. ctx.handlers = ctx.handlers[0:0]
  5302. ctx.currentHandlerIndex = 0
  5303. // execute the route from the (internal) context router
  5304. // this way we keep the sessions and the values
  5305. ctx.app.ServeHTTPC(ctx)
  5306. // set the request back to its previous state
  5307. req.RequestURI = backupPath
  5308. req.URL.Path = backupPath
  5309. req.Method = backupMethod
  5310. // set back the old handlers and the last known index
  5311. ctx.handlers = backupHandlers
  5312. ctx.currentHandlerIndex = backupPos
  5313. }
  5314. // RouteExists reports whether a particular route exists
  5315. // It will search from the current subdomain of context's host, if not inside the root domain.
  5316. func (ctx *Context) RouteExists(method, path string) bool {
  5317. return ctx.app.RouteExists(ctx, method, path)
  5318. }
  5319. const (
  5320. reflectValueContextKey = "iris.context.reflect_value"
  5321. // ControllerContextKey returns the context key from which
  5322. // the `Context.Controller` method returns the store's value.
  5323. ControllerContextKey = "iris.controller.reflect_value"
  5324. )
  5325. // ReflectValue caches and returns a []reflect.Value{reflect.ValueOf(ctx)}.
  5326. // It's just a helper to maintain variable inside the context itself.
  5327. func (ctx *Context) ReflectValue() []reflect.Value {
  5328. if v := ctx.values.Get(reflectValueContextKey); v != nil {
  5329. return v.([]reflect.Value)
  5330. }
  5331. v := []reflect.Value{reflect.ValueOf(ctx)}
  5332. ctx.values.Set(reflectValueContextKey, v)
  5333. return v
  5334. }
  5335. var emptyValue reflect.Value
  5336. // Controller returns a reflect Value of the custom Controller from which this handler executed.
  5337. // It will return a Kind() == reflect.Invalid if the handler was not executed from within a controller.
  5338. func (ctx *Context) Controller() reflect.Value {
  5339. if v := ctx.values.Get(ControllerContextKey); v != nil {
  5340. return v.(reflect.Value)
  5341. }
  5342. return emptyValue
  5343. }
  5344. // DependenciesContextKey is the context key for the context's value
  5345. // to keep the serve-time static dependencies raw values.
  5346. const DependenciesContextKey = "iris.dependencies"
  5347. // DependenciesMap is the type which context serve-time
  5348. // struct dependencies are stored with.
  5349. type DependenciesMap map[reflect.Type]reflect.Value
  5350. // RegisterDependency registers a struct or slice
  5351. // or pointer to struct dependency at request-time
  5352. // for the next handler in the chain. One value per type.
  5353. // Note that it's highly recommended to register
  5354. // your dependencies before server ran
  5355. // through Party.ConfigureContainer or mvc.Application.Register
  5356. // in sake of minimum performance cost.
  5357. //
  5358. // See `UnregisterDependency` too.
  5359. func (ctx *Context) RegisterDependency(v interface{}) {
  5360. if v == nil {
  5361. return
  5362. }
  5363. val, ok := v.(reflect.Value)
  5364. if !ok {
  5365. val = reflect.ValueOf(v)
  5366. }
  5367. cv := ctx.values.Get(DependenciesContextKey)
  5368. if cv != nil {
  5369. m, ok := cv.(DependenciesMap)
  5370. if !ok {
  5371. return
  5372. }
  5373. m[val.Type()] = val
  5374. return
  5375. }
  5376. ctx.values.Set(DependenciesContextKey, DependenciesMap{
  5377. val.Type(): val,
  5378. })
  5379. }
  5380. // UnregisterDependency removes a dependency based on its type.
  5381. // Reports whether a dependency with that type was found and removed successfully.
  5382. func (ctx *Context) UnregisterDependency(typ reflect.Type) bool {
  5383. cv := ctx.values.Get(DependenciesContextKey)
  5384. if cv != nil {
  5385. m, ok := cv.(DependenciesMap)
  5386. if ok {
  5387. delete(m, typ)
  5388. return true
  5389. }
  5390. }
  5391. return false
  5392. }
  5393. // Application returns the iris app instance which belongs to this context.
  5394. // Worth to notice that this function returns an interface
  5395. // of the Application, which contains methods that are safe
  5396. // to be executed at serve-time. The full app's fields
  5397. // and methods are not available here for the developer's safety.
  5398. func (ctx *Context) Application() Application {
  5399. return ctx.app
  5400. }
  5401. // IsDebug reports whether the application runs with debug log level.
  5402. // It is a shortcut of Application.IsDebug().
  5403. func (ctx *Context) IsDebug() bool {
  5404. return ctx.app.IsDebug()
  5405. }
  5406. // SetErr is just a helper that sets an error value
  5407. // as a context value, it does nothing more.
  5408. // Also, by-default this error's value is written to the client
  5409. // on failures when no registered error handler is available (see `Party.On(Any)ErrorCode`).
  5410. // See `GetErr` to retrieve it back.
  5411. //
  5412. // To remove an error simply pass nil.
  5413. //
  5414. // Note that, if you want to stop the chain
  5415. // with an error see the `StopWithError/StopWithPlainError` instead.
  5416. func (ctx *Context) SetErr(err error) {
  5417. if err == nil {
  5418. ctx.values.Remove(errorContextKey)
  5419. return
  5420. }
  5421. ctx.values.Set(errorContextKey, err)
  5422. }
  5423. // GetErr is a helper which retrieves
  5424. // the error value stored by `SetErr`.
  5425. //
  5426. // Note that, if an error was stored by `SetErrPrivate`
  5427. // then it returns the underline/original error instead
  5428. // of the internal error wrapper.
  5429. func (ctx *Context) GetErr() error {
  5430. _, err := ctx.GetErrPublic()
  5431. return err
  5432. }
  5433. // ErrPrivate if provided then the error saved in context
  5434. // should NOT be visible to the client no matter what.
  5435. type ErrPrivate interface {
  5436. error
  5437. IrisPrivateError()
  5438. }
  5439. // An internal wrapper for the `SetErrPrivate` method.
  5440. type privateError struct{ error }
  5441. func (e privateError) IrisPrivateError() {}
  5442. // PrivateError accepts an error and returns a wrapped private one.
  5443. func PrivateError(err error) ErrPrivate {
  5444. if err == nil {
  5445. return nil
  5446. }
  5447. errPrivate, ok := err.(ErrPrivate)
  5448. if !ok {
  5449. errPrivate = privateError{err}
  5450. }
  5451. return errPrivate
  5452. }
  5453. const errorContextKey = "iris.context.error"
  5454. // SetErrPrivate sets an error that it's only accessible through `GetErr`
  5455. // and it should never be sent to the client.
  5456. //
  5457. // Same as ctx.SetErr with an error that completes the `ErrPrivate` interface.
  5458. // See `GetErrPublic` too.
  5459. func (ctx *Context) SetErrPrivate(err error) {
  5460. ctx.SetErr(PrivateError(err))
  5461. }
  5462. // GetErrPublic reports whether the stored error
  5463. // can be displayed to the client without risking
  5464. // to expose security server implementation to the client.
  5465. //
  5466. // If the error is not nil, it is always the original one.
  5467. func (ctx *Context) GetErrPublic() (bool, error) {
  5468. if v := ctx.values.Get(errorContextKey); v != nil {
  5469. switch err := v.(type) {
  5470. case privateError:
  5471. // If it's an error set by SetErrPrivate then unwrap it.
  5472. return false, err.error
  5473. case ErrPrivate:
  5474. return false, err
  5475. case error:
  5476. return true, err
  5477. }
  5478. }
  5479. return false, nil
  5480. }
  5481. // ErrPanicRecovery may be returned from `Context` actions of a `Handler`
  5482. // which recovers from a manual panic.
  5483. type ErrPanicRecovery struct {
  5484. ErrPrivate
  5485. Cause interface{}
  5486. Callers []string // file:line callers.
  5487. Stack []byte // the full debug stack.
  5488. RegisteredHandlers []string // file:line of all registered handlers.
  5489. CurrentHandler string // the handler panic came from.
  5490. }
  5491. // Error implements the Go standard error type.
  5492. func (e *ErrPanicRecovery) Error() string {
  5493. if e.Cause != nil {
  5494. if err, ok := e.Cause.(error); ok {
  5495. return err.Error()
  5496. }
  5497. }
  5498. return fmt.Sprintf("%v\n%s", e.Cause, strings.Join(e.Callers, "\n"))
  5499. }
  5500. // Is completes the internal errors.Is interface.
  5501. func (e *ErrPanicRecovery) Is(err error) bool {
  5502. _, ok := IsErrPanicRecovery(err)
  5503. return ok
  5504. }
  5505. // IsErrPanicRecovery reports whether the given "err" is a type of ErrPanicRecovery.
  5506. func IsErrPanicRecovery(err error) (*ErrPanicRecovery, bool) {
  5507. if err == nil {
  5508. return nil, false
  5509. }
  5510. v, ok := err.(*ErrPanicRecovery)
  5511. return v, ok
  5512. }
  5513. // IsRecovered reports whether this handler has been recovered
  5514. // by the Iris recover middleware.
  5515. func (ctx *Context) IsRecovered() (*ErrPanicRecovery, bool) {
  5516. if ctx.GetStatusCode() == http.StatusInternalServerError {
  5517. // Panic error from recovery middleware is private.
  5518. return IsErrPanicRecovery(ctx.GetErr())
  5519. }
  5520. return nil, false
  5521. }
  5522. const (
  5523. funcsContextPrefixKey = "iris.funcs."
  5524. funcLogoutContextKey = "auth.logout_func"
  5525. )
  5526. // SetFunc registers a custom function to this Request.
  5527. // It's a helper to pass dynamic functions across handlers of the same chain.
  5528. // For a more complete solution please use Dependency Injection instead.
  5529. // This is just an easy to way to pass a function to the
  5530. // next handler like ctx.Values().Set/Get does.
  5531. // Sometimes is faster and easier to pass the object as a request value
  5532. // and cast it when you want to use one of its methods instead of using
  5533. // these `SetFunc` and `CallFunc` methods.
  5534. // This implementation is suitable for functions that may change inside the
  5535. // handler chain and the object holding the method is not predictable.
  5536. //
  5537. // The "name" argument is the custom name of the function,
  5538. // you will use its name to call it later on, e.g. "auth.myfunc".
  5539. //
  5540. // The second, "fn" argument is the raw function/method you want
  5541. // to pass through the next handler(s) of the chain.
  5542. //
  5543. // The last variadic input argument is optionally, if set
  5544. // then its arguments are passing into the function's input arguments,
  5545. // they should be always be the first ones to be accepted by the "fn" inputs,
  5546. // e.g. an object, a receiver or a static service.
  5547. //
  5548. // See its `CallFunc` to call the "fn" on the next handler.
  5549. //
  5550. // Example at:
  5551. // https://github.com/kataras/iris/tree/main/_examples/routing/writing-a-middleware/share-funcs
  5552. func (ctx *Context) SetFunc(name string, fn interface{}, persistenceArgs ...interface{}) {
  5553. f := newFunc(name, fn, persistenceArgs...)
  5554. ctx.values.Set(funcsContextPrefixKey+name, f)
  5555. }
  5556. // GetFunc returns the context function declaration which holds
  5557. // some information about the function registered under the given "name" by
  5558. // the `SetFunc` method.
  5559. func (ctx *Context) GetFunc(name string) (*Func, bool) {
  5560. fn := ctx.values.Get(funcsContextPrefixKey + name)
  5561. if fn == nil {
  5562. return nil, false
  5563. }
  5564. return fn.(*Func), true
  5565. }
  5566. // CallFunc calls the function registered by the `SetFunc`.
  5567. // The input arguments MUST match the expected ones.
  5568. //
  5569. // If the registered function was just a handler
  5570. // or a handler which returns an error
  5571. // or a simple function
  5572. // or a simple function which returns an error
  5573. // then this operation will perform without any serious cost,
  5574. // otherwise reflection will be used instead, which may slow down the overall performance.
  5575. //
  5576. // Retruns ErrNotFound if the function was not registered.
  5577. //
  5578. // For a more complete solution without limiations navigate through
  5579. // the Iris Dependency Injection feature instead.
  5580. func (ctx *Context) CallFunc(name string, args ...interface{}) ([]reflect.Value, error) {
  5581. fn, ok := ctx.GetFunc(name)
  5582. if !ok || fn == nil {
  5583. return nil, ErrNotFound
  5584. }
  5585. return fn.call(ctx, args...)
  5586. }
  5587. // SetLogoutFunc registers a custom logout function that will be
  5588. // available to use inside the next handler(s). The function
  5589. // may be registered multiple times but the last one is the valid.
  5590. // So a logout function may start with basic authentication
  5591. // and other middleware in the chain may change it to a custom sessions logout one.
  5592. // This method uses the `SetFunc` method under the hoods.
  5593. //
  5594. // See `Logout` method too.
  5595. func (ctx *Context) SetLogoutFunc(fn interface{}, persistenceArgs ...interface{}) {
  5596. ctx.SetFunc(funcLogoutContextKey, fn, persistenceArgs...)
  5597. }
  5598. // Logout calls the registered logout function.
  5599. // Returns ErrNotFound if a logout function was not specified
  5600. // by a prior call of `SetLogoutFunc`.
  5601. func (ctx *Context) Logout(args ...interface{}) error {
  5602. _, err := ctx.CallFunc(funcLogoutContextKey, args...)
  5603. return err
  5604. }
  5605. const userContextKey = "iris.user"
  5606. // SetUser sets a value as a User for this request.
  5607. // It's used by auth middlewares as a common
  5608. // method to provide user information to the
  5609. // next handlers in the chain.
  5610. //
  5611. // The "i" input argument can be:
  5612. // - A value which completes the User interface
  5613. // - A map[string]interface{}.
  5614. // - A value which does not complete the whole User interface
  5615. // - A value which does not complete the User interface at all
  5616. // (only its `User().GetRaw` method is available).
  5617. //
  5618. // Look the `User` method to retrieve it.
  5619. func (ctx *Context) SetUser(i interface{}) error {
  5620. if i == nil {
  5621. ctx.values.Remove(userContextKey)
  5622. return nil
  5623. }
  5624. u, ok := i.(User)
  5625. if !ok {
  5626. if m, ok := i.(Map); ok { // it's a map, convert it to a User.
  5627. u = UserMap(m)
  5628. } else {
  5629. // It's a structure, wrap it and let
  5630. // runtime decide the features.
  5631. p := newUserPartial(i)
  5632. if p == nil {
  5633. return ErrNotSupported
  5634. }
  5635. u = p
  5636. }
  5637. }
  5638. ctx.values.Set(userContextKey, u)
  5639. return nil
  5640. }
  5641. // User returns the registered User of this request.
  5642. // To get the original value (even if a value set by SetUser does not implement the User interface)
  5643. // use its GetRaw method.
  5644. // /
  5645. // See `SetUser` too.
  5646. func (ctx *Context) User() User {
  5647. if v := ctx.values.Get(userContextKey); v != nil {
  5648. if u, ok := v.(User); ok {
  5649. return u
  5650. }
  5651. }
  5652. return nil
  5653. }
  5654. // Ensure Iris Context implements the standard Context package, build-time.
  5655. var _ context.Context = (*Context)(nil)
  5656. // Deadline returns the time when work done on behalf of this context
  5657. // should be canceled. Deadline returns ok==false when no deadline is
  5658. // set. Successive calls to Deadline return the same results.
  5659. //
  5660. // Shortcut of Request().Context().Deadline().
  5661. func (ctx *Context) Deadline() (deadline time.Time, ok bool) {
  5662. return ctx.request.Context().Deadline()
  5663. }
  5664. // Done returns a channel that's closed when work done on behalf of this
  5665. // context should be canceled. Done may return nil if this context can
  5666. // never be canceled. Successive calls to Done return the same value.
  5667. // The close of the Done channel may happen asynchronously,
  5668. // after the cancel function returns.
  5669. //
  5670. // WithCancel arranges for Done to be closed when cancel is called;
  5671. // WithDeadline arranges for Done to be closed when the deadline
  5672. // expires; WithTimeout arranges for Done to be closed when the timeout
  5673. // elapses.
  5674. //
  5675. // Done is provided for use in select statements:
  5676. //
  5677. // // Stream generates values with DoSomething and sends them to out
  5678. // // until DoSomething returns an error or ctx.Done is closed.
  5679. // func Stream(ctx context.Context, out chan<- Value) error {
  5680. // for {
  5681. // v, err := DoSomething(ctx)
  5682. // if err != nil {
  5683. // return err
  5684. // }
  5685. // select {
  5686. // case <-ctx.Done():
  5687. // return ctx.Err()
  5688. // case out <- v:
  5689. // }
  5690. // }
  5691. // }
  5692. //
  5693. // See https://blog.golang.org/pipelines for more examples of how to use
  5694. // a Done channel for cancellation.
  5695. //
  5696. // Shortcut of Request().Context().Done().
  5697. func (ctx *Context) Done() <-chan struct{} {
  5698. return ctx.request.Context().Done()
  5699. }
  5700. // If Done is not yet closed, Err returns nil.
  5701. // If Done is closed, Err returns a non-nil error explaining why:
  5702. // Canceled if the context was canceled
  5703. // or DeadlineExceeded if the context's deadline passed.
  5704. // After Err returns a non-nil error, successive calls to Err return the same error.
  5705. //
  5706. // Shortcut of Request().Context().Err().
  5707. func (ctx *Context) Err() error {
  5708. return ctx.request.Context().Err()
  5709. }
  5710. // Value returns the value associated with this context for key, or nil
  5711. // if no value is associated with key. Successive calls to Value with
  5712. // the same key returns the same result.
  5713. //
  5714. // Shortcut of Request().Context().Value(key interface{}) interface{}.
  5715. func (ctx *Context) Value(key interface{}) interface{} {
  5716. if keyStr, ok := key.(string); ok { // check if the key is a type of string, which can be retrieved by the mem store.
  5717. if entry, exists := ctx.values.GetEntry(keyStr); exists {
  5718. return entry.ValueRaw
  5719. }
  5720. }
  5721. // otherwise return the chained value.
  5722. return ctx.request.Context().Value(key)
  5723. }
  5724. const idContextKey = "iris.context.id"
  5725. // SetID sets an ID, any value, to the Request Context.
  5726. // If possible the "id" should implement a `String() string` method
  5727. // so it can be rendered on `Context.String` method.
  5728. //
  5729. // See `GetID` and `middleware/requestid` too.
  5730. func (ctx *Context) SetID(id interface{}) {
  5731. ctx.values.Set(idContextKey, id)
  5732. }
  5733. // GetID returns the Request Context's ID.
  5734. // It returns nil if not given by a prior `SetID` call.
  5735. // See `middleware/requestid` too.
  5736. func (ctx *Context) GetID() interface{} {
  5737. return ctx.values.Get(idContextKey)
  5738. }
  5739. // String returns the string representation of this request.
  5740. //
  5741. // It returns the Context's ID given by a `SetID`call,
  5742. // followed by the client's IP and the method:uri.
  5743. func (ctx *Context) String() string {
  5744. id := ctx.GetID()
  5745. if id != nil {
  5746. if stringer, ok := id.(fmt.Stringer); ok {
  5747. id = stringer.String()
  5748. }
  5749. }
  5750. return fmt.Sprintf("[%v] %s ▶ %s:%s", id, ctx.RemoteAddr(), ctx.Method(), ctx.Request().RequestURI)
  5751. }