Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

complete mock webservice support

  • Loading branch information...
commit 9f58f51f20536c4bb874ccf7c6cd827e44cf0984 1 parent 3a2aac4
@marty-wang authored
View
15 README.md
@@ -4,6 +4,7 @@ NServe is a nodejs-powered static file server that is created to facilitate loca
* Easy and Fast. One command and serve away.
* Allow user-defined transfer rate to mimck the real situations.
+* Timeout mock webservices, including GET and POST.
* More to come...
# Installation
@@ -20,11 +21,13 @@ In the folder where you want to serve the files. Run the command below.
Options:
- -h, --help output usage information
- -V, --version output the version number
- -p, --port <n> specify the port number [3000]
- -r, --rate <bit rate> specify the file transfer rate, e.g. 100k or 5m
- -v, --verbose enter verbose mode
- -d, --directory <root> specify the root directory, either relative or absolute [current directory]
+ -h, --help output usage information
+ -V, --version output the version number
+ -p, --port <n> specify the port number [3000]
+ -r, --rate <bit rate> specify the file transfer rate, e.g. 100k or 5m
+ -v, --verbose enter verbose mode
+ -d, --directory <root> specify the root directory, relative or absolute [current directory]
+ -w, --webservice-folder <folder name> specify the webservice folder name ["ws"]
+ -t, --webservice-timeout <n> specify the webservice timeout in millisecond [0]
and open [http://localhost:3000](http://localhost:3000) in your browser.
View
2  lib/connect-file-transfer.js
@@ -23,7 +23,7 @@
stat = fs.statSync(path);
return fs.readFile(path, function(err, data) {
var contentType;
- if (!err) {
+ if (err == null) {
_callback("start", path);
contentType = mime.lookup(path);
res.writeHead(200, {
View
76 lib/connect-webservice.js
@@ -1,41 +1,69 @@
(function() {
- var parse, webservice, _isWS, _resHeader, _wsDir;
+ var fs, parse, path, webservice, _isWS, _readFile, _resHeader, _respond, _root, _timeout, _wsFolder;
parse = require("url").parse;
- _wsDir = 'ws';
+ fs = require('fs');
+ path = require('path');
+ _root = null;
+ _wsFolder = null;
+ _timeout = null;
_isWS = function(pathname) {
- return pathname === ("/" + _wsDir) || pathname.indexOf("/" + _wsDir + "/") === 0;
+ return pathname === ("/" + _wsFolder) || pathname.indexOf("/" + _wsFolder + "/") === 0;
};
_resHeader = {
'Content-Type': "text/plain",
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Requested-With'
};
- webservice = function() {
+ _readFile = function(req, res, path, statusCode) {
+ return fs.readFile(_root + path, function(err, data) {
+ var retData;
+ if (err == null) {
+ res.writeHead(statusCode, _resHeader);
+ return res.end(data);
+ } else {
+ res.writeHead(404, _resHeader);
+ retData = {
+ statusCode: 404,
+ responseText: "Unexpected Error: " + req.method + " " + path
+ };
+ return res.end(JSON.stringify(retData));
+ }
+ });
+ };
+ _respond = function(req, res, pathname, errorFile) {
+ return setTimeout((function() {
+ if (errorFile == null) {
+ return _readFile(req, res, pathname, 200);
+ } else {
+ pathname = path.resolve(pathname, "../" + errorFile);
+ return _readFile(req, res, pathname, 404);
+ }
+ }), _timeout);
+ };
+ webservice = function(root, webserviceFolder, timeout) {
+ if (root == null) {
+ root = '.';
+ }
+ if (webserviceFolder == null) {
+ webserviceFolder = 'ws';
+ }
+ if (timeout == null) {
+ timeout = 0;
+ }
+ _root = root;
+ _wsFolder = webserviceFolder;
+ _timeout = timeout;
return function(req, res, next) {
- var body, pUrl, pathname, query;
- pUrl = parse(req.url);
- pathname = pUrl.pathname;
+ var errorFile, pathname;
+ pathname = parse(req.url).pathname;
if (_isWS(pathname)) {
switch (req.method.toUpperCase()) {
case 'GET':
- query = pUrl.query;
- if ((query != null) && query.indexOf("error") > -1) {
- res.writeHead(404, _resHeader);
- return res.end("GET Failure: " + pathname);
- } else {
- res.writeHead(200, _resHeader);
- return res.end("GET: " + pathname);
- }
- break;
+ errorFile = req.query['error'];
+ return _respond(req, res, pathname, errorFile);
case 'POST':
- body = req.body;
- if (body['error'] == null) {
- res.writeHead(200, _resHeader);
- return res.end("POST Success: " + pathname);
- } else {
- res.writeHead(404, _resHeader);
- return res.end("POST Failure: " + pathname);
- }
+ errorFile = req.body['error'];
+ return _respond(req, res, pathname, errorFile);
}
} else {
return next();
View
21 lib/nserve.js
@@ -1,10 +1,13 @@
(function() {
- var DEFAULT_PORT, colors, connect, fileTransfer, fs, http, parse, program, start, sys, util, webservice, _fileTransferCallback, _init, _isVerbose, _now, _parseCLI, _port, _rate, _root, _router, _server, _version, _versionNumber;
+ var DEFAULT_PORT, DEFAULT_WEBSERVICE_FOLDER, DEFAULT_WEBSERVICE_TIMEOUT, colors, connect, fileTransfer, fs, http, parse, path, program, start, sys, util, webservice, _fileTransferCallback, _init, _isVerbose, _now, _parseCLI, _port, _rate, _root, _router, _server, _version, _versionNumber, _webserviceFolder, _webserviceTimeout;
DEFAULT_PORT = 3000;
+ DEFAULT_WEBSERVICE_FOLDER = "ws";
+ DEFAULT_WEBSERVICE_TIMEOUT = 0;
sys = require("sys");
fs = require("fs");
http = require("http");
parse = require("url").parse;
+ path = require("path");
connect = require("connect");
program = require("commander");
colors = require("colors");
@@ -18,6 +21,8 @@
_port = DEFAULT_PORT;
_rate = null;
_root = null;
+ _webserviceFolder = null;
+ _webserviceTimeout = 0;
_version = function() {
try {
return _versionNumber = util.getVersionNumber();
@@ -26,8 +31,8 @@
}
};
_parseCLI = function() {
- var port, root;
- program.version(_versionNumber).option('-p, --port <n>', 'specify the port number [3000]', parseInt).option('-r, --rate <bit rate>', 'specify the file transfer rate, e.g. 100k or 5m').option('-v, --verbose', 'enter verbose mode').option('-d, --directory <root>', 'specify the root directory, either relative or absolute [current directory]').parse(process.argv);
+ var port, root, wsFolder, wsTimeout;
+ program.version(_versionNumber).option('-p, --port <n>', 'specify the port number [3000]', parseInt).option('-r, --rate <bit rate>', 'specify the file transfer rate, e.g. 100k or 5m').option('-v, --verbose', 'enter verbose mode').option('-d, --directory <root>', 'specify the root directory, either relative or absolute [current directory]').option('-w, --webservice-folder <folder name>', 'specify the webservice folder name ["ws"]').option('-t, --webservice-timeout <n>', 'specify the webservice timeout in millisecond [0]', parseInt).parse(process.argv);
port = program.port;
if ((port != null) && !isNaN(port)) {
_port = port;
@@ -35,7 +40,11 @@
_isVerbose = !!program.verbose;
_rate = program.rate;
root = util.absoluteDirPath(program.directory);
- return _root = root != null ? root : process.cwd();
+ _root = root != null ? root : process.cwd();
+ wsFolder = program.webserviceFolder;
+ _webserviceFolder = wsFolder != null ? util.normalizeFolderName(wsFolder) : DEFAULT_WEBSERVICE_FOLDER;
+ wsTimeout = program.webserviceTimeout;
+ return _webserviceTimeout = (wsTimeout != null) && !isNaN(wsTimeout) ? wsTimeout : DEFAULT_WEBSERVICE_TIMEOUT;
};
_now = function() {
if (_isVerbose) {
@@ -68,7 +77,7 @@
});
};
_init = function() {
- return connect.createServer(connect.bodyParser(), _router(), webservice(), connect.favicon(), connect.directory(_root), fileTransfer(_rate, _root, _fileTransferCallback));
+ return connect.createServer(connect.bodyParser(), connect.query(), _router(), webservice(_root, _webserviceFolder, _webserviceTimeout), connect.favicon(), connect.directory(_root), fileTransfer(_rate, _root, _fileTransferCallback));
};
/* bootstrap */
_version();
@@ -82,6 +91,8 @@
console.log(" root ".cyan + ("" + _root));
console.log(" port ".cyan + ("" + _port));
console.log(" rate ".cyan + (_rate != null ? "" + _rate + " (bps)" : "unlimited"));
+ console.log(" webservice folder ".cyan + ("" + _webserviceFolder));
+ console.log(" webservice timeout ".cyan + ("" + _webserviceTimeout + " ms"));
if (_isVerbose) {
console.log(" mode ".cyan + "verbose");
}
View
8 lib/util.js
@@ -1,5 +1,5 @@
(function() {
- var absoluteDirPath, fs, getVersionNumber, now, path, _packagePath, _root;
+ var absoluteDirPath, fs, getVersionNumber, normalizeFolderName, now, path, _packagePath, _root;
path = require('path');
fs = require('fs');
_root = path.resolve(__dirname, "..");
@@ -33,6 +33,11 @@
}
return absDir;
};
+ normalizeFolderName = function(folder) {
+ var regEx;
+ regEx = /\\|\//g;
+ return folder.replace(regEx, '');
+ };
now = function() {
var nowArr, nowStr;
now = new Date();
@@ -43,5 +48,6 @@
/* exports */
exports.getVersionNumber = getVersionNumber;
exports.absoluteDirPath = absoluteDirPath;
+ exports.normalizeFolderName = normalizeFolderName;
exports.now = now;
}).call(this);
View
2  package.json
@@ -3,7 +3,7 @@
"name": "nserve",
"description": "A nodejs-powered static file server for development",
"keywords": ["static", "file", "web", "server"],
- "version": "0.0.4",
+ "version": "0.0.5",
"repository": {
"type": "git",
"url": "https://github.com/marty-wang/NServe"
View
16 samples/ajax.html
@@ -5,7 +5,7 @@
<script type="text/javascript" src="js/jquery.min.js"></script>
</head>
<body>
- <p>Open this page locally or run through other web server. You will see that the cross-domain ajax calls will work. This will be very handy for local development, because you will not need to change anything in your code, and it will just work as if they were same-domain ajax calls.</p>
+ <p>Open this page locally or run through other web server. You will see that the cross-domain ajax calls will work. This will be very handy for local development, because you will not need to change anything in your code, and it will just work as if they were same-domain ajax calls. Also you have the ability to specify the webservice timeout so that you can test your loader.</p>
<p id="message">This is message will be updated</p>
<button id="get_button_s">Get Request Success</button>
@@ -27,6 +27,9 @@
type: "get",
success: function(data) {
msg.innerHTML = "get success: " + data;
+ },
+ error: function(jqXHR, text) {
+ msg.innerHTML = "get error: " + jqXHR.responseText;
}
});
};
@@ -34,7 +37,7 @@
getBtnF.onclick = function(e) {
e.preventDefault();
$.ajax({
- url: "http://localhost:3000/ws/data.json?error=true",
+ url: "http://localhost:3000/ws/data.json?error=error.json",
type: "get",
error: function(jqXHR, text) {
msg.innerHTML = "get error: " + jqXHR.responseText;
@@ -45,11 +48,14 @@
postBtnS.onclick = function(e) {
e.preventDefault();
$.ajax({
- url: "http://localhost:3000/ws",
+ url: "http://localhost:3000/ws/data.json",
data: "key=value",
type: "post",
success: function(data) {
msg.innerHTML = "post success: " + data;
+ },
+ error: function(jqXHR, text) {
+ msg.innerHTML = "post error: " + jqXHR.responseText;
}
});
};
@@ -57,8 +63,8 @@
postBtnF.onclick = function(e) {
e.preventDefault();
$.ajax({
- url: "http://localhost:3000/ws",
- data: "error=true",
+ url: "http://localhost:3000/ws/data.json",
+ data: "error=error.json",
type: "post",
error: function(jqXHR, text) {
msg.innerHTML = "post error: " + jqXHR.responseText;
View
4 samples/ws/error.json
@@ -0,0 +1,4 @@
+{
+ "statusCode": "404",
+ "description": "An expected error just happened, oops!"
+}
View
2  src/connect-file-transfer.coffee
@@ -23,7 +23,7 @@ _transfer = (req, res, next, fn) ->
try
stat = fs.statSync path
fs.readFile path, (err, data)->
- unless err
+ unless err?
_callback "start", path
contentType = mime.lookup path
View
66 src/connect-webservice.coffee
@@ -1,12 +1,13 @@
parse = require("url").parse
+fs = require 'fs'
+path = require 'path'
-# TODO: add timeout var
-
-# should be configurable
-_wsDir = 'ws'
+_root = null
+_wsFolder = null
+_timeout = null
_isWS = (pathname) ->
- pathname is "/#{_wsDir}" or pathname.indexOf("/#{_wsDir}/") is 0
+ pathname is "/#{_wsFolder}" or pathname.indexOf("/#{_wsFolder}/") is 0
_resHeader = {
'Content-Type': "text/plain"
@@ -14,37 +15,46 @@ _resHeader = {
'Access-Control-Allow-Headers': 'X-Requested-With'
}
-webservice = () ->
+_readFile = (req, res, path, statusCode) ->
+ fs.readFile _root+path, (err, data) ->
+ unless err?
+ res.writeHead statusCode, _resHeader
+ res.end data
+ else
+ res.writeHead 404, _resHeader
+ retData = {
+ statusCode: 404
+ responseText: "Unexpected Error: #{req.method} #{path}"
+ }
+ res.end JSON.stringify retData
+
+_respond = (req, res, pathname, errorFile) ->
+ setTimeout (->
+ unless errorFile?
+ _readFile req, res, pathname, 200
+ else
+ pathname = path.resolve pathname, "../#{errorFile}"
+ _readFile req, res, pathname, 404
+ ), _timeout
+
+webservice = (root='.', webserviceFolder='ws', timeout=0) ->
+
+ _root = root
+ _wsFolder = webserviceFolder
+ _timeout = timeout
(req, res, next) ->
- pUrl = parse(req.url)
- pathname = pUrl.pathname
+ pathname = parse(req.url).pathname
if _isWS pathname
switch req.method.toUpperCase()
when 'GET'
- query = pUrl.query
-
- # TODO: add logic to get the file based on the pathname
- # return 404 if file cannot be found
-
- if query? and query.indexOf("error") > -1
- res.writeHead 404, _resHeader
- res.end "GET Failure: #{pathname}"
- else
- res.writeHead 200, _resHeader
- res.end "GET: #{pathname}"
-
+ errorFile = req.query['error']
+ _respond req, res, pathname, errorFile
when 'POST'
- body = req.body
-
- unless body['error']?
- res.writeHead 200, _resHeader
- res.end "POST Success: #{pathname}"
- else
- res.writeHead 404, _resHeader
- res.end "POST Failure: #{pathname}"
+ errorFile = req.body['error']
+ _respond req, res, pathname, errorFile
else
next()
View
20 src/nserve.coffee
@@ -1,9 +1,12 @@
DEFAULT_PORT = 3000
+DEFAULT_WEBSERVICE_FOLDER = "ws"
+DEFAULT_WEBSERVICE_TIMEOUT = 0
sys = require "sys"
fs = require "fs"
http = require "http"
parse = require("url").parse
+path = require "path"
connect = require "connect"
program = require "commander"
@@ -22,6 +25,8 @@ _isVerbose = false
_port = DEFAULT_PORT
_rate = null
_root = null
+_webserviceFolder = null
+_webserviceTimeout = 0
_version = ->
try
@@ -36,6 +41,8 @@ _parseCLI = ()->
.option('-r, --rate <bit rate>', 'specify the file transfer rate, e.g. 100k or 5m')
.option('-v, --verbose', 'enter verbose mode')
.option('-d, --directory <root>', 'specify the root directory, either relative or absolute [current directory]')
+ .option('-w, --webservice-folder <folder name>', 'specify the webservice folder name ["ws"]')
+ .option('-t, --webservice-timeout <n>', 'specify the webservice timeout in millisecond [0]', parseInt)
.parse(process.argv)
port = program.port
@@ -44,7 +51,13 @@ _parseCLI = ()->
_rate = program.rate
root = util.absoluteDirPath program.directory
- _root = if root? then root else process.cwd()
+ _root = if root? then root else process.cwd()
+
+ wsFolder = program.webserviceFolder
+ _webserviceFolder = if wsFolder? then util.normalizeFolderName(wsFolder) else DEFAULT_WEBSERVICE_FOLDER
+
+ wsTimeout = program.webserviceTimeout
+ _webserviceTimeout = if wsTimeout? and not isNaN(wsTimeout) then wsTimeout else DEFAULT_WEBSERVICE_TIMEOUT
_now = ->
if _isVerbose then " @ #{util.now()}" else ""
@@ -71,8 +84,9 @@ _router = ->
_init = () ->
connect.createServer(
connect.bodyParser(),
+ connect.query(),
_router(),
- webservice(),
+ webservice(_root, _webserviceFolder, _webserviceTimeout),
connect.favicon(),
connect.directory(_root),
fileTransfer(_rate, _root, _fileTransferCallback)
@@ -94,6 +108,8 @@ start = ->
console.log " root ".cyan + "#{_root}"
console.log " port ".cyan + "#{_port}"
console.log " rate ".cyan + if _rate? then "#{_rate} (bps)" else "unlimited"
+ console.log " webservice folder ".cyan + "#{_webserviceFolder}"
+ console.log " webservice timeout ".cyan + "#{_webserviceTimeout} ms"
console.log " mode ".cyan + "verbose" if _isVerbose
console.log "------------------------------------------"
View
6 src/util.coffee
@@ -28,6 +28,11 @@ absoluteDirPath = (pathStr) ->
absDir
+normalizeFolderName = (folder) ->
+ regEx = /\\|\//g
+ folder.replace regEx, ''
+
+
now = ->
now = new Date()
nowStr = now.toTimeString()
@@ -38,4 +43,5 @@ now = ->
exports.getVersionNumber = getVersionNumber
exports.absoluteDirPath = absoluteDirPath
+exports.normalizeFolderName = normalizeFolderName
exports.now = now
Please sign in to comment.
Something went wrong with that request. Please try again.