Skip to content

Commit 0af97fe

Browse files
authored
Merge branch 'master' into test-remove-leaky-handles
2 parents edd319e + b95dfcb commit 0af97fe

File tree

8 files changed

+1297
-917
lines changed

8 files changed

+1297
-917
lines changed

.github/workflows/node.js.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313

1414
strategy:
1515
matrix:
16-
node-version: [18.x, 20.x]
16+
node-version: [18.x, 20.x, 22.x]
1717

1818
steps:
1919
- uses: actions/checkout@v4
@@ -25,3 +25,4 @@ jobs:
2525
- run: npm run lint
2626
- run: npm test -- --coverage --maxWorkers 2
2727
- run: npx codecov
28+
continue-on-error: true

__tests__/lib/search-params.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const sp = require('../../lib/search-params')
2+
const assert = require('assert')
3+
4+
describe('search-params', () => {
5+
describe('stringify', () => {
6+
it('Should stringify a simple object', () => {
7+
assert.deepStrictEqual(sp.stringify({ a: 1, b: 'b' }), 'a=1&b=b')
8+
})
9+
10+
it('Should stringify an object with an array', () => {
11+
assert.deepStrictEqual(sp.stringify({ a: [1, 2] }), 'a=1&a=2')
12+
})
13+
14+
it('Should stringify an object with an array with a single value', () => {
15+
assert.deepStrictEqual(sp.stringify({ a: [1] }), 'a=1')
16+
})
17+
18+
it('Stringify an object with an array with a single empty value', () => {
19+
assert.deepStrictEqual(sp.stringify({ a: [''] }), 'a=')
20+
})
21+
22+
it('Should not stringify an object with a nested object', () => {
23+
assert.deepStrictEqual(sp.stringify({ a: { b: 1 } }), 'a=')
24+
})
25+
})
26+
27+
describe('parse', () => {
28+
it('Should parse a simple query string', () => {
29+
assert.deepStrictEqual(sp.parse('a=1&b=2'), { a: '1', b: '2' })
30+
})
31+
32+
it('Should parse a query string with same key and multiple values', () => {
33+
assert.deepEqual(sp.parse('a=1&a=2'), { a: ['1', '2'] })
34+
})
35+
36+
it('Should parse a query string with an array with a single empty value', () => {
37+
assert.deepStrictEqual(sp.parse('a='), { a: '' })
38+
})
39+
})
40+
})

docs/guide.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [Response Middleware](#response-middleware)
1616
- [Async operations](#async-operations)
1717
- [Debugging Koa](#debugging-koa)
18+
- [HTTP2](#http2)
1819

1920
## Writing Middleware
2021

@@ -246,3 +247,23 @@ app.use(publicFiles);
246247
```
247248
koa:application use static /public +0ms
248249
```
250+
251+
## HTTP2
252+
253+
Example of setting up an HTTP2 server with Koa using the HTTP compatibility layer:
254+
255+
```js
256+
import Koa from 'koa'
257+
import http2 from 'node:http2'
258+
import fs from 'node:fs'
259+
260+
const app = new Koa();
261+
262+
const onRequestHandler = app.callback();
263+
const serverOptions = {
264+
key: fs.readFileSync('key.pem'),
265+
cert: fs.readFileSync('cert.pem')
266+
}
267+
268+
const server = http2.createSecureServer(serverOptions, onRequestHandler);
269+
```

docs/koa-vs-express.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
| Sending Files | || |
1818
| JSONP | || |
1919

20+
> NOTE: this doesn't mean Koa is incapable of supporting these features, these features are simply supported by other modules (middleware, plugins, etc.) versus the framework itself.
2021
2122
Thus, if you'd like to be closer to Node.js and traditional Node.js-style coding, you probably want to stick to Connect/Express or similar frameworks.
2223
If you want to get rid of callbacks, use Koa.

lib/request.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ const accepts = require('accepts')
1010
const contentType = require('content-type')
1111
const stringify = require('url').format
1212
const parse = require('parseurl')
13-
const qs = require('querystring')
13+
const sp = require('./search-params.js')
14+
1415
const typeis = require('type-is')
1516
const fresh = require('fresh')
1617
const only = require('./only.js')
@@ -171,7 +172,7 @@ module.exports = {
171172
get query () {
172173
const str = this.querystring
173174
const c = this._querycache = this._querycache || {}
174-
return c[str] || (c[str] = qs.parse(str))
175+
return c[str] || (c[str] = sp.parse(str))
175176
},
176177

177178
/**
@@ -182,7 +183,7 @@ module.exports = {
182183
*/
183184

184185
set query (obj) {
185-
this.querystring = qs.stringify(obj)
186+
this.querystring = sp.stringify(obj)
186187
},
187188

188189
/**
@@ -210,7 +211,6 @@ module.exports = {
210211

211212
url.search = str
212213
url.path = null
213-
214214
this.url = stringify(url)
215215
},
216216

lib/search-params.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const URLSearchParams = require('url').URLSearchParams
2+
3+
module.exports = {
4+
stringify: (obj) => {
5+
const searchParams = new URLSearchParams()
6+
const addKey = (k, v, params) => {
7+
const val = typeof v === 'string' || typeof v === 'number' ? v : ''
8+
params.append(k, val)
9+
}
10+
11+
for (const [key, value] of Object.entries(obj)) {
12+
if (Array.isArray(value)) {
13+
const lgth = value.length
14+
for (let i = 0; i < lgth; i++) {
15+
addKey(key, value[i], searchParams)
16+
}
17+
} else {
18+
addKey(key, value, searchParams)
19+
}
20+
}
21+
return searchParams.toString()
22+
},
23+
24+
parse: (str) => {
25+
const searchParams = new URLSearchParams(str)
26+
const obj = {}
27+
for (const key of searchParams.keys()) {
28+
const values = searchParams.getAll(key)
29+
obj[key] = values.length <= 1 ? values[0] : values
30+
}
31+
return obj
32+
}
33+
}

0 commit comments

Comments
 (0)