diff --git a/cgi-bin/.htaccess b/cgi-bin/.htaccess new file mode 100644 index 0000000..e86c49d --- /dev/null +++ b/cgi-bin/.htaccess @@ -0,0 +1,2 @@ +Options ExecCGI +SetHandler cgi-script \ No newline at end of file diff --git a/cgi-bin/cgi-node.dev.js b/cgi-bin/cgi-node.dev.js new file mode 100644 index 0000000..47b9de5 --- /dev/null +++ b/cgi-bin/cgi-node.dev.js @@ -0,0 +1,44 @@ +#!"D:/Programs/nodejs/node.exe" + +/* +The MIT License (MIT) + +Copyright (c) 2014 UeiRicho + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +@Author: Uei Richo +@Email: Uei.Richo@gmail.com + + This allows us to run CGI-Node directly from the source files without having to build them while in development mode. +*/ + +// Add required modules. +var FS = require('fs'); + +// The list of files to included +var code = ''; +var dir = '../src/' +var files = ['CgiNodeConfig.js', 'CgiNodeContext.js', 'CgiNodeSession.js', 'CgiNodeResponse.js', 'CgiNodeRequest.js', 'CgiNodeParser.js', 'CgiNode.js']; + +// Loop through the files and get the content. +for (var index = 0; index < files.length; index++) code += '\n\n' + FS.readFileSync( dir + files[index] ); + +// Run the source code. +eval(code); \ No newline at end of file diff --git a/logo/logo.png b/logo/logo.png new file mode 100644 index 0000000..7524c4e Binary files /dev/null and b/logo/logo.png differ diff --git a/logo/logo.svg b/logo/logo.svg new file mode 100644 index 0000000..5a73318 --- /dev/null +++ b/logo/logo.svg @@ -0,0 +1,78 @@ + +image/svg+xml + + + + + + +CGI-Node + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..dc07a3b --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "cgi-node", + "displayName": "cgi-node", + "version": "0.1.0", + "description": "Run Node.js as CGI-Module on any Apache", + "homepage": "http://www.cgi-node.org", + "bugs": "https://code.google.com/p/cgi-node/issues/list", + "author": "Uei Richo ", + "license": "GNU GPL v3", + "repository": { + "type": "svn", + "url": "http://cgi-node.googlecode.com/svn/trunk/" + }, + "main": "./lib/cgi-node", + "bin": { + "cgi-node": "./bin/cgi-node" + }, + "dependencies": { + }, + "engines": { + "node": ">=0.10" + } +} \ No newline at end of file diff --git a/src/CgiNode.js b/src/CgiNode.js new file mode 100644 index 0000000..bb573ee --- /dev/null +++ b/src/CgiNode.js @@ -0,0 +1,78 @@ +/* +The MIT License (MIT) + +Copyright (c) 2014 UeiRicho + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +@Author: Uei Richo +@Email: Uei.Richo@gmail.com +*/ + +// Add the required modules. +var VM = require('vm'); +var FS = require('fs'); +var URL = require('url'); +var Path = require('path'); +var Crypto = require('crypto'); +var QueryString = require('querystring'); + +// The NodeCGI context. +var cgiNodeContext = null; + +/* + The first thing we are going to do is set up a way to catch any global + exceptions and send them to the client. This is extremely helpful when developing code. +*/ +process.on('uncaughtException', function(error) +{ + // Build the HTML error. + var htmlError = '
EXCEPTION: ' + error.message + '
' + error.stack + '

'; + + // If the CGI context has been created then use the response to send the error + if (cgiNodeContext !== null) cgiNodeContext.response.write( htmlError ); + + // Otherwise send an HTTP header followed by the error. + else process.stdout.write("Content-type: text/html; charset=iso-8859-1\n\n" + htmlError); +}); + +/* + When the process exists make sure to save any session data back to the file. +*/ +process.on('exit', function(code) +{ + // Save the session back to the file. + cgiNodeContext.session.save(); + + // Clean up any sessions that have expired. + cgiNodeContext.session.cleanUp(); +}); + +// Create the CGI context and execute the requested file. +cgiNodeContext = new CgiHttpContext(); + +// Create a callback function that will get called when everything is loaded and ready to go. This will execute the script. +var onReady = function() { cgiNodeContext.include(process.env.PATH_TRANSLATED); }; + +// TODO: remove this when the POST parser is done. +cgiNodeContext.request.method = 'GET'; + +// If the HTTP method is a 'POST' then read the post data. Otherwise process is ready. +if (cgiNodeContext.request.method != 'POST') onReady(); +else cgiNodeContext.request.readPost(onReady); diff --git a/src/CgiNodeConfig.js b/src/CgiNodeConfig.js new file mode 100644 index 0000000..12ef20d --- /dev/null +++ b/src/CgiNodeConfig.js @@ -0,0 +1,45 @@ +/* +The MIT License (MIT) + +Copyright (c) 2014 UeiRicho + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +@Author: Uei Richo +@Email: Uei.Richo@gmail.com + + This is the global configuration object for CgiNode. + + NOTE: It is not in a JSON file because we want to compile it directly within the final cig-node.js file to optimize load time. +*/ +var CgiNodeConfig = +{ + Version: '0.2', + + StartTag: ', path: , code: , content: []}; + */ + this.__scripts = []; + + /* + This is the VM context/sandbox used for every included script. + */ + this.__vmContext = null; + + /* + This object is created before the requested script is executed. It represents the HTTP request + and contains all the request information. This includes the headers, URL, query string, post data + and server information. + + See CgiHttpRequest for more details. + */ + this.request = new CgiHttpRequest(onFinished); + + /* + This object is created by the initially that implements header and write methods to send data back to the + client. + + See CgiHttpResponse for more details. + */ + this.response = new CgiHttpResponse(); + + /* + This is the current user session object. It is automatically saved and loaded for each request. + The session is sent through Cookies to the client which is automatically sent back and forth for every request. + + NOTE: this must be created after the request has been parsed. + */ + this.session = new CgiHttpSession(this.request, this.response); + + /* + This is an alias to the response.write method. + Can be used directly within CGI script, example: write('Hello World') + */ + this.write = this.response.write; + + /* + The node process object is made available to the scripts for any additional information they may require. + See http://nodejs.org/documentation/api/ under "process" for more information. + */ + this.process = process; + this.require = require; + + /* + Resolve the file path relative to the root of the website as defined within the configuration, + or if not specified then the base script path. + */ + this.mapPath = function(path) + { + var root = Path.dirname(self.request.server.path_translated) + return Path.resolve(root, path); + }; + + /* + Executes the given file within the current context. + If the given file path is is a '.js' file, it is executed as is, otherwise it is assumed to be an ASP page and is parsed first. + */ + this.include = function(filePath, options) + { + // If options is not defined then assume UTF8 as including. + if (options === undefined) options = {encoding: 'utf8'}; + + // Resolve the script path. + var path = self.mapPath(filePath); + + // Get the script file content. + var content = FS.readFileSync(path, options); + + // If the file extension is not '.js' then parse out the different code and content sections. + // TODO: use the configuration object to check if it is a script file or not. + if (Path.extname(filePath) != '.js') script = CgiParser.script(self.__scripts.length, path, content.toString()); + + // Otherwise just create a new script object + else script = {id: self.__scripts.length, path: path, script: null, code: content, content: []}; + + // Push the script onto the global script array. + self.__scripts.push(script); + + // If the VM context has not yet been created then create it. + if (self.__vmContext === null) self.__vmContext = VM.createContext(self); + + // Execute the script within the context. + VM.runInContext(script.code, self.__vmContext, script.path); + }; + + /* + This method is similar to PhpInfo(). It outputs all the HTTP request and server information and variables + to the stream in HTML format. + */ + this.CgiNodeInfo = function() + { + var drawObject = function(title, object) + { + self.response.write('' + title + ''); + for (var name in object) + { + var value = object[name]; + if (typeof(value) === 'function') continue; + else if (typeof(value) === 'object') + { + var htmlValue = '' + for (var subName in value) htmlValue += ''; + value = htmlValue + '
' + subName +'' + value[subName] +'
'; + } + + process.stdout.write('' + name +'' + value +''); + } + }; + + self.response.write(''); + self.response.write(''); + self.response.write(''); + + var session = {id: self.session.id, path: self.session.path, ipAddress: self.session.ipAddress}; + + drawObject('Node Versions', process.versions); + drawObject('CGI Command Line Arguments', process.argv); + drawObject('Server Variables', self.request.server); + drawObject('HTTP Request Headers', self.request.headers); + drawObject('HTTP Request Cookies', self.request.cookies); + drawObject('Session', session); + drawObject('Session Cookies', self.session.cookies); + drawObject('Session Data', self.session.data); + drawObject('URL Query String', self.request.query); + drawObject('Post Form', self.request.post.form); + drawObject('Post Files', self.request.post.files); + drawObject('Post Parts', self.request.post.parts); + + self.response.write('
'); + }; +} \ No newline at end of file diff --git a/src/CgiNodeParser.js b/src/CgiNodeParser.js new file mode 100644 index 0000000..efef79d --- /dev/null +++ b/src/CgiNodeParser.js @@ -0,0 +1,221 @@ +/* +The MIT License (MIT) + +Copyright (c) 2014 UeiRicho + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +@Author: Uei Richo +@Email: Uei.Richo@gmail.com + + This static object provides methods to facilitate parse data for the CGI process. +*/ +var CgiParser = +{ + /* + Splits the given file content into the content sections and the source code sections. + + NOTE: This expects a 'response.write' method to exist within the context of the executed code + and it should have access to '__scripts[id].