fastify 4.2.0 → 4.4.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.
Files changed (63) hide show
  1. package/README.md +13 -14
  2. package/docs/Guides/Database.md +2 -2
  3. package/docs/Guides/Ecosystem.md +42 -18
  4. package/docs/Guides/Migration-Guide-V4.md +29 -0
  5. package/docs/Guides/Plugins-Guide.md +5 -0
  6. package/docs/Reference/HTTP2.md +1 -3
  7. package/docs/Reference/Hooks.md +4 -1
  8. package/docs/Reference/Logging.md +1 -1
  9. package/docs/Reference/Reply.md +177 -0
  10. package/docs/Reference/Request.md +171 -0
  11. package/docs/Reference/Routes.md +4 -2
  12. package/docs/Reference/Server.md +4 -1
  13. package/docs/Reference/Type-Providers.md +1 -15
  14. package/docs/Reference/TypeScript.md +27 -3
  15. package/fastify.d.ts +1 -1
  16. package/fastify.js +3 -3
  17. package/lib/contentTypeParser.js +10 -2
  18. package/lib/context.js +10 -1
  19. package/lib/error-serializer.js +12 -12
  20. package/lib/errors.js +8 -0
  21. package/lib/handleRequest.js +2 -2
  22. package/lib/httpMethods.js +22 -0
  23. package/lib/reply.js +101 -24
  24. package/lib/request.js +97 -1
  25. package/lib/route.js +3 -1
  26. package/lib/symbols.js +15 -9
  27. package/package.json +7 -7
  28. package/test/build/error-serializer.test.js +3 -1
  29. package/test/content-parser.test.js +15 -0
  30. package/test/copy.test.js +41 -0
  31. package/test/internals/all.test.js +8 -2
  32. package/test/internals/reply-serialize.test.js +583 -0
  33. package/test/internals/reply.test.js +4 -1
  34. package/test/internals/request-validate.test.js +1269 -0
  35. package/test/internals/request.test.js +11 -2
  36. package/test/lock.test.js +73 -0
  37. package/test/mkcol.test.js +38 -0
  38. package/test/move.test.js +45 -0
  39. package/test/propfind.test.js +108 -0
  40. package/test/proppatch.test.js +78 -0
  41. package/test/request-error.test.js +44 -1
  42. package/test/schema-validation.test.js +71 -0
  43. package/test/search.test.js +100 -0
  44. package/test/trace.test.js +21 -0
  45. package/test/types/fastify.test-d.ts +12 -1
  46. package/test/types/hooks.test-d.ts +1 -2
  47. package/test/types/import.ts +1 -1
  48. package/test/types/instance.test-d.ts +4 -1
  49. package/test/types/logger.test-d.ts +4 -5
  50. package/test/types/reply.test-d.ts +44 -3
  51. package/test/types/request.test-d.ts +10 -29
  52. package/test/types/type-provider.test-d.ts +79 -7
  53. package/test/unlock.test.js +41 -0
  54. package/test/validation-error-handling.test.js +6 -1
  55. package/types/hooks.d.ts +19 -39
  56. package/types/instance.d.ts +78 -130
  57. package/types/logger.d.ts +7 -4
  58. package/types/reply.d.ts +7 -1
  59. package/types/request.d.ts +16 -3
  60. package/types/route.d.ts +23 -29
  61. package/types/schema.d.ts +4 -1
  62. package/types/type-provider.d.ts +8 -20
  63. package/types/utils.d.ts +2 -1
@@ -35,6 +35,19 @@ Request is a core Fastify object containing the following fields:
35
35
  - `connection` - Deprecated, use `socket` instead. The underlying connection of
36
36
  the incoming request.
37
37
  - `socket` - the underlying connection of the incoming request
38
+ - [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
39
+ Returns a validation function for the specified schema or http part,
40
+ if any of either are set or cached.
41
+ - [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema) -
42
+ Compiles the specified schema and returns a validation function
43
+ using the default (or customized) `ValidationCompiler`.
44
+ The optional `httpPart` is forwarded to the `ValidationCompiler`
45
+ if provided, defaults to `null`.
46
+ - [.validateInput(data, schema | httpPart, [httpPart])](#validate) -
47
+ Validates the specified input by using the specified
48
+ schema and returns the serialized payload. If the optional
49
+ `httpPart` is provided, the function will use the serializer
50
+ function given for that HTTP Status Code. Defaults to `null`.
38
51
  - `context` - A Fastify internal object. You should not use it directly or
39
52
  modify it. It is useful to access one special key:
40
53
  - `context.config` - The route [`config`](./Routes.md#routes-config) object.
@@ -77,3 +90,161 @@ fastify.post('/:params', options, function (request, reply) {
77
90
  request.log.info('some info')
78
91
  })
79
92
  ```
93
+ ### .getValidationFunction(schema | httpPart)
94
+ <a id="getvalidationfunction"></a>
95
+
96
+ By calling this function using a provided `schema` or `httpPart`,
97
+ it will return a `validation` function that can be used to
98
+ validate diverse inputs. It returns `undefined` if no
99
+ serialization function was found using either of the provided inputs.
100
+
101
+ ```js
102
+ const validate = request
103
+ .getValidationFunction({
104
+ type: 'object',
105
+ properties: {
106
+ foo: {
107
+ type: 'string'
108
+ }
109
+ }
110
+ })
111
+ validate({ foo: 'bar' }) // true
112
+
113
+ // or
114
+
115
+ const validate = request
116
+ .getValidationFunction('body')
117
+ validate({ foo: 0.5 }) // false
118
+ ```
119
+
120
+ See [.compilaValidationSchema(schema, [httpStatus])](#compilevalidationschema)
121
+ for more information on how to compile validation function.
122
+
123
+ ### .compileValidationSchema(schema, [httpPart])
124
+ <a id="compilevalidationschema"></a>
125
+
126
+ This function will compile a validation schema and
127
+ return a function that can be used to validate data.
128
+ The function returned (a.k.a. _validation function_) is compiled
129
+ by using the provided [`SchemaControler#ValidationCompiler`](./Server.md#schema-controller).
130
+ A `WeakMap` is used to cached this, reducing compilation calls.
131
+
132
+ The optional parameter `httpPart`, if provided, is forwarded directly
133
+ the `ValidationCompiler`, so it can be used to compile the validation
134
+ function if a custom `ValidationCompiler` is provided for the route.
135
+
136
+
137
+ ```js
138
+ const validate = request
139
+ .compileValidationSchema({
140
+ type: 'object',
141
+ properties: {
142
+ foo: {
143
+ type: 'string'
144
+ }
145
+ }
146
+ })
147
+ console.log(validate({ foo: 'bar' })) // true
148
+
149
+ // or
150
+
151
+ const validate = request
152
+ .compileValidationSchema({
153
+ type: 'object',
154
+ properties: {
155
+ foo: {
156
+ type: 'string'
157
+ }
158
+ }
159
+ }, 200)
160
+ console.log(validate({ hello: 'world' })) // false
161
+ ```
162
+
163
+ Note that you should be careful when using this function, as it will cache
164
+ the compiled validation functions based on the schema provided. If the
165
+ schemas provided are mutated or changed, the validation functions will not
166
+ detect that the schema has been altered and for instance it will reuse the
167
+ previously compiled validation function, as the cache is based on
168
+ the reference of the schema (Object) previously provided.
169
+
170
+ If there is a need to change the properties of a schema, always opt to create
171
+ a totally new schema (object), otherwise the implementation will not benefit from
172
+ the cache mechanism.
173
+
174
+ Using the following schema as an example:
175
+ ```js
176
+ const schema1 = {
177
+ type: 'object',
178
+ properties: {
179
+ foo: {
180
+ type: 'string'
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ *Not*
187
+ ```js
188
+ const validate = request.compileValidationSchema(schema1)
189
+
190
+ // Later on...
191
+ schema1.properties.foo.type. = 'integer'
192
+ const newValidate = request.compileValidationSchema(schema1)
193
+
194
+ console.log(newValidate === validate) // true
195
+ ```
196
+
197
+ *Instead*
198
+ ```js
199
+ const validate = request.compileValidationSchema(schema1)
200
+
201
+ // Later on...
202
+ const newSchema = Object.assign({}, schema1)
203
+ newSchema.properties.foo.type = 'integer'
204
+
205
+ const newValidate = request.compileValidationSchema(newSchema)
206
+
207
+ console.log(newValidate === validate) // false
208
+ ```
209
+
210
+ ### .validateInput(data, [schema | httpStatus], [httpStatus])
211
+ <a id="validate"></a>
212
+
213
+ This function will validate the input based on the provided schema,
214
+ or HTTP part passed. If both are provided, the `httpPart` parameter
215
+ will take precedence.
216
+
217
+ If there is not a validation function for a given `schema`, a new validation
218
+ function will be compiled, forwarding the `httpPart` if provided.
219
+
220
+ ```js
221
+ request
222
+ .validateInput({ foo: 'bar'}, {
223
+ type: 'object',
224
+ properties: {
225
+ foo: {
226
+ type: 'string'
227
+ }
228
+ }
229
+ }) // true
230
+
231
+ // or
232
+
233
+ request
234
+ .validateInput({ foo: 'bar'}, {
235
+ type: 'object',
236
+ properties: {
237
+ foo: {
238
+ type: 'string'
239
+ }
240
+ }
241
+ }, 'body') // true
242
+
243
+ // or
244
+
245
+ request
246
+ .validateInput({ hello: 'world'}, 'query') // false
247
+ ```
248
+
249
+ See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
250
+ for more information on how to compile validation schemas.
@@ -32,8 +32,10 @@ fastify.route(options)
32
32
  ### Routes options
33
33
  <a id="options"></a>
34
34
 
35
- *`method`: currently it supports `'DELETE'`, `'GET'`, `'HEAD'`, `'PATCH'`,
36
- `'POST'`, `'PUT'` and `'OPTIONS'`. It could also be an array of methods.
35
+ * `method`: currently it supports `'DELETE'`, `'GET'`, `'HEAD'`, `'PATCH'`,
36
+ `'POST'`, `'PUT'`, `'OPTIONS'`, `'SEARCH'`, `'TRACE'`, `'PROPFIND'`,
37
+ `'PROPPATCH'`, `'MKCOL'`, `'COPY'`, `'MOVE'`, `'LOCK'` and `'UNLOCK'`.
38
+ It could also be an array of methods.
37
39
  * `url`: the path of the URL to match this route (alias: `path`).
38
40
  * `schema`: an object containing the schemas for the request and response. They
39
41
  need to be in [JSON Schema](https://json-schema.org/) format, check
@@ -890,7 +890,7 @@ fastify.ready().then(() => {
890
890
  Starts the server and internally waits for the `.ready()` event. The signature
891
891
  is `.listen([options][, callback])`. Both the `options` object and the
892
892
  `callback` parameters follow the [Node.js
893
- core][https://nodejs.org/api/net.html#serverlistenoptions-callback] parameter
893
+ core](https://nodejs.org/api/net.html#serverlistenoptions-callback) parameter
894
894
  definitions.
895
895
 
896
896
  By default, the server will listen on the address(es) resolved by `localhost`
@@ -1402,6 +1402,9 @@ handlers. *async-await* is supported as well.
1402
1402
  *Note: If the error `statusCode` is less than 400, Fastify will automatically
1403
1403
  set it at 500 before calling the error handler.*
1404
1404
 
1405
+ *Also note* that `setErrorHandler` will ***not*** catch any error inside
1406
+ an `onResponse` hook because the response has already been sent to the client.
1407
+
1405
1408
  ```js
1406
1409
  fastify.setErrorHandler(function (error, request, reply) {
1407
1410
  // Log error
@@ -70,14 +70,7 @@ import { Type } from '@sinclair/typebox'
70
70
 
71
71
  import fastify from 'fastify'
72
72
 
73
- const server = fastify({
74
- ajv: {
75
- customOptions: {
76
- strict: 'log',
77
- keywords: ['kind', 'modifier'],
78
- },
79
- },
80
- }).withTypeProvider<TypeBoxTypeProvider>()
73
+ const server = fastify().withTypeProvider<TypeBoxTypeProvider>()
81
74
 
82
75
  server.get('/route', {
83
76
  schema: {
@@ -94,13 +87,6 @@ server.get('/route', {
94
87
  })
95
88
  ```
96
89
 
97
- TypeBox uses the properties `kind` and `modifier` internally. These properties
98
- are not strictly valid JSON schema which will cause `AJV@7` and newer versions
99
- to throw an invalid schema error. To remove the error it's either necessary to
100
- omit the properties by using
101
- [`Type.Strict()`](https://github.com/sinclairzx81/typebox#strict) or use the AJV
102
- options for adding custom keywords.
103
-
104
90
  See also the [TypeBox
105
91
  documentation](https://github.com/sinclairzx81/typebox#validation) on how to set
106
92
  up AJV to work with TypeBox.
@@ -143,7 +143,7 @@ route-level `request` object.
143
143
  curl localhost:8080/auth?username=admin&password=Password123!
144
144
  ```
145
145
  And it should return back `logged in!`
146
- 6. But wait theres more! The generic interfaces are also available inside route
146
+ 6. But wait there's more! The generic interfaces are also available inside route
147
147
  level hook methods. Modify the previous route by adding a `preValidation`
148
148
  hook:
149
149
  ```typescript
@@ -403,7 +403,7 @@ definitions.
403
403
  #### json-schema-to-ts
404
404
 
405
405
  If you do not want to generate types from your schemas, but want to use them
406
- diretly from your code, you can use the package
406
+ directly from your code, you can use the package
407
407
  [json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts).
408
408
 
409
409
  You can install it as dev-dependency.
@@ -661,6 +661,30 @@ However, there are a couple of suggestions to help improve this experience:
661
661
  [npm-check](https://www.npmjs.com/package/npm-check) to verify plugin
662
662
  dependencies are being used somewhere in your project.
663
663
 
664
+ Note that using `require` will not load the type definitions properly and may
665
+ cause type errors.
666
+ TypeScript can only identify the types that are directly imported into code,
667
+ which means that you can use require inline with import on top. For example:
668
+
669
+ ```typescript
670
+ import 'plugin' // here will trigger the type augmentation.
671
+
672
+ fastify.register(require('plugin'))
673
+ ```
674
+
675
+ ```typescript
676
+ import plugin from 'plugin' // here will trigger the type augmentation.
677
+
678
+ fastify.register(plugin)
679
+ ```
680
+
681
+ Or even explicit config on tsconfig
682
+ ```jsonc
683
+ {
684
+ "types": ["plugin"] // we force TypeScript to import the types
685
+ }
686
+ ```
687
+
664
688
  ## Code Completion In Vanilla JavaScript
665
689
 
666
690
  Vanilla JavaScript can use the published types to provide code completion (e.g.
@@ -1378,7 +1402,7 @@ FastifyError is a custom error object that includes status code and validation
1378
1402
  results.
1379
1403
 
1380
1404
  It extends the Node.js `Error` type, and adds two additional, optional
1381
- properties: `statusCode: number` and `validation: ValiationResult[]`.
1405
+ properties: `statusCode: number` and `validation: ValidationResult[]`.
1382
1406
 
1383
1407
  ##### fastify.ValidationResult
1384
1408
 
package/fastify.d.ts CHANGED
@@ -194,7 +194,7 @@ export type { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRe
194
194
  export { FastifyRequest, RequestGenericInterface } from './types/request'
195
195
  export { FastifyReply } from './types/reply'
196
196
  export { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
197
- export { FastifyInstance, PrintRoutesOptions } from './types/instance'
197
+ export { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
198
198
  export { FastifyLoggerOptions, FastifyBaseLogger, FastifyLoggerInstance, FastifyLogFn, LogLevel } from './types/logger'
199
199
  export { FastifyContext, FastifyContextConfig } from './types/context'
200
200
  export { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '4.2.0'
3
+ const VERSION = '4.4.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('http')
@@ -34,7 +34,7 @@ const {
34
34
  const { createServer, compileValidateHTTPVersion } = require('./lib/server')
35
35
  const Reply = require('./lib/reply')
36
36
  const Request = require('./lib/request')
37
- const supportedMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS']
37
+ const { supportedMethods } = require('./lib/httpMethods')
38
38
  const decorator = require('./lib/decorate')
39
39
  const ContentTypeParser = require('./lib/contentTypeParser')
40
40
  const SchemaController = require('./lib/schema-controller')
@@ -621,7 +621,7 @@ function fastify (options) {
621
621
  // https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
622
622
 
623
623
  // If the socket is not writable, there is no reason to try to send data.
624
- if (socket.writable && socket.bytesWritten === 0) {
624
+ if (socket.writable) {
625
625
  socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
626
626
  }
627
627
  socket.destroy(err)
@@ -92,10 +92,18 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
92
92
  }
93
93
 
94
94
  ContentTypeParser.prototype.getParser = function (contentType) {
95
+ if (contentType in this.customParsers) {
96
+ return this.customParsers[contentType]
97
+ }
98
+
99
+ if (this.cache.has(contentType)) {
100
+ return this.cache.get(contentType)
101
+ }
102
+
95
103
  // eslint-disable-next-line no-var
96
104
  for (var i = 0; i !== this.parserList.length; ++i) {
97
105
  const parserName = this.parserList[i]
98
- if (contentType.indexOf(parserName) > -1) {
106
+ if (contentType.indexOf(parserName) !== -1) {
99
107
  const parser = this.customParsers[parserName]
100
108
  this.cache.set(contentType, parser)
101
109
  return parser
@@ -137,7 +145,7 @@ ContentTypeParser.prototype.remove = function (contentType) {
137
145
  }
138
146
 
139
147
  ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
140
- const parser = this.cache.get(contentType) || this.getParser(contentType)
148
+ const parser = this.getParser(contentType)
141
149
  const resource = new AsyncResource('content-type-parser:run', request)
142
150
 
143
151
  if (parser === undefined) {
package/lib/context.js CHANGED
@@ -10,7 +10,9 @@ const {
10
10
  kBodyLimit,
11
11
  kLogLevel,
12
12
  kContentTypeParser,
13
- kRouteByFastify
13
+ kRouteByFastify,
14
+ kRequestValidateWeakMap,
15
+ kReplySerializeWeakMap
14
16
  } = require('./symbols.js')
15
17
 
16
18
  // Objects that holds the context of every request
@@ -24,6 +26,8 @@ function Context ({
24
26
  logLevel,
25
27
  logSerializers,
26
28
  attachValidation,
29
+ validatorCompiler,
30
+ serializerCompiler,
27
31
  replySerializer,
28
32
  schemaErrorFormatter,
29
33
  server,
@@ -54,6 +58,11 @@ function Context ({
54
58
  this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter
55
59
  this[kRouteByFastify] = isFastify
56
60
 
61
+ this[kRequestValidateWeakMap] = null
62
+ this[kReplySerializeWeakMap] = null
63
+ this.validatorCompiler = validatorCompiler || null
64
+ this.serializerCompiler = serializerCompiler || null
65
+
57
66
  this.server = server
58
67
  }
59
68
 
@@ -74,24 +74,24 @@ class Serializer {
74
74
  return bool === null ? 'null' : this.asBoolean(bool)
75
75
  }
76
76
 
77
- asDatetime (date) {
78
- const quotes = '"'
77
+ asDateTime (date) {
78
+ if (date === null) return '""'
79
79
  if (date instanceof Date) {
80
- return quotes + date.toISOString() + quotes
80
+ return '"' + date.toISOString() + '"'
81
81
  }
82
- return this.asString(date)
82
+ throw new Error(`The value "${date}" cannot be converted to a date-time.`)
83
83
  }
84
84
 
85
- asDatetimeNullable (date) {
86
- return date === null ? 'null' : this.asDatetime(date)
85
+ asDateTimeNullable (date) {
86
+ return date === null ? 'null' : this.asDateTime(date)
87
87
  }
88
88
 
89
89
  asDate (date) {
90
- const quotes = '"'
90
+ if (date === null) return '""'
91
91
  if (date instanceof Date) {
92
- return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + quotes
92
+ return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + '"'
93
93
  }
94
- return this.asString(date)
94
+ throw new Error(`The value "${date}" cannot be converted to a date.`)
95
95
  }
96
96
 
97
97
  asDateNullable (date) {
@@ -99,11 +99,11 @@ class Serializer {
99
99
  }
100
100
 
101
101
  asTime (date) {
102
- const quotes = '"'
102
+ if (date === null) return '""'
103
103
  if (date instanceof Date) {
104
- return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + quotes
104
+ return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + '"'
105
105
  }
106
- return this.asString(date)
106
+ throw new Error(`The value "${date}" cannot be converted to a time.`)
107
107
  }
108
108
 
109
109
  asTimeNullable (date) {
package/lib/errors.js CHANGED
@@ -160,6 +160,14 @@ const codes = {
160
160
  'FST_ERR_BAD_TRAILER_VALUE',
161
161
  "Called reply.trailer('%s', fn) with an invalid type: %s. Expected a function."
162
162
  ),
163
+ FST_ERR_MISSING_SERIALIZATION_FN: createError(
164
+ 'FST_ERR_MISSING_SERIALIZATION_FN',
165
+ 'Missing serialization function. Key "%s"'
166
+ ),
167
+ FST_ERR_REQ_INVALID_VALIDATION_INVOCATION: createError(
168
+ 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION',
169
+ 'Invalid validation invocation. Missing validation function for HTTP part "%s" nor schema provided.'
170
+ ),
163
171
 
164
172
  /**
165
173
  * schemas
@@ -18,14 +18,14 @@ function handleRequest (err, request, reply) {
18
18
  const method = request.raw.method
19
19
  const headers = request.headers
20
20
 
21
- if (method === 'GET' || method === 'HEAD') {
21
+ if (method === 'GET' || method === 'HEAD' || method === 'SEARCH') {
22
22
  handler(request, reply)
23
23
  return
24
24
  }
25
25
 
26
26
  const contentType = headers['content-type']
27
27
 
28
- if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
28
+ if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE') {
29
29
  if (contentType === undefined) {
30
30
  if (
31
31
  headers['transfer-encoding'] === undefined &&
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ supportedMethods: [
5
+ 'DELETE',
6
+ 'GET',
7
+ 'HEAD',
8
+ 'PATCH',
9
+ 'POST',
10
+ 'PUT',
11
+ 'OPTIONS',
12
+ 'PROPFIND',
13
+ 'PROPPATCH',
14
+ 'MKCOL',
15
+ 'COPY',
16
+ 'MOVE',
17
+ 'LOCK',
18
+ 'UNLOCK',
19
+ 'TRACE',
20
+ 'SEARCH'
21
+ ]
22
+ }