/* Ċ Ġ* ĠJ aval in Ġ- Ġhttps :// jav al in . io Ċ Ġ* ĠCopyright Ġ 2 0 1 7 ĠDavid ĠÃ ħ se Ċ Ġ* ĠLicensed Ġunder ĠApache Ġ 2 . 0 : Ġhttps :// github . com / tip sy / jav al in / blob / master / LICENSE Ċ Ġ*/ Ċ Ċ package Ġio . jav al in . core Ċ Ċ import Ġio . jav al in . Context Ċ import Ġio . jav al in . H alt Exception Ċ import Ġio . jav al in . LogLevel Ċ import Ġio . jav al in . core . util . Context Util Ċ import Ġio . jav al in . core . util . Header Ċ import Ġio . jav al in . core . util . Log Util Ċ import Ġio . jav al in . core . util . Method Not Allowed Util Ċ import Ġio . jav al in . embedded server . Cached Request Wrapper Ċ import Ġio . jav al in . embedded server . Cached Response Wrapper Ċ import Ġio . jav al in . embedded server . Static Resource Handler Ċ import Ġio . jav al in . embedded server . jetty . websocket . WebSocket Handler Ċ import Ġorg . slf 4 j . LoggerFactory Ċ import Ġjava . io . InputStream Ċ import Ġjava . util . zip . GZIP OutputStream Ċ import Ġjavax . servlet . Servlet Request Ċ import Ġjavax . servlet . Servlet Response Ċ import Ġjavax . servlet . http . HttpServletRequest Ċ import Ġjavax . servlet . http . HttpServletResponse Ċ import Ġkotlin . properties . Deleg ates Ċ Ċ class ĠJ aval in Servlet ( ĊĠĠĠĠĠĠĠ Ġval Ġcontext Path : ĠString , ĊĠĠĠĠĠĠĠ Ġval Ġmatcher : ĠPath Matcher , ĊĠĠĠĠĠĠĠ Ġval Ġexception Mapper : ĠException Mapper , ĊĠĠĠĠĠĠĠ Ġval Ġerror Mapper : ĠError Mapper , ĊĠĠĠĠĠĠĠ Ġval Ġjet ty Ws Handlers : ĠMap < String , ĠAny >, ĊĠĠĠĠĠĠĠ Ġval Ġj aval in Ws Handlers : ĠList < WebSocket Handler >, ĊĠĠĠĠĠĠĠ Ġval Ġlog Level : ĠLogLevel , ĊĠĠĠĠĠĠĠ Ġval Ġdynamic G zip Enabled : ĠBoolean , ĊĠĠĠĠĠĠĠ Ġval Ġdefault ContentType : ĠString , ĊĠĠĠĠĠĠĠ Ġval Ġdefault Character Encoding : ĠString , ĊĠĠĠĠĠĠĠ Ġval Ġmax Request Cache Body Size : ĠLong , ĊĠĠĠĠĠĠĠ Ġval Ġprefer 4 0 5 over 4 0 4 : ĠBoolean ) Ġ{ ĊĊĠĠĠ Ġprivate Ġval Ġlog Ġ= ĠLoggerFactory . getLogger ( J aval in Servlet :: class . java ) ĊĊĠĠĠ Ġvar Ġstatic Resource Handler : ĠStatic Resource Handler Ġby ĠDeleg ates . notNull () ĊĊĠĠĠ Ġfun Ġservice ( servlet Request : ĠServlet Request , Ġservlet Response : ĠServlet Response ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġval Ġreq Ġ= ĠCached Request Wrapper ( servlet Request Ġas ĠHttpServletRequest , Ġmax Request Cache Body Size ) Ġ// Ġcached Ġfor Ġreading Ġmultiple Ġtimes ĊĠĠĠĠĠĠĠ Ġval Ġres Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( logLevel Ġ== ĠLogLevel . EXT EN SIVE ) ĠCached Response Wrapper ( servlet Response Ġas ĠHttpServletResponse ) Ġ// Ġbody Ġneeds Ġto Ġbe Ġcopied Ġfor Ġlogging ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġservlet Response Ġas ĠHttpServletResponse ĊĠĠĠĠĠĠĠ Ġval Ġtype Ġ= ĠHandler Type . from Servlet Request ( req ) ĊĠĠĠĠĠĠĠ Ġval Ġrequest Uri Ġ= Ġreq . request URI ĊĠĠĠĠĠĠĠ Ġval Ġctx Ġ= ĠContext Util . create ( res , Ġreq ) ĊĊĠĠĠĠĠĠĠ Ġctx . header (" Server ", Ġ" J aval in ") ĊĠĠĠĠĠĠĠ Ġctx . attribute (" jav al in - request - log - start - time ", ĠSystem . nano Time ()) ĊĊĠĠĠĠĠĠĠ Ġres . character Encoding Ġ= Ġdefault Character Encoding ĊĠĠĠĠĠĠĠ Ġres . contentType Ġ= Ġdefault ContentType ĊĊĠĠĠĠĠĠĠ Ġfun Ġtry With Exception Mapper ( func : Ġ() Ġ-> ĠUnit ) Ġ= Ġexception Mapper . catch Exception ( ctx , Ġfunc ) ĊĊĠĠĠĠĠĠĠ Ġfun Ġtry Before And Endpoint Handlers () Ġ= Ġtry With Exception Mapper Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmatcher . find Entries ( Handler Type . BEFORE , Ġrequest Uri ). forEach Ġ{ Ġentry Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġentry . handler . handle ( Context Util . update ( ctx , Ġentry , Ġrequest Uri )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġendpoint Entries Ġ= Ġmatcher . find Entries ( type , Ġrequest Uri ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġendpoint Entries . forEach Ġ{ Ġentry Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġctx . future Can Be Set Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġentry . handler . handle ( Context Util . update ( ctx , Ġentry , Ġrequest Uri )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġctx . future Can Be Set Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! ctx . next ed ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ try With Exception Mapper ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( endpoint Entries . isEmpty () Ġ&& Ġtype Ġ!= ĠHandler Type . HEAD Ġ&& Ġtype Ġ!= ĠHandler Type . GET ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġavailable Handler Types Ġ= ĠMethod Not Allowed Util . find Available Http Handler Types ( matcher , Ġrequest Uri ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( prefer 4 0 5 over 4 0 4 Ġ&& Ġ! available Handler Types . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Method Not Allowed ( ctx , Ġavailable Handler Types ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠH alt Exception ( 4 0 4 , Ġ" Not Ġfound ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( should Check For Static Files ( endpoint Entries , Ġtype , Ġrequest Uri )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstatic Resource Handler . handle ( req , Ġres ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġtry Error Handlers () Ġ= Ġtry With Exception Mapper Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġerror Mapper . handle ( ctx . status (), Ġctx ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġtry After Handlers () Ġ= Ġtry With Exception Mapper Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmatcher . find Entries ( Handler Type . AFTER , Ġrequest Uri ). forEach Ġ{ Ġentry Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġentry . handler . handle ( Context Util . update ( ctx , Ġentry , Ġrequest Uri )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġtry Before And Endpoint Handlers () Ġ// Ġstart Ġrequest Ġlifecycle ĊĊĠĠĠĠĠĠĠ Ġval Ġfuture Ġ= Ġctx . result Future () ĊĠĠĠĠĠĠĠ Ġif Ġ( future Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Error Handlers () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry After Handlers () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwrite Result ( ctx , Ġres ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreq . start Async (). let Ġ{ Ġasync Context Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfuture . exception ally Ġ{ Ġthrowable Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( throwable Ġis ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexception Mapper . handle ( throwable , Ġctx ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. then Accept Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( it ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠInputStream Ġ-> Ġctx . result ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠString Ġ-> Ġctx . result ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Error Handlers () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry After Handlers () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwrite Result ( ctx , Ġasync Context . response Ġas ĠHttpServletResponse ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġasync Context . complete () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġthrow Method Not Allowed ( ctx : ĠContext , Ġavailable Handler Types : ĠList < Handler Type >) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġacceptable Return Types Ġ= Ġctx . header (" Accept ") ĊĊĠĠĠĠĠĠĠ Ġval Ġbody Ġ= Ġif Ġ( accept able Return Types Ġ!= Ġnull Ġ&& Ġacceptable Return Types . contains (" application / json ")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠMethod Not Allowed Util . create Json Method Not Allowed ( available Handler Types ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠMethod Not Allowed Util . create Html Method Not Allowed ( available Handler Types ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġthrow ĠH alt Exception ( 4 0 5 , Ġbody ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġwrite Result ( ctx : ĠContext , Ġres : ĠHttpServletResponse ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! res . is Commit ted ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġctx . result Stream ()?. let Ġ{ Ġresult Stream Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( gzip ShouldBe Done ( ctx )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠG ZIP OutputStream ( res . output Stream , Ġtrue ). use Ġ{ Ġgz ipped Stream Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġres . setHeader ( Header . CONTENT _ ENCODING , Ġ" gzip ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresult Stream . copy To ( gz ipped Stream ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresult Stream . copy To ( res . output Stream ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠLog Util . log Request And Response ( ctx , Ġlog Level , Ġmatcher , Ġlog , Ġgzip ShouldBe Done ( ctx )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġshould Check For Static Files ( endpoint Entries : ĠList < Handler Entry >, Ġtype : ĠHandler Type , Ġrequest Uri : ĠString ) Ġ= Ġwhen Ġ{ ĊĠĠĠĠĠĠĠ Ġtype Ġ== ĠHandler Type . GET Ġ&& Ġendpoint Entries . isEmpty () Ġ-> Ġtrue ĊĠĠĠĠĠĠĠ Ġtype Ġ== ĠHandler Type . HEAD Ġ&& Ġmatcher . find Entries ( Handler Type . GET , Ġrequest Uri ). isEmpty () Ġ-> Ġtrue ĊĠĠĠĠĠĠĠ Ġelse Ġ-> Ġfalse ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġgzip ShouldBe Done ( ctx : ĠContext ) Ġ= Ġdynamic G zip Enabled ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ&& Ġctx . result Stream ()?. available () Ġ?: Ġ 0 Ġ> Ġ 1 5 0 0 Ġ// Ġmt u Ġis Ġapparently Ġ~ 1 5 0 0 Ġbytes ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ&& Ġ( ctx . header ( Header . ACCEPT _ ENCODING ) Ġ?: Ġ""). contains (" gzip ", Ġignore Case Ġ= Ġtrue ) Ċ } Ċ