WebFund 2016W: Assignment 3: Difference between revisions
Line 9: | Line 9: | ||
<li> [1] How you could return a 404 error to all requests from iPhones in tinywebserver.js? | <li> [1] How you could return a 404 error to all requests from iPhones in tinywebserver.js? | ||
<li> [6] How would the behavior of form-demo changed when you make the following changes? | <li> [6] How would the behavior of form-demo changed when you make the following changes? | ||
<ol style="list-style-type:lower- | <ol style="list-style-type:lower-alpha"> | ||
<li> Delete form-demo/bin/www:7 | <li> Delete form-demo/bin/www:7 | ||
<li> Change form-demo/bin/www:15 to be "var port=3000;". | <li> Change form-demo/bin/www:15 to be "var port=3000;". |
Revision as of 19:43, 1 February 2016
This assignment is not yet finalized (still in progress!).
Questions
- [1] In simplegrep_async.js:14, what is the type of all of the symbols referenced in the function? Specfiically, what is the type of lines, rawContents, and split?
- [1] If I create a line 24 in simplegrep_async.js that says 'console.log("finished!");', when will finished! be printed relative to the other output of the program?
- [1] What is a one-line change to tinywebserver.js that would make every HTTP response have a 404 response code?
- [1] How you could return a 404 error to all requests from iPhones in tinywebserver.js?
- [6] How would the behavior of form-demo changed when you make the following changes?
- Delete form-demo/bin/www:7
- Change form-demo/bin/www:15 to be "var port=3000;".
- Change form-demo/app.js:13 to be "app.set('views', '.');"
- Delete form-demo/routes/index.js:24
- Delete form-demo/views/layout.jade:8
- Change the indentation of form-demo/views/index.jade:24 such that it is at the same indentation as form in line 8.
Code
Full source: simplegrep_async.js, tinywebserver.js, form-demo.zip
simplegrep_async.js
var fs = require('fs');
if (process.argv.length < 4) {
console.error('Not enough parameters given. Try this: ' +
'"node simplegrep_async term filename.txt"');
process.exit(1);
}
var searchterm = process.argv[2];
var filename = process.argv[3];
var returnMatches = function(err, rawContents) {
var lines = rawContents.split('\n');
lines.forEach(function(theLine) {
if (theLine.indexOf(searchterm) > -1) {
console.log(theLine);
}
});
}
fs.readFile(filename, 'utf-8', returnMatches);
tinywebserver.js
var path = require('path');
var http = require('http');
var fs = require('fs');
var MIME_TYPES = {
'css': 'text/css',
'gif': 'image/gif',
'htm': 'text/html',
'html': 'text/html',
'ico': 'image/x-icon',
'jpeg': 'image/jpeg',
'jpg': 'image/jpeg',
'js': 'text/javascript',
'json': 'application/json',
'png': 'image/png',
'txt': 'text/text'
};
var options = {
host: 'localhost',
port: 8080,
index: 'index.html',
docroot: '.'
};
var get_mime = function(filename) {
var ext, type;
for (ext in MIME_TYPES) {
type = MIME_TYPES[ext];
if (filename.indexOf(ext, filename.length - ext.length) !== -1) {
return type;
}
}
return null;
};
var respond = function(request, response, status, content, content_type) {
if (!status) {
status = 200;
}
if (!content_type) {
content_type = 'text/plain';
}
console.log("" + status + "\t" +
request.method + "\t" + request.url);
response.writeHead(status, {
"Content-Type": content_type
});
if (content) {
response.write(content);
}
return response.end();
};
var serve_file = function(request, response, requestpath) {
return fs.readFile(requestpath, function(error, content) {
if (error != null) {
console.error("ERROR: Encountered error while processing " +
request.method + " of \"" + request.url +
"\".", error);
return respond(request, response, 500);
} else {
return respond(request, response, 200,
content, get_mime(requestpath));
}
});
};
var return_index = function(request, response, requestpath) {
var exists_callback = function(file_exists) {
if (file_exists) {
return serve_file(request, response, requestpath);
} else {
return respond(request, response, 404);
}
}
if (requestpath.substr(-1) !== '/') {
requestpath += "/";
}
requestpath += options.index;
return fs.exists(requestpath, exists_callback);
}
var request_handler = function(request, response) {
var requestpath;
if (request.url.match(/((\.|%2E|%2e)(\.|%2E|%2e))|(~|%7E|%7e)/) != null) {
console.warn("WARNING: " + request.method +
" of \"" + request.url +
"\" rejected as insecure.");
return respond(request, response, 403);
} else {
requestpath = path.normalize(path.join(options.docroot, request.url));
return fs.exists(requestpath, function(file_exists) {
if (file_exists) {
return fs.stat(requestpath, function(err, stat) {
if (err != null) {
console.error("ERROR: Encountered error calling" +
"fs.stat on \"" + requestpath +
"\" while processing " +
request.method + " of \"" +
request.url + "\".", err);
return respond(request, response, 500);
} else {
if ((stat != null) && stat.isDirectory()) {
return return_index(request, response, requestpath);
} else {
return serve_file(request, response, requestpath);
}
}
});
} else {
return respond(request, response, 404);
}
});
}
};
var server = http.createServer(request_handler);
server.listen(options.port, options.host, function() {
return console.log("Server listening at http://" +
options.host + ":" + options.port + "/");
});
form-demo/bin/www
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('form-demo:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
form-demo/app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
if (app.get('env') === 'development') {
// development error handler
// will print stacktrace
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
app.locals.pretty = true;
} else {
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
}
module.exports = app;
form-demo/routes/index.js
var express = require('express');
var router = express.Router();
var state = [];
router.get('/', function(req, res, next) {
res.render('index', { title: 'COMP 2406 Simple form demo' });
});
router.post('/add', function(req, res) {
var obj = { name: req.body.name,
city: req.body.city,
country: req.body.country,
birthday: req.body.birthday,
email: req.body.email };
state.push(obj);
res.render('add', { title: 'Person just added', item: obj });
});
router.get('/list', function(req, res) {
res.render('list', { title: 'People Listing', items: state});
});
module.exports = router;
form-demo/views/layout.jade
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
block header
body
block content
form-demo/views/index.jade
extends layout
block content
h1= title
div
p Fill out your info
form(method="post", action="/add")
div
input#name(type="text", name="name")
label Name
div
input#country(type="text", name="city")
label City
div
input#country(type="text", name="country")
label Country
div
input#birthday(type="text", name="birthday")
label Birthday
div
input#email(type="text", name="email")
label Email
button(type="submit") Submit
form-demo/views/add.jade
extends layout
block content
h1= title
p Name: #{item.name}
p City: #{item.city}
p Country: #{item.country}
p Birthday: #{item.birthday}
p Email: #{item.email}
form-demo/views/list.jade
extends layout
block content
h1= title
div
div
table
thead
th Name
th City
th Country
th Birthday
th Email
tbody
each item in items
tr
td #{item.name}
td #{item.city}
td #{item.country}
td #{item.birthday}
td #{item.email}
form(method="get", action="/")
button(type="submit") Home
form-demo/views/error.jade
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}