diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..05b1cf3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +**/node_modules/* +**/vendor/* +**/*.min.js +**/coverage/* +**/build/* diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..8dc6807 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,21 @@ +{ + "rules": { + "no-console": "off", + "indent": [ "error", 2 ], + "quotes": [ "error", "single" ], + "semi": ["error", "always"], + "linebreak-style": [ "error", "unix" ] + }, + "env": { + "es6": true, + "node": true, + "mocha": true, + "jasmine": true + }, + "ecmaFeatures": { + "modules": true, + "experimentalObjectRestSpread": true, + "impliedStrict": true + }, + "extends": "eslint:recommended" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..345130c --- /dev/null +++ b/.gitignore @@ -0,0 +1,136 @@ +# Created by https://www.gitignore.io/api/osx,vim,node,macos,windows + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + + +### OSX ### + +# Icon must end with two \r + +# Thumbnails + +# Files that might appear in the root of a volume + +# Directories potentially created on remote AFP share + +### Vim ### +# swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/osx,vim,node,macos,windows diff --git a/README.md b/README.md index d3d8a98..8186c39 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,6 @@ Your lab directory must include ## Bonus * **2pts:** add the ability to change the cowfile - **ex: dragon, sheep, etc** _(note: this should be done through the querystring)_ + +## Questions and Observations +###### I wish these functions had better error handling, it took me forever to finish the assignment because of one error that I could not figure out because of bad error handling. Other than that the assignment was a breeze, even the extra credit. diff --git a/lib/body-parser-helper.js b/lib/body-parser-helper.js new file mode 100644 index 0000000..db97036 --- /dev/null +++ b/lib/body-parser-helper.js @@ -0,0 +1,22 @@ +'use strict'; + +const bodyParser = module.exports = (request, callback) => { + // initalizing the body property + request.body = ''; + // looking for data keyword and finding it's contents + request.on('data', (data) => { + // adding each piece of data to the body property + request.body += data.toString(); + }); + request.on('end', () => { + // once request has finished it will try to parse the body property to make it's properties acessible + try{ + request.body = JSON.parse(request.body); + // finishing callback loop + callback(null, request.body); + } catch(err){ + // if there is a err returning an err + callback(err); + } + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..bf38edd --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "07-http_servers", + "version": "1.0.0", + "description": "![cf](https://i.imgur.com/7v5ASc8.png) Lab 07: Vanilla HTTP Server ======", + "main": "server.js", + "scripts": { + "test": "chai", + "start": "node server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/loganabsher/07-http_servers.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/loganabsher/07-http_servers/issues" + }, + "homepage": "https://github.com/loganabsher/07-http_servers#readme", + "dependencies": { + "cowsay": "^1.1.9" + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..b1a9ee0 --- /dev/null +++ b/server.js @@ -0,0 +1,75 @@ +'use strict'; +// imported node modules +const http = require('http'); +const url = require('url'); +const querystring = require('querystring'); +const cowsay = require('cowsay'); +// imported modules +const bodyParser = require('./lib/body-parser-helper.js'); +// local host +const PORT = process.env.PORT || 3000; +// initalizing server +const server = http.createServer((request, response) => { + request.url = url.parse(request.url); + request.url.query = querystring.parse(request.url.query); + response.headers = { + 'Content-Type': 'text/plain' + }; + // NOTE: if you are going to change cows type f=="dragon" or if you are POSTing f="dragon" + // to run this simply type: http :PORT or http localhost:PORT or http GET localhost:PORT + if(request.method === 'GET' && request.url.pathname === '/'){ + response.statusCode = 200; + response.write(`Content-Type: ${response.headers['Content-Type']}\n`); + response.write(`Status: ${response.statusCode}\n`); + response.write('Hello from my server!\n'); + response.end(); + return; + } + + // to run this type: http :PORT/cowsay + if(request.method === 'GET' && request.url.pathname === '/cowsay'){ + // to have your own messsage run: http :PORT/cowsay text=="hi all!" + if(request.url.query.text){ + response.statusCode = 200; + response.write(`Status: ${response.statusCode}\n`); + response.write(cowsay.say({f: request.url.query.f, text: request.url.query.text}) + '\n'); + response.end(); + return; + } + // if no text is given it will error with this status code and messsage + else{ + response.statusCode = 400; + response.write(`Status: ${response.statusCode}\n`); + response.write(cowsay.say({f: 'dragon', text: 'Bad request'}) + '\n'); + response.end(); + return; + } + } + + // to post a message type: http POST :PORT/cowsay thing="hi all!" thing2="sup" + if(request.method === 'POST' && request.url.pathname === '/cowsay'){ + response.write(`Content-Type: ${response.headers['Content-Type']}\n`); + bodyParser(request, function(err){ + if(err){ + response.statusCode = 400; + response.write(`Status: ${response.statusCode}\n`); + response.write(cowsay.say({f: 'dragon', text: 'bad request'}) + '\n'); + response.end(); + return; + } + response.statusCode = 200; + response.write(`status: ${response.statusCode}\n`); + response.write(cowsay.say({f: request.url.query.f, text: request.body.text}) + '\n'); + response.end(); + return; + }); + } + // NOTE: for some reason the closing end() breaks the POST block. + // ending request + // response.end(); + // return; +}); +// listening on server for requests +server.listen(PORT, () => { + console.log('server up at', PORT); +});