core/REST/handler.js
function (res_obj, data, conn) {

		// check if we should return empty response
		if (typeof res_obj === 'undefined') {
			SR.REST.reply(res, {});
			return true;
		}

		// check for special case processing (SR_REDIRECT)
		if (res_obj[SR.Tags.UPDATE] === 'SR_REDIRECT' && res_obj[SR.Tags.PARA] && res_obj[SR.Tags.PARA].url) {

			var url = res_obj[SR.Tags.PARA].url;
			LOG.warn('redirecting to: ' + url, l_name);

			/*
			res.writeHead(302, {
				'Location': url
			});
			res.end();
			*/

			// redirect by page 
			// TODO: merge with same code in FB.js
			var page =
				'<html><body><script>\n' +
				'if (navigator.appName.indexOf("Microsoft") != -1)\n' +
				'    window.top.location.href="' + url + '";\n' +
				'else\n' +
				'	 top.location.href="' + url + '";\n' +
				'</script></body></html>\n';

			res.writeHead(200, {
				'Content-Type': 'text/html'
			});
			res.end(page);

			return true;
		}
		
		// check for special case processing (SR_HTML)
		if (res_obj[SR.Tags.UPDATE] === 'SR_HTML' && res_obj[SR.Tags.PARA].page) {
			res.writeHead(200, {
				'Content-Type': 'text/html'
			});
			res.end(res_obj[SR.Tags.PARA].page);
			return true;
		}

		// check for special case processing (SR_DOWNLOAD)
		if (res_obj[SR.Tags.UPDATE] === 'SR_DOWNLOAD' && res_obj[SR.Tags.PARA].data && res_obj[SR.Tags.PARA].filename) {

			var filename = res_obj[SR.Tags.PARA].filename;
			LOG.warn('allow client to download file: ' + filename, l_name);

			var data = res_obj[SR.Tags.PARA].data;
			res.writeHead(200, {
				'Content-Type': 'application/octet-stream',
				'Content-Disposition': 'attachment; filename=' + filename,
				'Content-Length': data.length
			});
			res.end(data);
			return true;
		}

		// check for special case processing (SR_RESOURCE)
		if (res_obj[SR.Tags.UPDATE] === 'SR_RESOURCE' && res_obj[SR.Tags.PARA].address) {

			var file = res_obj[SR.Tags.PARA].address;
						
			// check if resource exists & its states
			SR.fs.stat(file, function (err, stats) {
										
				var resHeader = typeof res_obj[SR.Tags.PARA].header === 'object' ? res_obj[SR.Tags.PARA].header : {};
				
				if (err) {			
					LOG.error(err, l_name);
					res.writeHead(404, resHeader);
					res.end();
					return;
				}
				
				var extFilename = file.match(/[\W\w]*\.([\W\w]*)/)[1];
				if (typeof extFilename === 'string')
					extFilename = extFilename.toLowerCase();
				
				// default to 200 status
				var resStatus = 200;
				resHeader['Accept-Ranges'] = 'bytes';
				resHeader['Cache-Control'] = 'no-cache';
				resHeader['Content-Length'] = stats.size;
				
				if (l_extList[extFilename]) {
					resHeader['Content-Type'] = l_extList[extFilename];
				};
				
				var start = undefined;
				var end = undefined;
				
				// check if request range exists (e.g., streaming media such as webm/mp4) to return 206 status
				// see: https://delog.wordpress.com/2011/04/25/stream-webm-file-to-chrome-using-node-js/						
				if (req.headers.range) {
					var range = req.headers.range.split(/bytes=([0-9]*)-([0-9]*)/);
					resStatus = 206;
					
					start = parseInt(range[1] || 0);
					end = parseInt(range[2] || stats.size - 1);
					
					if (start > end) {
						LOG.error('stream file start > end. start: ' + start + ' end: ' + end, l_name);
						var resHeader = typeof res_obj[SR.Tags.PARA].header === 'object' ? res_obj[SR.Tags.PARA].header : {};
						res.writeHead(404, resHeader);
						res.end();
						return;  // abnormal if we've reached here
					}
					
					LOG.debug('requesting bytes ' + start + ' to ' + end + ' for file: ' + file, l_name);
							 
					resHeader['Connection'] = 'close';
					resHeader['Content-Length'] = end - start + 1;
					resHeader['Content-Range'] = 'bytes ' + start + '-' + end + '/' + stats.size;
					resHeader['Transfer-Encoding'] = 'chunked';
				} 
				// otherwise assume it's a regular file
				else if (l_directExt.hasOwnProperty(extFilename)) {
					// NOTE: code below will cause the file be downloaded in a "Save As.." format
					// (instead of being displayed directly), we only want this behavior for certain file types (such as .zip)				
					var filename = file.replace(/^.*[\\\/]/, '')
					LOG.warn('requesting a file: ' + filename, l_name);
					resHeader['Content-Disposition'] = 'attachment; filename=' + filename;
				}
				
				LOG.sys('SR_RESOURCE header:', l_name);
				LOG.sys(resHeader);
				res.writeHead(resStatus, resHeader);

				// start streaming
				SR.fs.createReadStream(file, {
					flags: 'r',
					start: start,
					end: end
				}).pipe(res);			
			});
			
			return true;
		}

		var origin = _getOrigin(req);

		// send back via res object if hadn't responded yet
		if (res.headersSent === false) {
			// NOTE: cookie may be undefined;
			SR.REST.reply(res, data, {
				origin: origin,
				cookie: cookie
			});
		}
		else {
			LOG.error('HTTP request has already responded (cannot respond twice)', l_name);
			LOG.stack();
		}

		return true;
	}
function (res_obj, data, conn) {

		// check if we should return empty response
		if (typeof res_obj === 'undefined') {
			SR.REST.reply(res, {});
			return true;
		}

		// check for special case processing (SR_REDIRECT)
		if (res_obj[SR.Tags.UPDATE] === 'SR_REDIRECT' && res_obj[SR.Tags.PARA] && res_obj[SR.Tags.PARA].url) {

			var url = res_obj[SR.Tags.PARA].url;
			LOG.warn('redirecting to: ' + url, l_name);

			/*
			res.writeHead(302, {
				'Location': url
			});
			res.end();
			*/

			// redirect by page 
			// TODO: merge with same code in FB.js
			var page =
				'<html><body><script>\n' +
				'if (navigator.appName.indexOf("Microsoft") != -1)\n' +
				'    window.top.location.href="' + url + '";\n' +
				'else\n' +
				'	 top.location.href="' + url + '";\n' +
				'</script></body></html>\n';

			res.writeHead(200, {
				'Content-Type': 'text/html'
			});
			res.end(page);

			return true;
		}
		
		// check for special case processing (SR_HTML)
		if (res_obj[SR.Tags.UPDATE] === 'SR_HTML' && res_obj[SR.Tags.PARA].page) {
			res.writeHead(200, {
				'Content-Type': 'text/html'
			});
			res.end(res_obj[SR.Tags.PARA].page);
			return true;
		}

		// check for special case processing (SR_DOWNLOAD)
		if (res_obj[SR.Tags.UPDATE] === 'SR_DOWNLOAD' && res_obj[SR.Tags.PARA].data && res_obj[SR.Tags.PARA].filename) {

			var filename = res_obj[SR.Tags.PARA].filename;
			LOG.warn('allow client to download file: ' + filename, l_name);

			var data = res_obj[SR.Tags.PARA].data;
			res.writeHead(200, {
				'Content-Type': 'application/octet-stream',
				'Content-Disposition': 'attachment; filename=' + filename,
				'Content-Length': data.length
			});
			res.end(data);
			return true;
		}

		// check for special case processing (SR_RESOURCE)
		if (res_obj[SR.Tags.UPDATE] === 'SR_RESOURCE' && res_obj[SR.Tags.PARA].address) {

			var file = res_obj[SR.Tags.PARA].address;
						
			// check if resource exists & its states
			SR.fs.stat(file, function (err, stats) {
										
				var resHeader = typeof res_obj[SR.Tags.PARA].header === 'object' ? res_obj[SR.Tags.PARA].header : {};
				
				if (err) {			
					LOG.error(err, l_name);
					res.writeHead(404, resHeader);
					res.end();
					return;
				}
				
				var extFilename = file.match(/[\W\w]*\.([\W\w]*)/)[1];
				if (typeof extFilename === 'string')
					extFilename = extFilename.toLowerCase();
				
				// default to 200 status
				var resStatus = 200;
				resHeader['Accept-Ranges'] = 'bytes';
				resHeader['Cache-Control'] = 'no-cache';
				resHeader['Content-Length'] = stats.size;
				
				if (l_extList[extFilename]) {
					resHeader['Content-Type'] = l_extList[extFilename];
				};
				
				var start = undefined;
				var end = undefined;
				
				// check if request range exists (e.g., streaming media such as webm/mp4) to return 206 status
				// see: https://delog.wordpress.com/2011/04/25/stream-webm-file-to-chrome-using-node-js/						
				if (req.headers.range) {
					var range = req.headers.range.split(/bytes=([0-9]*)-([0-9]*)/);
					resStatus = 206;
					
					start = parseInt(range[1] || 0);
					end = parseInt(range[2] || stats.size - 1);
					
					if (start > end) {
						LOG.error('stream file start > end. start: ' + start + ' end: ' + end, l_name);
						var resHeader = typeof res_obj[SR.Tags.PARA].header === 'object' ? res_obj[SR.Tags.PARA].header : {};
						res.writeHead(404, resHeader);
						res.end();
						return;  // abnormal if we've reached here
					}
					
					LOG.debug('requesting bytes ' + start + ' to ' + end + ' for file: ' + file, l_name);
							 
					resHeader['Connection'] = 'close';
					resHeader['Content-Length'] = end - start + 1;
					resHeader['Content-Range'] = 'bytes ' + start + '-' + end + '/' + stats.size;
					resHeader['Transfer-Encoding'] = 'chunked';
				} 
				// otherwise assume it's a regular file
				else if (l_directExt.hasOwnProperty(extFilename)) {
					// NOTE: code below will cause the file be downloaded in a "Save As.." format
					// (instead of being displayed directly), we only want this behavior for certain file types (such as .zip)				
					var filename = file.replace(/^.*[\\\/]/, '')
					LOG.warn('requesting a file: ' + filename, l_name);
					resHeader['Content-Disposition'] = 'attachment; filename=' + filename;
				}
				
				LOG.sys('SR_RESOURCE header:', l_name);
				LOG.sys(resHeader);
				res.writeHead(resStatus, resHeader);

				// start streaming
				SR.fs.createReadStream(file, {
					flags: 'r',
					start: start,
					end: end
				}).pipe(res);			
			});
			
			return true;
		}

		var origin = _getOrigin(req);

		// send back via res object if hadn't responded yet
		if (res.headersSent === false) {
			// NOTE: cookie may be undefined;
			SR.REST.reply(res, data, {
				origin: origin,
				cookie: cookie
			});
		}
		else {
			LOG.error('HTTP request has already responded (cannot respond twice)', l_name);
			LOG.stack();
		}

		return true;
	}
function ( res_obj , data , conn ) { // check if we should return empty response if ( typeof res_obj === 'undefined' ) { SR . REST . reply ( res , { } ) ; return true ; } // check for special case processing (SR_REDIRECT) if ( res_obj [ SR . Tags . UPDATE ] === 'SR_REDIRECT' && res_obj [ SR . Tags . PARA ] && res_obj [ SR . Tags . PARA ] . url ) { var url = res_obj [ SR . Tags . PARA ] . url ; LOG . warn ( 'redirecting to: ' + url , l_name ) ; /*
			res.writeHead(302, {
				'Location': url
			});
			res.end();
			*/ // redirect by page  // TODO: merge with same code in FB.js var page = '<html><body><script>\n' + 'if (navigator.appName.indexOf("Microsoft") != -1)\n' + '    window.top.location.href="' + url + '";\n' + 'else\n' + '	 top.location.href="' + url + '";\n' + '</script></body></html>\n' ; res . writeHead ( 200 , { 'Content-Type' : 'text/html' } ) ; res . end ( page ) ; return true ; } // check for special case processing (SR_HTML) if ( res_obj [ SR . Tags . UPDATE ] === 'SR_HTML' && res_obj [ SR . Tags . PARA ] . page ) { res . writeHead ( 200 , { 'Content-Type' : 'text/html' } ) ; res . end ( res_obj [ SR . Tags . PARA ] . page ) ; return true ; } // check for special case processing (SR_DOWNLOAD) if ( res_obj [ SR . Tags . UPDATE ] === 'SR_DOWNLOAD' && res_obj [ SR . Tags . PARA ] . data && res_obj [ SR . Tags . PARA ] . filename ) { var filename = res_obj [ SR . Tags . PARA ] . filename ; LOG . warn ( 'allow client to download file: ' + filename , l_name ) ; var data = res_obj [ SR . Tags . PARA ] . data ; res . writeHead ( 200 , { 'Content-Type' : 'application/octet-stream' , 'Content-Disposition' : 'attachment; filename=' + filename , 'Content-Length' : data . length } ) ; res . end ( data ) ; return true ; } // check for special case processing (SR_RESOURCE) if ( res_obj [ SR . Tags . UPDATE ] === 'SR_RESOURCE' && res_obj [ SR . Tags . PARA ] . address ) { var file = res_obj [ SR . Tags . PARA ] . address ; // check if resource exists & its states SR . fs . stat ( file , function ( err , stats ) { var resHeader = typeof res_obj [ SR . Tags . PARA ] . header === 'object' ? res_obj [ SR . Tags . PARA ] . header : { } ; if ( err ) { LOG . error ( err , l_name ) ; res . writeHead ( 404 , resHeader ) ; res . end ( ) ; return ; } var extFilename = file . match ( / [\W\w]*\.([\W\w]*) / ) [ 1 ] ; if ( typeof extFilename === 'string' ) extFilename = extFilename . toLowerCase ( ) ; // default to 200 status var resStatus = 200 ; resHeader [ 'Accept-Ranges' ] = 'bytes' ; resHeader [ 'Cache-Control' ] = 'no-cache' ; resHeader [ 'Content-Length' ] = stats . size ; if ( l_extList [ extFilename ] ) { resHeader [ 'Content-Type' ] = l_extList [ extFilename ] ; } ; var start = undefined ; var end = undefined ; // check if request range exists (e.g., streaming media such as webm/mp4) to return 206 status // see: https://delog.wordpress.com/2011/04/25/stream-webm-file-to-chrome-using-node-js/						 if ( req . headers . range ) { var range = req . headers . range . split ( / bytes=([0-9]*)-([0-9]*) / ) ; resStatus = 206 ; start = parseInt ( range [ 1 ] || 0 ) ; end = parseInt ( range [ 2 ] || stats . size - 1 ) ; if ( start > end ) { LOG . error ( 'stream file start > end. start: ' + start + ' end: ' + end , l_name ) ; var resHeader = typeof res_obj [ SR . Tags . PARA ] . header === 'object' ? res_obj [ SR . Tags . PARA ] . header : { } ; res . writeHead ( 404 , resHeader ) ; res . end ( ) ; return ; // abnormal if we've reached here } LOG . debug ( 'requesting bytes ' + start + ' to ' + end + ' for file: ' + file , l_name ) ; resHeader [ 'Connection' ] = 'close' ; resHeader [ 'Content-Length' ] = end - start + 1 ; resHeader [ 'Content-Range' ] = 'bytes ' + start + '-' + end + '/' + stats . size ; resHeader [ 'Transfer-Encoding' ] = 'chunked' ; } // otherwise assume it's a regular file else if ( l_directExt . hasOwnProperty ( extFilename ) ) { // NOTE: code below will cause the file be downloaded in a "Save As.." format // (instead of being displayed directly), we only want this behavior for certain file types (such as .zip)				 var filename = file . replace ( / ^.*[\\\/] / , '' ) LOG . warn ( 'requesting a file: ' + filename , l_name ) ; resHeader [ 'Content-Disposition' ] = 'attachment; filename=' + filename ; } LOG . sys ( 'SR_RESOURCE header:' , l_name ) ; LOG . sys ( resHeader ) ; res . writeHead ( resStatus , resHeader ) ; // start streaming SR . fs . createReadStream ( file , { flags : 'r' , start : start , end : end } ) . pipe ( res ) ; } ) ; return true ; } var origin = _getOrigin ( req ) ; // send back via res object if hadn't responded yet if ( res . headersSent === false ) { // NOTE: cookie may be undefined; SR . REST . reply ( res , data , { origin : origin , cookie : cookie } ) ; } else { LOG . error ( 'HTTP request has already responded (cannot respond twice)' , l_name ) ; LOG . stack ( ) ; } return true ; }
callback to return response to client
callback to return response to client