UNPKG

@doodad-js/http

Version:
2 lines 67.3 kB
// Copyright 2015-2018 Claude Petit, licensed under Apache License version 2.0 "use strict";const nodeFs=require('fs'),nodeZlib=require('zlib'),nodeHttp=require('http'),nodeCrypto=require('crypto'),nodeCluster=require('cluster');exports.add=function add(modules){modules=(modules||{});modules['Doodad.NodeJs.Server.Http']={version:'2.2.1a',dependencies:['Doodad.Server.Http',],create:function create(root,_options,_shared){const doodad=root.Doodad,types=doodad.Types,tools=doodad.Tools,files=tools.Files,namespaces=doodad.Namespaces,mime=tools.Mime,mixIns=doodad.MixIns,io=doodad.IO,ioMixIns=io.MixIns,nodejs=doodad.NodeJs,cluster=nodejs.Cluster,nodejsIO=nodejs.IO,nodejsIOInterfaces=nodejsIO.Interfaces,server=doodad.Server,ipc=server.Ipc,http=server.Http,httpMixIns=http.MixIns,nodejsServer=nodejs.Server,nodejsHttp=nodejsServer.Http,minifiers=io.Minifiers,templates=doodad.Templates,templatesHtml=templates.Html,dates=tools.Dates,moment=dates.Moment;const modulePath=files.parsePath(module.filename).set({file:null});const __Internal__={};tools.complete(_shared.Natives,{windowJSON:global.JSON,globalBuffer:global.Buffer,globalProcess:global.process,mathRound:global.Math.round,mathMax:global.Math.max,});nodejsHttp.REGISTER(doodad.EXPANDABLE(http.Response.$extend(mixIns.NodeEvents,{$TYPE_NAME:'Response',$TYPE_UUID:'' +'b629f7b7-66bf-48c8-9d0e-fb51fa5dcded',__endRacer:doodad.PRIVATE(null),nodeJsStream:doodad.PROTECTED(null),nodeJsStreamOnError:doodad.NODE_EVENT('error',function nodeJsStreamOnError(context,err){err.trapped=true;if(!this.ended){this.__endRacer.resolve(this.end(true))}}),nodeJsStreamOnClose:doodad.NODE_EVENT('close',function nodeJsStreamOnClose(context){if(!this.ended){this.__endRacer.resolve(this.end(!!this.nodeJsStream.finished))}}),nodeJsStreamOnFinish:doodad.NODE_EVENT('finish',function nodeJsStreamOnFinish(context){if(!this.ended){this.__endRacer.resolve(this.end(true))}}),create:doodad.OVERRIDE(function create(request,nodeJsStream){types.setAttribute(this,'message',nodeHttp.STATUS_CODES[this.status]);this._super(request);const Promise=types.getPromise();this.__endRacer=Promise.createRacer();this.nodeJsStream=nodeJsStream;this.nodeJsStreamOnError.attach(nodeJsStream);this.nodeJsStreamOnClose.attachOnce(nodeJsStream);this.nodeJsStreamOnFinish.attachOnce(nodeJsStream)}),destroy:doodad.OVERRIDE(function destroy(){if(!types.DESTROYED(this.nodeJsStream)){this.nodeJsStream.end()};this.nodeJsStreamOnError.clear();this.nodeJsStreamOnClose.clear();this.nodeJsStreamOnFinish.clear();const racer=this.__endRacer;if(racer&&!racer.isSolved()){this.__endRacer.reject(new types.ScriptInterruptedError("Response object is about to be destroyed."))};types.DESTROY(this.stream);this._super()}),end:doodad.PUBLIC(doodad.NON_REENTRANT(doodad.ASYNC(function end(forceDisconnect){if(this.ended){throw new server.EndOfRequest()};const Promise=types.getPromise();return Promise.try(function tryEnd(){types.setAttribute(this,'ended',true);this.__ending=true;if(!forceDisconnect){if(this.status!==types.HttpStatus.OK){const ev=new doodad.Event({promise:Promise.resolve()});this.onStatus(ev);if(ev.prevent){return ev.data.promise}}};return undefined},this).finally(function(){let promise=null;const stream=this.stream,destroyed=stream&&types.DESTROYED(stream),buffered=stream&&!destroyed&&stream._implements(ioMixIns.BufferedStreamBase);if(forceDisconnect||destroyed||this.nodeJsStream.finished){types.DESTROY(this.nodeJsStream)}else{if(!this.trailersSent){this.sendTrailers()};promise=Promise.create(function(resolve,reject){this.nodeJsStream.once('destroy',resolve);this.nodeJsStream.once('close',resolve);this.nodeJsStream.once('finish',resolve);this.nodeJsStream.once('error',reject);if(buffered){stream.flushAsync({purge:true}).then(function(dummy){if(stream.canWrite()){stream.write(io.EOF);return stream.flushAsync({purge:true})}else{this.nodeJsStream.end()};return undefined},null,this).catch(reject)}else if(stream&&stream.canWrite()){return stream.writeAsync(io.EOF)}else{this.nodeJsStream.end()};return undefined},this)};this.__ending=false;return promise},this).then(function(dummy){if(!this.request.ended){return this.request.end(forceDisconnect)};return undefined},null,this).then(function(dummy){throw new server.EndOfRequest()})}))),setStatus:doodad.OVERRIDE(function setStatus(status,message){status=status||types.HttpStatus.OK;message=message||nodeHttp.STATUS_CODES[status];this._super(status,message)}),sendHeaders:doodad.PUBLIC(function sendHeaders(){if(this.ended&&!this.__ending){throw new server.EndOfRequest()};if(this.headersSent){throw new types.NotAvailable("Can't respond with a new status or new headers because the headers have already been sent to the client.")};if(this.nodeJsStream.headersSent){throw new types.NotAvailable("Can't send the headers and the status because Node.js has already sent headers to the client.")};this.onSendHeaders(new doodad.Event());const response=this.nodeJsStream;response.statusCode=this.status;response.statusMessage=this.message;tools.forEach(this.headers,function(value,name){if(value){response.setHeader(name,value)}else{response.removeHeader(name)}});types.setAttribute(this,'headersSent',true)}),__streamOnWrite:doodad.PROTECTED(function __streamOnWrite(ev){if((!this.ended||this.__ending)&&!this.headersSent){this.sendHeaders()}}),__streamOnError:doodad.PROTECTED(function __streamOnError(ev){ev.preventDefault();if(!this.ended){this.__endRacer.resolve(this.end(true))}}),getStream:doodad.OVERRIDE(doodad.NON_REENTRANT(function getStream(options){if(this.ended&&!this.__ending){throw new server.EndOfRequest()};const Promise=types.getPromise();options=tools.nullObject(options);const status=options.status,message=options.message,headers=options.headers;if(status||headers){if(this.headersSent){throw new types.NotAvailable("Can't set a new status or new headers because the headers have been sent to the client.")};if(headers){this.addHeaders(headers)};if(status){this.setStatus(status,message)}};if(options.contentType){this.setContentType(options.contentType,{encoding:options.encoding})}else if(options.encoding){this.setContentType(this.contentType||'text/plain',{encoding:options.encoding})};const currentStream=this.stream;if(currentStream){return currentStream};if(!this.contentType){throw new types.Error("'Content-Type' has not been set.")};const responseStream=new nodejsIO.BinaryOutputStream(this.nodeJsStream);this.request.onSanitize.attachOnce(null,function(){types.DESTROY(responseStream)});responseStream.onWrite.attachOnce(this,this.__streamOnWrite,10);const ev=new doodad.Event({stream:Promise.resolve(responseStream),options:options,});this.onGetStream(ev);return this.__endRacer.race(Promise.resolve(ev.data.stream).then(function(responseStream){if(types.isNothing(responseStream)){throw new http.StreamAborted()};root.DD_ASSERT&&root.DD_ASSERT(types._implements(responseStream,ioMixIns.OutputStreamBase),"Invalid response stream.");let headers=null;tools.forEach(this.__pipes,function(pipe){const pipeHeaders=pipe.options.headers;if(pipeHeaders){if(headers){tools.extend(headers,pipeHeaders)}else{headers=tools.nullObject(pipeHeaders)}};pipe.options.pipeOptions=tools.nullObject(pipe.options.pipeOptions);const pipeStream=pipe.stream;const isNodeStream=!types._implements(pipeStream,ioMixIns.StreamBase);const sourceStream=(isNodeStream?new nodejsIO.BinaryInputOutputStream(pipeStream):pipeStream);sourceStream.pipe(responseStream,pipe.options.pipeOptions);if(isNodeStream){this.request.onSanitize.attachOnce(null,function(){types.DESTROY(sourceStream)})};responseStream=sourceStream},this);this.__pipes=null;if(headers){this.onSendHeaders.attachOnce(this,function(ev){this.addHeaders(headers)})};const encoding=this.contentType.params.charset;if(types._implements(responseStream,io.Stream)){if(encoding&&!types._implements(responseStream,ioMixIns.TextOutputStream)){const textStream=new io.TextDecoderStream({encoding:encoding});this.request.onSanitize.attachOnce(null,function(){types.DESTROY(textStream)});textStream.pipe(responseStream);responseStream=textStream}}else{if(encoding){if(!nodejsIO.TextInputStream.$isValidEncoding(encoding)){throw new types.Error("Invalid encoding.")};responseStream=new nodejsIO.TextOutputStream(responseStream,{encoding:encoding})}else{responseStream=new nodejsIO.BinaryOutputStream(responseStream)};this.request.onSanitize.attachOnce(null,function(){types.DESTROY(responseStream)})};responseStream.onError.attach(this,this.__streamOnError,10);this.stream=responseStream;this.request.setFullfilled(true);return responseStream},null,this).catch(function(err){types.DESTROY(responseStream);throw err},this))})),sendTrailers:doodad.PROTECTED(function sendTrailers(trailers){if(this.ended&&!this.__ending){throw new server.EndOfRequest()};if(this.trailersSent){throw new types.NotAvailable("Trailers have already been sent and the request will be closed.")};if(!this.headersSent){this.sendHeaders()};if(trailers){this.addTrailers(trailers)};trailers=this.trailers;if(!types.isEmpty(trailers)){this.nodeJsStream.addTrailers(trailers)};types.setAttribute(this,'trailersSent',true)}),clear:doodad.OVERRIDE(function clear(){if(this.ended){throw new server.EndOfRequest()};if(!this.headersSent){this.clearHeaders()};if(!this.trailersSent){this.clearTrailers()};if(this.stream){this.stream.clear()}}),respondWithStatus:doodad.OVERRIDE(function respondWithStatus(status,message,headers,data){if(this.ended){throw new server.EndOfRequest()};if(this.headersSent){throw new types.NotAvailable("Can't respond with a new status or new headers because the headers have already been sent to the client.")};this.addHeaders(headers);types.setAttributes(this,{status:status,message:message||nodeHttp.STATUS_CODES[status],statusData:data,});this.request.setFullfilled(true);return this.request.end()}),respondWithError:doodad.OVERRIDE(function respondWithError(ex){if(this.ended){throw new server.EndOfRequest()};if(ex.critical){throw ex}else{ex.trapped=true;if(!ex.bubble){this.clear();this.request.setFullfilled(true);if(!this.nodeJsStream){return this.end()}else if(this.headersSent){return this.request.end()}else{return this.respondWithStatus(types.HttpStatus.InternalError,null,null,ex)}}};return undefined}),sendFile:doodad.PUBLIC(doodad.ASYNC(function sendFile(path){const Promise=types.getPromise();if(this.ended){throw new server.EndOfRequest()};if(!(path instanceof files.Path)){path=files.Path.parse(path)};return Promise.create(function tryStat(resolve,reject){nodeFs.stat(path.toApiString(),doodad.Callback(this,function getStatsCallback(err,stats){if(err){reject(err)}else{resolve(stats)}}))},this).then(function parseStats(stats){if(!stats.isFile()){throw new types.HttpError(types.HttpStatus.NotFound)};const contentTypes=this.request.getAcceptables(mime.getTypes(path.file)||['application/octet-stream']);if(!contentTypes.length){throw new types.HttpError(types.HttpStatus.UnsupportedMediaType)};this.setContentType(contentTypes[0]);this.addHeaders({'Last-Modified':http.toRFC1123Date(stats.mtime), 'Content-Length':stats.size,});if(!this.getHeader('Content-Disposition')){this.addHeader('Content-Disposition','attachment; filename="'+path.file.replace(/"/g,'\\"')+'"')};if(this.request.verb!=='HEAD'){return this.getStream()};return undefined},null,this).then(function(outputStream){if(outputStream){const inputStream=nodeFs.createReadStream(path.toApiString());this.request.onSanitize.attachOnce(null,function(){types.DESTROY(inputStream)});const iwritable=outputStream.getInterface(nodejsIOInterfaces.IWritable);inputStream.pipe(iwritable);return outputStream.onEOF.promise()};return undefined},null,this).catch(function cacthError(err){if(err.code==='ENOENT'){throw new types.HttpError(types.HttpStatus.NotFound)}else if(err.code==='EPERM'){throw new types.HttpError(types.HttpStatus.Forbidden)}else{throw err}},this)})),})));nodejsHttp.REGISTER(doodad.EXPANDABLE(http.Request.$extend(mixIns.NodeEvents,{$TYPE_NAME:'Request',$TYPE_UUID:'' +'fd128c87-0bd8-4ef8-a5c8-61560bede8f8',__endRacer:doodad.PRIVATE(null),nodeJsStream:doodad.PROTECTED(null),startTime:doodad.PROTECTED(null),$__setAbortedWhenEnded:doodad.PROTECTED(false),__aborted:doodad.PROTECTED(false),$__time:doodad.PROTECTED(doodad.TYPE(null)),$__totalHour:doodad.PROTECTED(doodad.TYPE(0)),$__perSecond:doodad.PROTECTED(doodad.TYPE(0.0)),$__perMinute:doodad.PROTECTED(doodad.TYPE(0.0)),$__perHour:doodad.PROTECTED(doodad.TYPE(0.0)),$__oldPerSecond:doodad.PROTECTED(doodad.TYPE(null)),$__noActivityStart:doodad.PROTECTED(doodad.TYPE(null)),$__noActivityTimeout:doodad.PROTECTED(doodad.TYPE(null)),$__statsUpdated:doodad.PROTECTED(doodad.TYPE(false)),$getStats:doodad.OVERRIDE(function $getStats(){const stats=this._super();return tools.extend(stats,{perSecond:this.$__perSecond,perMinute:this.$__perMinute,perHour:this.$__perHour,})}),$clearStats:doodad.OVERRIDE(function $clearStats(){this._super();this.$__time=null;this.$__totalHour=0;this.$__perSecond=0.0;this.$__perMinute=0.0;this.$__perHour=0.0;const oldPerSecond=this.$__oldPerSecond;if(oldPerSecond){oldPerSecond.length=0}else{this.$__oldPerSecond=[]};const noActivityTimeout=this.$__noActivityTimeout;if(noActivityTimeout){noActivityTimeout.cancel();this.$__noActivityTimeout=null};this.$__noActivityStart=null;this.$__statsUpdated=false}),$compileStats:doodad.PROTECTED(doodad.TYPE(function $compileStats(){const oldPerSecond=this.$__oldPerSecond;let perSecond=0.0;const time=this.$__time;let seconds=0.0;if(time){const diff=_shared.Natives.globalProcess.hrtime(time);seconds=diff[0]+(diff[1]/1e9);if(seconds>0.0){perSecond=this.$__totalHour/seconds};if(seconds>86400.0){this.$__time=null;this.$__totalHour=0}};oldPerSecond.push(perSecond);let count=oldPerSecond.length;if(count>60){oldPerSecond.shift();count--};if(count>1){const max=count-1;for(let i=0;i<max;i++){perSecond+=oldPerSecond[i]};perSecond/=count};this.$__perSecond=perSecond;const perMinute=(seconds>=60.0?perSecond*60.0:0.0);this.$__perMinute=perMinute;this.$__perHour=(seconds>=3600.0?perMinute*60.0:0.0)})),$watchNoActivity:doodad.PROTECTED(doodad.TYPE(function $watchNoActivity(){this.$__noActivityStart=_shared.Natives.globalProcess.hrtime();this.$__noActivityTimeout=tools.callAsync(function noActivityTimer(){this.$__noActivityTimeout=null;if(this.$__statsUpdated){this.$__statsUpdated=false;this.$watchNoActivity()}else{const oldPerSecond=this.$__oldPerSecond;const diff=_shared.Natives.globalProcess.hrtime(this.$__noActivityStart);let seconds=diff[0]+(diff[1]/1e9);seconds=_shared.Natives.mathRound(seconds);let count=oldPerSecond.length;if(count>0){let totalHour=this.$__totalHour;while((seconds>0)&&(count>0)){totalHour-=_shared.Natives.mathMax(_shared.Natives.mathRound(oldPerSecond.shift()),1);if(totalHour<0){totalHour=0;break};seconds--;count--};this.$__totalHour=totalHour};this.$compileStats();if(this.$__perSecond>0.0){this.$watchNoActivity()}else{this.$__time=null;this.$__totalHour=0;oldPerSecond.length=0}}},1000,this,null,true)})),nodeJsStreamOnError:doodad.NODE_EVENT('error',function nodeJsStreamOnError(context,err){err.trapped=true;if(!this.ended){this.__endRacer.resolve(this.end(true))}}),nodeJsStreamOnClose:doodad.NODE_EVENT('close',function nodeJsStreamOnClose(context){if(this.ended){const type=types.getType(this);if(type.$__setAbortedWhenEnded){this.__aborted=true}}else{this.__endRacer.resolve(this.end(!!this.nodeJsStream.aborted))}}),$create:doodad.OVERRIDE(function $create(...args){this._super(...args);this.$__setAbortedWhenEnded=(tools.Version.compare("10.2.1",process.versions.node)<0)}),create:doodad.OVERRIDE(function create(server,nodeJsRequest,nodeJsResponse){const Promise=types.getPromise();this.startTime=_shared.Natives.globalProcess.hrtime();this.nodeJsStream=nodeJsRequest;this.nodeJsStreamOnError.attach(nodeJsRequest);this.nodeJsStreamOnClose.attachOnce(nodeJsRequest);this._super(server,nodeJsRequest.method,nodeJsRequest.url,nodeJsRequest.headers,[nodeJsResponse]);this.__endRacer=Promise.createRacer();const type=types.getType(this);type.$__totalHour++;if(type.$__time){type.$compileStats()}else{type.$__time=_shared.Natives.globalProcess.hrtime()};type.$__statsUpdated=true;if(!type.$__noActivityTimeout){type.$watchNoActivity()}}),destroy:doodad.OVERRIDE(function destroy(){this.nodeJsStreamOnError.clear();this.nodeJsStreamOnClose.clear();types.DESTROY(this.stream);const racer=this.__endRacer;if(racer&&!racer.isSolved()){this.__endRacer.reject(new types.ScriptInterruptedError("Request object is about to be destroyed."))};this._super()}),createResponse:doodad.OVERRIDE(function createResponse(nodeJsRequest){return new nodejsHttp.Response(this,nodeJsRequest)}),proceed:doodad.OVERRIDE(function proceed(handlersOptions,options){return this.__endRacer.race(this._super(handlersOptions,options))}),end:doodad.OVERRIDE(function end(forceDisconnect){const Promise=types.getPromise();if(this.ended){throw new server.EndOfRequest()};function wait(){if(!forceDisconnect){const queue=this.__waitQueue;if(queue.length){this.__waitQueue=[];return this.__endRacer.race(Promise.all(queue)).then(wait,null,this)}};return undefined};return Promise.try(function tryEndRequest(){types.setAttribute(this,'ended',true);this.__ending=true;if(!this.response.ended){return this.response.end(forceDisconnect).catch(server.EndOfRequest,function(){})};return undefined},this).then(function(dummy){this.__ending=false;const stream=this.stream,destroyed=stream&&types.DESTROYED(stream),buffered=stream&&!destroyed&&stream._implements(ioMixIns.BufferedStreamBase);if(forceDisconnect||destroyed){types.DESTROY(this.nodeJsStream);this.sanitize()}else{if(buffered){return stream.flushAsync({purge:true})}};return undefined},null,this).then(wait,null,this).catch(this.catchError,this).nodeify(function(err,dummy){const type=types.getType(this);if(this.__aborted||forceDisconnect||types.DESTROYED(this.response)){type.$__aborted++}else{const status=this.response.status;if(types.HttpStatus.isInformative(status)||types.HttpStatus.isSuccessful(status)){type.$__successful++}else if(types.HttpStatus.isRedirect(status)){type.$__redirected++}else{const failed=type.$__failed;if(types.has(failed,status)){failed[status]++}else{failed[status]=1}}};this.onEnd();if(err){throw err};throw new server.EndOfRequest()},this)}),__streamOnError:doodad.PROTECTED(function __streamOnError(ev){ev.preventDefault();if(!this.ended){this.__endRacer.resolve(this.end(true))}}),getStream:doodad.OVERRIDE(doodad.NON_REENTRANT(function getStream(options){const Promise=types.getPromise();if(this.ended&&!this.__ending){throw new server.EndOfRequest()};options=tools.nullObject(this.__streamOptions,options);const currentStream=this.stream;if(currentStream){return currentStream};const acceptContentEncodings=(this.__contentEncodings.length?this.__contentEncodings:['identity']);const contentEncoding=(this.getHeader('Content-Encoding')||'identity').toLowerCase();if(acceptContentEncodings.indexOf(contentEncoding)<0){return this.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)};const requestStream=new nodejsIO.BinaryInputStream(this.nodeJsStream);this.onSanitize.attachOnce(null,function(){types.DESTROY(requestStream)});const ev=new doodad.Event({stream:Promise.resolve(requestStream),options:options,});this.onGetStream(ev);return this.__endRacer.race(Promise.resolve(ev.data.stream).then(function(requestStream){if(types.isNothing(requestStream)){throw new http.StreamAborted()};root.DD_ASSERT&&root.DD_ASSERT(types._implements(requestStream,ioMixIns.InputStreamBase),"Invalid request stream.");let accept=options.accept;if(types.isString(accept)){accept=[http.parseAcceptHeader(accept)]};if(!accept||!accept.length){return this.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)};const requestType=this.contentType;if(!requestType){return this.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)};let requestEncoding=null;if(types.has(requestType.params,'charset')){requestEncoding=requestType.params.charset};const contentTypes=tools.filter(accept,function(type){return(((type.name===requestType.name)||(type.name==='*/*')||((type.type===requestType.type)&&(type.subtype==='*')))&&(type.weight>0.0))});if(types.isEmpty(contentTypes)){return this.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)};if(!requestEncoding){requestEncoding=options.encoding};requestStream.onError.attach(this,this.__streamOnError,10);tools.forEach(this.__pipes,function forEachPipe(pipe){pipe.options.pipeOptions=tools.nullObject(pipe.options.pipeOptions);const pipeStream=pipe.stream;const isNodeStream=!types._implements(pipeStream,ioMixIns.StreamBase);const destStream=(isNodeStream?new nodejsIO.BinaryOutputStream(pipeStream):pipeStream);requestStream.pipe(destStream,pipe.options.pipeOptions);const sourceStream=(isNodeStream?new nodejsIO.BinaryInputStream(pipeStream):pipeStream);if(isNodeStream){this.onSanitize.attachOnce(null,function(){types.DESTROY(destStream);types.DESTROY(sourceStream)})};requestStream=sourceStream},this);this.__pipes=null;if(types._implements(requestStream,io.Stream)){if(requestEncoding&&!types._implements(requestStream,[ioMixIns.TextInputStream,ioMixIns.ObjectTransformableOut])){const textStream=new io.TextDecoderStream({encoding:requestEncoding});requestStream.pipe(textStream);requestStream=textStream}}else{if(requestEncoding){if(!nodejsIO.TextInputStream.$isValidEncoding(requestEncoding)){return this.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)};requestStream=new nodejsIO.TextInputStream(requestStream,{encoding:requestEncoding})}else{requestStream=new nodejsIO.BinaryInputStream(requestStream)}};this.stream=requestStream;this.setFullfilled(true);return requestStream},null,this).catch(function(err){types.DESTROY(requestStream);throw err},this))})),getTime:doodad.PUBLIC(function getTime(){if(this.ended&&!this.__ending){throw new server.EndOfRequest()};const time=_shared.Natives.globalProcess.hrtime(this.startTime);return(time[0]*1000)+(time[1]/1e6)}),getSource:doodad.PUBLIC(function getSource(){if(this.ended&&!this.__ending){throw new server.EndOfRequest()};return tools.nullObject({address:this.nodeJsStream.socket.remoteAddress,})}),})));nodejsHttp.REGISTER(http.Server.$extend(mixIns.NodeEvents,{$TYPE_NAME:'Server',$TYPE_UUID:'' +'41fed400-b070-40c3-9e90-800e2511f562',__nodeServer:doodad.PROTECTED(doodad.READ_ONLY()),__address:doodad.PROTECTED(doodad.READ_ONLY()),__listening:doodad.PROTECTED(false),onNodeRequest:doodad.NODE_EVENT('request',function onNodeRequest(context,nodeRequest,nodeResponse){if(this.__listening){if(this.options.validHosts){const host=nodeRequest.headers['host'];if(tools.indexOf(this.options.validHosts,host)<0){nodeResponse.writeHead(types.HttpStatus.BadRequest);nodeResponse.end();return}};try{const request=new nodejsHttp.Request(this,nodeRequest,nodeResponse);request.onError.attach(this,function(ev){this.onError(ev)});request.response.onError.attach(this,function(ev){this.onError(ev)});const ev=new doodad.Event({request:request,});this.onNewRequest(ev);if(!ev.prevent){request.proceed(this.handlersOptions).catch(request.catchError).then(function endRequest(){if(!types.DESTROYED(request)&&!request.ended){if(request.isFullfilled()){return request.end()}else{request.response.clear();return request.response.respondWithStatus(types.HttpStatus.NotFound)}};return undefined}).catch(request.catchError).nodeify(function requestCleanup(err,result){types.DESTROY(request);types.DESTROY(nodeRequest);types.DESTROY(nodeResponse);if(err){throw err}}).catch(tools.catchAndExit)}}catch(ex){nodeResponse.statusCode=types.HttpStatus.InternalError;nodeResponse.end(function(){types.DESTROY(nodeRequest);types.DESTROY(nodeResponse)});throw ex}}}),onNodeListening:doodad.NODE_EVENT('listening',function onNodeListening(context){types.setAttribute(this,'__address',this.__nodeServer.address());tools.log(tools.LogLevels.Info,"HTTP server listening on port '~port~', address '~address~'.",this.__address);tools.log(tools.LogLevels.Warning,"IMPORTANT: It is an experimental and not finished software. Don't use it on production, or do it at your own risks. Please report bugs and suggestions to 'doodadjs [at] gmail <dot> com'.")}),onNodeError:doodad.NODE_EVENT('error',function onNodeError(context,ex){this.onError(new doodad.ErrorEvent(ex))}),onNodeClose:doodad.NODE_EVENT('close',function onNodeClose(context){const server=this.__nodeServer;this.onNodeListening.detach(server);this.onNodeError.detach(server);this.onNodeClose.detach(server);tools.log(tools.LogLevels.Info,"Listening socket closed (address '~address~', port '~port~').",this.__address);types.setAttribute(this,'__nodeServer',null)}),isListening:doodad.OVERRIDE(function isListening(){return this.__listening}),listen:doodad.OVERRIDE(function listen(options){if(!this.__listening){this.__listening=true;options=tools.nullObject(options);const protocol=options.protocol||'http';let factory;if((protocol==='http')||(protocol==='https')){factory=require(protocol)}else{throw new doodad.Error("Invalid protocol : '~0~'.",[protocol])};let server;if(protocol==='https'){const opts=tools.nullObject();if(options.pfxFile){opts.pfx=nodeFs.readFileSync(types.toString(options.pfxFile))}else if(options.rawPfx){opts.pfx=options.rawPfx}else{if(options.keyFile){opts.key=nodeFs.readFileSync(types.toString(options.keyFile))}else if(options.rawKey){opts.key=options.rawKey}else{throw new types.Error("Missing private key file.")};if(options.certFile){opts.cert=nodeFs.readFileSync(types.toString(options.certFile))}else if(options.rawCert){opts.cert=options.rawCert}else{throw new types.Error("Missing certificate file.")}};if(!opts.pfx&&!opts.key&&!opts.cert){throw new types.Error("Missing private key and certificate files.")};server=factory.createServer(opts)}else{server=factory.createServer()};if(types.has(options,'timeout')){server.setTimeout(options.timeout)}else{server.setTimeout(5*60*1000)};this.onNodeRequest.attach(server);this.onNodeListening.attach(server);this.onNodeError.attach(server);this.onNodeClose.attach(server);types.setAttribute(this,'__nodeServer',server);const target=options.target||'127.0.0.1';const type=options.type||'tcp';if(type==='tcp'){const port=options.port||(protocol==='https'?443:80);const queueLength=options.queueLength;if(root.DD_ASSERT){root.DD_ASSERT(types.isString(target),"Invalid target.");root.DD_ASSERT(types.isInteger(port)&&(port>=0)&&(port<=65535),"Invalid port.");root.DD_ASSERT(types.isNothing(queueLength)||(types.isInteger(queueLength)&&(queueLength>0)),"Invalid queue length.")};server.listen(port,target,queueLength)}else if(type==='unix'){root.DD_ASSERT&&root.DD_ASSERT(types.isString(target),"Invalid target.");server.listen(target)}else if(type==='handle'){root.DD_ASSERT&&root.DD_ASSERT(types.isObject(target)&&(('_handle'in target)||('fd'in target)),"Invalid target.");server.listen(target)}else{throw new doodad.Error("Invalid target type option : '~0~'.",[type])};types.setAttribute(this,'protocol',protocol);this.onListen(new doodad.Event())}}),stopListening:doodad.OVERRIDE(function stopListening(){if(this.__listening){this.__listening=false;this.onStopListening(new doodad.Event());this.__nodeServer.close();types.setAttributes(this,{__nodeServer:null,__address:null,})}}),}));nodejsHttp.REGISTER(doodad.BASE(templatesHtml.PageTemplate.$extend({$TYPE_NAME:'FolderPageTemplate',$TYPE_UUID:'' +'36c6d23e-b8bd-4afa-ab36-88f871294ae3',path:doodad.PROTECTED(null),$readDir:doodad.PUBLIC(doodad.ASYNC(function $readDir(handler,path){return files.readdir(path,{async:true}).then(function sortFiles(filesList){filesList=filesList.filter(function(file){if(file.isFolder){return true};if(!handler.options.mimeTypes){return true};const mimeTypes=mime.getTypes(file.name)||['application/octet-stream'];file.mimeTypes=mimeTypes.filter(function(type){return tools.some(handler.options.mimeTypes,function(mimeType){return mimeType.name===type})});return(file.mimeTypes.length>0)}).sort(function(file1,file2){const n1=file1.name.toUpperCase(),n2=file2.name.toUpperCase();if((!file1.isFolder&&file2.isFolder)){return 1}else if(file1.isFolder&&!file2.isFolder){return-1}else if(n1>n2){return 1}else if(n1<n2){return-1}else{return 0}});return filesList},null,this)})),create:doodad.OVERRIDE(function create(request,cacheHandler,path){this._super(request,cacheHandler);this.path=path;if(cacheHandler){const state=request.getHandlerState(cacheHandler);state.onNewCached.attachOnce(this,function(handler,cached){files.watch(this.path.toApiString(),function(){cached.invalidate()})})}}),readDir:doodad.PUBLIC(doodad.ASYNC(function readDir(){return types.getType(this).$readDir(this.request.currentHandler,this.path)})),})));nodejsHttp.REGISTER(http.FileSystemPage.$extend({$TYPE_NAME:'FileSystemPage',$TYPE_UUID:'' +'53789fb7-083e-4134-9f48-e7e0dd856a52',$applyGlobalHandlerStates:doodad.OVERRIDE(function $applyGlobalHandlerStates(server){this._super(server);const resType=this.DD_FULL_NAME;server.applyGlobalHandlerState(nodejsHttp.CacheHandler,{generateKey:doodad.OVERRIDE(function generateKey(request,handler,keyObj){this._super(request,handler,keyObj);const res=!request.url.file&&request.url.getArg('res',true);if(res){keyObj.url.path=null;keyObj.url.file=null;keyObj.resType=resType;keyObj.res=res}}),})}),$prepare:doodad.OVERRIDE(function $prepare(options){types.getDefault(options,'depth',Infinity);options=this._super(options);let val;options.defaultEncoding=options.defaultEncoding||'utf-8';val=files.parsePath(options.path);const stats=nodeFs.statSync(val.toApiString());options.isFolder=!stats.isFile();if(options.isFolder){val=val.pushFile()};options.path=val;options.showFolders=types.toBoolean(options.showFolders);if(options.showFolders){val=options.folderTemplate;if(types.isNothing(val)){val=modulePath.combine('./res/templates/Folder.ddt')}else if(!(val instanceof files.Path)){val=files.Path.parse(val)};root.DD_ASSERT&&root.DD_ASSERT((val instanceof files.Path),"Invalid folder template.");options.folderTemplate=val};return options}),getSystemPath:doodad.OVERRIDE(function getSystemPath(request,targetUrl){let path=null;if(targetUrl){if(this.options.isFolder){if(targetUrl.args.has('res')){path=this.options.folderTemplate.set({file:''}).combine('./public/'+targetUrl.args.get('res',true))}else if(targetUrl.isRelative){path=this.options.path.combine(targetUrl.set({domain:null}))}else{const handlerState=request.getHandlerState(this);const handlerUrl=handlerState.url.pushFile();const relativeUrl=targetUrl.relative(handlerUrl);path=this.options.path.combine(relativeUrl)}}else if(!targetUrl.isRelative&&!targetUrl.args.has('res')){path=this.options.path}};return path}),__getFileUrl:doodad.PROTECTED(function getFileUrl(request){const state=request.getHandlerState(this);const urlRemaining=state.matcherResult.urlRemaining;const url=(urlRemaining&&(urlRemaining.path.length||urlRemaining.file)?urlRemaining:request.url);return url}),createStream:doodad.OVERRIDE(function createStream(request,options){let url=types.get(options,'url',null);if(!url){url=this.__getFileUrl(request)};const path=this.getSystemPath(request,url);if(!path){return null};const nodeStream=nodeFs.createReadStream(path.toApiString());const inputStream=new nodejsIO.BinaryInputStream(nodeStream);request.onSanitize.attachOnce(null,function(){types.DESTROY(inputStream);types.DESTROY(nodeStream)});return inputStream}),addHeaders:doodad.PROTECTED(doodad.ASYNC(function addHeaders(request){const Promise=types.getPromise();const url=this.__getFileUrl(request);const path=this.getSystemPath(request,url);if(!path){return null};const stat=function(path){return Promise.create(function tryStat(resolve,reject){const pathStr=path.toApiString();nodeFs.stat(pathStr,doodad.Callback(this,function getStatsCallback(err,stats){if(err){if(err.code==='ENOENT'){resolve(null)}else{reject(err)}}else{if(stats.isFile()){if(path.file){stats.path=pathStr}else{const newPath=path.popFile();stats.path=(newPath?newPath.toApiString():pathStr)}}else if(path.file){stats.path=path.pushFile().toApiString()}else{stats.path=pathStr};resolve(stats)}}))},this).then(function toCanonical(stats){if(stats){if(this.options.caseSensitive&&this.options.forceCaseSensitive){return files.getCanonical(path,{async:true}).then(function(canonicalPath){if(stats.isFile()){if(canonicalPath.file){stats.realPath=canonicalPath.toApiString()}else{const newPath=canonicalPath.popFile();stats.realPath=(newPath?newPath.toApiString():canonicalPath.toApiString())}}else if(canonicalPath.file){stats.realPath=canonicalPath.pushFile().toApiString()}else{stats.realPath=canonicalPath.toApiString()};return stats})}else{stats.realPath=stats.path}};return stats},null,this)};return stat.call(this,path).then(function(stats){if(!stats&&(path.extension==='ddtx')){return stat.call(this,path.set({extension:'ddt'}))};return stats},null,this).then(function parseStats(stats){if(!stats){return null};if(stats.path!==stats.realPath){return null};let contentTypes,handler=null;if(stats.isFile()){contentTypes=mime.getTypes(path.file)||['application/octet-stream'];handler=request.currentHandler}else{contentTypes=['text/html; charset=utf-8','application/json; charset=utf-8']};let contentType;if(request.url.args.has('res')){contentType=contentTypes[0]}else{contentType=request.getAcceptables(contentTypes,{handler:handler})[0]};if(!contentType){return request.response.respondWithStatus(types.HttpStatus.NotAcceptable)};request.response.addHeaders({'Last-Modified':http.toRFC1123Date(stats.mtime),});if(stats.isFile()){request.response.addHeaders({'Content-Disposition':'filename="'+path.file.replace(/"/g,'\\"')+'"',})}else{const state=request.getHandlerState(this);if(state.matcherResult){types.setAttribute(state.matcherResult,'url',state.matcherResult.url.pushFile())};request.response.setVary('Accept')};request.response.clearHeaders('Content-Length');request.response.setContentType(contentType,{handler:handler});return tools.nullObject({contentType:contentType,stats:stats,url:url,path:path,})},null,this)})),sendDDT:doodad.PROTECTED(doodad.ASYNC(function sendDDT(request,data){request.data.isFolder=false;if(!request.url.file){return request.redirectClient(request.url.popFile())};if(request.url.extension==='ddt'){return request.redirectClient(request.url.set({extension:'ddtx'}))};if(data.path){return templatesHtml.getTemplate(null,data.path.set({extension:'ddt'})).then(function renderTemplate(templType){const cacheHandlers=request.getHandlers(nodejsHttp.CacheHandler);const cacheHandler=(cacheHandlers.length>0?cacheHandlers[cacheHandlers.length-1]:null);const templ=new templType(request,cacheHandler,{variables:this.options.variables});return request.response.getStream({encoding:templType.$options.encoding}).then(function(stream){templ.pipe(stream);return templ.render()},null,this).nodeify(function cleanup(err,result){types.DESTROY(templ);if(err){throw err}else{return result}})},null,this).then(function(){return request.end()})};return undefined})),sendFile:doodad.PROTECTED(doodad.ASYNC(function sendFile(request,data){if(data.path){request.data.isFolder=false;if(!request.url.file&&!request.url.args.has('res')){return request.redirectClient(request.url.popFile())};const options=(root.getOptions().debug?{watch:data.path}:null);return request.response.getStream(options).then(function(outputStream){return this.createStream(request,{url:data.url}).then(function(inputStream){inputStream.pipe(outputStream);return outputStream.onEOF.promise()},null,this)},null,this).then(function(){return request.end()})};return undefined})),sendFolder:doodad.PROTECTED(doodad.ASYNC(function sendFolder(request,data){request.data.isFolder=true;if(request.url.file){return request.redirectClient(request.url.pushFile())};function sendHtml(filesList){return templatesHtml.getTemplate(null,this.options.folderTemplate).then(function renderTemplate(templType){const cacheHandlers=request.getHandlers(nodejsHttp.CacheHandler);const cacheHandler=(cacheHandlers.length>0?cacheHandlers[cacheHandlers.length-1]:null);const templ=new templType(request,cacheHandler,data.path);return request.response.getStream({encoding:templType.$options.encoding}).then(function(stream){templ.pipe(stream);return templ.render()},null,this).nodeify(function cleanup(err,result){types.DESTROY(templ);if(err){throw err}else{return result}})},null,this)};function sendJson(){return nodejsHttp.FolderPageTemplate.$readDir(this,data.path).then(function stringifyDir(filesList){filesList=tools.map(filesList,function(file){return tools.nullObject({isFolder:file.isFolder,name:file.name,size:file.size,})});const json=_shared.Natives.windowJSON.stringify(filesList);return request.response.getStream().then(function(stream){return stream.writeAsync(json)},null,this)},null,this)};function send(filesList){if(data.contentType.name==='text/html'){return sendHtml.call(this,filesList)}else{return sendJson.call(this,filesList)}};return send.call(this).then(function(){return request.end()},null,this)})),execute_HEAD:doodad.OVERRIDE(function execute_HEAD(request){return this.addHeaders(request).then(function(data){if(!data){request.setFullfilled(false)}})}),execute_GET:doodad.OVERRIDE(function execute_GET(request){return this.addHeaders(request).then(function(data){if(data){if(data.stats.isFile()){const isDDT=(data.path.extension==='ddt')||(data.path.extension==='ddi')||(data.path.extension==='ddtx');if(isDDT&&(data.contentType.name==='text/html')){return this.sendDDT(request,data)}else if(!isDDT||this.options.showFolders){return this.sendFile(request,data)}else{return request.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)}}else if(this.options.showFolders&&((data.contentType.name==='text/html')||(data.contentType.name==='application/json'))){return this.sendFolder(request,data)}else{return request.response.respondWithStatus(types.HttpStatus.UnsupportedMediaType)}}else{request.setFullfilled(false)};return undefined},this)}),}));nodejsHttp.REGISTER(doodad.Object.$extend(ipc.MixIns.Service,{$TYPE_NAME:'ClusterDataServiceMaster',$TYPE_UUID:'' +'fd42e7f9-ec8c-4232-b7fd-b474786f5e9b',syncData:ipc.CALLABLE(function syncData(request,id,handlerName,token){const Promise=types.getPromise();if(nodeCluster.isMaster){const keys=types.keys(nodeCluster.workers);return Promise.map(keys,function(key){const worker=nodeCluster.workers[key];if(worker.id!==request.msg.worker.id){return request.server.callService(nodejsHttp.ClusterDataServiceWorker.DD_FULL_NAME,'setData',[id,handlerName,token],{worker:worker})};return undefined})};return undefined}),}));nodejsHttp.REGISTER(doodad.Object.$extend(ipc.MixIns.Service,{$TYPE_NAME:'ClusterDataServiceWorker',$TYPE_UUID:'' +'97da531d-ae1d-4e0a-9972-4bbd65669223',setData:ipc.CALLABLE(function setData(request,id,handlerName,token){if(nodeCluster.isWorker&&id&&handlerName&&token&&token.data){const handler=namespaces.get(handlerName);if(handler){return nodejsHttp.ClusterDataHandler.$set(request,handler,token.data,{id:id,ttl:token.ttl})}};return undefined}),}));nodejsHttp.REGISTER(doodad.Object.$extend(httpMixIns.Handler,{$TYPE_NAME:'DataHandler',$TYPE_UUID:'' +'cbb40562-5609-4e63-a0a2-5da857c17b50',$timeoutDelay:doodad.PUBLIC(30),$__exchangedDatas:doodad.PROTECTED(null),$__dataTimeoutId:doodad.PROTECTED(null),$createToken:doodad.PROTECTED(doodad.ASYNC(function $createToken(request,handler,id,tokenData,options){return tokenData})),$set:doodad.PUBLIC(doodad.TYPE(doodad.ASYNC(function $set(request,handler,data,options){const MAX_RETRIES=5;root.DD_ASSERT&&root.DD_ASSERT(types._implements(handler,httpMixIns.Handler),"Invalid handler.");const ttl=types.get(options,'ttl',5*60);root.DD_ASSERT&&root.DD_ASSERT(types.isInteger(ttl),"Invalid TTL option.");const handlerType=types.getType(handler);const exchanged=this.$__exchangedDatas;let storage=exchanged.get(handlerType);if(!storage){storage=tools.nullObject();exchanged.set(handlerType,storage)};let id=null;const foreignId=types.get(options,'id');if(foreignId){if(types.has(storage,foreignId)){throw new types.Error("That id is not available : ~0~.",[foreignId])};id=foreignId}else{id=tools.generateUUID();let retries=0;while((retries<MAX_RETRIES)&&types.has(storage,id)){id=tools.generateUUID();retries++};if(retries>=MAX_RETRIES){throw new types.Error("Can't generate a new ID.")}};return this.$createToken(request,handler,id,{data:data,ttl:ttl,},options).then(function(token){token.time=process.hrtime();storage[id]=types.freezeObject(token);if(!this.$__dataTimeoutId){const createTimeout=function _createTimeout(){return tools.callAsync(function(){try{const exchanged=this.$__exchangedDatas;tools.forEach(exchanged,function(storage,handlerType){tools.forEach(storage,function(token,id){const diff=process.hrtime(token.time);const seconds=diff[0]+(diff[1]/1e9);if(seconds>=token.ttl){delete storage[id]}},this)},this)}catch(o){if(root.getOptions().debug){types.DEBUGGER()}};if(this.$__dataTimeoutId){this.$__dataTimeoutId=createTimeout.call(this)}},this.$timeoutDelay*1000,this,null,true)};this.$__dataTimeoutId=createTimeout.call(this)};return id},null,this)}))),$get:doodad.PUBLIC(doodad.TYPE(doodad.ASYNC(function $get(request,handler,id,options){const exchanged=this.$__exchangedDatas;const handlerType=types.getType(handler);const storage=exchanged.get(handlerType);if(storage){const token=types.get(storage,id,null);if(token){return token.data}};return null}))),$applyGlobalHandlerStates:doodad.OVERRIDE(function $applyGlobalHandlerStates(server){this._super(server);server.applyGlobalHandlerState(nodejsHttp.CacheHandler,{generateKey:doodad.OVERRIDE(function generateKey(request,handler,keyObj){this._super(request,handler,keyObj);if(!keyObj.isSection){const varsId=request.url.getArg('vars',true);if(!types.isNothing(varsId)){keyObj.varsId=varsId}}}),})}),$prepare:doodad.OVERRIDE(function $prepare(options){options=this._super(options);options.defaultTTL=types.toInteger(options.defaultTTL)||5*60;return options}),$create:doodad.OVERRIDE(function $create(){this._super();this.$__exchangedDatas=new types.Map()}),$destroy:doodad.OVERRIDE(function $destroy(){if(this.$__dataTimeoutId){this.$__dataTimeoutId.cancel();this.$__dataTimeoutId=null};this._super()}),getData:doodad.PUBLIC(doodad.ASYNC(function getData(request,handler,id,options){return types.getType(this).$get(request,handler,id,options)})),setData:doodad.PUBLIC(doodad.ASYNC(function setData(request,handler,data,options){return types.getType(this).$set(request,handler,data,tools.nullObject({ttl:this.options.defaultTTL,},options))})),execute:doodad.OVERRIDE(function(request){return this._super(request)}),}));nodejsHttp.REGISTER(nodejsHttp.DataHandler.$extend({$TYPE_NAME:'ClusterDataHandler',$TYPE_UUID:'' +'62e78465-f495-4db7-a3a4-af5f887de733',$createToken:doodad.OVERRIDE(function $createToken(request,handler,id,tokenData,options){return this._super(request,handler,id,tokenData,options).then(function(tokenData){if(nodeCluster.isWorker&&types.has(options,'messenger')&&!types.has(options,'id')){const handlerType=types.getType(handler);const handlerName=handlerType.DD_FULL_NAME;root.DD_ASSERT&&root.DD_ASSERT(namespaces.get(handlerName)===handlerType,"Handler is not registred.");return options.messenger.callService(nodejsHttp.ClusterDataServiceMaster.DD_FULL_NAME,'syncData',[id,handlerName,tokenData]).then(function(dummy){return tokenData})};return tokenData})}),$prepare:doodad.OVERRIDE(function $prepare(options){options=this._super(options);if(nodeCluster.isWorker){if(!types._instanceof(options.messenger,cluster.ClusterMessenger)){throw new types.ValueError("Invalid or missing 'messenger' option.")}};return options}),setData:doodad.OVERRIDE(function setData(request,handler,data,options){return this._super(request,handler,data,tools.nullObject(options,{messenger:this.options.messenger,}))}),}));nodejsHttp.REGISTER(nodejsHttp.FileSystemPage.$extend({$TYPE_NAME:'JavascriptFileSystemPage',$TYPE_UUID:'' +'d9fcff70-1fa8-4def-926e-ae43dff65537',$prepare:doodad.OVERRIDE(function $prepare(options){options=this._super(options);options.runDirectives=types.toBoolean(options.runDirectives);options.keepComments=types.toBoolean(options.keepComments);options.keepSpaces=types.toBoolean(options.keepSpaces);options.variables=tools.nullObject(options.variables);return options}),getJsVars:doodad.PUBLIC(doodad.ASYNC(function getJsVars(request,id,options){const dataHandlers=request.getHandlers(nodejsHttp.DataHandler);const dataHandler=(dataHandlers.length>0?dataHandlers[dataHandlers.length-1]:null);if(!dataHandler){throw new types.NotAvailable("Data handler is not loaded.")};return dataHandler.getData(request,this,id)})),setJsVars:doodad.PUBLIC(doodad.ASYNC(function setJsVars(request,vars,options){const dataHandlers=request.getHandlers(nodejsHttp.DataHandler);const dataHandler=(dataHandlers.length>0?dataHandlers[dataHandlers.length-1]:null);if(!dataHandler){throw new types.NotAvailable("Data handler is not loaded.")};const ttl=types.get(options,'ttl',5*60);return dataHandler.setData(request,this,vars,{ttl:ttl})})),createStream:doodad.OVERRIDE(function createStream(request,options){const Promise=types.getPromise();return this._super(request,options).then(function(inputStream){if(!inputStream){return null};const url=types.get(options,'url',request.url);const file=(url.hasArg('res')?url.getArg('res',true):url.file);const fileTypes=mime.getTypes(file);if(!tools.some(fileTypes,function(fileType){return fileType==='application/javascript'})){return inputStream};const mimeType=request.getAcceptables('application/javascript',{handler:this})[0];const encoding=(mimeType&&mimeType.params.charset||'utf-8');const jsStream=new minifiers.Javascript({runDirectives:this.options.runDirectives,keepComments:this.options.keepComments,keepSpaces:this.options.keepSpaces,encoding:encoding,});request.onSanitize.attachOnce(null,function sanitize(){types.DESTROY(jsStream)});let promise=Promise.resolve();const varsId=url.getArg('vars',true);if(varsId){promise=promise.then(function(dummy){return this.getJsVars(request,varsId)},null,this).then(function(vars){tools.forEach(vars,function forEachVar(value,name){jsStream.define(name,value)})},null,this)};return promise.then(function(dummy){tools.forEach(this.options.variables,function forEachVar(value,name){jsStream.define(name,value)});return inputStream.pipe(jsStream)},null,this)},null,this)}),}));nodejsHttp.REGISTER(io.BufferedInputOutputStream.$extend(ioMixIns.BinaryTransformableIn,ioMixIns.BinaryTransformableOut,{$TYPE_NAME:'CacheStream',$TYPE_UUID:'' +'0a99959c-0d42-4e0e-b677-6082b73dae4b',__remaining:doodad.PROTECTED(null),__headersCompiled:doodad.PROTECTED(false),__headers:doodad.PROTECTED(null),__verb:doodad.PROTECTED(null),__file:doodad.PROTECTED(null),__status:doodad.PROTECTED(null),__message:doodad.PROTECTED(null),__encoding:doodad.PROTECTED(null),__listening:doodad.PROTECTED(false),create:doodad.OVERRIDE(function create(options){this._super(options);types.getDefault(this.options,'headersOnly',false)}),reset:doodad.OVERRIDE(function reset(){this._super();this.__remaining=null;this.__headersCompiled=false;this.__headers=tools.nullObject();this.__verb=null;this.__file=null;this.__status=null;this.__message=null;this.__encoding=null}),onWrite:doodad.OVERRIDE(function onWrite(ev){const retval=this._super(ev);if(this.__listening){ev.preventDefault();const data=ev.data;const eof=(data.raw===io.EOF);let buf=data.valueOf();const remaining=this.__remaining;this.__remaining=null;if(remaining){if(buf){buf=_shared.Natives.globalBuffer.concat([remaining,buf],remaining.length+buf.length)}else{buf=remaining}};if(this.__headersCompiled||eof){if(buf){this.submit(new io.BinaryData(buf),{callback:data.defer()})};if(eof){this.submit(new io.BinaryData(io.EOF),{callback:data.defer()})}}else{let index,lastIndex=0;while((index=buf.indexOf(0x0A,lastIndex))>=0){if(index===lastIndex){this.__headersCompiled=true;this.submit(new io.BinaryData(io.BOF,{data:{code:this.__status,message:this.__message,verb:this.__verb,file:this.__file,encoding:this.__encoding,headers:this.__headers}}),{callback:data.defer()});break};const str=buf.slice(lastIndex,index).toString('utf-8');const header=tools.split(str,':',2);const name=tools.trim(header[0]||'');const value=tools.trim(header[1]||'');if(name==='X-Cache-Key'){}else if(name==='X-Cache-File'){const val=tools.split(value,' ',2);this.__verb=val[0]||'';this.__file=val[1]||''}else if(name==='X-Cache-Status'){const val=tools.split(value,' ',2);this.__status=parseInt(val[0],10)||200;this.__message=val[1]||''}else if(name==='X-Cache-Section'){}else if(name==='X-Cache-Parent'){}else if(name==='X-Cache-Encoding'){this.__encoding=value}else if(name.slice(0,8)==='X-Cache-'){}else if(name){this.__headers[name]=value};lastIndex=index+1};if(this.__headersCompiled&&this.options.headersOnly){this.submit(new io.BinaryData(io.EOF),{callback:data.defer()});this.stopListening()}else{let remaining=null;if((index>=0)&&(index<buf.length-1)){remaining=buf.slice(index+1)};if(remaining){if(this.__headersCompiled){this.submit(new io.BinaryData(remaining),{callback:data.defer()})}else{this.__remaining=remaining}}}}};return retval}),isListening:doodad.REPLACE(function isListening(){return this.__listening}),listen:doodad.REPLACE(function listen(options){if(!this.__listening){this.__listening=true;this.onListen()}}),stopListening:doodad.REPLACE(function stopListening(){if(this.__listening){this.__listening=false;this.onStopListening()}}),}));__Internal__.keyObjToString=function keyObjToString(){const keys=types.keys(this);keys.sort(function(key1,key2){if(key1<key2){return-1}else if(key1>key2){return 1}else{return 0}});return'{'+tools.reduce(keys,function(str,key){const val=this[key];if((key==='toString')||types.isNothing(val)||types.isFunction(val)){return str}else if(types.isPrimitive(val)){return str+key+':'+types.toString(val)+'|'}else if(types._instanceof(val,nodejsHttp.CacheHeaders)){return str+key+':'+val.toString()+'|'}else if(types.isArray(val)){return'['