Comparar commits

...

21 Commits

Autor SHA1 Mensagem Data
Roman Shtylman b0da4b1a94 streaming view rendering
Allows for a view engine to return a stream upon being asked to render a
path. This allows for the engine to simply stream out data as it is
loaded from disk (or other IO location) without having to collect it all
first and then send it.

Fallback mode for all existing engines that call `fn` upon completion
takes over if no stream is returned. This works for both app.render and
res.render
2013-11-09 21:27:01 -05:00
Jonathan Ong 2bc703cfc2 Merge pull request #1802 from kapouer/patch-1
Remove leading ./ when using res.location('./relative')
2013-11-02 15:09:30 -07:00
Jérémy Lal c9865b821d Test location with leading ./ and containing .. 2013-11-02 02:28:54 +01:00
Jérémy Lal 9c0de23645 Update tests expectancy of location headers 2013-11-02 02:28:49 +01:00
Jérémy Lal b7a38af41d Use url.resolve to compute location header of relative paths 2013-11-02 02:28:29 +01:00
Jérémy Lal 661914781e semicolons 2013-11-02 00:39:32 +01:00
Jonathan Ong 6e3f3887e9 pin deps using semver1
somebody is going to complain that they can't install stuff because
they haven't upgraded npm
2013-10-30 20:55:11 -07:00
Jonathan Ong a66d6bb034 pin dev deps to semver compatible versions 2013-10-30 20:51:10 -07:00
Jonathan Ong 2e197e2b98 be less picky with ENOENT errors in tests
closes #1580
2013-10-30 20:37:01 -07:00
Jonathan Ong 55d1a4f964 always send ETag when content-length > 0
closes #1780
2013-10-30 20:34:16 -07:00
Jonathan Ong 82a7d7a977 no semver2 so travis stops crying 2013-10-29 22:44:01 -07:00
Jonathan Ong dae54b456f 3.4.4 2013-10-29 10:33:32 -07:00
Jonathan Ong 1b7a044f33 bump connect 2013-10-29 10:30:26 -07:00
Jonathan Ong 18264403b1 bump supertest to 0.8.1 2013-10-28 15:24:48 -07:00
Jonathan Ong 04d43b7039 remove .gitmodules
it's empty
2013-10-28 14:38:46 -07:00
TJ Holowaychuk 2dfecfb661 update methods for SEARCH 2013-10-28 12:02:24 -07:00
Jonathan Ong 250f1f5f6e Merge pull request #1796 from malixsys/patch-1
2013-100-23 -> 2013-10-23
2013-10-25 10:59:48 -07:00
M Alix 3ac718763f 2013-100-23 -> 2013-10-23 2013-10-25 14:28:24 +02:00
Jonathan Ong 05e1555c0d Merge pull request #1795 from chirag04/master
replace bodyparser with json and urlencoded
2013-10-25 03:31:24 -07:00
chirag04 855d1e2bf5 replace bodyparser with json and urlencoded 2013-10-25 15:45:25 +05:30
Jonathan Ong f0bfb3b2b2 3.4.3 2013-10-23 11:19:48 -07:00
14 arquivos alterados com 183 adições e 35 exclusões
Ver Arquivo
+1 -1
Ver Arquivo
@@ -1,4 +1,4 @@
language: node_js
node_js:
- "0.8"
- "0.10"
- "0.10"
+15
Ver Arquivo
@@ -1,10 +1,25 @@
3.4.4 / 2013-10-29
==================
* update connect
* update supertest
* update methods
* express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04
3.4.3 / 2013-10-23
==================
* update connect
3.4.2 / 2013-10-18
==================
* update connect
* downgrade commander
3.4.1 / 2013-10-15
==================
* update connect
* update commander
* jsonp: check if callback is a function
+2 -1
Ver Arquivo
@@ -222,7 +222,8 @@ var app = [
, 'app.set(\'view engine\', \':TEMPLATE\');'
, 'app.use(express.favicon());'
, 'app.use(express.logger(\'dev\'));'
, 'app.use(express.bodyParser());'
, 'app.use(express.json());'
, 'app.use(express.urlencoded());'
, 'app.use(express.methodOverride());{sess}'
, 'app.use(app.router);{css}'
, 'app.use(express.static(path.join(__dirname, \'public\')));'
+20 -1
Ver Arquivo
@@ -501,7 +501,26 @@ app.render = function(name, options, fn){
// render
try {
view.render(opts, fn);
var view_stream = view.render(opts, fn);
// if the engine returned a stream AND user specified a function
// then we will capture data for user
if (view_stream && fn) {
var body = '';
view_stream.on('data', function(chunk) {
body += chunk;
});
view_stream.once('error', function(err) {
fn(err);
});
view_stream.once('end', function() {
fn(null, body);
});
}
return view_stream;
} catch (err) {
fn(err);
}
+48 -10
Ver Arquivo
@@ -14,6 +14,7 @@ var http = require('http')
, cookie = require('cookie')
, send = require('send')
, mime = connect.mime
, resolve = require('url').resolve
, basename = path.basename
, extname = path.extname;
@@ -132,7 +133,7 @@ res.send = function(body){
// ETag support
// TODO: W/ support
if (app.settings.etag && len > 1024 && 'GET' == req.method) {
if (app.settings.etag && len && 'GET' == req.method) {
if (!this.get('ETag')) {
this.set('ETag', etag(body));
}
@@ -633,7 +634,8 @@ res.cookie = function(name, val, options){
res.location = function(url){
var app = this.app
, req = this.req;
, req = this.req
, path;
// setup redirect map
var map = { back: req.get('Referrer') || '/' };
@@ -643,12 +645,11 @@ res.location = function(url){
// relative
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
var path
// relative to path
if ('.' == url[0]) {
path = req.originalUrl.split('?')[0]
url = path + ('/' == path[path.length - 1] ? '' : '/') + url;
path = req.originalUrl.split('?')[0];
path = path + ('/' == path[path.length - 1] ? '' : '/');
url = resolve(path, url);
// relative to mount-point
} else if ('/' != url[0]) {
path = app.path();
@@ -791,12 +792,49 @@ res.render = function(view, options, fn){
// merge res.locals
options._locals = self.locals;
// default callback to respond
fn = fn || function(err, str){
// support for non streaming view rendering
// if renderer uses streams, this will not be called
// see below for how streams are handled
var respond = fn || function(err, str){
if (view_stream) return;
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, options, fn);
var view_stream = app.render(view, options, respond);
// old style, will have already called respond for us
if (!view_stream) {
return;
}
// user wants to handle sending themselves
if (fn) {
var body = '';
view_stream.on('data', function(chunk) {
body += chunk;
});
view_stream.once('error', function(err) {
fn(err);
});
view_stream.once('end', function() {
fn(null, body);
});
return;
}
// set response headers
self.statusCode = 200;
if (!self.get('Content-Type')) {
self.charset = self.charset || 'utf-8';
self.type('html');
}
self.setHeader('Transfer-Encoding', 'chunked');
// start streaming the response
view_stream.pipe(self);
};
+1 -1
Ver Arquivo
@@ -73,5 +73,5 @@ View.prototype.lookup = function(path){
*/
View.prototype.render = function(options, fn){
this.engine(this.path, options, fn);
return this.engine(this.path, options, fn);
};
+13 -13
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.4.2",
"version": "3.4.4",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
{
@@ -22,28 +22,28 @@
}
],
"dependencies": {
"connect": "2.9.2",
"connect": "2.11.0",
"commander": "1.3.2",
"range-parser": "0.0.4",
"mkdirp": "0.3.5",
"cookie": "0.1.0",
"buffer-crc32": "0.2.1",
"fresh": "0.2.0",
"methods": "0.0.1",
"methods": "0.1.0",
"send": "0.1.4",
"cookie-signature": "1.0.1",
"debug": "*"
"debug": ">= 0.7.3 < 1"
},
"devDependencies": {
"ejs": "*",
"mocha": "*",
"ejs": ">= 0.8.4 < 1",
"mocha": ">= 1.13.0 < 2",
"jade": "0.30.0",
"hjs": "*",
"stylus": "*",
"should": "2",
"connect-redis": "*",
"marked": "*",
"supertest": "0.6.0"
"hjs": ">= 0.0.6 < 1",
"stylus": ">= 0.39.1 < 1",
"should": ">= 2.0.2 < 3",
"connect-redis": ">= 1.4.5 < 2",
"marked": ">= 0.2.9 < 1",
"supertest": ">= 0.8.1 < 1"
},
"keywords": [
"express",
@@ -66,6 +66,6 @@
"test": "make test"
},
"engines": {
"node": "*"
"node": ">= 0.8.0"
}
}
+42
Ver Arquivo
@@ -1,5 +1,6 @@
var express = require('../')
, request = require('./support/http')
, fs = require('fs');
function render(path, options, fn) {
@@ -10,6 +11,10 @@ function render(path, options, fn) {
});
}
function streaming_render(path, options, fn) {
return fs.createReadStream(path, { encoding: 'utf-8' });
}
describe('app', function(){
describe('.engine(ext, fn)', function(){
it('should map a template engine', function(done){
@@ -76,5 +81,42 @@ describe('app', function(){
done();
})
})
it('should support streaming engines', function(done) {
var app = express();
app.set('views', __dirname + '/fixtures');
app.engine('.html', streaming_render);
app.set('view engine', '.html');
app.locals.user = { name: 'tobi' };
// using function should just call the function when done
app.render('user', function(err, str){
if (err) return done(err);
str.should.equal('<p>{{user.name}}</p>');
done();
})
});
it('should render a response using the streaming engine', function(done) {
var app = express();
app.set('views', __dirname + '/fixtures');
app.engine('.html', streaming_render);
app.set('view engine', '.html');
app.locals.user = { name: 'tobi' };
app.get('/', function(req, res) {
res.render('user');
});
request(app)
.get('/')
.expect(200)
.end(function(err, res) {
if (err) return done(err);
res.header['transfer-encoding'].should.equal('chunked');
res.text.should.equal('<p>{{user.name}}</p>');
done();
});
});
})
})
+1
Ver Arquivo
@@ -29,6 +29,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Accept-Encoding', '')
.expect(200, done);
})
})
+19 -2
Ver Arquivo
@@ -64,7 +64,7 @@ describe('res', function(){
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/1/./edit');
res.headers.should.have.property('location', '/post/1/edit');
done();
})
})
@@ -81,7 +81,24 @@ describe('res', function(){
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/1/../new');
res.headers.should.have.property('location', '/post/new');
done();
})
})
})
describe('with leading ./ and containing ..', function(){
it('should construct path-relative urls', function(done){
var app = express();
app.use(function(req, res){
res.location('./skip/../../new').end();
});
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/new');
done();
})
})
+5 -5
Ver Arquivo
@@ -210,17 +210,17 @@ describe('res', function(){
request(root)
.get('/depth1')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/./index');
res.headers.should.have.property('location', '/depth1/index');
request(root)
.get('/depth1/depth2')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/depth2/./index');
res.headers.should.have.property('location', '/depth1/depth2/index');
request(root)
.get('/depth1/depth2/depth3')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/depth2/depth3/./index');
res.headers.should.have.property('location', '/depth1/depth2/depth3/index');
done();
})
})
@@ -231,11 +231,11 @@ describe('res', function(){
request(root)
.get('/depth2')
.end(function(err, res){
res.headers.should.have.property('location', '/depth2/./index');
res.headers.should.have.property('location', '/depth2/index');
request(root)
.get('/depth3')
.end(function(err, res){
res.headers.should.have.property('location', '/depth3/./index');
res.headers.should.have.property('location', '/depth3/index');
done();
})
})
+15
Ver Arquivo
@@ -321,6 +321,21 @@ describe('res', function(){
describe('"etag" setting', function(){
describe('when enabled', function(){
it('should send ETag even when content-length < 1024', function(done){
var app = express();
app.use(function(req, res){
res.send('kajdslfkasdf');
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('etag');
done();
});
})
it('should send ETag ', function(done){
var app = express();
+1 -1
Ver Arquivo
@@ -51,7 +51,7 @@ describe('res', function(){
.get('/')
.end(function(err, res){
assert(1 == calls, 'called too many times');
res.text.should.equal("ENOENT, stat 'test/fixtures/nope.html'");
res.text.should.startWith("ENOENT, stat");
res.statusCode.should.equal(200);
done();
});