Skip to content

Commit

Permalink
Merge pull request #4 from koajs/strict-first-last
Browse files Browse the repository at this point in the history
Make strict to array item and add first and last mode for strict string item
  • Loading branch information
dead-horse committed Feb 28, 2015
2 parents 37a5b66 + 0c35b41 commit 515784b
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 24 deletions.
36 changes: 35 additions & 1 deletion README.md
Expand Up @@ -54,12 +54,46 @@ If you want to use this mode, don't use this module.

## `strict` mode

This mode make `this.query.foo` return strict `string`. Disable multi values.
This mode make `this.query.foo` return strict `array`.

```js
require('koa-qs')(app, 'strict')
```

#### What's different

A normal request `GET /foo?p=a&q=foo&q=bar`.

- before patch

```js
console.log('%j', this.query);
{
"p": "a",
"q": ["foo", "bar"]
}
```

- after patch

```js
console.log('%j', this.query);
{
"p": ["a"],
"q": ["foo", "bar"]
}
```

## `first` mode

This mode make `this.query.foo` return strict `string`. Disable multi values.

If querystring contains multi same name params, return the **first** item.

```js
require('koa-qs')(app, 'first')
```

In 95% use cases, application only want `string` query params.

This patch can avoid some stupid `TypeError` and some security issues like [MongoDB inject](http://www.wooyun.org/bugs/wooyun-2010-086474)
Expand Down
24 changes: 18 additions & 6 deletions index.js
Expand Up @@ -6,6 +6,22 @@ module.exports = function (app, mode) {
if (mode === 'extended') {
qs = require('qs');
}
var converter = null;
if (mode === 'strict') {
converter = function (value) {
if (!Array.isArray(value)) {
return [value];
}
return value;
};
} else if (mode === 'first') {
converter = function (value) {
if (Array.isArray(value)) {
return value[0];
}
return value;
};
}

merge(app.request, {

Expand All @@ -24,13 +40,9 @@ module.exports = function (app, mode) {
var query = c[str];
if (!query) {
c[str] = query = qs.parse(str);
if (mode === 'strict') {
// return string params only, disable multi values
if (converter) {
for (var key in query) {
var value = query[key];
if (Array.isArray(value)) {
query[key] = value[0];
}
query[key] = converter(query[key]);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -17,7 +17,7 @@
"devDependencies": {
"istanbul-harmony": "*",
"koa": "0",
"mocha": "1",
"mocha": "2",
"should": "3",
"supertest": "0",
"urllib": "2"
Expand Down
59 changes: 43 additions & 16 deletions test/test.js
Expand Up @@ -39,11 +39,11 @@ describe('Koa Querystring', function () {
.expect(204, done)
})

describe('strict mode', function () {
describe('strict mode: array item', function () {
var app = qs(koa(), 'strict')

app.use(function* () {
this.body = [this.query, this.query]
this.body = this.query;
})

var host
Expand All @@ -54,25 +54,19 @@ describe('Koa Querystring', function () {
})
})

it('should return the first query params string', function (done) {
it('should return the query params array', function (done) {
urllib.request(host + '/foo?p=a,b&p=b,c&empty=&empty=&empty=&n=1&n=2&n=1&ok=true', {
dataType: 'json'
}, function (err, body, res) {
res.statusCode.should.equal(200)
body.should.eql([
{
p: 'a,b',
empty: '',
n: '1',
ok: 'true'
},
body.should.eql(
{
p: 'a,b',
empty: '',
n: '1',
ok: 'true'
p: ['a,b', 'b,c'],
empty: ['', '', ''],
n: ['1', '2', '1'],
ok: ['true']
}
])
)
done(err)
})
})
Expand All @@ -82,7 +76,40 @@ describe('Koa Querystring', function () {
dataType: 'json'
}, function (err, body, res) {
res.statusCode.should.equal(200)
body.should.eql([{}, {}])
body.should.eql({})
done(err)
})
})
})

describe('first mode: first string item', function () {
var app = qs(koa(), 'first')

app.use(function* () {
this.body = this.query;
})

var host
before(function (done) {
app.listen(0, function () {
host = 'http://localhost:' + this.address().port
done()
})
})

it('should return the first query params string', function (done) {
urllib.request(host + '/foo?p=a,b&p=b,c&empty=&empty=&empty=&n=1&n=2&n=1&ok=true', {
dataType: 'json'
}, function (err, body, res) {
res.statusCode.should.equal(200)
body.should.eql(
{
p: 'a,b',
empty: '',
n: '1',
ok: 'true'
}
)
done(err)
})
})
Expand Down

0 comments on commit 515784b

Please sign in to comment.