Permalink
Fetching contributors…
Cannot retrieve contributors at this time
213 lines (189 sloc) 7.12 KB
# ***** BEGIN LICENSE BLOCK *****
# Copyright (c) 2011-2012 VMware, Inc.
#
# For the license see COPYING.
# ***** END LICENSE BLOCK *****
url = require('url')
querystring = require('querystring')
fs = require('fs')
http = require('http')
utils = require('./utils')
execute_request = (app, funs, req, res, data) ->
try
while funs.length > 0
fun = funs.shift()
req.last_fun = fun
data = app[fun](req, res, data, req.next_filter)
catch x
if typeof x is 'object' and 'status' of x
if x.status is 0
return
else if 'handle_' + x.status of app
app['handle_' + x.status](req, res, x)
else
app['handle_error'](req, res, x)
else
app['handle_error'](req, res, x)
app['log_request'](req, res, true)
fake_response = (req, res) ->
# This is quite simplistic, don't expect much.
headers = {'Connection': 'close'}
res.writeHead = (status, user_headers = {}) ->
r = []
r.push('HTTP/' + req.httpVersion + ' ' + status +
' ' + http.STATUS_CODES[status])
utils.objectExtend(headers, user_headers)
for k of headers
r.push(k + ': ' + headers[k])
r = r.concat(['', ''])
try
res.write(r.join('\r\n'))
catch x
try
res.end()
catch x
res.setHeader = (k, v) -> headers[k] = v
exports.generateHandler = (app, dispatcher) ->
return (req, res, head) ->
if typeof res.writeHead is "undefined"
fake_response(req, res)
utils.objectExtend(req, url.parse(req.url, true))
req.start_date = new Date()
found = false
allowed_methods = []
for row in dispatcher
[method, path, funs] = row
if path.constructor isnt Array
path = [path]
# path[0] must be a regexp
m = req.pathname.match(path[0])
if not m
continue
if not req.method.match(new RegExp(method))
allowed_methods.push(method)
continue
for i in [1...path.length]
req[path[i]] = m[i]
funs = funs[0..]
funs.push('log_request')
req.next_filter = (data) ->
execute_request(app, funs, req, res, data)
req.next_filter(head)
found = true
break
if not found
if allowed_methods.length isnt 0
app['handle_405'](req, res, allowed_methods)
else
app['handle_404'](req, res)
app['log_request'](req, res, true)
return
exports.GenericApp = class GenericApp
handle_404: (req, res, x) ->
if res.finished
return x
res.writeHead(404, {})
res.end()
return true
handle_405:(req, res, methods) ->
res.writeHead(405, {'Allow': methods.join(', ')})
res.end()
return true
handle_error: (req, res, x) ->
# console.log('handle_error', x.stack)
if res.finished
return x
if typeof x is 'object' and 'status' of x
res.writeHead(x.status, {})
res.end((x.message or ""))
else
try
res.writeHead(500, {})
res.end("500 - Internal Server Error")
catch x
@log('error', 'Exception on "'+ req.method + ' ' + req.href + '" in filter "' + req.last_fun + '":\n' + (x.stack || x))
return true
log_request: (req, res, data) ->
td = (new Date()) - req.start_date
@log('info', req.method + ' ' + req.url + ' ' + td + 'ms ' +
(if res.finished then res.statusCode else '(unfinished)'))
return data
log: (severity, line) ->
console.log(line)
expose_html: (req, res, content) ->
if res.finished
return content
if not res.getHeader('Content-Type')
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
return @expose(req, res, content)
expose_json: (req, res, content) ->
if res.finished
return content
if not res.getHeader('Content-Type')
res.setHeader('Content-Type', 'application/json')
return @expose(req, res, JSON.stringify(content))
expose: (req, res, content) ->
if res.finished
return content
if content and not res.getHeader('Content-Type')
res.setHeader('Content-Type', 'text/plain')
if content
res.setHeader('Content-Length', content.length)
res.writeHead(res.statusCode)
res.end(content, 'utf8')
return true
serve_file: (req, res, filename, next_filter) ->
a = (error, content) ->
if error
res.writeHead(500)
res.end("can't read file")
else
res.setHeader('Content-length', content.length)
res.writeHead(res.statusCode, res.headers)
res.end(content, 'utf8')
next_filter(true)
fs.readFile(filename, a)
throw {status:0}
cache_for: (req, res, content) ->
res.cache_for = res.cache_for or 365 * 24 * 60 * 60 # one year.
# See: http://code.google.com/speed/page-speed/docs/caching.html
res.setHeader('Cache-Control', 'public, max-age=' + res.cache_for)
exp = new Date()
exp.setTime(exp.getTime() + res.cache_for * 1000)
res.setHeader('Expires', exp.toGMTString())
return content
h_no_cache: (req, res, content) ->
res.setHeader('Cache-Control', 'no-store, no-cache, no-transform, must-revalidate, max-age=0')
return content
expect_form: (req, res, _data, next_filter) ->
data = new Buffer(0)
req.on 'data', (d) =>
data = utils.buffer_concat(data, new Buffer(d, 'binary'))
req.on 'end', =>
data = data.toString('utf-8')
switch (req.headers['content-type'] or '').split(';')[0]
when 'application/x-www-form-urlencoded'
q = querystring.parse(data)
when 'text/plain', ''
q = data
else
@log('error', "Unsupported content-type " +
req.headers['content-type'])
q = undefined
next_filter(q)
throw {status:0}
expect_xhr: (req, res, _data, next_filter) ->
data = new Buffer(0)
req.on 'data', (d) =>
data = utils.buffer_concat(data, new Buffer(d, 'binary'))
req.on 'end', =>
data = data.toString('utf-8')
switch (req.headers['content-type'] or '').split(';')[0]
when 'text/plain', 'T', 'application/json', 'application/xml', '', 'text/xml'
q = data
else
@log('error', 'Unsupported content-type ' +
req.headers['content-type'])
q = undefined
next_filter(q)
throw {status:0}