WebFund 2016W: Assignment 3: Difference between revisions

From Soma-notes
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 type="a">
<ol style="list-style-type=lower-roman">
<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. [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?
  2. [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?
  3. [1] What is a one-line change to tinywebserver.js that would make every HTTP response have a 404 response code?
  4. [1] How you could return a 404 error to all requests from iPhones in tinywebserver.js?
  5. [6] How would the behavior of form-demo changed when you make the following changes?
    1. Delete form-demo/bin/www:7
    2. Change form-demo/bin/www:15 to be "var port=3000;".
    3. Change form-demo/app.js:13 to be "app.set('views', '.');"
    4. Delete form-demo/routes/index.js:24
    5. Delete form-demo/views/layout.jade:8
    6. 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}