1
1
'use strict' ;
2
2
3
- const Url = require ( 'url' ) ;
3
+ const { URL , URLSearchParams } = require ( 'url' ) ;
4
4
5
5
const Boom = require ( 'boom' ) ;
6
6
const Bounce = require ( 'bounce' ) ;
@@ -70,7 +70,13 @@ exports = module.exports = internals.Request = class {
70
70
71
71
// Parse request url
72
72
73
- this . setUrl ( req . url , this . _core . settings . router . stripTrailingSlash ) ;
73
+ try {
74
+ this . setUrl ( req . url , this . _core . settings . router . stripTrailingSlash ) ;
75
+ }
76
+ catch ( err ) {
77
+ Bounce . ignore ( err , 'boom' ) ;
78
+ this . url = err ;
79
+ }
74
80
}
75
81
76
82
static generate ( server , req , res , options ) {
@@ -103,11 +109,31 @@ exports = module.exports = internals.Request = class {
103
109
104
110
Hoek . assert ( this . params === null , 'Cannot change request URL after routing' ) ;
105
111
106
- url = ( typeof url === 'string' ? Url . parse ( url , true ) : Hoek . clone ( url ) ) ;
112
+ if ( url instanceof URL ) {
113
+ url = url . href ;
114
+ }
115
+
116
+ Hoek . assert ( typeof url === 'string' , 'Url must be a string or URL object' ) ;
117
+
118
+ const parseFull = url . length === 0 || url [ 0 ] !== '/' ;
119
+ try {
120
+ if ( parseFull ) {
121
+ url = new URL ( url ) ;
122
+ }
123
+ else {
124
+ const hostname = this . info . host || `${ this . _core . info . host } :${ this . _core . info . port } ` ;
125
+ url = new URL ( url , `${ this . _core . info . protocol } ://${ hostname } ` ) ;
126
+ }
127
+ }
128
+ catch ( err ) {
129
+ Bounce . ignore ( err , TypeError ) ;
130
+
131
+ throw Boom . boomify ( err , { statusCode : 400 } ) ;
132
+ }
107
133
108
134
// Apply path modifications
109
135
110
- let path = this . _core . router . normalize ( url . pathname || '' ) ; // pathname excludes query
136
+ let path = this . _core . router . normalize ( url . pathname ) ; // pathname excludes query
111
137
112
138
if ( stripTrailingSlash &&
113
139
path . length > 1 &&
@@ -116,21 +142,14 @@ exports = module.exports = internals.Request = class {
116
142
path = path . slice ( 0 , - 1 ) ;
117
143
}
118
144
119
- // Update derived url properties
120
-
121
- if ( path !== url . pathname ) {
122
- url . pathname = path ;
123
- url . path = url . search ? path + url . search : path ;
124
- url . href = Url . format ( url ) ;
125
- }
145
+ url . pathname = path ;
126
146
127
147
// Store request properties
128
148
129
149
this . url = url ;
130
- this . query = url . query ;
131
- this . path = url . pathname ;
150
+ this . path = path ;
132
151
133
- if ( url . hostname ) {
152
+ if ( parseFull ) {
134
153
this . info . hostname = url . hostname ;
135
154
this . info . host = url . host ;
136
155
}
@@ -162,6 +181,7 @@ exports = module.exports = internals.Request = class {
162
181
}
163
182
164
183
this . _lookup ( ) ;
184
+ this . _queryParse ( ) ;
165
185
this . _setTimeouts ( ) ;
166
186
await this . _lifecycle ( ) ;
167
187
this . _reply ( ) ;
@@ -184,10 +204,8 @@ exports = module.exports = internals.Request = class {
184
204
185
205
// Validate path
186
206
187
- if ( ! this . path ||
188
- this . path [ 0 ] !== '/' ) {
189
-
190
- throw Boom . badRequest ( 'Invalid path' ) ;
207
+ if ( this . url instanceof Error ) {
208
+ throw this . url ;
191
209
}
192
210
}
193
211
@@ -222,6 +240,46 @@ exports = module.exports = internals.Request = class {
222
240
}
223
241
}
224
242
243
+ _queryParse ( ) {
244
+
245
+ const { queryParser } = this . _route . settings ;
246
+
247
+ const baseParser = ( iterator ) => {
248
+
249
+ const query = Object . create ( null ) ;
250
+ for ( let [ key , value ] of iterator ) {
251
+ const entry = query [ key ] ;
252
+ if ( entry !== undefined ) {
253
+ value = [ ] . concat ( entry , value ) ;
254
+ }
255
+
256
+ query [ key ] = value ;
257
+ }
258
+
259
+ return query ;
260
+ } ;
261
+
262
+ if ( queryParser ) {
263
+ try {
264
+ let result = queryParser ( this ) ;
265
+
266
+ Hoek . assert ( typeof result === 'object' && result !== null , 'Parsed query must be an object' ) ;
267
+
268
+ if ( result instanceof URLSearchParams || result instanceof Map ) {
269
+ result = baseParser ( result ) ;
270
+ }
271
+
272
+ this . query = result ;
273
+ }
274
+ catch ( err ) {
275
+ return this . _reply ( err ) ;
276
+ }
277
+ }
278
+ else {
279
+ this . query = baseParser ( this . url . searchParams ) ;
280
+ }
281
+ }
282
+
225
283
_setTimeouts ( ) {
226
284
227
285
if ( this . raw . req . socket &&
0 commit comments