Comparar commits
76 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| d893009a8d | |||
| b62e1741be | |||
| 903c2aa642 | |||
| d0a8bb550e | |||
| f96f1423e1 | |||
| 7bf17f2f61 | |||
| 670b6cfc15 | |||
| b6d2c8479c | |||
| 5aaa114271 | |||
| e99c2791bb | |||
| 656d7754cd | |||
| 4aaf10fbfc | |||
| 85e77b77aa | |||
| f23ef09247 | |||
| 440d956438 | |||
| acd2852cf3 | |||
| 4246f43bdf | |||
| 7d33769cd2 | |||
| 31fdba80d4 | |||
| 77f8e460d0 | |||
| 51e51db9f7 | |||
| 73c506f19c | |||
| 79143f3334 | |||
| 128ba9040e | |||
| 300cfe74ad | |||
| f008af05bd | |||
| 3aa870d6bd | |||
| 25e1a8c001 | |||
| 0ba3b114b0 | |||
| c429e88e8e | |||
| c7a2fe8440 | |||
| de237e760b | |||
| 927f5c9883 | |||
| 88f461baf2 | |||
| 3251ae26a0 | |||
| e84c81633e | |||
| a2ec966ac7 | |||
| 69660fbfda | |||
| dcedca1a80 | |||
| 6455e954fc | |||
| 646904688f | |||
| 62779fc972 | |||
| fdee4cde26 | |||
| 0c18ac5adc | |||
| 6da4a942ca | |||
| 565f68d2d7 | |||
| a7cee4c889 | |||
| 4f315f9b11 | |||
| 51febfec2d | |||
| df8bd96b2e | |||
| 9da9beb342 | |||
| f93af823df | |||
| 5e74723a92 | |||
| ec77e1acea | |||
| 1afad64972 | |||
| a3365dda07 | |||
| 4c246a4cd1 | |||
| 934ffd0731 | |||
| 790e2c233d | |||
| 9e9967381c | |||
| 891ed08827 | |||
| 55d13a6f08 | |||
| 5569ea4397 | |||
| 693e37459a | |||
| 90de1fa55d | |||
| 6d6e1557ce | |||
| 2d84f16dc0 | |||
| 2f98ef9f6d | |||
| e0c07d2385 | |||
| 0b2413d8c0 | |||
| e92b01f813 | |||
| 27ff13459f | |||
| 3e80915454 | |||
| 4063d2e2c4 | |||
| ce9416857b | |||
| 575d5e8e57 |
@@ -1 +1,3 @@
|
||||
.DS_Store
|
||||
*.seed
|
||||
*.log
|
||||
+8
-8
@@ -1,12 +1,12 @@
|
||||
[submodule "lib/support/haml"]
|
||||
path = lib/support/haml
|
||||
url = git://github.com/creationix/haml-js.git
|
||||
[submodule "lib/support/js-oo"]
|
||||
path = lib/support/js-oo
|
||||
[submodule "lib/support/oo"]
|
||||
path = lib/support/oo
|
||||
url = git://github.com/visionmedia/js-oo.git
|
||||
[submodule "lib/support/sass"]
|
||||
path = lib/support/sass
|
||||
url = git://github.com/visionmedia/sass.js.git
|
||||
[submodule "lib/support/ext"]
|
||||
path = lib/support/ext
|
||||
url = git://github.com/visionmedia/ext.js.git
|
||||
[submodule "lib/support/sass"]
|
||||
path = lib/support/sass
|
||||
url = git://github.com/visionmedia/sass.js.git
|
||||
[submodule "lib/support/haml"]
|
||||
path = lib/support/haml
|
||||
url = git://github.com/creationix/haml-js.git
|
||||
|
||||
@@ -1,4 +1,46 @@
|
||||
|
||||
0.7.3 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Added package.json
|
||||
* Fixed requiring of haml / sass due to kiwi removal
|
||||
|
||||
0.7.2 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Fixed GIT submodules (HAH!)
|
||||
|
||||
0.7.1 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Changed; Express now using submodules again until a PM is adopted
|
||||
* Changed; chat example using millisecond conversions from ext
|
||||
|
||||
0.7.0 / 2010-03-15
|
||||
==================
|
||||
|
||||
* Added Request#pass() support (finds the next matching route, or the given path)
|
||||
* Added Logger plugin (default "common" format replaces CommonLogger)
|
||||
* Removed Profiler plugin
|
||||
* Removed CommonLogger plugin
|
||||
|
||||
0.6.0 / 2010-03-11
|
||||
==================
|
||||
|
||||
* Added seed.yml for kiwi package management support
|
||||
* Added HTTP client query string support when method is GET. Closes #205
|
||||
|
||||
* Added support for arbitrary view engines.
|
||||
For example "foo.engine.html" will now require('engine'),
|
||||
the exports from this module are cached after the first require().
|
||||
|
||||
* Added async plugin support
|
||||
|
||||
* Removed usage of RESTful route funcs as http client
|
||||
get() etc, use http.get() and friends
|
||||
|
||||
* Removed custom exceptions
|
||||
|
||||
0.5.0 / 2010-03-10
|
||||
==================
|
||||
|
||||
|
||||
+1
-4
@@ -3,9 +3,6 @@ NODE = node
|
||||
|
||||
all: test
|
||||
|
||||
init:
|
||||
@git submodule init && git submodule update
|
||||
|
||||
test:
|
||||
@$(NODE) spec/node.js all
|
||||
|
||||
@@ -17,4 +14,4 @@ app-chat:
|
||||
app-upload:
|
||||
@$(NODE) examples/upload/app.js
|
||||
|
||||
.PHONY: init test app
|
||||
.PHONY: test app
|
||||
+19
-28
@@ -24,14 +24,16 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Currently Express must be cloned (or downloaded), you can use the following command to
|
||||
get rolling and initialize the submodule dependencies:
|
||||
Install the [Kiwi package manager for nodejs](http://github.com/visionmedia/kiwi)
|
||||
and run:
|
||||
|
||||
$ kiwi -v install express
|
||||
|
||||
or
|
||||
|
||||
$ git clone git://github.com/visionmedia/express.git && cd express && git submodule update --init && make app
|
||||
|
||||
Or with the [gh](http://github.com/visionmedia/gh) utility:
|
||||
|
||||
$ gh clone visionmedia express && cd express && git submodule update --init && make app
|
||||
Install via git clone:
|
||||
|
||||
$ git://github.com/visionmedia/express.git && cd express && git submodule update --init
|
||||
|
||||
## Performance
|
||||
|
||||
@@ -42,41 +44,31 @@ Or with the [gh](http://github.com/visionmedia/gh) utility:
|
||||
|
||||
## Examples
|
||||
|
||||
Below is a minimal app example when express is already within your load path.
|
||||
Below is a tiny Express application. View the [Wiki](http://wiki.github.com/visionmedia/express/) for detailed information.
|
||||
|
||||
require.paths.unshift('express/lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
set('root', __dirname)
|
||||
get('/user', function(){
|
||||
this.redirect('/user/' + this.currentUser.id)
|
||||
})
|
||||
|
||||
get('/hello', function(){
|
||||
this.contentType('html')
|
||||
return '<h1>World<h1>'
|
||||
})
|
||||
|
||||
get('/user/:id?', function(id) {
|
||||
get('/user/:id', function(id){
|
||||
this.render('user.haml.html', {
|
||||
locals: {
|
||||
name: id ? 'User ' + id : 'You'
|
||||
user: this.currentUser,
|
||||
usersOnline: Session.store.length()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
run()
|
||||
|
||||
## Running Tests
|
||||
|
||||
First we need to ensure all submodules are updated:
|
||||
|
||||
$ make init
|
||||
|
||||
Express uses the [JSpec](http://jspec.info) BDD JavaScript testing
|
||||
framework to write and run elegant spec suites. JSpec is frozen
|
||||
to spec/lib and does not require separate installation.
|
||||
to spec/lib and **does not** require separate installation.
|
||||
|
||||
$ make test
|
||||
|
||||
@@ -88,13 +80,12 @@ Run individual suites:
|
||||
...
|
||||
|
||||
Express is currently being developed with node --version:
|
||||
v0.1.31
|
||||
v0.1.32
|
||||
|
||||
## More Information
|
||||
|
||||
* [JavaScript Extensions & Utilities](http://github.com/visionmedia/ext.js)
|
||||
* [JavaScript Sass](http://github.com/visionmedia/sass.js)
|
||||
* [Scons Build System](http://www.scons.org/) (some development dependencies rely on this, ex libxmljs)
|
||||
* Featured in [Advanced JavaScript e-book](http://www.dev-mag.com/2010/02/18/advanced-javascript/) for only $4
|
||||
|
||||
## Contributors
|
||||
|
||||
+11
-13
@@ -3,23 +3,21 @@ require.paths.unshift('lib')
|
||||
require('express')
|
||||
require('express/plugins')
|
||||
|
||||
configure(function(){
|
||||
var fiveMinutes = 300000,
|
||||
oneMinute = 60000
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(CommonLogger)
|
||||
use(Cookie)
|
||||
use(Cache, { lifetime: fiveMinutes, reapInterval: oneMinute })
|
||||
use(Session, { lifetime: fiveMinutes, reapInterval: oneMinute })
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
var messages = [],
|
||||
utils = require('express/utils')
|
||||
|
||||
configure(function(){
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(Cookie)
|
||||
use(Cache, { lifetime: (5).minutes, reapInterval: (1).minute })
|
||||
use(Session, { lifetime: (15).minutes, reapInterval: (1).minute })
|
||||
use(Logger)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
get('/', function(){
|
||||
this.redirect('/chat')
|
||||
this.pass('/chat')
|
||||
})
|
||||
|
||||
get('/chat', function(){
|
||||
|
||||
@@ -6,10 +6,10 @@ require('express/plugins')
|
||||
configure(function(){
|
||||
use(MethodOverride)
|
||||
use(ContentLength)
|
||||
use(CommonLogger)
|
||||
use(Cookie)
|
||||
use(Session)
|
||||
use(Flash)
|
||||
use(Logger)
|
||||
set('root', __dirname)
|
||||
})
|
||||
|
||||
|
||||
+2
-4
@@ -1,9 +1,7 @@
|
||||
|
||||
require.paths.unshift(__dirname + '/support/js-oo/lib')
|
||||
require.paths.unshift(__dirname + '/support/ejs/lib')
|
||||
require.paths.unshift(__dirname + '/support/ext/lib')
|
||||
require.paths.unshift(__dirname + '/support/haml/lib')
|
||||
require.paths.unshift(__dirname + '/support/sass/lib')
|
||||
require.paths.unshift(__dirname + '/support/ext/lib')
|
||||
require('oo')
|
||||
require('ext')
|
||||
require('support/oo/lib/oo')
|
||||
require('express/core')
|
||||
+37
-26
@@ -11,7 +11,6 @@ var multipart = require('multipart'),
|
||||
fs = require('fs')
|
||||
|
||||
global.merge(require('sys'))
|
||||
global.merge(require('express/exceptions'))
|
||||
global.merge(require('express/event'))
|
||||
global.merge(require('express/request'))
|
||||
global.merge(require('express/plugin'))
|
||||
@@ -68,16 +67,16 @@ Route = Class({
|
||||
|
||||
normalize: function(path) {
|
||||
var self = this
|
||||
this.params = []
|
||||
this.keys = []
|
||||
if (path instanceof RegExp) return path
|
||||
return new RegExp('^' + RegExp.escape(normalizePath(path), '.')
|
||||
.replace(/\*/g, '(.+)')
|
||||
.replace(/(\/|\\\.):(\w+)\?/g, function(_, c, key){
|
||||
self.params.push(key)
|
||||
self.keys.push(key)
|
||||
return '(?:' + c + '([^\/]+))?'
|
||||
})
|
||||
.replace(/:(\w+)/g, function(_, key){
|
||||
self.params.push(key)
|
||||
self.keys.push(key)
|
||||
return '([^\/]+)'
|
||||
}) + '$', 'i')
|
||||
}
|
||||
@@ -105,10 +104,19 @@ Router = Class({
|
||||
* @api private
|
||||
*/
|
||||
|
||||
route: function(){
|
||||
var route = this.matchingRoute()
|
||||
if (route)
|
||||
return route.fn.apply(this.request, this.request.captures.slice(1))
|
||||
route: function() {
|
||||
var body,
|
||||
route = this.matchingRoute()
|
||||
if (route) {
|
||||
body = route.fn.apply(this.request, this.request.captures.slice(1));
|
||||
if (this.request.passed) {
|
||||
if (typeof this.request.passed === 'string')
|
||||
this.request.url.pathname = this.request.passed
|
||||
this.request.passed = false
|
||||
return this.route()
|
||||
}
|
||||
return body
|
||||
}
|
||||
else if (this.request.accepts('html') && set('helpful 404'))
|
||||
this.request.halt(404, require('express/pages/not-found').render(this.request))
|
||||
else
|
||||
@@ -122,10 +130,13 @@ Router = Class({
|
||||
* @api private
|
||||
*/
|
||||
|
||||
matchingRoute: function(){
|
||||
return Express.routes.find(function(route){
|
||||
return this.match(route)
|
||||
}, this)
|
||||
matchingRoute: function() {
|
||||
this.lastMatchingRoute = this.lastMatchingRoute || 0
|
||||
var routes = Express.routes, route
|
||||
while (route = routes[this.lastMatchingRoute++])
|
||||
if (this.match(route))
|
||||
break
|
||||
return route
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -154,7 +165,7 @@ Router = Class({
|
||||
*/
|
||||
|
||||
mapParams: function(route) {
|
||||
route.params.each(function(key, i){
|
||||
route.keys.each(function(key, i){
|
||||
this.request.params.path[key] = this.request.captures[++i]
|
||||
}, this)
|
||||
}
|
||||
@@ -264,16 +275,18 @@ Server = Class({
|
||||
*/
|
||||
|
||||
route: function(request, response){
|
||||
request = new Request(request, response)
|
||||
request.trigger('request')
|
||||
if (request.response.finished) return
|
||||
try {
|
||||
if (typeof (body = (new Router(request)).route()) == 'string')
|
||||
request.halt(200, body)
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e, request)
|
||||
}
|
||||
var self = this,
|
||||
request = new Request(request, response)
|
||||
request.trigger('request', function(e) {
|
||||
try {
|
||||
if (e) throw e
|
||||
if (request.response.finished) return
|
||||
if (typeof (body = (new Router(request)).route()) === 'string')
|
||||
request.halt(200, body)
|
||||
} catch (e) {
|
||||
self.error(e, request)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -286,8 +299,6 @@ Server = Class({
|
||||
*/
|
||||
|
||||
error: function (e, request, response) {
|
||||
if (e instanceof ExpressError)
|
||||
throw e
|
||||
if (!(request instanceof Request))
|
||||
request = new Request(request, response),
|
||||
request.trigger('request')
|
||||
@@ -303,7 +314,7 @@ Server = Class({
|
||||
// --- Express
|
||||
|
||||
Express = {
|
||||
version: '0.5.0',
|
||||
version: '0.7.3',
|
||||
config: [],
|
||||
routes: [],
|
||||
plugins: [],
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
|
||||
// Express - DSL - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('express/http')
|
||||
|
||||
/**
|
||||
* Return a routing function for _method_.
|
||||
*
|
||||
@@ -19,9 +13,7 @@ function route(method) {
|
||||
return function(path, options, fn){
|
||||
if (options instanceof Function)
|
||||
fn = options, options = {}
|
||||
if (path.startsWith('http://'))
|
||||
return http[method].apply(this, arguments)
|
||||
else if (!Express.server.running)
|
||||
if (!Express.server.running)
|
||||
Express.routes.push(new Route(method, path, fn, options))
|
||||
else
|
||||
throw new Error('cannot create route ' + method.toUpperCase() + " `" + path + "' at runtime")
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
// Express - Exceptions - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
// --- ExpressError
|
||||
|
||||
ExpressError = Class({
|
||||
name: 'ExpressError',
|
||||
init: function(message) {
|
||||
this.message = message
|
||||
},
|
||||
toString: function() {
|
||||
return this.name + ': ' + this.message
|
||||
}
|
||||
})
|
||||
@@ -30,18 +30,22 @@ function request(method, url, data, headers, fn, redirects) {
|
||||
search = url.search || '',
|
||||
hash = url.hash || '',
|
||||
port = url.port || 80,
|
||||
headers = utils.mixin(headers, { host: url.hostname }),
|
||||
headers = { host: url.hostname }.merge(headers || {}),
|
||||
client = http.createClient(port, url.hostname)
|
||||
if (headers.redirect)
|
||||
redirects = headers.redirect,
|
||||
delete headers.redirect
|
||||
if (data) {
|
||||
data = queryString.stringify(data)
|
||||
headers['content-length'] = data.length
|
||||
headers['content-type'] = 'application/x-www-form-urlencoded'
|
||||
if (method === 'GET')
|
||||
search += (search ? '&' : '?') + data
|
||||
else
|
||||
headers['content-length'] = data.length,
|
||||
headers['content-type'] = 'application/x-www-form-urlencoded'
|
||||
}
|
||||
|
||||
var req = client.request(method, path + search + hash, headers)
|
||||
if (data) req.write(data)
|
||||
if (data && method !== 'GET') req.write(data)
|
||||
req.addListener('response', function(res){
|
||||
if (req.statusCode < 200 || req.statusCode >= 400)
|
||||
fn(new Error('request failed with status ' + res.statusCode + ' "' + http.STATUS_CODES[res.statusCode] + '"'))
|
||||
|
||||
@@ -62,15 +62,15 @@ exports.render = function(request, e) {
|
||||
</table> \n\
|
||||
<h3>Params</h3> \n\
|
||||
<table id="route-params"> \n\
|
||||
' + hash(request.params) + ' \n\
|
||||
' + hash(request.params.path) + ' \n\
|
||||
</table> \n\
|
||||
<h3>GET</h3> \n\
|
||||
<table id="get-params"> \n\
|
||||
' + hash(request.url.params) + ' \n\
|
||||
' + hash(request.params.get) + ' \n\
|
||||
</table> \n\
|
||||
<h3>POST</h3> \n\
|
||||
<table id="post-params"> \n\
|
||||
' + hash(request.url.post) + ' \n\
|
||||
' + hash(request.params.post) + ' \n\
|
||||
</table> \n\
|
||||
</div> \n\
|
||||
</body> \n\
|
||||
|
||||
@@ -53,9 +53,9 @@ exports.Plugin = Class({
|
||||
* @api private
|
||||
*/
|
||||
|
||||
trigger: function(event) {
|
||||
trigger: function(event, callback) {
|
||||
if ('on' in this)
|
||||
if (event.name in this.on)
|
||||
this.on[event.name].call(this, event)
|
||||
return this.on[event.name].call(this, event, callback)
|
||||
}
|
||||
})
|
||||
@@ -1,13 +1,11 @@
|
||||
|
||||
// Express - Plugins - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var utils = require('express/utils')
|
||||
utils.mixin(require('express/plugins/hooks'))
|
||||
utils.mixin(require('express/plugins/flash'))
|
||||
utils.mixin(require('express/plugins/cache'))
|
||||
utils.mixin(require('express/plugins/cookie'))
|
||||
utils.mixin(require('express/plugins/session'))
|
||||
utils.mixin(require('express/plugins/profiler'))
|
||||
utils.mixin(require('express/plugins/common-logger'))
|
||||
utils.mixin(require('express/plugins/content-length'))
|
||||
utils.mixin(require('express/plugins/method-override'))
|
||||
global.merge(require('express/plugins/hooks'))
|
||||
global.merge(require('express/plugins/flash'))
|
||||
global.merge(require('express/plugins/cache'))
|
||||
global.merge(require('express/plugins/cookie'))
|
||||
global.merge(require('express/plugins/session'))
|
||||
global.merge(require('express/plugins/logger'))
|
||||
global.merge(require('express/plugins/content-length'))
|
||||
global.merge(require('express/plugins/method-override'))
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
// Express - CommonLogger - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Months.
|
||||
*/
|
||||
|
||||
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
||||
/**
|
||||
* Format _date_.
|
||||
*
|
||||
* @param {Date} date
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function format(date) {
|
||||
var d = date.getDate(),
|
||||
m = months[date.getMonth()],
|
||||
y = date.getFullYear(),
|
||||
h = date.getHours(),
|
||||
mi = date.getMinutes(),
|
||||
s = date.getSeconds()
|
||||
return (d < 10 ? '0' : '') + d + '/' + m + '/' + y + ' ' +
|
||||
(h < 10 ? '0' : '') + h + ':' + (mi < 10 ? '0' : '') +
|
||||
mi + ':' + (s < 10 ? '0' : '') + s
|
||||
}
|
||||
|
||||
// --- CommonLogger
|
||||
|
||||
exports.CommonLogger = Plugin.extend({
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Output log data.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
puts([event.request.connection.remoteAddress,
|
||||
'-',
|
||||
'-',
|
||||
'[' + format(new Date) + ']',
|
||||
'"' + event.request.method.toUpperCase() + ' ' + (event.request.url.pathname || '/') +
|
||||
' HTTP/' + event.request.httpVersion + '"',
|
||||
event.request.response.status,
|
||||
event.request.response.headers['content-length'] || 0].join(' '))
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
// Express - Logger - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var sys = require('sys')
|
||||
|
||||
/**
|
||||
* Log formats
|
||||
*/
|
||||
|
||||
var formats = {
|
||||
common: function(event, start) {
|
||||
printf('%s - - [%s] "%s %s HTTP/%d" %s %d %0.3f',
|
||||
event.request.connection.remoteAddress,
|
||||
(new Date).format('%d/%b/%Y %H:%M:%S'),
|
||||
event.request.method.uppercase,
|
||||
event.request.url.pathname || '/',
|
||||
event.request.httpVersion,
|
||||
event.request.response.status,
|
||||
event.request.response.headers['content-length'] || 0,
|
||||
(Number(new Date) - start) / 1000)
|
||||
},
|
||||
combined: function(event, start) {
|
||||
formats.common(event, start)
|
||||
printf('"%s" "%s"',
|
||||
event.request.headers['referrer'] || event.request.headers['referer'] || '-',
|
||||
event.request.headers['user-agent'])
|
||||
},
|
||||
plot: function(event, start) {
|
||||
sys.print(Number(new Date) - start)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Logger
|
||||
|
||||
exports.Logger = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize logger options.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - format
|
||||
* 'common' outputs log in CommonLog format (DEFAULT)
|
||||
* 'combined' outputs log in Apache Combined format
|
||||
* 'plot' outputs request duration in milliseconds only
|
||||
*
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(options) {
|
||||
this.merge(options || {})
|
||||
}
|
||||
},
|
||||
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Start timer.
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
this.start = Number(new Date)
|
||||
},
|
||||
|
||||
/**
|
||||
* Output log data.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
formats[exports.Logger.format || 'common'](event, this.start)
|
||||
sys.print('\n')
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
// Express - Profiler - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var n = 0
|
||||
|
||||
exports.Profiler = Plugin.extend({
|
||||
extend: {
|
||||
|
||||
/**
|
||||
* Initialize profiler options.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - format 'plot' outputs request duration in milliseconds only
|
||||
*
|
||||
* @param {hash} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
init: function(options) {
|
||||
this.merge(options || {})
|
||||
}
|
||||
},
|
||||
|
||||
// --- Events
|
||||
|
||||
on: {
|
||||
|
||||
/**
|
||||
* Start timer.
|
||||
*/
|
||||
|
||||
request: function(event) {
|
||||
this.start = Number(new Date)
|
||||
},
|
||||
|
||||
/**
|
||||
* Output duration.
|
||||
*/
|
||||
|
||||
response: function(event) {
|
||||
if (exports.Profiler.format === 'plot')
|
||||
puts(Number(new Date) - this.start)
|
||||
else
|
||||
puts(event.request.method + ' ' +
|
||||
event.request.url.pathname + ': ' +
|
||||
(Number(new Date) - this.start) + ' ms' +
|
||||
' #' + ++n)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -168,12 +168,9 @@ exports.Session = Plugin.extend({
|
||||
*/
|
||||
|
||||
startReaper: function() {
|
||||
var self = this,
|
||||
oneDay = 86400000,
|
||||
oneHour = 3600000
|
||||
setInterval(function(){
|
||||
self.store.reap(self.lifetime || oneDay)
|
||||
}, self.reapInterval || self.reapEvery || oneHour)
|
||||
this.store.reap(this.lifetime || (1).day)
|
||||
}, this.reapInterval || this.reapEvery || (1).hour, this)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -10,14 +10,10 @@ var utils = require('express/utils'),
|
||||
fs = require('fs')
|
||||
|
||||
/**
|
||||
* Supported template engines.
|
||||
* Cache supported template engine exports.
|
||||
*/
|
||||
|
||||
var engine = {
|
||||
ejs: require('ejs'),
|
||||
haml: require('haml'),
|
||||
sass: require('sass')
|
||||
}
|
||||
var engines = {}
|
||||
|
||||
// --- View
|
||||
|
||||
@@ -73,7 +69,7 @@ exports.View = Plugin.extend({
|
||||
options.context = options.context || this
|
||||
self.contentType(ext)
|
||||
function render(content) {
|
||||
content = engine[type].render(content, options)
|
||||
content = (engines[type] = engines[type] || require(type)).render(content, options)
|
||||
if (layout)
|
||||
self.render(layout + '.' + type + ext, utils.mixin(true, options, {
|
||||
layout: false,
|
||||
|
||||
+54
-40
@@ -12,24 +12,6 @@ var StaticFile = require('express/static').File,
|
||||
utils = require('express/utils'),
|
||||
url = require('url')
|
||||
|
||||
// --- InvalidStatusCode
|
||||
|
||||
InvalidStatusCode = ExpressError.extend({
|
||||
name: 'InvalidStatusCode',
|
||||
init: function(status) {
|
||||
this.message = status + ' is an invalid HTTP response code'
|
||||
}
|
||||
})
|
||||
|
||||
// --- InvalidResponseBody
|
||||
|
||||
InvalidResponseBody = ExpressError.extend({
|
||||
name: 'InvalidResponseBody',
|
||||
init: function(request) {
|
||||
this.message = request.method + ' ' + JSON.encode(request.url.pathname) + ' did not respond with a body string'
|
||||
}
|
||||
})
|
||||
|
||||
// --- Helpers
|
||||
|
||||
/**
|
||||
@@ -89,9 +71,9 @@ exports.Request = Class({
|
||||
*/
|
||||
|
||||
header: function(key, val) {
|
||||
return val === undefined ?
|
||||
this.headers[key.toLowerCase()] :
|
||||
this.response.headers[key.toLowerCase()] = val
|
||||
return val === undefined
|
||||
? this.headers[key.toLowerCase()]
|
||||
: this.response.headers[key.toLowerCase()] = val
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -161,9 +143,6 @@ exports.Request = Class({
|
||||
* default to the default body associated with the response
|
||||
* _code_.
|
||||
*
|
||||
* When an invalid status _code_ is passed, InvalidStatusCode
|
||||
* will be thrown.
|
||||
*
|
||||
* @param {int} code
|
||||
* @param {string} body
|
||||
* @param {string} encoding
|
||||
@@ -171,11 +150,10 @@ exports.Request = Class({
|
||||
* @api public
|
||||
*/
|
||||
|
||||
halt: function(code, body, encoding) {
|
||||
halt: function(code, body, encoding, callback) {
|
||||
this.status(code = code || 404)
|
||||
if (body = body || statusBodies[code])
|
||||
return this.respond(body, encoding)
|
||||
throw new InvalidStatusCode(code)
|
||||
return this.respond(body, encoding, callback)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -187,14 +165,33 @@ exports.Request = Class({
|
||||
* @api private
|
||||
*/
|
||||
|
||||
respond: function(body, encoding) {
|
||||
respond: function(body, encoding, callback) {
|
||||
var self = this
|
||||
this.response.body = body
|
||||
this.trigger('response')
|
||||
if (typeof this.response.body != 'string') throw new InvalidResponseBody(this)
|
||||
if (typeof this.response.status != 'number') throw new InvalidStatusCode(this.response.status)
|
||||
this.response.writeHeader(this.response.status, this.response.headers)
|
||||
this.response.write(this.response.body, encoding)
|
||||
this.response.close()
|
||||
this.trigger('response', function(e) {
|
||||
if (e)
|
||||
if (callback !== undefined) callback(e)
|
||||
else throw e
|
||||
self.response.writeHeader(self.response.status, self.response.headers)
|
||||
self.response.write(self.response.body, encoding)
|
||||
self.response.close()
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Pass control to the next matching route, or
|
||||
* the given _path_.
|
||||
*
|
||||
* NOTE: _path_ may be the request pathname only,
|
||||
* and may not contain a query string etc.
|
||||
*
|
||||
* @param {string} path
|
||||
* @api public
|
||||
*/
|
||||
|
||||
pass: function(path) {
|
||||
this.passed = path || true
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -212,20 +209,37 @@ exports.Request = Class({
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger even _name_ with optional _data_.
|
||||
* Trigger event _name_ with optional _data_ and _callback_ function.
|
||||
* The _callback_ function may be the second or third argument.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {hash} data
|
||||
* @param {object} data
|
||||
* @param {function} callback
|
||||
* @return {Request}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
trigger: function(name, data) {
|
||||
trigger: function(name, data, callback) {
|
||||
if (data instanceof Function)
|
||||
callback = data,
|
||||
data = null
|
||||
data = data || {}
|
||||
data.merge({ request: this, response: this.response })
|
||||
this.plugins.each(function(plugin){
|
||||
plugin.trigger(new Event(name, data))
|
||||
})
|
||||
var self = this,
|
||||
complete = 0,
|
||||
total = this.plugins.length
|
||||
;(function next(e) {
|
||||
if (e || complete === total)
|
||||
callback(e)
|
||||
else {
|
||||
try {
|
||||
if (self.plugins.at(complete++).trigger(new Event(name, data), next) !== true)
|
||||
next()
|
||||
} catch(e) {
|
||||
next(e)
|
||||
}
|
||||
}
|
||||
})()
|
||||
return this
|
||||
},
|
||||
|
||||
|
||||
+6
-10
@@ -1,18 +1,13 @@
|
||||
|
||||
// Express - Static - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs')
|
||||
|
||||
// --- InvalidPathError
|
||||
|
||||
InvalidPathError = ExpressError.extend({
|
||||
name: 'InvalidPathError',
|
||||
init: function(path) {
|
||||
this.message = "`" + path + "' is not a valid path"
|
||||
}
|
||||
})
|
||||
|
||||
// --- File
|
||||
|
||||
exports.File = Class({
|
||||
@@ -26,7 +21,8 @@ exports.File = Class({
|
||||
|
||||
init: function(path) {
|
||||
this.path = path
|
||||
if (path.indexOf('..') != -1) throw new InvalidPathError(path)
|
||||
if (path.indexOf('..') != -1)
|
||||
Error.raise('InvalidPathError', "`" + path + "' is not a valid path")
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/* Ejs template parser for CommonJS
|
||||
*
|
||||
* Copyright (c) 2009, Howard Rauscher
|
||||
* Licensed under the MIT License
|
||||
*
|
||||
* base on:
|
||||
* Simple JavaScript Templating (http://ejohn.org/blog/javascript-micro-templating/)
|
||||
* John Resig - http://ejohn.org/ - MIT Licensed
|
||||
*/
|
||||
|
||||
(function(){
|
||||
var cache = {};
|
||||
|
||||
var ejs = this.ejs = {};
|
||||
|
||||
ejs.parse = function tmpl(str, options) {
|
||||
options = options || {};
|
||||
options.context = options.context || {};
|
||||
options.locals = options.locals || {};
|
||||
|
||||
// Figure out if we're getting a template, or if we need to
|
||||
// load the template - and be sure to cache the result.
|
||||
var fn = cache[str] ||
|
||||
|
||||
// Generate a reusable function that will serve as a template
|
||||
// generator (and which will be cached).
|
||||
new Function("obj",
|
||||
"var p=[];" +
|
||||
|
||||
// Introduce the data as local variables using with(){}
|
||||
"with(obj){p.push('" +
|
||||
|
||||
// Convert the template into pure JavaScript
|
||||
str
|
||||
.replace(/\-%>(\n|\r)/g, "%>")
|
||||
.replace(/[\t\b\f]/g, " ")
|
||||
.replace(/[\n\r]/g, "\f")
|
||||
.split("<%").join("\t")
|
||||
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
|
||||
.replace(/\t=(.*?)%>/g, "',$1,'")
|
||||
.split("\t").join("');")
|
||||
.split("%>").join("p.push('")
|
||||
.split("\r").join("\\'").replace(/\f+/g, '\\n') +
|
||||
"');}return p.join('');");
|
||||
|
||||
cache[str] = fn;
|
||||
|
||||
// Provide some basic currying to the user
|
||||
return fn.call(options.context, options.locals);
|
||||
};
|
||||
})();
|
||||
|
||||
exports.render = ejs.parse;
|
||||
+1
-1
Submodule lib/support/ext updated: dc9652d67f...967039b7d6
+1
-1
Submodule lib/support/haml updated: 908480ed5d...389c33c6e4
+1
-1
Submodule lib/support/sass updated: 0dd500e7cd...2a648b3766
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "Express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "0.7.3",
|
||||
"keywords": ["framework", "sinatra", "web", "rest", "restful"],
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "git submodule update --init",
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": { "node": ">= 0.1.30" }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
name: Express
|
||||
description: Sinatra inspired web development framework
|
||||
version: 0.7.3
|
||||
@@ -25,7 +25,6 @@ specs = {
|
||||
'plugins',
|
||||
'plugins.cache',
|
||||
'plugins.view',
|
||||
'plugins.common-logger',
|
||||
'plugins.content-length',
|
||||
'plugins.method-override',
|
||||
'plugins.body-decoder',
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
describe 'Express'
|
||||
before_each
|
||||
reset()
|
||||
use(require('express/plugins/common-logger').CommonLogger)
|
||||
end
|
||||
|
||||
describe 'CommonLogger'
|
||||
describe 'on'
|
||||
describe 'response'
|
||||
it 'should output in common log format'
|
||||
GLOBAL.stub('puts')
|
||||
GLOBAL.should.receive('puts')
|
||||
get('/style.css', function(){
|
||||
this.contentType('css')
|
||||
return 'body { background: #000; }'
|
||||
})
|
||||
get('/style.css')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
+28
-13
@@ -107,18 +107,6 @@ describe 'Express'
|
||||
get('/user').body.should.include('Oh noes!')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when given an invalid status code'
|
||||
it 'should throw an InvalidStatusCode exception'
|
||||
// TODO: use throw_error when fixed...
|
||||
get('/user', function(){ this.halt(123123) })
|
||||
try { get('/user') }
|
||||
catch (e) {
|
||||
e.should.be_an_instance_of ExpressError
|
||||
e.should.be_an_instance_of InvalidStatusCode
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#contentType()'
|
||||
@@ -210,6 +198,33 @@ describe 'Express'
|
||||
})
|
||||
get('/public/app.js').body.should.eql 'public, app, js'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pass()'
|
||||
it 'should pass control to the next matching route'
|
||||
get('/user', function(){
|
||||
this.pass()
|
||||
})
|
||||
get('/user', function(){
|
||||
this.pass()
|
||||
return 'nodejs'
|
||||
})
|
||||
get('/user', function(){ return 'success'})
|
||||
get('/user').body.should.eql 'success'
|
||||
end
|
||||
|
||||
describe 'given a string'
|
||||
it 'should pass to the given route'
|
||||
get('/user', function(){
|
||||
this.pass('/user/1')
|
||||
})
|
||||
get('/user/:id', function(){
|
||||
return 'Supa doopa usa'
|
||||
})
|
||||
get('/user').body.should.eql 'Supa doopa usa'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -84,19 +84,6 @@ describe 'Express'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with no response body'
|
||||
it 'should throw a InvalidResponseBody'
|
||||
// TODO: use throw_error when fixed...
|
||||
get('/user', function(){
|
||||
this.respond()
|
||||
})
|
||||
try { get('/user') }
|
||||
catch (e) {
|
||||
e.should.be_an_instance_of InvalidResponseBody
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with regular expression'
|
||||
it 'should match'
|
||||
get(/^\/user\/(\d+)\/(\w+)/, function(id, operation){
|
||||
|
||||
@@ -14,7 +14,8 @@ describe 'Express'
|
||||
// TODO: use throw_error when fixed...
|
||||
try { new StaticFile('/../foobar') }
|
||||
catch (e) {
|
||||
e.should.be_an_instance_of InvalidPathError
|
||||
e.name.should.eql 'InvalidPathError'
|
||||
e.message.should.eql "`/../foobar' is not a valid path"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário