"use strict";
// vwf.js
// This file contains the functions that handle the top level parsing and responses to
// requests for the VWF nodeJS server.
var parseurl = require( './parse-url' ),
serve = require( './serve' ),
persistence = require( './persistence' ),
servehandler = require( './serve-handler' ),
helpers = require( './helpers' ),
application = require( './application' ),
url = require( 'url' );
// HandleParsableRequest takes the incoming request, and uses the helper library functions to parse the
// URL into its 'public_path, application, instance and private_path' components, and then attempts to redirect
// or serve that request as appropriate. If it succesfully completes the request, it returns true, otherwise it
// returns false.
function HandleParsableRequest( request, response ) {
var parsedRequest = parseurl.Process( url.parse(request.url).pathname );
// if (parsedRequest.application == undefined) {
// return false
// }
// Used to check if the URL referer was an application instance. Components added by the "includes" keyword
// in yaml are loaded using jQuery which appends a query parameter to handle the callback. Checking the referer
// allows those URLs to be handled correctly, instead of treating them as a new application that needs an instance ID.
var parsedReferer = request.headers.referer ? parseurl.Process( url.parse(request.headers.referer).pathname ) : undefined;
if ( ( request.url[ request.url.length - 1 ] != "/" ) && ( parsedRequest[ 'private_path' ] == undefined ) && ( url.parse( request.url ).search == undefined ||
( parsedReferer && parsedReferer[ 'instance' ] != undefined ) ) ) { // If the referer was an application, allow it even if it has query parameters
var browserIsIE8 = ( request.headers['user-agent'] ) && ( request.headers['user-agent'].indexOf("MSIE 8.0" ) > -1 );
var urlIsUnsupportedPage = ( request.url.indexOf("/web/unsupported.html") !== -1 );
var refererIsUnsupportedPage = ( request.headers.referer && ( request.headers.referer.indexOf( "/web/unsupported.html" ) !== -1 ) );
if ( browserIsIE8 && !( urlIsUnsupportedPage || refererIsUnsupportedPage ) ) {
serve.Redirect( "/web/unsupported.html", response ); // Redirect unsupported browsers to web/docs/unsupported.html
return true;
}
else if ( ( parsedRequest[ 'instance' ] == undefined ) && ( request.headers['accept'].indexOf( "text/html" ) == -1 ) ) {
return servehandler.Component( request, response, helpers.JoinPath( global.applicationRoot, parsedRequest[ 'public_path' ], parsedRequest[ 'application' ] ) );
}
else if ( parsedRequest[ 'instance' ] == undefined && request.headers['accept'].indexOf( "text/html" ) != -1 && helpers.IsFile( helpers.JoinPath( global.applicationRoot, request.url ) ) ) {
return servehandler.File( request, response, helpers.JoinPath( global.applicationRoot, request.url ) );
}
else {
serve.Redirect( request.url + "/", response );
return true;
}
}
else if ( ( parsedRequest[ 'instance' ] == undefined ) && ( parsedRequest[ 'private_path' ] == undefined ) ) {
if ( request.url != "/" ) {
// Redirect if the requested url is either a specified directory or application
if ( helpers.IsDirectory( helpers.JoinPath( global.applicationRoot + request.url )) || parsedRequest['application'] != undefined ) {
// Get the driver specific url parameters if applicable
var queryString = url.parse( request.url ).search;
if ( queryString == undefined ) {
serve.Redirect( request.url + helpers.GenerateInstanceID( ), response );
return true;
}
else {
// Tack on the driver specific configuration parameters
serve.Redirect( helpers.JoinPath( url.parse( request.url ).pathname, helpers.GenerateInstanceID( ), queryString.replace( /\/$/, '' ) ), response );
return true;
}
}
}
else if ( isDefaultApp( request.url ) ) {
// Redirect if the url request does not include an application/file && a default 'index.vwf.yaml' exists
serve.Redirect( request.url + helpers.GenerateInstanceID( ), response );
return true;
} else {
return false;
}
}
else {
return application.Serve( request, response, parsedRequest );
}
}
// Assuming no application or file was specified in the url request, check for the existance of
// the default 'index.vwf.yaml' in either applicationRoot or cwd.
function isDefaultApp ( requestURL ) {
if ( helpers.IsFile( helpers.JoinPath( global.applicationRoot, "/index.vwf.yaml" ) )
|| helpers.IsFile( helpers.JoinPath( process.cwd(), "/index.vwf.yaml" ) ) ) {
return true;
}
return false;
}
// HandleProxyRequest attempts to identify any of the 'proxy' based URL paths and serves then attempts to
// serve them out of the the support/proxy subdirectories.
// If the request is identified as being a proxy request and succesfully served, this returns true,
// if it is not a proxy request (or it is a proxy request, but fails due to the file not being present),
// then this will return false.
function HandleProxyRequest( request, response ) {
var updatedURL = url.parse( request.url ).pathname;
var segments = helpers.GenerateSegments( updatedURL );
if ( ( segments.length > 0 ) && ( segments[ 0 ] == "proxy" ) ) {
if ( servehandler.File( request, response, helpers.JoinPath( global.vwfRoot + "/support/", updatedURL ) ) ) {
return true;
}
if ( servehandler.Component( request, response, helpers.JoinPath( global.vwfRoot + "/support/", updatedURL ) ) ) {
return true;
}
}
return false;
}
// HandleFileRequest simply attempts to handle the incoming URL as if it is a direct request for a file within the public directory
// structure.
// The function returns true if a file is succesfully served, false if it is not.
function HandleFileRequest( request, response ) {
var updatedURL = url.parse( request.url ).pathname;
var segments = helpers.GenerateSegments( updatedURL );
if ( segments.length == 0 ) {
updatedURL = "/index.html";
}
return servehandler.File( request, response, helpers.JoinPath( global.applicationRoot, updatedURL ) );
}
function HandleWebAppRequest(request, response) {
var updatedURL = url.parse(request.url).pathname;
var address = request.headers.host;
var res = false;
switch (updatedURL) {
case '/app':
response.writeHead(200, { 'content-type': 'text/html' });
console.log(global.instances);
for (var prop in global.instances) {
response.write("" + prop + "" + "
");
}
response.end();
res = true;
break;
case '/allinstances.json':
response.writeHead(200, {"Content-Type": "application/json"});
var obj = {};
console.log(global.instances);
for (var prop in global.instances) {
//var name = prop.split('/');
obj[prop] = {
"instance":address + prop,
"clients": Object.keys(global.instances[prop].clients).length
};
//response.write("" + prop + "" + "
");
}
var json = JSON.stringify(obj);
response.end(json);
res = true;
break;
default:
break;
}
return res;
}
function parseUrlForReflector( pathName ) {
try
{
var namespace = pathName;
if(!namespace) return null;
if (namespace[namespace.length - 1] != "/")
namespace += "/";
return parseurl.Process( namespace );
}
catch (e)
{
return null;
}
}
function GetLoadForSocket( processedURL ) {
if ( processedURL[ 'private_path' ] ) {
return persistence.GetLoadInformation( processedURL );
}
return { 'save_name': undefined, 'save_revision': undefined, 'explicit_revision': undefined, 'application_path': undefined };
}
function HandleReflectorRequest(request, response) {
//var updatedURL = url.parse(request.url).pathname;
// var address = request.headers.host;
var res = false;
if (request.method === 'POST' && request.url === '/parseurl') {
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
let pathUrl = JSON.parse(body);
let refPath = parseUrlForReflector( pathUrl.url );
//prepare for persistence request in case that's what this is
let loadInfo = GetLoadForSocket( refPath );
let saveObject = persistence.LoadSaveObject( loadInfo );
let resObj = {
path: refPath,
loadInfo: loadInfo,
saveObject: saveObject
}
//console.log(resObj);
let json = JSON.stringify(resObj);
response.writeHead(200, {"Content-Type": "application/json"});
response.end(json);
});
} else {
//response.statusCode = 404;
//response.end();
}
return res;
}
// Serve is the top level function for serving requests. It first attempts to
// serve the request based on parsing the incoming URL.
// If that fails, it continues to attempt to serve the request as a 'proxy' request,
// if that also does not serve anything to the request, then an attempt is made
// to handle the request as a simple direct request for a file within the public
// directory structure.
// If all that fails, serve up a 404 response since the request was not handled.
function Serve( request, response ) {
var handledRequest = HandleReflectorRequest( request, response );
if ( ! ( handledRequest ) ) {
handledRequest = HandleParsableRequest( request, response ); }
if ( ! ( handledRequest ) ) {
handledRequest = HandleProxyRequest( request, response );
}
if ( ! ( handledRequest ) ) {
handledRequest = HandleFileRequest( request, response );
}
if ( ! ( handledRequest ) ) {
handledRequest = HandleWebAppRequest( request, response );
}
if ( ! ( handledRequest ) ) {
global.log("404 : " + url.parse( request.url ).pathname )
serve._404( response, "404.html" );
}
}
exports.Serve = Serve;