vwf.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. "use strict";
  2. // vwf.js
  3. // This file contains the functions that handle the top level parsing and responses to
  4. // requests for the VWF nodeJS server.
  5. var parseurl = require( './parse-url' ),
  6. serve = require( './serve' ),
  7. persistence = require( './persistence' ),
  8. servehandler = require( './serve-handler' ),
  9. helpers = require( './helpers' ),
  10. application = require( './application' ),
  11. url = require( 'url' );
  12. // HandleParsableRequest takes the incoming request, and uses the helper library functions to parse the
  13. // URL into its 'public_path, application, instance and private_path' components, and then attempts to redirect
  14. // or serve that request as appropriate. If it succesfully completes the request, it returns true, otherwise it
  15. // returns false.
  16. function HandleParsableRequest( request, response ) {
  17. var parsedRequest = parseurl.Process( url.parse(request.url).pathname );
  18. // if (parsedRequest.application == undefined) {
  19. // return false
  20. // }
  21. // Used to check if the URL referer was an application instance. Components added by the "includes" keyword
  22. // in yaml are loaded using jQuery which appends a query parameter to handle the callback. Checking the referer
  23. // allows those URLs to be handled correctly, instead of treating them as a new application that needs an instance ID.
  24. var parsedReferer = request.headers.referer ? parseurl.Process( url.parse(request.headers.referer).pathname ) : undefined;
  25. if ( ( request.url[ request.url.length - 1 ] != "/" ) && ( parsedRequest[ 'private_path' ] == undefined ) && ( url.parse( request.url ).search == undefined ||
  26. ( parsedReferer && parsedReferer[ 'instance' ] != undefined ) ) ) { // If the referer was an application, allow it even if it has query parameters
  27. var browserIsIE8 = ( request.headers['user-agent'] ) && ( request.headers['user-agent'].indexOf("MSIE 8.0" ) > -1 );
  28. var urlIsUnsupportedPage = ( request.url.indexOf("/web/unsupported.html") !== -1 );
  29. var refererIsUnsupportedPage = ( request.headers.referer && ( request.headers.referer.indexOf( "/web/unsupported.html" ) !== -1 ) );
  30. if ( browserIsIE8 && !( urlIsUnsupportedPage || refererIsUnsupportedPage ) ) {
  31. serve.Redirect( "/web/unsupported.html", response ); // Redirect unsupported browsers to web/docs/unsupported.html
  32. return true;
  33. }
  34. else if ( ( parsedRequest[ 'instance' ] == undefined ) && ( request.headers['accept'].indexOf( "text/html" ) == -1 ) ) {
  35. return servehandler.Component( request, response, helpers.JoinPath( global.applicationRoot, parsedRequest[ 'public_path' ], parsedRequest[ 'application' ] ) );
  36. }
  37. else if ( parsedRequest[ 'instance' ] == undefined && request.headers['accept'].indexOf( "text/html" ) != -1 && helpers.IsFile( helpers.JoinPath( global.applicationRoot, request.url ) ) ) {
  38. return servehandler.File( request, response, helpers.JoinPath( global.applicationRoot, request.url ) );
  39. }
  40. else {
  41. serve.Redirect( request.url + "/", response );
  42. return true;
  43. }
  44. }
  45. else if ( ( parsedRequest[ 'instance' ] == undefined ) && ( parsedRequest[ 'private_path' ] == undefined ) ) {
  46. if ( request.url != "/" ) {
  47. // Redirect if the requested url is either a specified directory or application
  48. if ( helpers.IsDirectory( helpers.JoinPath( global.applicationRoot + request.url )) || parsedRequest['application'] != undefined ) {
  49. // Get the driver specific url parameters if applicable
  50. var queryString = url.parse( request.url ).search;
  51. if ( queryString == undefined ) {
  52. serve.Redirect( request.url + helpers.GenerateInstanceID( ), response );
  53. return true;
  54. }
  55. else {
  56. // Tack on the driver specific configuration parameters
  57. serve.Redirect( helpers.JoinPath( url.parse( request.url ).pathname, helpers.GenerateInstanceID( ), queryString.replace( /\/$/, '' ) ), response );
  58. return true;
  59. }
  60. }
  61. }
  62. else if ( isDefaultApp( request.url ) ) {
  63. // Redirect if the url request does not include an application/file && a default 'index.vwf.yaml' exists
  64. serve.Redirect( request.url + helpers.GenerateInstanceID( ), response );
  65. return true;
  66. } else {
  67. return false;
  68. }
  69. }
  70. else {
  71. return application.Serve( request, response, parsedRequest );
  72. }
  73. }
  74. // Assuming no application or file was specified in the url request, check for the existance of
  75. // the default 'index.vwf.yaml' in either applicationRoot or cwd.
  76. function isDefaultApp ( requestURL ) {
  77. if ( helpers.IsFile( helpers.JoinPath( global.applicationRoot, "/index.vwf.yaml" ) )
  78. || helpers.IsFile( helpers.JoinPath( process.cwd(), "/index.vwf.yaml" ) ) ) {
  79. return true;
  80. }
  81. return false;
  82. }
  83. // HandleProxyRequest attempts to identify any of the 'proxy' based URL paths and serves then attempts to
  84. // serve them out of the the support/proxy subdirectories.
  85. // If the request is identified as being a proxy request and succesfully served, this returns true,
  86. // if it is not a proxy request (or it is a proxy request, but fails due to the file not being present),
  87. // then this will return false.
  88. function HandleProxyRequest( request, response ) {
  89. var updatedURL = url.parse( request.url ).pathname;
  90. var segments = helpers.GenerateSegments( updatedURL );
  91. if ( ( segments.length > 0 ) && ( segments[ 0 ] == "proxy" ) ) {
  92. if ( servehandler.File( request, response, helpers.JoinPath( global.vwfRoot + "/support/", updatedURL ) ) ) {
  93. return true;
  94. }
  95. if ( servehandler.Component( request, response, helpers.JoinPath( global.vwfRoot + "/support/", updatedURL ) ) ) {
  96. return true;
  97. }
  98. }
  99. return false;
  100. }
  101. // HandleFileRequest simply attempts to handle the incoming URL as if it is a direct request for a file within the public directory
  102. // structure.
  103. // The function returns true if a file is succesfully served, false if it is not.
  104. function HandleFileRequest( request, response ) {
  105. var updatedURL = url.parse( request.url ).pathname;
  106. var segments = helpers.GenerateSegments( updatedURL );
  107. if ( segments.length == 0 ) {
  108. updatedURL = "/index.html";
  109. }
  110. return servehandler.File( request, response, helpers.JoinPath( global.applicationRoot, updatedURL ) );
  111. }
  112. function HandleWebAppRequest(request, response) {
  113. var updatedURL = url.parse(request.url).pathname;
  114. var address = request.headers.host;
  115. var res = false;
  116. switch (updatedURL) {
  117. case '/app':
  118. response.writeHead(200, { 'content-type': 'text/html' });
  119. console.log(global.instances);
  120. for (var prop in global.instances) {
  121. response.write("<a href=http://" + address + prop + ">" + prop + "</a>" + "<br>");
  122. }
  123. response.end();
  124. res = true;
  125. break;
  126. case '/allinstances.json':
  127. response.writeHead(200, {"Content-Type": "application/json"});
  128. var obj = {};
  129. console.log(global.instances);
  130. for (var prop in global.instances) {
  131. //var name = prop.split('/');
  132. obj[prop] = {
  133. "instance":address + prop,
  134. "clients": Object.keys(global.instances[prop].clients).length
  135. };
  136. //response.write("<a href=http://" + address + prop + ">" + prop + "</a>" + "<br>");
  137. }
  138. var json = JSON.stringify(obj);
  139. response.end(json);
  140. res = true;
  141. break;
  142. default:
  143. break;
  144. }
  145. return res;
  146. }
  147. function parseUrlForReflector( pathName ) {
  148. try
  149. {
  150. var namespace = pathName;
  151. if(!namespace) return null;
  152. if (namespace[namespace.length - 1] != "/")
  153. namespace += "/";
  154. return parseurl.Process( namespace );
  155. }
  156. catch (e)
  157. {
  158. return null;
  159. }
  160. }
  161. function GetLoadForSocket( processedURL ) {
  162. if ( processedURL[ 'private_path' ] ) {
  163. return persistence.GetLoadInformation( processedURL );
  164. }
  165. return { 'save_name': undefined, 'save_revision': undefined, 'explicit_revision': undefined, 'application_path': undefined };
  166. }
  167. function HandleReflectorRequest(request, response) {
  168. //var updatedURL = url.parse(request.url).pathname;
  169. // var address = request.headers.host;
  170. var res = false;
  171. if (request.method === 'POST' && request.url === '/parseurl') {
  172. let body = [];
  173. request.on('data', (chunk) => {
  174. body.push(chunk);
  175. }).on('end', () => {
  176. body = Buffer.concat(body).toString();
  177. let pathUrl = JSON.parse(body);
  178. let refPath = parseUrlForReflector( pathUrl.url );
  179. //prepare for persistence request in case that's what this is
  180. let loadInfo = GetLoadForSocket( refPath );
  181. let saveObject = persistence.LoadSaveObject( loadInfo );
  182. let resObj = {
  183. path: refPath,
  184. loadInfo: loadInfo,
  185. saveObject: saveObject
  186. }
  187. //console.log(resObj);
  188. let json = JSON.stringify(resObj);
  189. response.writeHead(200, {"Content-Type": "application/json"});
  190. response.end(json);
  191. });
  192. } else {
  193. //response.statusCode = 404;
  194. //response.end();
  195. }
  196. return res;
  197. }
  198. // Serve is the top level function for serving requests. It first attempts to
  199. // serve the request based on parsing the incoming URL.
  200. // If that fails, it continues to attempt to serve the request as a 'proxy' request,
  201. // if that also does not serve anything to the request, then an attempt is made
  202. // to handle the request as a simple direct request for a file within the public
  203. // directory structure.
  204. // If all that fails, serve up a 404 response since the request was not handled.
  205. function Serve( request, response ) {
  206. var handledRequest = HandleReflectorRequest( request, response );
  207. if ( ! ( handledRequest ) ) {
  208. handledRequest = HandleParsableRequest( request, response ); }
  209. if ( ! ( handledRequest ) ) {
  210. handledRequest = HandleProxyRequest( request, response );
  211. }
  212. if ( ! ( handledRequest ) ) {
  213. handledRequest = HandleFileRequest( request, response );
  214. }
  215. if ( ! ( handledRequest ) ) {
  216. handledRequest = HandleWebAppRequest( request, response );
  217. }
  218. if ( ! ( handledRequest ) ) {
  219. global.log("404 : " + url.parse( request.url ).pathname )
  220. serve._404( response, "404.html" );
  221. }
  222. }
  223. exports.Serve = Serve;