@nocobase/plugin-idp-oauth 2.1.0-alpha.17 → 2.1.0-alpha.19

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 (221) hide show
  1. package/build.config.ts +1 -1
  2. package/dist/externalVersion.js +6 -4
  3. package/dist/node_modules/light-my-request/package.json +1 -1
  4. package/dist/node_modules/undici/LICENSE +21 -0
  5. package/dist/node_modules/undici/README.md +741 -0
  6. package/dist/node_modules/undici/docs/docs/api/Agent.md +84 -0
  7. package/dist/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
  8. package/dist/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
  9. package/dist/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
  10. package/dist/node_modules/undici/docs/docs/api/Client.md +285 -0
  11. package/dist/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
  12. package/dist/node_modules/undici/docs/docs/api/Connector.md +115 -0
  13. package/dist/node_modules/undici/docs/docs/api/ContentType.md +57 -0
  14. package/dist/node_modules/undici/docs/docs/api/Cookies.md +101 -0
  15. package/dist/node_modules/undici/docs/docs/api/Debug.md +62 -0
  16. package/dist/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +315 -0
  17. package/dist/node_modules/undici/docs/docs/api/Dispatcher.md +1392 -0
  18. package/dist/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
  19. package/dist/node_modules/undici/docs/docs/api/Errors.md +49 -0
  20. package/dist/node_modules/undici/docs/docs/api/EventSource.md +45 -0
  21. package/dist/node_modules/undici/docs/docs/api/Fetch.md +60 -0
  22. package/dist/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
  23. package/dist/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
  24. package/dist/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
  25. package/dist/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
  26. package/dist/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
  27. package/dist/node_modules/undici/docs/docs/api/MockClient.md +81 -0
  28. package/dist/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
  29. package/dist/node_modules/undici/docs/docs/api/MockPool.md +555 -0
  30. package/dist/node_modules/undici/docs/docs/api/Pool.md +84 -0
  31. package/dist/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
  32. package/dist/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
  33. package/dist/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
  34. package/dist/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
  35. package/dist/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
  36. package/dist/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
  37. package/dist/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
  38. package/dist/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +274 -0
  39. package/dist/node_modules/undici/docs/docs/api/Util.md +25 -0
  40. package/dist/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
  41. package/dist/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
  42. package/dist/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
  43. package/dist/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
  44. package/dist/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
  45. package/dist/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
  46. package/dist/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
  47. package/dist/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
  48. package/dist/node_modules/undici/index-fetch.js +65 -0
  49. package/dist/node_modules/undici/index.d.ts +3 -0
  50. package/dist/node_modules/undici/index.js +234 -0
  51. package/dist/node_modules/undici/lib/api/abort-signal.js +59 -0
  52. package/dist/node_modules/undici/lib/api/api-connect.js +110 -0
  53. package/dist/node_modules/undici/lib/api/api-pipeline.js +252 -0
  54. package/dist/node_modules/undici/lib/api/api-request.js +214 -0
  55. package/dist/node_modules/undici/lib/api/api-stream.js +209 -0
  56. package/dist/node_modules/undici/lib/api/api-upgrade.js +111 -0
  57. package/dist/node_modules/undici/lib/api/index.js +7 -0
  58. package/dist/node_modules/undici/lib/api/readable.js +580 -0
  59. package/dist/node_modules/undici/lib/cache/memory-cache-store.js +234 -0
  60. package/dist/node_modules/undici/lib/cache/sqlite-cache-store.js +461 -0
  61. package/dist/node_modules/undici/lib/core/connect.js +137 -0
  62. package/dist/node_modules/undici/lib/core/constants.js +143 -0
  63. package/dist/node_modules/undici/lib/core/diagnostics.js +227 -0
  64. package/dist/node_modules/undici/lib/core/errors.js +477 -0
  65. package/dist/node_modules/undici/lib/core/request.js +438 -0
  66. package/dist/node_modules/undici/lib/core/socks5-client.js +407 -0
  67. package/dist/node_modules/undici/lib/core/socks5-utils.js +203 -0
  68. package/dist/node_modules/undici/lib/core/symbols.js +75 -0
  69. package/dist/node_modules/undici/lib/core/tree.js +160 -0
  70. package/dist/node_modules/undici/lib/core/util.js +992 -0
  71. package/dist/node_modules/undici/lib/dispatcher/agent.js +158 -0
  72. package/dist/node_modules/undici/lib/dispatcher/balanced-pool.js +219 -0
  73. package/dist/node_modules/undici/lib/dispatcher/client-h1.js +1610 -0
  74. package/dist/node_modules/undici/lib/dispatcher/client-h2.js +995 -0
  75. package/dist/node_modules/undici/lib/dispatcher/client.js +659 -0
  76. package/dist/node_modules/undici/lib/dispatcher/dispatcher-base.js +165 -0
  77. package/dist/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
  78. package/dist/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
  79. package/dist/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
  80. package/dist/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
  81. package/dist/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
  82. package/dist/node_modules/undici/lib/dispatcher/pool.js +118 -0
  83. package/dist/node_modules/undici/lib/dispatcher/proxy-agent.js +318 -0
  84. package/dist/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
  85. package/dist/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
  86. package/dist/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +249 -0
  87. package/dist/node_modules/undici/lib/encoding/index.js +33 -0
  88. package/dist/node_modules/undici/lib/global.js +50 -0
  89. package/dist/node_modules/undici/lib/handler/cache-handler.js +578 -0
  90. package/dist/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
  91. package/dist/node_modules/undici/lib/handler/decorator-handler.js +67 -0
  92. package/dist/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
  93. package/dist/node_modules/undici/lib/handler/redirect-handler.js +238 -0
  94. package/dist/node_modules/undici/lib/handler/retry-handler.js +394 -0
  95. package/dist/node_modules/undici/lib/handler/unwrap-handler.js +100 -0
  96. package/dist/node_modules/undici/lib/handler/wrap-handler.js +105 -0
  97. package/dist/node_modules/undici/lib/interceptor/cache.js +495 -0
  98. package/dist/node_modules/undici/lib/interceptor/decompress.js +259 -0
  99. package/dist/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
  100. package/dist/node_modules/undici/lib/interceptor/dns.js +571 -0
  101. package/dist/node_modules/undici/lib/interceptor/dump.js +112 -0
  102. package/dist/node_modules/undici/lib/interceptor/redirect.js +21 -0
  103. package/dist/node_modules/undici/lib/interceptor/response-error.js +95 -0
  104. package/dist/node_modules/undici/lib/interceptor/retry.js +19 -0
  105. package/dist/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  106. package/dist/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
  107. package/dist/node_modules/undici/lib/llhttp/constants.js +531 -0
  108. package/dist/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
  109. package/dist/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
  110. package/dist/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
  111. package/dist/node_modules/undici/lib/llhttp/utils.js +12 -0
  112. package/dist/node_modules/undici/lib/mock/mock-agent.js +232 -0
  113. package/dist/node_modules/undici/lib/mock/mock-call-history.js +248 -0
  114. package/dist/node_modules/undici/lib/mock/mock-client.js +68 -0
  115. package/dist/node_modules/undici/lib/mock/mock-errors.js +29 -0
  116. package/dist/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
  117. package/dist/node_modules/undici/lib/mock/mock-pool.js +68 -0
  118. package/dist/node_modules/undici/lib/mock/mock-symbols.js +32 -0
  119. package/dist/node_modules/undici/lib/mock/mock-utils.js +486 -0
  120. package/dist/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
  121. package/dist/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
  122. package/dist/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
  123. package/dist/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
  124. package/dist/node_modules/undici/lib/util/cache.js +407 -0
  125. package/dist/node_modules/undici/lib/util/date.js +653 -0
  126. package/dist/node_modules/undici/lib/util/promise.js +28 -0
  127. package/dist/node_modules/undici/lib/util/runtime-features.js +124 -0
  128. package/dist/node_modules/undici/lib/util/stats.js +32 -0
  129. package/dist/node_modules/undici/lib/util/timers.js +425 -0
  130. package/dist/node_modules/undici/lib/web/cache/cache.js +864 -0
  131. package/dist/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
  132. package/dist/node_modules/undici/lib/web/cache/util.js +45 -0
  133. package/dist/node_modules/undici/lib/web/cookies/constants.js +12 -0
  134. package/dist/node_modules/undici/lib/web/cookies/index.js +199 -0
  135. package/dist/node_modules/undici/lib/web/cookies/parse.js +322 -0
  136. package/dist/node_modules/undici/lib/web/cookies/util.js +282 -0
  137. package/dist/node_modules/undici/lib/web/eventsource/eventsource-stream.js +399 -0
  138. package/dist/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
  139. package/dist/node_modules/undici/lib/web/eventsource/util.js +29 -0
  140. package/dist/node_modules/undici/lib/web/fetch/LICENSE +21 -0
  141. package/dist/node_modules/undici/lib/web/fetch/body.js +509 -0
  142. package/dist/node_modules/undici/lib/web/fetch/constants.js +131 -0
  143. package/dist/node_modules/undici/lib/web/fetch/data-url.js +596 -0
  144. package/dist/node_modules/undici/lib/web/fetch/formdata-parser.js +575 -0
  145. package/dist/node_modules/undici/lib/web/fetch/formdata.js +259 -0
  146. package/dist/node_modules/undici/lib/web/fetch/global.js +40 -0
  147. package/dist/node_modules/undici/lib/web/fetch/headers.js +719 -0
  148. package/dist/node_modules/undici/lib/web/fetch/index.js +2397 -0
  149. package/dist/node_modules/undici/lib/web/fetch/request.js +1115 -0
  150. package/dist/node_modules/undici/lib/web/fetch/response.js +641 -0
  151. package/dist/node_modules/undici/lib/web/fetch/util.js +1520 -0
  152. package/dist/node_modules/undici/lib/web/infra/index.js +229 -0
  153. package/dist/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
  154. package/dist/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
  155. package/dist/node_modules/undici/lib/web/webidl/index.js +1006 -0
  156. package/dist/node_modules/undici/lib/web/websocket/connection.js +329 -0
  157. package/dist/node_modules/undici/lib/web/websocket/constants.js +126 -0
  158. package/dist/node_modules/undici/lib/web/websocket/events.js +331 -0
  159. package/dist/node_modules/undici/lib/web/websocket/frame.js +133 -0
  160. package/dist/node_modules/undici/lib/web/websocket/permessage-deflate.js +118 -0
  161. package/dist/node_modules/undici/lib/web/websocket/receiver.js +450 -0
  162. package/dist/node_modules/undici/lib/web/websocket/sender.js +109 -0
  163. package/dist/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
  164. package/dist/node_modules/undici/lib/web/websocket/stream/websocketstream.js +497 -0
  165. package/dist/node_modules/undici/lib/web/websocket/util.js +347 -0
  166. package/dist/node_modules/undici/lib/web/websocket/websocket.js +751 -0
  167. package/dist/node_modules/undici/package.json +152 -0
  168. package/dist/node_modules/undici/scripts/strip-comments.js +10 -0
  169. package/dist/node_modules/undici/types/README.md +6 -0
  170. package/dist/node_modules/undici/types/agent.d.ts +32 -0
  171. package/dist/node_modules/undici/types/api.d.ts +43 -0
  172. package/dist/node_modules/undici/types/balanced-pool.d.ts +30 -0
  173. package/dist/node_modules/undici/types/cache-interceptor.d.ts +179 -0
  174. package/dist/node_modules/undici/types/cache.d.ts +36 -0
  175. package/dist/node_modules/undici/types/client-stats.d.ts +15 -0
  176. package/dist/node_modules/undici/types/client.d.ts +123 -0
  177. package/dist/node_modules/undici/types/connector.d.ts +36 -0
  178. package/dist/node_modules/undici/types/content-type.d.ts +21 -0
  179. package/dist/node_modules/undici/types/cookies.d.ts +30 -0
  180. package/dist/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
  181. package/dist/node_modules/undici/types/dispatcher.d.ts +273 -0
  182. package/dist/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
  183. package/dist/node_modules/undici/types/errors.d.ts +177 -0
  184. package/dist/node_modules/undici/types/eventsource.d.ts +66 -0
  185. package/dist/node_modules/undici/types/fetch.d.ts +231 -0
  186. package/dist/node_modules/undici/types/formdata.d.ts +114 -0
  187. package/dist/node_modules/undici/types/global-dispatcher.d.ts +9 -0
  188. package/dist/node_modules/undici/types/global-origin.d.ts +7 -0
  189. package/dist/node_modules/undici/types/h2c-client.d.ts +73 -0
  190. package/dist/node_modules/undici/types/handlers.d.ts +14 -0
  191. package/dist/node_modules/undici/types/header.d.ts +160 -0
  192. package/dist/node_modules/undici/types/index.d.ts +91 -0
  193. package/dist/node_modules/undici/types/interceptors.d.ts +80 -0
  194. package/dist/node_modules/undici/types/mock-agent.d.ts +68 -0
  195. package/dist/node_modules/undici/types/mock-call-history.d.ts +111 -0
  196. package/dist/node_modules/undici/types/mock-client.d.ts +27 -0
  197. package/dist/node_modules/undici/types/mock-errors.d.ts +12 -0
  198. package/dist/node_modules/undici/types/mock-interceptor.d.ts +94 -0
  199. package/dist/node_modules/undici/types/mock-pool.d.ts +27 -0
  200. package/dist/node_modules/undici/types/patch.d.ts +29 -0
  201. package/dist/node_modules/undici/types/pool-stats.d.ts +19 -0
  202. package/dist/node_modules/undici/types/pool.d.ts +41 -0
  203. package/dist/node_modules/undici/types/proxy-agent.d.ts +29 -0
  204. package/dist/node_modules/undici/types/readable.d.ts +68 -0
  205. package/dist/node_modules/undici/types/retry-agent.d.ts +8 -0
  206. package/dist/node_modules/undici/types/retry-handler.d.ts +125 -0
  207. package/dist/node_modules/undici/types/round-robin-pool.d.ts +41 -0
  208. package/dist/node_modules/undici/types/snapshot-agent.d.ts +109 -0
  209. package/dist/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
  210. package/dist/node_modules/undici/types/util.d.ts +18 -0
  211. package/dist/node_modules/undici/types/utility.d.ts +7 -0
  212. package/dist/node_modules/undici/types/webidl.d.ts +347 -0
  213. package/dist/node_modules/undici/types/websocket.d.ts +188 -0
  214. package/dist/server/collections/oidcStates.d.ts +10 -0
  215. package/dist/server/collections/oidcStates.js +96 -0
  216. package/dist/server/db-adapter.d.ts +25 -0
  217. package/dist/server/db-adapter.js +156 -0
  218. package/dist/server/service.js +11 -10
  219. package/package.json +2 -2
  220. package/dist/server/cache-adapter.d.ts +0 -33
  221. package/dist/server/cache-adapter.js +0 -159
@@ -0,0 +1,575 @@
1
+ 'use strict'
2
+
3
+ const { bufferToLowerCasedHeaderName } = require('../../core/util')
4
+ const { HTTP_TOKEN_CODEPOINTS } = require('./data-url')
5
+ const { makeEntry } = require('./formdata')
6
+ const { webidl } = require('../webidl')
7
+ const assert = require('node:assert')
8
+ const { isomorphicDecode } = require('../infra')
9
+
10
+ const dd = Buffer.from('--')
11
+ const decoder = new TextDecoder()
12
+ const decoderIgnoreBOM = new TextDecoder('utf-8', { ignoreBOM: true })
13
+
14
+ /**
15
+ * @param {string} chars
16
+ */
17
+ function isAsciiString (chars) {
18
+ for (let i = 0; i < chars.length; ++i) {
19
+ if ((chars.charCodeAt(i) & ~0x7F) !== 0) {
20
+ return false
21
+ }
22
+ }
23
+ return true
24
+ }
25
+
26
+ /**
27
+ * @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-boundary
28
+ * @param {string} boundary
29
+ */
30
+ function validateBoundary (boundary) {
31
+ const length = boundary.length
32
+
33
+ // - its length is greater or equal to 27 and lesser or equal to 70, and
34
+ if (length < 27 || length > 70) {
35
+ return false
36
+ }
37
+
38
+ // - it is composed by bytes in the ranges 0x30 to 0x39, 0x41 to 0x5A, or
39
+ // 0x61 to 0x7A, inclusive (ASCII alphanumeric), or which are 0x27 ('),
40
+ // 0x2D (-) or 0x5F (_).
41
+ for (let i = 0; i < length; ++i) {
42
+ const cp = boundary.charCodeAt(i)
43
+
44
+ if (!(
45
+ (cp >= 0x30 && cp <= 0x39) ||
46
+ (cp >= 0x41 && cp <= 0x5a) ||
47
+ (cp >= 0x61 && cp <= 0x7a) ||
48
+ cp === 0x27 ||
49
+ cp === 0x2d ||
50
+ cp === 0x5f
51
+ )) {
52
+ return false
53
+ }
54
+ }
55
+
56
+ return true
57
+ }
58
+
59
+ /**
60
+ * @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-parser
61
+ * @param {Buffer} input
62
+ * @param {ReturnType<import('./data-url')['parseMIMEType']>} mimeType
63
+ */
64
+ function multipartFormDataParser (input, mimeType) {
65
+ // 1. Assert: mimeType’s essence is "multipart/form-data".
66
+ assert(mimeType !== 'failure' && mimeType.essence === 'multipart/form-data')
67
+
68
+ const boundaryString = mimeType.parameters.get('boundary')
69
+
70
+ // 2. If mimeType’s parameters["boundary"] does not exist, return failure.
71
+ // Otherwise, let boundary be the result of UTF-8 decoding mimeType’s
72
+ // parameters["boundary"].
73
+ if (boundaryString === undefined) {
74
+ throw parsingError('missing boundary in content-type header')
75
+ }
76
+
77
+ const boundary = Buffer.from(`--${boundaryString}`, 'utf8')
78
+
79
+ // 3. Let entry list be an empty entry list.
80
+ const entryList = []
81
+
82
+ // 4. Let position be a pointer to a byte in input, initially pointing at
83
+ // the first byte.
84
+ const position = { position: 0 }
85
+
86
+ // Note: Per RFC 2046 Section 5.1.1, we must ignore anything before the
87
+ // first boundary delimiter line (preamble). Search for the first boundary.
88
+ const firstBoundaryIndex = input.indexOf(boundary)
89
+
90
+ if (firstBoundaryIndex === -1) {
91
+ throw parsingError('no boundary found in multipart body')
92
+ }
93
+
94
+ // Start parsing from the first boundary, ignoring any preamble
95
+ position.position = firstBoundaryIndex
96
+
97
+ // 5. While true:
98
+ while (true) {
99
+ // 5.1. If position points to a sequence of bytes starting with 0x2D 0x2D
100
+ // (`--`) followed by boundary, advance position by 2 + the length of
101
+ // boundary. Otherwise, return failure.
102
+ // Note: boundary is padded with 2 dashes already, no need to add 2.
103
+ if (input.subarray(position.position, position.position + boundary.length).equals(boundary)) {
104
+ position.position += boundary.length
105
+ } else {
106
+ throw parsingError('expected a value starting with -- and the boundary')
107
+ }
108
+
109
+ // 5.2. If position points to the sequence of bytes 0x2D 0x2D 0x0D 0x0A
110
+ // (`--` followed by CR LF) followed by the end of input, return entry list.
111
+ // Note: Per RFC 2046 Section 5.1.1, we must ignore anything after the
112
+ // final boundary delimiter (epilogue). Check for -- or --CRLF and return
113
+ // regardless of what follows.
114
+ if (bufferStartsWith(input, dd, position)) {
115
+ // Found closing boundary delimiter (--), ignore any epilogue
116
+ return entryList
117
+ }
118
+
119
+ // 5.3. If position does not point to a sequence of bytes starting with 0x0D
120
+ // 0x0A (CR LF), return failure.
121
+ if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {
122
+ throw parsingError('expected CRLF')
123
+ }
124
+
125
+ // 5.4. Advance position by 2. (This skips past the newline.)
126
+ position.position += 2
127
+
128
+ // 5.5. Let name, filename and contentType be the result of parsing
129
+ // multipart/form-data headers on input and position, if the result
130
+ // is not failure. Otherwise, return failure.
131
+ const result = parseMultipartFormDataHeaders(input, position)
132
+
133
+ let { name, filename, contentType, encoding } = result
134
+
135
+ // 5.6. Advance position by 2. (This skips past the empty line that marks
136
+ // the end of the headers.)
137
+ position.position += 2
138
+
139
+ // 5.7. Let body be the empty byte sequence.
140
+ let body
141
+
142
+ // 5.8. Body loop: While position is not past the end of input:
143
+ // TODO: the steps here are completely wrong
144
+ {
145
+ const boundaryIndex = input.indexOf(boundary.subarray(2), position.position)
146
+
147
+ if (boundaryIndex === -1) {
148
+ throw parsingError('expected boundary after body')
149
+ }
150
+
151
+ body = input.subarray(position.position, boundaryIndex - 4)
152
+
153
+ position.position += body.length
154
+
155
+ // Note: position must be advanced by the body's length before being
156
+ // decoded, otherwise the parsing will fail.
157
+ if (encoding === 'base64') {
158
+ body = Buffer.from(body.toString(), 'base64')
159
+ }
160
+ }
161
+
162
+ // 5.9. If position does not point to a sequence of bytes starting with
163
+ // 0x0D 0x0A (CR LF), return failure. Otherwise, advance position by 2.
164
+ if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {
165
+ throw parsingError('expected CRLF')
166
+ } else {
167
+ position.position += 2
168
+ }
169
+
170
+ // 5.10. If filename is not null:
171
+ let value
172
+
173
+ if (filename !== null) {
174
+ // 5.10.1. If contentType is null, set contentType to "text/plain".
175
+ contentType ??= 'text/plain'
176
+
177
+ // 5.10.2. If contentType is not an ASCII string, set contentType to the empty string.
178
+
179
+ // Note: `buffer.isAscii` can be used at zero-cost, but converting a string to a buffer is a high overhead.
180
+ // Content-Type is a relatively small string, so it is faster to use `String#charCodeAt`.
181
+ if (!isAsciiString(contentType)) {
182
+ contentType = ''
183
+ }
184
+
185
+ // 5.10.3. Let value be a new File object with name filename, type contentType, and body body.
186
+ value = new File([body], filename, { type: contentType })
187
+ } else {
188
+ // 5.11. Otherwise:
189
+
190
+ // 5.11.1. Let value be the UTF-8 decoding without BOM of body.
191
+ value = decoderIgnoreBOM.decode(Buffer.from(body))
192
+ }
193
+
194
+ // 5.12. Assert: name is a scalar value string and value is either a scalar value string or a File object.
195
+ assert(webidl.is.USVString(name))
196
+ assert((typeof value === 'string' && webidl.is.USVString(value)) || webidl.is.File(value))
197
+
198
+ // 5.13. Create an entry with name and value, and append it to entry list.
199
+ entryList.push(makeEntry(name, value, filename))
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Parses content-disposition attributes (e.g., name="value" or filename*=utf-8''encoded)
205
+ * @param {Buffer} input
206
+ * @param {{ position: number }} position
207
+ * @returns {{ name: string, value: string }}
208
+ */
209
+ function parseContentDispositionAttribute (input, position) {
210
+ // Skip leading semicolon and whitespace
211
+ if (input[position.position] === 0x3b /* ; */) {
212
+ position.position++
213
+ }
214
+
215
+ // Skip whitespace
216
+ collectASequenceOfBytes(
217
+ (char) => char === 0x20 || char === 0x09,
218
+ input,
219
+ position
220
+ )
221
+
222
+ // Collect attribute name (token characters)
223
+ const attributeName = collectASequenceOfBytes(
224
+ (char) => isToken(char) && char !== 0x3d && char !== 0x2a, // not = or *
225
+ input,
226
+ position
227
+ )
228
+
229
+ if (attributeName.length === 0) {
230
+ return null
231
+ }
232
+
233
+ const attrNameStr = attributeName.toString('ascii').toLowerCase()
234
+
235
+ // Check for extended notation (attribute*)
236
+ const isExtended = input[position.position] === 0x2a /* * */
237
+ if (isExtended) {
238
+ position.position++ // skip *
239
+ }
240
+
241
+ // Expect = sign
242
+ if (input[position.position] !== 0x3d /* = */) {
243
+ return null
244
+ }
245
+ position.position++ // skip =
246
+
247
+ // Skip whitespace
248
+ collectASequenceOfBytes(
249
+ (char) => char === 0x20 || char === 0x09,
250
+ input,
251
+ position
252
+ )
253
+
254
+ let value
255
+
256
+ if (isExtended) {
257
+ // Extended attribute format: charset'language'encoded-value
258
+ const headerValue = collectASequenceOfBytes(
259
+ (char) => char !== 0x20 && char !== 0x0d && char !== 0x0a && char !== 0x3b, // not space, CRLF, or ;
260
+ input,
261
+ position
262
+ )
263
+
264
+ // Check for utf-8'' prefix (case insensitive)
265
+ if (
266
+ (headerValue[0] !== 0x75 && headerValue[0] !== 0x55) || // u or U
267
+ (headerValue[1] !== 0x74 && headerValue[1] !== 0x54) || // t or T
268
+ (headerValue[2] !== 0x66 && headerValue[2] !== 0x46) || // f or F
269
+ headerValue[3] !== 0x2d || // -
270
+ headerValue[4] !== 0x38 // 8
271
+ ) {
272
+ throw parsingError('unknown encoding, expected utf-8\'\'')
273
+ }
274
+
275
+ // Skip utf-8'' and decode the rest
276
+ value = decodeURIComponent(decoder.decode(headerValue.subarray(7)))
277
+ } else if (input[position.position] === 0x22 /* " */) {
278
+ // Quoted string
279
+ position.position++ // skip opening quote
280
+
281
+ const quotedValue = collectASequenceOfBytes(
282
+ (char) => char !== 0x0a && char !== 0x0d && char !== 0x22, // not LF, CR, or "
283
+ input,
284
+ position
285
+ )
286
+
287
+ if (input[position.position] !== 0x22) {
288
+ throw parsingError('Closing quote not found')
289
+ }
290
+ position.position++ // skip closing quote
291
+
292
+ value = decoder.decode(quotedValue)
293
+ .replace(/%0A/ig, '\n')
294
+ .replace(/%0D/ig, '\r')
295
+ .replace(/%22/g, '"')
296
+ } else {
297
+ // Token value (no quotes)
298
+ const tokenValue = collectASequenceOfBytes(
299
+ (char) => isToken(char) && char !== 0x3b, // not ;
300
+ input,
301
+ position
302
+ )
303
+
304
+ value = decoder.decode(tokenValue)
305
+ }
306
+
307
+ return { name: attrNameStr, value }
308
+ }
309
+
310
+ /**
311
+ * @see https://andreubotella.github.io/multipart-form-data/#parse-multipart-form-data-headers
312
+ * @param {Buffer} input
313
+ * @param {{ position: number }} position
314
+ */
315
+ function parseMultipartFormDataHeaders (input, position) {
316
+ // 1. Let name, filename and contentType be null.
317
+ let name = null
318
+ let filename = null
319
+ let contentType = null
320
+ let encoding = null
321
+
322
+ // 2. While true:
323
+ while (true) {
324
+ // 2.1. If position points to a sequence of bytes starting with 0x0D 0x0A (CR LF):
325
+ if (input[position.position] === 0x0d && input[position.position + 1] === 0x0a) {
326
+ // 2.1.1. If name is null, return failure.
327
+ if (name === null) {
328
+ throw parsingError('header name is null')
329
+ }
330
+
331
+ // 2.1.2. Return name, filename and contentType.
332
+ return { name, filename, contentType, encoding }
333
+ }
334
+
335
+ // 2.2. Let header name be the result of collecting a sequence of bytes that are
336
+ // not 0x0A (LF), 0x0D (CR) or 0x3A (:), given position.
337
+ let headerName = collectASequenceOfBytes(
338
+ (char) => char !== 0x0a && char !== 0x0d && char !== 0x3a,
339
+ input,
340
+ position
341
+ )
342
+
343
+ // 2.3. Remove any HTTP tab or space bytes from the start or end of header name.
344
+ headerName = removeChars(headerName, true, true, (char) => char === 0x9 || char === 0x20)
345
+
346
+ // 2.4. If header name does not match the field-name token production, return failure.
347
+ if (!HTTP_TOKEN_CODEPOINTS.test(headerName.toString())) {
348
+ throw parsingError('header name does not match the field-name token production')
349
+ }
350
+
351
+ // 2.5. If the byte at position is not 0x3A (:), return failure.
352
+ if (input[position.position] !== 0x3a) {
353
+ throw parsingError('expected :')
354
+ }
355
+
356
+ // 2.6. Advance position by 1.
357
+ position.position++
358
+
359
+ // 2.7. Collect a sequence of bytes that are HTTP tab or space bytes given position.
360
+ // (Do nothing with those bytes.)
361
+ collectASequenceOfBytes(
362
+ (char) => char === 0x20 || char === 0x09,
363
+ input,
364
+ position
365
+ )
366
+
367
+ // 2.8. Byte-lowercase header name and switch on the result:
368
+ switch (bufferToLowerCasedHeaderName(headerName)) {
369
+ case 'content-disposition': {
370
+ name = filename = null
371
+
372
+ // Collect the disposition type (should be "form-data")
373
+ const dispositionType = collectASequenceOfBytes(
374
+ (char) => isToken(char),
375
+ input,
376
+ position
377
+ )
378
+
379
+ if (dispositionType.toString('ascii').toLowerCase() !== 'form-data') {
380
+ throw parsingError('expected form-data for content-disposition header')
381
+ }
382
+
383
+ // Parse attributes recursively until CRLF
384
+ while (
385
+ position.position < input.length &&
386
+ input[position.position] !== 0x0d &&
387
+ input[position.position + 1] !== 0x0a
388
+ ) {
389
+ const attribute = parseContentDispositionAttribute(input, position)
390
+
391
+ if (!attribute) {
392
+ break
393
+ }
394
+
395
+ if (attribute.name === 'name') {
396
+ name = attribute.value
397
+ } else if (attribute.name === 'filename') {
398
+ filename = attribute.value
399
+ }
400
+ }
401
+
402
+ if (name === null) {
403
+ throw parsingError('name attribute is required in content-disposition header')
404
+ }
405
+
406
+ break
407
+ }
408
+ case 'content-type': {
409
+ // 1. Let header value be the result of collecting a sequence of bytes that are
410
+ // not 0x0A (LF) or 0x0D (CR), given position.
411
+ let headerValue = collectASequenceOfBytes(
412
+ (char) => char !== 0x0a && char !== 0x0d,
413
+ input,
414
+ position
415
+ )
416
+
417
+ // 2. Remove any HTTP tab or space bytes from the end of header value.
418
+ headerValue = removeChars(headerValue, false, true, (char) => char === 0x9 || char === 0x20)
419
+
420
+ // 3. Set contentType to the isomorphic decoding of header value.
421
+ contentType = isomorphicDecode(headerValue)
422
+
423
+ break
424
+ }
425
+ case 'content-transfer-encoding': {
426
+ let headerValue = collectASequenceOfBytes(
427
+ (char) => char !== 0x0a && char !== 0x0d,
428
+ input,
429
+ position
430
+ )
431
+
432
+ headerValue = removeChars(headerValue, false, true, (char) => char === 0x9 || char === 0x20)
433
+
434
+ encoding = isomorphicDecode(headerValue)
435
+
436
+ break
437
+ }
438
+ default: {
439
+ // Collect a sequence of bytes that are not 0x0A (LF) or 0x0D (CR), given position.
440
+ // (Do nothing with those bytes.)
441
+ collectASequenceOfBytes(
442
+ (char) => char !== 0x0a && char !== 0x0d,
443
+ input,
444
+ position
445
+ )
446
+ }
447
+ }
448
+
449
+ // 2.9. If position does not point to a sequence of bytes starting with 0x0D 0x0A
450
+ // (CR LF), return failure. Otherwise, advance position by 2 (past the newline).
451
+ if (input[position.position] !== 0x0d && input[position.position + 1] !== 0x0a) {
452
+ throw parsingError('expected CRLF')
453
+ } else {
454
+ position.position += 2
455
+ }
456
+ }
457
+ }
458
+
459
+ /**
460
+ * @param {(char: number) => boolean} condition
461
+ * @param {Buffer} input
462
+ * @param {{ position: number }} position
463
+ */
464
+ function collectASequenceOfBytes (condition, input, position) {
465
+ let start = position.position
466
+
467
+ while (start < input.length && condition(input[start])) {
468
+ ++start
469
+ }
470
+
471
+ return input.subarray(position.position, (position.position = start))
472
+ }
473
+
474
+ /**
475
+ * @param {Buffer} buf
476
+ * @param {boolean} leading
477
+ * @param {boolean} trailing
478
+ * @param {(charCode: number) => boolean} predicate
479
+ * @returns {Buffer}
480
+ */
481
+ function removeChars (buf, leading, trailing, predicate) {
482
+ let lead = 0
483
+ let trail = buf.length - 1
484
+
485
+ if (leading) {
486
+ while (lead < buf.length && predicate(buf[lead])) lead++
487
+ }
488
+
489
+ if (trailing) {
490
+ while (trail > 0 && predicate(buf[trail])) trail--
491
+ }
492
+
493
+ return lead === 0 && trail === buf.length - 1 ? buf : buf.subarray(lead, trail + 1)
494
+ }
495
+
496
+ /**
497
+ * Checks if {@param buffer} starts with {@param start}
498
+ * @param {Buffer} buffer
499
+ * @param {Buffer} start
500
+ * @param {{ position: number }} position
501
+ */
502
+ function bufferStartsWith (buffer, start, position) {
503
+ if (buffer.length < start.length) {
504
+ return false
505
+ }
506
+
507
+ for (let i = 0; i < start.length; i++) {
508
+ if (start[i] !== buffer[position.position + i]) {
509
+ return false
510
+ }
511
+ }
512
+
513
+ return true
514
+ }
515
+
516
+ function parsingError (cause) {
517
+ return new TypeError('Failed to parse body as FormData.', { cause: new TypeError(cause) })
518
+ }
519
+
520
+ /**
521
+ * CTL = <any US-ASCII control character
522
+ * (octets 0 - 31) and DEL (127)>
523
+ * @param {number} char
524
+ */
525
+ function isCTL (char) {
526
+ return char <= 0x1f || char === 0x7f
527
+ }
528
+
529
+ /**
530
+ * tspecials := "(" / ")" / "<" / ">" / "@" /
531
+ * "," / ";" / ":" / "\" / <">
532
+ * "/" / "[" / "]" / "?" / "="
533
+ * ; Must be in quoted-string,
534
+ * ; to use within parameter values
535
+ * @param {number} char
536
+ */
537
+ function isTSpecial (char) {
538
+ return (
539
+ char === 0x28 || // (
540
+ char === 0x29 || // )
541
+ char === 0x3c || // <
542
+ char === 0x3e || // >
543
+ char === 0x40 || // @
544
+ char === 0x2c || // ,
545
+ char === 0x3b || // ;
546
+ char === 0x3a || // :
547
+ char === 0x5c || // \
548
+ char === 0x22 || // "
549
+ char === 0x2f || // /
550
+ char === 0x5b || // [
551
+ char === 0x5d || // ]
552
+ char === 0x3f || // ?
553
+ char === 0x3d // +
554
+ )
555
+ }
556
+
557
+ /**
558
+ * token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
559
+ * or tspecials>
560
+ * @param {number} char
561
+ */
562
+ function isToken (char) {
563
+ return (
564
+ char <= 0x7f && // ascii
565
+ char !== 0x20 && // space
566
+ char !== 0x09 &&
567
+ !isCTL(char) &&
568
+ !isTSpecial(char)
569
+ )
570
+ }
571
+
572
+ module.exports = {
573
+ multipartFormDataParser,
574
+ validateBoundary
575
+ }