Comparar commits
45 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| db2eb658ca | |||
| 70483484ce | |||
| d21afc43a1 | |||
| 7ad0803f2e | |||
| ec4bfd55f9 | |||
| f65174a0db | |||
| 8b1fcd4dd7 | |||
| 9509237958 | |||
| f20fd20a06 | |||
| 8e48120fb7 | |||
| 44cc5ac883 | |||
| 9a43cc8c4b | |||
| 8dfc0d54f4 | |||
| 77febd21de | |||
| 84a997c66b | |||
| b900a59fc2 | |||
| ca782dbc58 | |||
| 746cda27ec | |||
| 16d1651656 | |||
| 4735fb2377 | |||
| ec6b518fd2 | |||
| 580ad1b192 | |||
| 23d8810486 | |||
| d579d62eb6 | |||
| 529f785e3c | |||
| 0581ae87b4 | |||
| cda1059336 | |||
| 1aed6b5c30 | |||
| 4e68705b24 | |||
| 216cb1ea12 | |||
| 8ef6a0b432 | |||
| 5dc152c46e | |||
| c3a21437e4 | |||
| 32bc8dcbf9 | |||
| 677ca7b4aa | |||
| dfc2331104 | |||
| cd06bbfb8d | |||
| 1d596bcbac | |||
| 0cb7b9c13d | |||
| a180efeca7 | |||
| eef24ea29c | |||
| 458bb3d7f7 | |||
| ffb23d92c0 | |||
| b0884ad7c3 | |||
| cf09f86df2 |
@@ -1,4 +1,26 @@
|
||||
|
||||
0.13.0 / 2010-06-01
|
||||
==================
|
||||
|
||||
* Added node v0.1.97 compatibility
|
||||
* Added support for deleting cookies via Request#cookie('key', null)
|
||||
* Updated haml submodule
|
||||
* Fixed not-found page, now using using charset utf-8
|
||||
* Fixed show-exceptions page, now using using charset utf-8
|
||||
* Fixed view support due to fs.readFile Buffers
|
||||
* Changed; mime.type() no longer accepts ".type" due to node extname() changes
|
||||
|
||||
0.12.0 / 2010-05-22
|
||||
==================
|
||||
|
||||
* Added node v0.1.96 compatibility
|
||||
* Added view `helpers` export which act as additional local variables
|
||||
* Updated haml submodule
|
||||
* Changed ETag; removed inode, modified time only
|
||||
* Fixed LF to CRLF for setting multiple cookies
|
||||
* Fixed cookie complation; values are now urlencoded
|
||||
* Fixed cookies parsing; accepts quoted values and url escaped cookies
|
||||
|
||||
0.11.0 / 2010-05-06
|
||||
==================
|
||||
|
||||
|
||||
+2
-1
@@ -25,6 +25,7 @@
|
||||
* Route passing
|
||||
* View support (ejs, haml, sass, etc)
|
||||
* View partials
|
||||
* View globals/helpers support
|
||||
* Full test coverage
|
||||
* Logger plugin with several formats
|
||||
* Upload size restrictions
|
||||
@@ -86,7 +87,7 @@ Run individual suites:
|
||||
...
|
||||
|
||||
The latest release of Express is compatible with node --version:
|
||||
v0.1.94
|
||||
v0.1.97
|
||||
|
||||
With _EDGE_ Express we do our best to keep up to date with node's _EDGE_
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
.images
|
||||
- each img in images
|
||||
%img{ src: img }
|
||||
|
||||
%h2 Singles
|
||||
%form{ method: 'post', enctype: 'multipart/form-data' }
|
||||
%input{ type: 'file', name: 'images[0]' }
|
||||
@@ -10,7 +9,7 @@
|
||||
%input{ type: 'file', name: 'images[2]' }
|
||||
%div.panel
|
||||
%input{ type: 'submit', value: 'Upload' }
|
||||
|
||||
|
||||
%h2 Multiple
|
||||
%form{ method: 'post', enctype: 'multipart/form-data' }
|
||||
%input{ type: 'file', name: 'images[]', multiple: 'multiple' }
|
||||
|
||||
@@ -209,7 +209,7 @@ Server = new Class({
|
||||
var server = http
|
||||
.createServer(function(req, response){
|
||||
var request, pendingFiles = 0
|
||||
req.setBodyEncoding('binary')
|
||||
req.setEncoding('binary')
|
||||
request = new Request(req, response)
|
||||
request.body = ''
|
||||
function callback(err) {
|
||||
@@ -291,7 +291,7 @@ Server = new Class({
|
||||
// --- Express
|
||||
|
||||
Express = {
|
||||
version: '0.11.0',
|
||||
version: '0.13.0',
|
||||
config: [],
|
||||
routes: [],
|
||||
plugins: [],
|
||||
|
||||
@@ -352,7 +352,6 @@ exports.types = {
|
||||
*
|
||||
* var mime = require('express/mime')
|
||||
* mime.type('png') // => 'image/png'
|
||||
* mime.type('.png') // => 'image/png'
|
||||
* mime.type('image.png') // => 'image/png'
|
||||
* mime.type('path/to/image.png') // => 'image/png'
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
var style = require('express/pages/style').style
|
||||
|
||||
exports.render = function(request) {
|
||||
request.charset = 'UTF-8'
|
||||
request.contentType('html')
|
||||
var method = request.method.toLowerCase(),
|
||||
path = request.url.pathname || '/'
|
||||
|
||||
@@ -79,6 +79,7 @@ function hashText(hash) {
|
||||
}
|
||||
|
||||
exports.render = function(request, e) {
|
||||
request.charset = 'UTF-8'
|
||||
request.contentType('html')
|
||||
return '<html> \n\
|
||||
<head> \n\
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Request = require('express/request').Request
|
||||
var Request = require('express/request').Request,
|
||||
queryString = require('querystring')
|
||||
|
||||
/**
|
||||
* Parse an HTTP _cookie_ string into a hash.
|
||||
@@ -16,10 +17,18 @@ var Request = require('express/request').Request
|
||||
*/
|
||||
|
||||
exports.parseCookie = function(cookie) {
|
||||
return cookie.replace(/^ *| *$/g, '').split(/ *; */).reduce(function(hash, pair){
|
||||
var parts = pair.split(/ *= */)
|
||||
hash[parts[0]] = parts[1]
|
||||
return hash
|
||||
return cookie.split(/[;,] */).reduce(function(cookies, pair) {
|
||||
var eql = pair.indexOf('=')
|
||||
if (eql === -1) return cookies
|
||||
var key = queryString.unescape(pair.slice(0, eql).trim(), true)
|
||||
var val = queryString.unescape(pair.slice(eql + 1).trim(), true)
|
||||
var captures = val.match(/^("|')([^\1]*)\1$/)
|
||||
if (captures) val = captures[2].replace('\\' + captures[1], captures[1])
|
||||
//RFC2109 states the most specific path will be
|
||||
//listed first
|
||||
if (cookies[key] === undefined)
|
||||
cookies[key] = val
|
||||
return cookies
|
||||
}, {})
|
||||
}
|
||||
|
||||
@@ -36,7 +45,7 @@ exports.parseCookie = function(cookie) {
|
||||
exports.compileCookie = function(name, val, options) {
|
||||
if (!options) return name + '=' + val
|
||||
var val,
|
||||
buf = [name + '=' + val],
|
||||
buf = [queryString.escape(name) + '=' + queryString.escape(val)],
|
||||
keys = Object.keys(options)
|
||||
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||
val = options[keys[i]]
|
||||
@@ -62,7 +71,8 @@ exports.Cookie = Plugin.extend({
|
||||
Request.include({
|
||||
|
||||
/**
|
||||
* Get or set cookie values.
|
||||
* Get or set cookie values. To delete a cookie
|
||||
* simply pass a null _val_.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
@@ -85,10 +95,13 @@ exports.Cookie = Plugin.extend({
|
||||
cookie: function(name, val, options) {
|
||||
options = options || {}
|
||||
options.path = options.path || '/'
|
||||
return val ?
|
||||
this.response.cookies.push(exports.compileCookie(name, val, options)) :
|
||||
this.cookies[name]
|
||||
}
|
||||
if (null === val)
|
||||
val = "delete",
|
||||
options.expires = new Date(10000000)
|
||||
return val
|
||||
? this.response.cookies.push(exports.compileCookie(name, val, options))
|
||||
: this.cookies[name]
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -115,7 +128,7 @@ exports.Cookie = Plugin.extend({
|
||||
response: function(event) {
|
||||
if (event.response.cookies &&
|
||||
event.response.cookies.length)
|
||||
event.request.header('Set-Cookie', event.response.cookies.join('\nSet-Cookie: '))
|
||||
event.request.header('Set-Cookie', event.response.cookies.join('\r\nSet-Cookie: '))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -62,7 +62,7 @@ exports.Static = Plugin.extend({
|
||||
return 'errno' in err && err.errno === 2
|
||||
? self.notFound()
|
||||
: self.error(err, callback)
|
||||
var etag = stat.ino + '-' + stat.size + '-' + Number(stat.mtime)
|
||||
var etag = Number(stat.mtime)
|
||||
if (self.header('If-None-Match') &&
|
||||
self.header('If-None-Match') == etag)
|
||||
return self.respond(304, null)
|
||||
|
||||
@@ -19,7 +19,14 @@ var engines = {}
|
||||
* View cache.
|
||||
*/
|
||||
|
||||
var cache = { views: {}, partials: {}}
|
||||
var cache = { views: {}, partials: {} }
|
||||
|
||||
|
||||
/**
|
||||
* View helpers (merged with locals).
|
||||
*/
|
||||
|
||||
var helpers = exports.helpers = {}
|
||||
|
||||
/**
|
||||
* Cache view files where _type_ is
|
||||
@@ -35,7 +42,7 @@ function cacheFiles(type) {
|
||||
fs.readdirSync(dir).each(function(file){
|
||||
file = dir + '/' + file
|
||||
if (!fs.statSync(file).isFile()) return
|
||||
cache[type][file] = fs.readFileSync(file)
|
||||
cache[type][file] = fs.readFileSync(file).toString('utf8')
|
||||
})
|
||||
} catch (e) {
|
||||
if (e.errno !== process.ENOENT) throw e
|
||||
@@ -153,10 +160,12 @@ exports.View = Plugin.extend({
|
||||
layout = options.layout === undefined
|
||||
? 'layout'
|
||||
: options.layout
|
||||
options.locals = options.locals || {}
|
||||
Object.merge(options.locals, helpers)
|
||||
options.filename = path
|
||||
if (set('cache view contents'))
|
||||
options.cache = true
|
||||
var content = cache[type][path] || fs.readFileSync(path)
|
||||
var content = cache[type][path] || fs.readFileSync(path).toString(options.encoding || 'utf8')
|
||||
options.context = options.context || this
|
||||
content = (engines[engine] = engines[engine] || require(engine)).render(content, options)
|
||||
if (type === 'views') this.contentType(contentType)
|
||||
@@ -178,5 +187,4 @@ exports.View = Plugin.extend({
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
@@ -193,7 +193,9 @@ exports.Request = new Class({
|
||||
if (encoding instanceof Function)
|
||||
callback = encoding,
|
||||
encoding = null
|
||||
if (body !== null)
|
||||
if (204 === code)
|
||||
body = null
|
||||
else if (body !== null)
|
||||
body = body || statusBodies[code]
|
||||
if (encoding === 'utf8' ||
|
||||
encoding === 'utf-8')
|
||||
|
||||
+1
-1
Submodule lib/support/haml updated: 1dfd334372...6644f8429d
+3
-3
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "Express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "0.11.0",
|
||||
"version": "0.13.0",
|
||||
"keywords": ["framework", "sinatra", "web", "rest", "restful"],
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
"lib": "./lib"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "git submodule update --init",
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": { "node": ">= 0.1.93" }
|
||||
"engines": { "node": ">= 0.1.97" }
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
---
|
||||
name: Express
|
||||
description: Sinatra inspired web development framework
|
||||
version: 0.11.0
|
||||
version: 0.12.0
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Testing
|
||||
externo
+1
@@ -0,0 +1 @@
|
||||
%span= _('Hello world')
|
||||
+1
@@ -0,0 +1 @@
|
||||
%span= _(body)
|
||||
+17
-13
@@ -4,7 +4,7 @@
|
||||
;(function(){
|
||||
|
||||
JSpec = {
|
||||
version : '4.2.1',
|
||||
version : '4.3.2',
|
||||
assert : true,
|
||||
cache : {},
|
||||
suites : [],
|
||||
@@ -1749,10 +1749,14 @@
|
||||
|
||||
// --- Node.js support
|
||||
|
||||
if (typeof GLOBAL === 'object' && typeof exports === 'object')
|
||||
quit = process.exit,
|
||||
print = require('sys').puts,
|
||||
readFile = require('fs').readFileSync
|
||||
if (typeof GLOBAL === 'object' && typeof exports === 'object') {
|
||||
var fs = require('fs')
|
||||
quit = process.exit
|
||||
print = require('sys').puts
|
||||
readFile = function(file){
|
||||
return fs.readFileSync(file).toString('utf8')
|
||||
}
|
||||
}
|
||||
|
||||
// --- Utility functions
|
||||
|
||||
@@ -1872,17 +1876,17 @@
|
||||
},
|
||||
|
||||
have_prop : function(actual, property, value) {
|
||||
return actual[property] === undefined ||
|
||||
actual[property] instanceof Function ? false:
|
||||
value === undefined ? true:
|
||||
does(actual[property], 'eql', value)
|
||||
var actualVal = actual[property], actualType = typeof actualVal
|
||||
return (actualType == 'function' || actualType == 'undefined') ? false :
|
||||
typeof value === 'undefined' ||
|
||||
does(actual[property],'eql',value)
|
||||
},
|
||||
|
||||
have_property : function(actual, property, value) {
|
||||
return actual[property] === undefined ||
|
||||
actual[property] instanceof Function ? false:
|
||||
value === undefined ? true:
|
||||
value === actual[property]
|
||||
var actualVal = actual[property], actualType = typeof actualVal
|
||||
return (actualType == 'function' || actualType == 'undefined') ? false :
|
||||
typeof value === 'undefined' ||
|
||||
value === actualVal
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
*/
|
||||
|
||||
getAllResponseHeaders : function(){
|
||||
return this.responseHeaders
|
||||
return JSpec.inject(this.responseHeaders, '', function(buf, key, val){
|
||||
return buf + key + ': ' + val + '\r\n'
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,10 +4,6 @@ require("jspec")
|
||||
require("express")
|
||||
require("express/spec")
|
||||
|
||||
print = require('sys').puts
|
||||
quit = process.exit
|
||||
readFile = require('fs').readFileSync
|
||||
|
||||
function run(specs) {
|
||||
specs.forEach(function(spec){
|
||||
JSpec.exec('spec/spec.' + spec + '.js')
|
||||
|
||||
@@ -10,12 +10,6 @@ describe 'Express'
|
||||
|
||||
describe 'mime'
|
||||
describe 'type()'
|
||||
describe 'when given an extension with leading dot'
|
||||
it 'should return the associated mime type'
|
||||
mime.type('.png').should.eql 'image/png'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when given an extension without leading dot'
|
||||
it 'should return the associated mime type'
|
||||
mime.type('png').should.eql 'image/png'
|
||||
|
||||
@@ -55,6 +55,21 @@ describe 'Express'
|
||||
var attrs = ' SID = 1232431234234 ; data = foo'
|
||||
parseCookie(attrs).should.eql { SID: '1232431234234', data: 'foo' }
|
||||
end
|
||||
|
||||
it 'should support complex quoted values'
|
||||
var attrs = 'SID="123456789"; fbs_0011223355="uid=0987654321&name=Test+User"'
|
||||
parseCookie(attrs).should.eql { SID: '123456789', fbs_0011223355: 'uid=0987654321&name=Test User' }
|
||||
end
|
||||
|
||||
it 'should not override when a duplicate key is found'
|
||||
var attrs = 'SID=1234; SID=9999'
|
||||
parseCookie(attrs).should.eql { SID: '1234' }
|
||||
end
|
||||
|
||||
it 'should support malformed cookies'
|
||||
var attrs = 'SID'
|
||||
parseCookie(attrs).should.eql {}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'on'
|
||||
@@ -82,7 +97,25 @@ describe 'Express'
|
||||
this.cookie('foo', 'bar')
|
||||
return ''
|
||||
})
|
||||
get('/user').headers['Set-Cookie'].should.eql 'SID=732423sdfs73243; path=/; secure\nSet-Cookie: foo=bar; path=/'
|
||||
get('/user').headers['Set-Cookie'].should.eql 'SID=732423sdfs73243; path=/; secure\r\nSet-Cookie: foo=bar; path=/'
|
||||
end
|
||||
|
||||
it 'should delete the cookie'
|
||||
get('/user', function(){
|
||||
this.cookie('ninja', null)
|
||||
this.cookie('pirate', null)
|
||||
return ''
|
||||
})
|
||||
get('/user').headers['Set-Cookie'].should.eql 'ninja=delete; path=/; expires=Thu, 01 Jan 1970 02:46:40 GMT\r\nSet-Cookie: pirate=delete; path=/; expires=Thu, 01 Jan 1970 02:46:40 GMT'
|
||||
end
|
||||
|
||||
it 'should support URL unfriendly characters'
|
||||
get('/user', function(){
|
||||
this.cookie('spaceship', '<*==*>', { path: '/', secure: true })
|
||||
this.cookie(':)', 'smileyface')
|
||||
return ''
|
||||
})
|
||||
get('/user').headers['Set-Cookie'].should.eql 'spaceship=%3C*%3D%3D*%3E; path=/; secure\r\nSet-Cookie: %3A)=smileyface; path=/'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -92,9 +125,9 @@ describe 'Express'
|
||||
get('/user', function(){
|
||||
return this.cookie('foo')
|
||||
})
|
||||
get('/user', { headers: { cookie: 'foo=bar' }}).body.should.eql 'bar'
|
||||
get('/user', { headers: { cookie: 'foo=bar%3D%3D' }}).body.should.eql 'bar=='
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
ejs = require('ejs')
|
||||
helpers = require('express/plugins/view').helpers
|
||||
|
||||
describe 'Express'
|
||||
before_each
|
||||
@@ -178,7 +179,7 @@ describe 'Express'
|
||||
get('/', function(){
|
||||
this.render('hello.html.haml', { layout: 'front' })
|
||||
})
|
||||
-{ get('/') }.should.throw_error 'ENOENT, No such file or directory'
|
||||
-{ get('/') }.should.throw_error "ENOENT, No such file or directory 'spec/fixtures/front.html.haml'"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -213,6 +214,27 @@ describe 'Express'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when a global is set'
|
||||
it 'should include the helper and translate the text in the view'
|
||||
helpers._ = function(text){
|
||||
if (text == 'Hello world') return 'Hola mundo'
|
||||
}
|
||||
get('/', function(){
|
||||
this.render('helpers.html.haml', { layout: false })
|
||||
})
|
||||
get('/').body.should.include 'Hola mundo'
|
||||
end
|
||||
it 'should include the helper and translate the text in the layout'
|
||||
helpers._ = function(text){
|
||||
if (text == 'Testing') return 'Probando'
|
||||
}
|
||||
get('/', function(){
|
||||
this.render('helpers-layout.html.haml', { layout: 'layout-helper' })
|
||||
})
|
||||
get('/').body.should.include 'Probando'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when engine cannot be found'
|
||||
it 'should throw an error'
|
||||
get('/', function(){
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário