BotanSS/net/WebFrame.js

243 lines
5.3 KiB
JavaScript
Raw Normal View History

2016-02-12 21:03:21 +00:00
"use strict";
2016-12-21 10:34:55 +00:00
const zlib = require( "zlib" );
2022-04-02 22:54:57 +00:00
const os = require( "os" )
2022-04-04 13:28:39 +00:00
const fs = require( "fs" );
2016-12-21 10:34:55 +00:00
2016-10-14 16:25:57 +00:00
const cl = global.botanLoader;
const Dragonfly = global.Dragonfly;
const PageCache = global.botanPageCache;
2015-04-18 14:14:36 +00:00
2017-09-26 04:52:42 +00:00
const Router = cl.load( "botanss.net.Router" );
2016-10-14 16:25:57 +00:00
const CondStream = cl.load( "botanss.utils.CondStream" );
const FatalError = cl.load( "botanss.errors.FatalError" );
2014-10-10 08:38:06 +00:00
2016-02-12 21:03:21 +00:00
class WebFrame
2014-10-10 08:38:06 +00:00
{
2016-02-12 21:03:21 +00:00
constructor( Http )
{
var _self = this;
2015-04-15 10:38:44 +00:00
2016-02-12 21:03:21 +00:00
this.HTTP = Http;
this.result = 0;
this.planted = false;
2016-10-15 03:28:55 +00:00
this.allowCache = true;
2016-02-12 21:03:21 +00:00
this.requestStr = "";
this.requestObj = {};
2014-10-10 08:38:06 +00:00
2016-02-12 21:03:21 +00:00
var router = new Router( Http );
2016-07-26 02:46:18 +00:00
router.addRoute( "301", false, "301" );
2016-02-12 21:03:21 +00:00
router.addRoute( "302", false, "302" );
2016-10-17 07:39:29 +00:00
router.addRoute( "400", false, "400" );
2016-02-12 21:03:21 +00:00
router.addRoute( "403", false, "403" );
router.addRoute( "404", false, "404" );
router.addRoute( "500", false, "500" );
router.addListener( "Route", this.__parse.bind( this ) );
2015-04-15 10:38:44 +00:00
2016-02-12 21:03:21 +00:00
this.router = router;
2015-04-15 10:38:44 +00:00
2016-02-12 21:03:21 +00:00
var res = this.HTTP.response;
2014-10-10 08:38:06 +00:00
2016-02-12 21:03:21 +00:00
this.handlers = {
"403": function()
{
res.statusCode = 403;
_self.result = "403 Forbidden";
_self.plantResult();
}
2016-10-17 07:39:29 +00:00
, "400": function()
{
res.statusCode = 404;
_self.result = "400 Bad Request";
_self.plantResult();
}
2016-02-12 21:03:21 +00:00
, "404": function()
{
res.statusCode = 404;
_self.result = "404 Not Found";
_self.plantResult();
}
2016-07-26 02:46:18 +00:00
, "301": function()
{
res.statusCode = 301;
res.headers[ "Location" ] = router.relaying.params[0];
_self.result = "";
2016-10-25 09:52:20 +00:00
_self.plantResult( true );
2016-07-26 02:46:18 +00:00
}
2016-02-12 21:03:21 +00:00
, "302": function()
{
res.statusCode = 302;
res.headers[ "Location" ] = router.relaying.params[0];
_self.result = "";
_self.plantResult();
}
, "500": function()
{
res.statusCode = 500;
_self.result = "500 Internal Server Error";
_self.plantResult();
}
2015-04-15 10:38:44 +00:00
}
2014-10-10 08:38:06 +00:00
}
2016-02-12 21:03:21 +00:00
run()
2014-10-10 08:38:06 +00:00
{
2016-02-12 21:03:21 +00:00
var _self = this;
2015-07-23 09:15:24 +00:00
2016-02-12 21:03:21 +00:00
var method = "GET";
if( this.HTTP.request.isPost )
{
2022-04-02 22:54:57 +00:00
this.requestStr = new CondStream( os.tmpdir(), 2048 );
2015-07-23 09:15:24 +00:00
2016-02-12 21:03:21 +00:00
this.HTTP.request.raw.addListener(
"data" , ( x ) => _self.requestStr.write( x )
);
this.HTTP.request.raw.addListener(
"end", () => _self.requestStr.end( () => _self.__parse() )
);
method = "POST";
}
var url = this.HTTP.request.raw.url;
Dragonfly.Info(
( this.HTTP.request.raw.headers[ "x-forwarded-for" ] || this.HTTP.request.remoteAddr ) + " "
2022-04-02 22:54:57 +00:00
+ method + ": " + url
2016-02-12 21:03:21 +00:00
+ " - " + this.HTTP.request.raw.headers["user-agent"]
, Dragonfly.Visibility.VISIBLE
2015-07-23 09:15:24 +00:00
);
2015-04-15 10:38:44 +00:00
2016-02-12 21:03:21 +00:00
if( method == "GET" )
{
this.queryStr = url.split( "?" )[1];
this.__parse();
}
2014-10-10 08:38:06 +00:00
}
2016-02-12 21:03:21 +00:00
addHandler( name, method )
2015-05-30 12:07:42 +00:00
{
2016-02-12 21:03:21 +00:00
this.handlers[ name ] = method.bind( this );
2015-05-30 12:07:42 +00:00
}
2014-10-10 08:38:06 +00:00
2016-10-14 16:25:57 +00:00
plantResult( cache, ttl )
2014-10-10 08:38:06 +00:00
{
2016-02-12 21:03:21 +00:00
if( this.planted ) return;
2014-10-10 08:38:06 +00:00
2016-02-12 21:03:21 +00:00
this.planted = true;
if( this.HTTP )
{
if( !( this.result instanceof Buffer ) )
2014-10-10 08:38:06 +00:00
{
2016-02-12 21:03:21 +00:00
this.result = new Buffer( this.result + "" );
2014-10-10 08:38:06 +00:00
}
2016-02-12 21:03:21 +00:00
2016-12-21 10:34:55 +00:00
var acceptEncoding = this.HTTP.request.headers[ "accept-encoding" ] || "";
if( ~acceptEncoding.indexOf( "deflate" ) )
{
zlib.deflate( this.result, ( e, buff ) => {
if( e ) throw e;
this.HTTP.response.headers[ "Content-Encoding" ] = "deflate";
this.__writeOut( buff );
this.__storeCache( buff, cache, ttl );
} );
}
else if( ~acceptEncoding.indexOf( "gzip" ) )
{
zlib.gzip( this.result, ( e, buff ) => {
if( e ) throw e;
this.HTTP.response.headers[ "Content-Encoding" ] = "gzip";
this.__writeOut( buff );
this.__storeCache( buff, cache, ttl );
} );
}
else
{
this.__writeOut( this.result );
this.__storeCache( this.result, cache, ttl );
}
2014-10-10 08:38:06 +00:00
}
2016-02-12 21:03:21 +00:00
// Release resources
if( this.requestStr )
{
2016-02-12 21:03:21 +00:00
this.requestStr.discard();
}
2014-10-10 08:38:06 +00:00
}
2016-12-21 10:34:55 +00:00
__writeOut( data )
{
this.HTTP.response.headers["Content-Length"] = data.length;
this.HTTP.response.write( data );
this.HTTP.response.end();
2022-04-03 12:52:44 +00:00
Dragonfly.Debug( `Result Planted: ${process.hrtime.bigint() - this.HTTP.response.raw._hrtime}ns` );
2016-12-21 10:34:55 +00:00
}
__storeCache( data, cache, ttl )
2016-10-14 16:25:57 +00:00
{
2016-10-15 03:28:55 +00:00
if( this.allowCache && cache && PageCache )
2016-10-14 16:25:57 +00:00
{
if( ttl == undefined ) ttl = 30;
PageCache.store(
this.HTTP.request.raw
, this.HTTP.response
2016-12-21 10:34:55 +00:00
, data, ttl
2016-10-14 16:25:57 +00:00
);
}
}
2016-02-12 21:03:21 +00:00
// This won't handle path exists
// throwing an error is better than handling it
// Need to handle it somewhere else
plantFile( path, name )
{
if( this.planted ) return;
var _self = this;
this.planted = true;
2014-10-10 08:38:06 +00:00
2016-02-12 21:03:21 +00:00
var resp = this.HTTP.response;
2015-05-26 09:02:42 +00:00
2016-02-12 21:03:21 +00:00
if( !name )
2014-10-10 08:38:06 +00:00
{
2016-02-12 21:03:21 +00:00
var p = require( "path" );
name = p.basename( path );
2014-10-10 08:38:06 +00:00
}
2016-02-12 21:03:21 +00:00
resp.headers[ "Content-Disposition" ] = "attachment; filename=\"" + name + "\"";
2015-05-26 09:02:42 +00:00
2016-02-12 21:03:21 +00:00
Dragonfly.Debug( "Stream out: " + path );
2015-05-26 09:02:42 +00:00
2016-02-12 21:03:21 +00:00
var rs = fs.createReadStream( path );
rs.addListener( "data", ( x ) => resp.write( x ) );
rs.addListener( "end", () => resp.end() );
2014-10-10 08:38:06 +00:00
}
2015-05-26 09:02:42 +00:00
2016-02-12 21:03:21 +00:00
__parse()
{
if( this.router.routable )
{
var method = this.router.route();
if( method )
{
Dragonfly.Debug( "Call " + method, Dragonfly.Spheres.THERMO );
2015-05-26 09:02:42 +00:00
2016-02-12 21:03:21 +00:00
if( this.handlers[ method ] )
{
this.handlers[ method ]( this.router.routeObj );
return;
}
}
else if( method === false )
{
Dragonfly.Debug( "No route is defined to handle this URI", Dragonfly.Spheres.THERMO );
this.router.routeObj.reRoute( "404", true );
return;
}
2015-05-26 09:02:42 +00:00
2016-02-12 21:03:21 +00:00
throw new FatalError( "Relay handler \"" + method + "\" is not defined" );
}
}
}
2014-10-10 08:38:06 +00:00
2016-02-12 21:03:21 +00:00
module.exports = WebFrame;