mockaton 11.2.6 → 11.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -841
- package/index.js +1 -1
- package/package.json +7 -1
- package/src/client/app-store.test.js +81 -0
- package/src/client/app.js +21 -7
- package/src/client/styles.css +6 -2
- package/src/server/Api.js +44 -47
- package/src/server/MockDispatcher.js +3 -4
- package/src/server/Mockaton.js +11 -13
- package/src/server/Mockaton.test.js +1190 -0
- package/src/server/ProxyRelay.js +3 -4
- package/src/server/StaticDispatcher.js +3 -4
- package/src/server/Watcher.js +2 -3
- package/src/server/WatcherDevClient.js +3 -4
- package/src/server/config.js +1 -1
- package/src/server/utils/{http-request.js → HttpIncomingMessage.js} +7 -1
- package/src/server/utils/HttpServerResponse.js +117 -0
- package/src/server/utils/http-cors.js +1 -1
- package/src/server/utils/http-cors.test.js +225 -0
- package/src/server/utils/logger.js +1 -1
- package/src/server/utils/mime.test.js +24 -0
- package/src/server/utils/validate.test.js +47 -0
- package/src/server/utils/http-response.js +0 -113
package/index.js
CHANGED
|
@@ -3,6 +3,6 @@ export { Commander } from './src/client/ApiCommander.js'
|
|
|
3
3
|
export { Mockaton } from './src/server/Mockaton.js'
|
|
4
4
|
export { jwtCookie } from './src/server/utils/jwt.js'
|
|
5
5
|
export { jsToJsonPlugin } from './src/server/MockDispatcher.js'
|
|
6
|
-
export { parseJSON, BodyReaderError } from './src/server/utils/
|
|
6
|
+
export { parseJSON, BodyReaderError } from './src/server/utils/HttpIncomingMessage.js'
|
|
7
7
|
|
|
8
8
|
export const defineConfig = opts => opts
|
package/package.json
CHANGED
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "HTTP Mock Server",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "11.
|
|
5
|
+
"version": "11.3.0",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"import": "./index.js",
|
|
9
9
|
"types": "./index.d.ts"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"index.js",
|
|
15
|
+
"index.d.ts"
|
|
16
|
+
],
|
|
12
17
|
"license": "MIT",
|
|
18
|
+
"homepage": "https://mockaton.com",
|
|
13
19
|
"repository": "https://github.com/ericfortis/mockaton",
|
|
14
20
|
"keywords": [
|
|
15
21
|
"mock-server",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import { deepEqual } from 'node:assert'
|
|
3
|
+
|
|
4
|
+
import { dittoSplitPaths, BrokerRowModel, t } from './app-store.js'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
test('dittoSplitPaths', () => {
|
|
8
|
+
const input = [
|
|
9
|
+
'/api/user',
|
|
10
|
+
'/api/user/avatar',
|
|
11
|
+
'/api/user/friends',
|
|
12
|
+
'/api/vid',
|
|
13
|
+
'/api/video/id',
|
|
14
|
+
'/api/video/stats',
|
|
15
|
+
'/v2/foo',
|
|
16
|
+
'/v2/foo/bar'
|
|
17
|
+
]
|
|
18
|
+
deepEqual(dittoSplitPaths(input), [
|
|
19
|
+
['', '/api/user'],
|
|
20
|
+
['/api/user/', 'avatar'],
|
|
21
|
+
['/api/user/', 'friends'],
|
|
22
|
+
['/api/', 'vid'],
|
|
23
|
+
['/api/', 'video/id'],
|
|
24
|
+
['/api/video/', 'stats'],
|
|
25
|
+
['', '/v2/foo'],
|
|
26
|
+
['/v2/foo/', 'bar']
|
|
27
|
+
])
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
test('BrokerRowModel', () => {
|
|
32
|
+
test('has Auto500 when is autogenerated 500', () => {
|
|
33
|
+
const broker = {
|
|
34
|
+
auto500: true,
|
|
35
|
+
file: 'api/user.GET.200.json',
|
|
36
|
+
mocks: ['api/user.GET.200.json']
|
|
37
|
+
}
|
|
38
|
+
const row = new BrokerRowModel(broker, false)
|
|
39
|
+
const opts = row.opts.map(([, n, selected]) => [n, selected])
|
|
40
|
+
deepEqual(opts, [
|
|
41
|
+
['200 json', false],
|
|
42
|
+
[t`Auto500`, true],
|
|
43
|
+
])
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('filename has extension except when empty or unknown', () => {
|
|
47
|
+
const broker = {
|
|
48
|
+
file: `api/user0.GET.200.empty`,
|
|
49
|
+
mocks: [
|
|
50
|
+
`api/user0.GET.200.empty`,
|
|
51
|
+
`api/user1.GET.200.unknown`,
|
|
52
|
+
`api/user2.GET.200.json`,
|
|
53
|
+
`api/user3(another json).GET.200.json`,
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
const row = new BrokerRowModel(broker, false)
|
|
57
|
+
const opts = row.opts.map(([, n, selected]) => [n, selected])
|
|
58
|
+
deepEqual(opts, [
|
|
59
|
+
['200', true],
|
|
60
|
+
['200', false],
|
|
61
|
+
['200 json', false],
|
|
62
|
+
['200 json (another json)', false]
|
|
63
|
+
])
|
|
64
|
+
// TODO Think about, in cases like this, the only option the user has
|
|
65
|
+
// for discerning empty and unknown is on the Previewer Title
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('appends "Proxied" label iff current is proxied', () => {
|
|
69
|
+
const broker = {
|
|
70
|
+
file: 'api/foo',
|
|
71
|
+
proxied: true,
|
|
72
|
+
mocks: [`api/foo.GET.200.json`]
|
|
73
|
+
}
|
|
74
|
+
const row = new BrokerRowModel(broker, true)
|
|
75
|
+
deepEqual(row.opts.map(([, n, selected]) => [n, selected]), [
|
|
76
|
+
['200 json', false],
|
|
77
|
+
[t`Proxied`, true]
|
|
78
|
+
])
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
package/src/client/app.js
CHANGED
|
@@ -19,6 +19,7 @@ const CSS = {
|
|
|
19
19
|
GlobalDelayField: null,
|
|
20
20
|
GroupByMethod: null,
|
|
21
21
|
InternalServerErrorToggler: null,
|
|
22
|
+
Logo: null,
|
|
22
23
|
MenuTrigger: null,
|
|
23
24
|
Method: null,
|
|
24
25
|
MockList: null,
|
|
@@ -107,12 +108,16 @@ function App() {
|
|
|
107
108
|
function Header() {
|
|
108
109
|
return (
|
|
109
110
|
r('header', null,
|
|
110
|
-
r('
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
r('a', {
|
|
112
|
+
className: CSS.Logo,
|
|
113
|
+
href: 'https://mockaton.com',
|
|
114
|
+
},
|
|
115
|
+
r('object', {
|
|
116
|
+
data: 'logo.svg',
|
|
117
|
+
type: 'image/svg+xml',
|
|
118
|
+
width: 120,
|
|
119
|
+
height: 22
|
|
120
|
+
})),
|
|
116
121
|
r('div', null,
|
|
117
122
|
GlobalDelayField(),
|
|
118
123
|
BulkSelector(),
|
|
@@ -271,11 +276,17 @@ function SettingsMenu(id) {
|
|
|
271
276
|
}),
|
|
272
277
|
r('span', className(CSS.checkboxBody), t`Group by Method`)),
|
|
273
278
|
|
|
279
|
+
r('a', {
|
|
280
|
+
href: 'https://mockaton.com',
|
|
281
|
+
target: '_blank',
|
|
282
|
+
rel: 'noopener noreferrer'
|
|
283
|
+
}, t`Website`),
|
|
284
|
+
|
|
274
285
|
r('a', {
|
|
275
286
|
href: 'https://github.com/ericfortis/mockaton',
|
|
276
287
|
target: '_blank',
|
|
277
288
|
rel: 'noopener noreferrer'
|
|
278
|
-
}, t`
|
|
289
|
+
}, t`Source Code`),
|
|
279
290
|
|
|
280
291
|
r('p', null, `v${store.mockatonVersion}`)
|
|
281
292
|
)))
|
|
@@ -914,3 +925,6 @@ function SyntaxXML(xml) {
|
|
|
914
925
|
return frag
|
|
915
926
|
}
|
|
916
927
|
|
|
928
|
+
|
|
929
|
+
/*
|
|
930
|
+
*/
|
package/src/client/styles.css
CHANGED
|
@@ -133,10 +133,14 @@ header {
|
|
|
133
133
|
border-bottom: 1px solid var(--colorSecondaryActionBorder);
|
|
134
134
|
background: var(--colorHeaderBackground);
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
.Logo {
|
|
137
137
|
align-self: end;
|
|
138
138
|
margin-right: 22px;
|
|
139
|
-
margin-bottom:
|
|
139
|
+
margin-bottom: 3px;
|
|
140
|
+
|
|
141
|
+
object {
|
|
142
|
+
pointer-events: none;
|
|
143
|
+
}
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
> div {
|
package/src/server/Api.js
CHANGED
|
@@ -21,9 +21,6 @@ import { config, ConfigValidator } from './config.js'
|
|
|
21
21
|
import * as staticCollection from './staticCollection.js'
|
|
22
22
|
import * as mockBrokersCollection from './mockBrokersCollection.js'
|
|
23
23
|
|
|
24
|
-
import { parseJSON } from './utils/http-request.js'
|
|
25
|
-
import { sendOK, sendJSON, sendUnprocessable, sendFile, sendHTML } from './utils/http-response.js'
|
|
26
|
-
|
|
27
24
|
|
|
28
25
|
export const apiGetReqs = new Map([
|
|
29
26
|
[API.dashboard, serveDashboard],
|
|
@@ -61,17 +58,17 @@ export const apiPatchReqs = new Map([
|
|
|
61
58
|
/** # GET */
|
|
62
59
|
|
|
63
60
|
function serveDashboard(_, response) {
|
|
64
|
-
|
|
61
|
+
response.html(IndexHtml(config.hotReload), CSP)
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
function serveStatic(f) {
|
|
68
65
|
return (_, response) => {
|
|
69
|
-
|
|
66
|
+
response.file(join(CLIENT_DIR, f))
|
|
70
67
|
}
|
|
71
68
|
}
|
|
72
69
|
|
|
73
70
|
function getState(_, response) {
|
|
74
|
-
|
|
71
|
+
response.json({
|
|
75
72
|
cookies: cookie.list(),
|
|
76
73
|
comments: mockBrokersCollection.extractAllComments(),
|
|
77
74
|
|
|
@@ -93,161 +90,161 @@ function getState(_, response) {
|
|
|
93
90
|
function reinitialize(_, response) {
|
|
94
91
|
mockBrokersCollection.init()
|
|
95
92
|
staticCollection.init()
|
|
96
|
-
|
|
93
|
+
response.ok()
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
|
|
100
97
|
async function setCorsAllowed(req, response) {
|
|
101
|
-
const corsAllowed = await
|
|
98
|
+
const corsAllowed = await req.json()
|
|
102
99
|
|
|
103
100
|
if (!ConfigValidator.corsAllowed(corsAllowed))
|
|
104
|
-
|
|
101
|
+
response.unprocessable(`Expected boolean for "corsAllowed"`)
|
|
105
102
|
else {
|
|
106
103
|
config.corsAllowed = corsAllowed
|
|
107
|
-
|
|
104
|
+
response.ok()
|
|
108
105
|
}
|
|
109
106
|
}
|
|
110
107
|
|
|
111
108
|
|
|
112
109
|
async function setGlobalDelay(req, response) {
|
|
113
|
-
const delay = await
|
|
110
|
+
const delay = await req.json()
|
|
114
111
|
|
|
115
112
|
if (!ConfigValidator.delay(delay))
|
|
116
|
-
|
|
113
|
+
response.unprocessable(`Expected non-negative integer for "delay"`)
|
|
117
114
|
else {
|
|
118
115
|
config.delay = delay
|
|
119
|
-
|
|
116
|
+
response.ok()
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
|
|
124
121
|
async function selectCookie(req, response) {
|
|
125
|
-
const cookieKey = await
|
|
122
|
+
const cookieKey = await req.json()
|
|
126
123
|
|
|
127
124
|
const error = cookie.setCurrent(cookieKey)
|
|
128
125
|
if (error)
|
|
129
|
-
|
|
126
|
+
response.unprocessable(error?.message || error)
|
|
130
127
|
else
|
|
131
|
-
|
|
128
|
+
response.json(cookie.list())
|
|
132
129
|
}
|
|
133
130
|
|
|
134
131
|
|
|
135
132
|
async function setProxyFallback(req, response) {
|
|
136
|
-
const fallback = await
|
|
133
|
+
const fallback = await req.json()
|
|
137
134
|
|
|
138
135
|
if (!ConfigValidator.proxyFallback(fallback))
|
|
139
|
-
|
|
136
|
+
response.unprocessable(`Invalid Proxy Fallback URL`)
|
|
140
137
|
else {
|
|
141
138
|
config.proxyFallback = fallback
|
|
142
|
-
|
|
139
|
+
response.ok()
|
|
143
140
|
}
|
|
144
141
|
}
|
|
145
142
|
|
|
146
143
|
async function setCollectProxied(req, response) {
|
|
147
|
-
const collectProxied = await
|
|
144
|
+
const collectProxied = await req.json()
|
|
148
145
|
|
|
149
146
|
if (!ConfigValidator.collectProxied(collectProxied))
|
|
150
|
-
|
|
147
|
+
response.unprocessable(`Expected a boolean for "collectProxied"`)
|
|
151
148
|
else {
|
|
152
149
|
config.collectProxied = collectProxied
|
|
153
|
-
|
|
150
|
+
response.ok()
|
|
154
151
|
}
|
|
155
152
|
}
|
|
156
153
|
|
|
157
154
|
|
|
158
155
|
|
|
159
156
|
async function bulkUpdateBrokersByCommentTag(req, response) {
|
|
160
|
-
const comment = await
|
|
157
|
+
const comment = await req.json()
|
|
161
158
|
|
|
162
159
|
mockBrokersCollection.setMocksMatchingComment(comment)
|
|
163
|
-
|
|
160
|
+
response.ok()
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
|
|
167
164
|
async function selectMock(req, response) {
|
|
168
|
-
const file = await
|
|
165
|
+
const file = await req.json()
|
|
169
166
|
|
|
170
167
|
const broker = mockBrokersCollection.brokerByFilename(file)
|
|
171
168
|
if (!broker || !broker.hasMock(file))
|
|
172
|
-
|
|
169
|
+
response.unprocessable(`Missing Mock: ${file}`)
|
|
173
170
|
else {
|
|
174
171
|
broker.selectFile(file)
|
|
175
|
-
|
|
172
|
+
response.json(broker)
|
|
176
173
|
}
|
|
177
174
|
}
|
|
178
175
|
|
|
179
176
|
|
|
180
177
|
async function toggleRoute500(req, response) {
|
|
181
|
-
const [method, urlMask] = await
|
|
178
|
+
const [method, urlMask] = await req.json()
|
|
182
179
|
|
|
183
180
|
const broker = mockBrokersCollection.brokerByRoute(method, urlMask)
|
|
184
181
|
if (!broker)
|
|
185
|
-
|
|
182
|
+
response.unprocessable(`Route does not exist: ${method} ${urlMask}`)
|
|
186
183
|
else {
|
|
187
184
|
broker.toggle500()
|
|
188
|
-
|
|
185
|
+
response.json(broker)
|
|
189
186
|
}
|
|
190
187
|
}
|
|
191
188
|
|
|
192
189
|
|
|
193
190
|
async function setRouteIsDelayed(req, response) {
|
|
194
|
-
const [method, urlMask, delayed] = await
|
|
191
|
+
const [method, urlMask, delayed] = await req.json()
|
|
195
192
|
|
|
196
193
|
const broker = mockBrokersCollection.brokerByRoute(method, urlMask)
|
|
197
194
|
if (!broker)
|
|
198
|
-
|
|
195
|
+
response.unprocessable(`Route does not exist: ${method} ${urlMask}`)
|
|
199
196
|
else if (typeof delayed !== 'boolean')
|
|
200
|
-
|
|
197
|
+
response.unprocessable(`Expected boolean for "delayed"`)
|
|
201
198
|
else {
|
|
202
199
|
broker.setDelayed(delayed)
|
|
203
|
-
|
|
200
|
+
response.json(broker)
|
|
204
201
|
}
|
|
205
202
|
}
|
|
206
203
|
|
|
207
204
|
|
|
208
205
|
async function setRouteIsProxied(req, response) {
|
|
209
|
-
const [method, urlMask, proxied] = await
|
|
206
|
+
const [method, urlMask, proxied] = await req.json()
|
|
210
207
|
|
|
211
208
|
const broker = mockBrokersCollection.brokerByRoute(method, urlMask)
|
|
212
209
|
if (!broker)
|
|
213
|
-
|
|
210
|
+
response.unprocessable( `Route does not exist: ${method} ${urlMask}`)
|
|
214
211
|
else if (typeof proxied !== 'boolean')
|
|
215
|
-
|
|
212
|
+
response.unprocessable(`Expected boolean for "proxied"`)
|
|
216
213
|
else if (proxied && !config.proxyFallback)
|
|
217
|
-
|
|
214
|
+
response.unprocessable(`There’s no proxy fallback`)
|
|
218
215
|
else {
|
|
219
216
|
broker.setProxied(proxied)
|
|
220
|
-
|
|
217
|
+
response.json(broker)
|
|
221
218
|
}
|
|
222
219
|
}
|
|
223
220
|
|
|
224
221
|
|
|
225
222
|
|
|
226
223
|
async function setStaticRouteStatusCode(req, response) {
|
|
227
|
-
const [route, status] = await
|
|
224
|
+
const [route, status] = await req.json()
|
|
228
225
|
|
|
229
226
|
const broker = staticCollection.brokerByRoute(route)
|
|
230
227
|
if (!broker)
|
|
231
|
-
|
|
228
|
+
response.unprocessable(`Static route does not exist: ${route}`)
|
|
232
229
|
else if (!(status === 200 || status === 404))
|
|
233
|
-
|
|
230
|
+
response.unprocessable(`Expected 200 or 404 status code`)
|
|
234
231
|
else {
|
|
235
232
|
broker.setStatus(status)
|
|
236
|
-
|
|
233
|
+
response.ok()
|
|
237
234
|
}
|
|
238
235
|
}
|
|
239
236
|
|
|
240
237
|
|
|
241
238
|
async function setStaticRouteIsDelayed(req, response) {
|
|
242
|
-
const [route, delayed] = await
|
|
239
|
+
const [route, delayed] = await req.json()
|
|
243
240
|
|
|
244
241
|
const broker = staticCollection.brokerByRoute(route)
|
|
245
242
|
if (!broker)
|
|
246
|
-
|
|
243
|
+
response.unprocessable(`Static route does not exist: ${route}`)
|
|
247
244
|
else if (typeof delayed !== 'boolean')
|
|
248
|
-
|
|
245
|
+
response.unprocessable(`Expected boolean for "delayed"`)
|
|
249
246
|
else {
|
|
250
247
|
broker.setDelayed(delayed)
|
|
251
|
-
|
|
248
|
+
response.ok()
|
|
252
249
|
}
|
|
253
250
|
}
|
|
@@ -4,7 +4,6 @@ import { pathToFileURL } from 'node:url'
|
|
|
4
4
|
|
|
5
5
|
import { logger } from './utils/logger.js'
|
|
6
6
|
import { mimeFor } from './utils/mime.js'
|
|
7
|
-
import { sendInternalServerError, sendMockNotFound } from './utils/http-response.js'
|
|
8
7
|
|
|
9
8
|
import { proxy } from './ProxyRelay.js'
|
|
10
9
|
import { cookie } from './cookie.js'
|
|
@@ -25,7 +24,7 @@ export async function dispatchMock(req, response) {
|
|
|
25
24
|
return
|
|
26
25
|
}
|
|
27
26
|
if (!broker) {
|
|
28
|
-
|
|
27
|
+
response.mockNotFound()
|
|
29
28
|
return
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -52,9 +51,9 @@ export async function dispatchMock(req, response) {
|
|
|
52
51
|
}
|
|
53
52
|
catch (error) { // TESTME
|
|
54
53
|
if (error?.code === 'ENOENT') // mock-file has been deleted
|
|
55
|
-
|
|
54
|
+
response.mockNotFound()
|
|
56
55
|
else
|
|
57
|
-
|
|
56
|
+
response.internalServerError(error)
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
package/src/server/Mockaton.js
CHANGED
|
@@ -3,12 +3,10 @@ import { createServer } from 'node:http'
|
|
|
3
3
|
import pkgJSON from '../../package.json' with { type: 'json' }
|
|
4
4
|
|
|
5
5
|
import { logger } from './utils/logger.js'
|
|
6
|
+
import { ServerResponse } from './utils/HttpServerResponse.js'
|
|
7
|
+
import { IncomingMessage } from './utils/HttpIncomingMessage.js'
|
|
6
8
|
import { setCorsHeaders, isPreflight } from './utils/http-cors.js'
|
|
7
|
-
import { BodyReaderError, hasControlChars } from './utils/
|
|
8
|
-
import {
|
|
9
|
-
setHeaders, sendNoContent, sendInternalServerError,
|
|
10
|
-
sendUnprocessable, sendTooLongURI, sendBadRequest
|
|
11
|
-
} from './utils/http-response.js'
|
|
9
|
+
import { BodyReaderError, hasControlChars } from './utils/HttpIncomingMessage.js'
|
|
12
10
|
|
|
13
11
|
import { API } from './ApiConstants.js'
|
|
14
12
|
import { config, setup } from './config.js'
|
|
@@ -38,7 +36,7 @@ export function Mockaton(options) {
|
|
|
38
36
|
if (config.hotReload)
|
|
39
37
|
watchDevSPA()
|
|
40
38
|
|
|
41
|
-
const server = createServer(onRequest)
|
|
39
|
+
const server = createServer({ IncomingMessage, ServerResponse }, onRequest)
|
|
42
40
|
server.on('error', reject)
|
|
43
41
|
server.listen(config.port, config.host, () => {
|
|
44
42
|
const url = `http://${server.address().address}:${server.address().port}`
|
|
@@ -54,17 +52,17 @@ export function Mockaton(options) {
|
|
|
54
52
|
async function onRequest(req, response) {
|
|
55
53
|
response.on('error', logger.warn)
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
response.setHeader('Server', `Mockaton ${pkgJSON.version}`)
|
|
56
|
+
response.setHeaderList(config.extraHeaders)
|
|
59
57
|
|
|
60
58
|
const url = req.url || ''
|
|
61
59
|
|
|
62
60
|
if (url.length > 2048) {
|
|
63
|
-
|
|
61
|
+
response.uriTooLong()
|
|
64
62
|
return
|
|
65
63
|
}
|
|
66
64
|
if (hasControlChars(url)) {
|
|
67
|
-
|
|
65
|
+
response.badRequest()
|
|
68
66
|
return
|
|
69
67
|
}
|
|
70
68
|
|
|
@@ -76,7 +74,7 @@ async function onRequest(req, response) {
|
|
|
76
74
|
const { pathname } = new URL(url, 'http://_')
|
|
77
75
|
|
|
78
76
|
if (isPreflight(req))
|
|
79
|
-
|
|
77
|
+
response.noContent()
|
|
80
78
|
|
|
81
79
|
else if (method === 'PATCH' && apiPatchReqs.has(pathname))
|
|
82
80
|
await apiPatchReqs.get(pathname)(req, response)
|
|
@@ -92,8 +90,8 @@ async function onRequest(req, response) {
|
|
|
92
90
|
}
|
|
93
91
|
catch (error) {
|
|
94
92
|
if (error instanceof BodyReaderError)
|
|
95
|
-
|
|
93
|
+
response.unprocessable(`${error.name}: ${error.message}`)
|
|
96
94
|
else
|
|
97
|
-
|
|
95
|
+
response.internalServerError(error)
|
|
98
96
|
}
|
|
99
97
|
}
|