@dooboostore/simple-boot-http-server 1.0.22 → 1.0.24

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 (181) hide show
  1. package/README.MD +27 -3
  2. package/dist/cjs/SimpleBootHttpServer.js +93 -36
  3. package/dist/cjs/SimpleBootHttpServer.js.map +3 -3
  4. package/dist/cjs/codes/HttpHeaders.js +14 -3
  5. package/dist/cjs/codes/HttpHeaders.js.map +2 -2
  6. package/dist/cjs/codes/HttpStatus.js +1 -0
  7. package/dist/cjs/codes/HttpStatus.js.map +2 -2
  8. package/dist/cjs/codes/Mimes.js +2 -0
  9. package/dist/cjs/codes/Mimes.js.map +2 -2
  10. package/dist/cjs/decorators/MethodMapping.js +8 -6
  11. package/dist/cjs/decorators/MethodMapping.js.map +3 -3
  12. package/dist/cjs/endpoints/WebSocketEndPoint.js +16 -0
  13. package/dist/cjs/endpoints/WebSocketEndPoint.js.map +7 -0
  14. package/dist/cjs/filters/CacheFilter.js +75 -35
  15. package/dist/cjs/filters/CacheFilter.js.map +3 -3
  16. package/dist/cjs/filters/IntentSchemeFilter.js +98 -0
  17. package/dist/cjs/filters/IntentSchemeFilter.js.map +7 -0
  18. package/dist/cjs/filters/ResourceFilter.js +4 -1
  19. package/dist/cjs/filters/ResourceFilter.js.map +2 -2
  20. package/dist/cjs/filters/TopicProtocolFilter.js +343 -0
  21. package/dist/cjs/filters/TopicProtocolFilter.js.map +7 -0
  22. package/dist/cjs/filters/index.js +2 -0
  23. package/dist/cjs/filters/index.js.map +2 -2
  24. package/dist/cjs/index.js +28 -0
  25. package/dist/cjs/index.js.map +2 -2
  26. package/dist/cjs/models/RequestResponse.js +56 -89
  27. package/dist/cjs/models/RequestResponse.js.map +3 -3
  28. package/dist/cjs/models/datas/body/ReqPathData.js +29 -0
  29. package/dist/cjs/models/datas/body/ReqPathData.js.map +7 -0
  30. package/dist/cjs/models/datas/search/ReqSearchParamsObj.js +29 -0
  31. package/dist/cjs/models/datas/search/ReqSearchParamsObj.js.map +7 -0
  32. package/dist/cjs/option/HttpServerOption.js +25 -5
  33. package/dist/cjs/option/HttpServerOption.js.map +2 -2
  34. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js +141 -0
  35. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js.map +7 -0
  36. package/dist/cjs/proxy/SymbolIntentApiServiceProxyBase.js +35 -0
  37. package/dist/cjs/proxy/SymbolIntentApiServiceProxyBase.js.map +7 -0
  38. package/dist/cjs/proxy/TopicProtocolApiServiceProxy.js +324 -0
  39. package/dist/cjs/proxy/TopicProtocolApiServiceProxy.js.map +7 -0
  40. package/dist/cjs/proxy/index.js +26 -0
  41. package/dist/cjs/proxy/index.js.map +7 -0
  42. package/dist/cjs/resolvers/ResourceResolver.js +2 -2
  43. package/dist/cjs/resolvers/ResourceResolver.js.map +2 -2
  44. package/dist/cjs/session/SessionManager.js +2 -2
  45. package/dist/cjs/session/SessionManager.js.map +2 -2
  46. package/dist/cjs/websocket/WebSocketClient.js +554 -0
  47. package/dist/cjs/websocket/WebSocketClient.js.map +7 -0
  48. package/dist/cjs/websocket/WebSocketManager.js +652 -0
  49. package/dist/cjs/websocket/WebSocketManager.js.map +7 -0
  50. package/dist/cjs/websocket/index.js +24 -0
  51. package/dist/cjs/websocket/index.js.map +7 -0
  52. package/dist/esm/SimpleBootHttpServer.js +76 -19
  53. package/dist/esm/SimpleBootHttpServer.js.map +2 -2
  54. package/dist/esm/codes/HttpHeaders.js +12 -2
  55. package/dist/esm/codes/HttpHeaders.js.map +2 -2
  56. package/dist/esm/codes/HttpStatus.js +1 -0
  57. package/dist/esm/codes/HttpStatus.js.map +2 -2
  58. package/dist/esm/codes/Mimes.js +2 -0
  59. package/dist/esm/codes/Mimes.js.map +2 -2
  60. package/dist/esm/decorators/MethodMapping.js +3 -1
  61. package/dist/esm/decorators/MethodMapping.js.map +2 -2
  62. package/dist/esm/endpoints/WebSocketEndPoint.js +1 -0
  63. package/dist/esm/endpoints/WebSocketEndPoint.js.map +7 -0
  64. package/dist/esm/filters/CacheFilter.js +67 -27
  65. package/dist/esm/filters/CacheFilter.js.map +2 -2
  66. package/dist/esm/filters/IntentSchemeFilter.js +75 -0
  67. package/dist/esm/filters/IntentSchemeFilter.js.map +7 -0
  68. package/dist/esm/filters/ResourceFilter.js +4 -1
  69. package/dist/esm/filters/ResourceFilter.js.map +2 -2
  70. package/dist/esm/filters/TopicProtocolFilter.js +310 -0
  71. package/dist/esm/filters/TopicProtocolFilter.js.map +7 -0
  72. package/dist/esm/filters/index.js +1 -0
  73. package/dist/esm/filters/index.js.map +2 -2
  74. package/dist/esm/index.js +12 -0
  75. package/dist/esm/index.js.map +2 -2
  76. package/dist/esm/models/RequestResponse.js +52 -85
  77. package/dist/esm/models/RequestResponse.js.map +2 -2
  78. package/dist/esm/models/datas/body/ReqPathData.js +6 -0
  79. package/dist/esm/models/datas/body/ReqPathData.js.map +7 -0
  80. package/dist/esm/models/datas/search/ReqSearchParamsObj.js +6 -0
  81. package/dist/esm/models/datas/search/ReqSearchParamsObj.js.map +7 -0
  82. package/dist/esm/option/HttpServerOption.js +24 -4
  83. package/dist/esm/option/HttpServerOption.js.map +2 -2
  84. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js +118 -0
  85. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js.map +7 -0
  86. package/dist/esm/proxy/SymbolIntentApiServiceProxyBase.js +12 -0
  87. package/dist/esm/proxy/SymbolIntentApiServiceProxyBase.js.map +7 -0
  88. package/dist/esm/proxy/TopicProtocolApiServiceProxy.js +301 -0
  89. package/dist/esm/proxy/TopicProtocolApiServiceProxy.js.map +7 -0
  90. package/dist/esm/proxy/index.js +4 -0
  91. package/dist/esm/proxy/index.js.map +7 -0
  92. package/dist/esm/resolvers/ResourceResolver.js +1 -1
  93. package/dist/esm/resolvers/ResourceResolver.js.map +1 -1
  94. package/dist/esm/session/SessionManager.js +1 -1
  95. package/dist/esm/session/SessionManager.js.map +1 -1
  96. package/dist/esm/websocket/WebSocketClient.js +529 -0
  97. package/dist/esm/websocket/WebSocketClient.js.map +7 -0
  98. package/dist/esm/websocket/WebSocketManager.js +622 -0
  99. package/dist/esm/websocket/WebSocketManager.js.map +7 -0
  100. package/dist/esm/websocket/index.js +3 -0
  101. package/dist/esm/websocket/index.js.map +7 -0
  102. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js +13563 -5071
  103. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js.map +4 -4
  104. package/dist/types/SimpleBootHttpServer.d.ts +5 -3
  105. package/dist/types/SimpleBootHttpServer.d.ts.map +1 -1
  106. package/dist/types/codes/HttpHeaders.d.ts +3 -0
  107. package/dist/types/codes/HttpHeaders.d.ts.map +1 -1
  108. package/dist/types/codes/HttpStatus.d.ts +13 -1
  109. package/dist/types/codes/HttpStatus.d.ts.map +1 -1
  110. package/dist/types/codes/Mimes.d.ts +3 -1
  111. package/dist/types/codes/Mimes.d.ts.map +1 -1
  112. package/dist/types/decorators/MethodMapping.d.ts +4 -2
  113. package/dist/types/decorators/MethodMapping.d.ts.map +1 -1
  114. package/dist/types/endpoints/WebSocketEndPoint.d.ts +17 -0
  115. package/dist/types/endpoints/WebSocketEndPoint.d.ts.map +1 -0
  116. package/dist/types/filters/CacheFilter.d.ts +6 -0
  117. package/dist/types/filters/CacheFilter.d.ts.map +1 -1
  118. package/dist/types/filters/IntentSchemeFilter.d.ts +20 -0
  119. package/dist/types/filters/IntentSchemeFilter.d.ts.map +1 -0
  120. package/dist/types/filters/ResourceFilter.d.ts.map +1 -1
  121. package/dist/types/filters/TopicProtocolFilter.d.ts +34 -0
  122. package/dist/types/filters/TopicProtocolFilter.d.ts.map +1 -0
  123. package/dist/types/filters/index.d.ts +1 -0
  124. package/dist/types/filters/index.d.ts.map +1 -1
  125. package/dist/types/index.d.ts +12 -0
  126. package/dist/types/index.d.ts.map +1 -1
  127. package/dist/types/models/RequestResponse.d.ts +10 -6
  128. package/dist/types/models/RequestResponse.d.ts.map +1 -1
  129. package/dist/types/models/datas/body/ReqPathData.d.ts +4 -0
  130. package/dist/types/models/datas/body/ReqPathData.d.ts.map +1 -0
  131. package/dist/types/models/datas/search/ReqSearchParamsObj.d.ts +4 -0
  132. package/dist/types/models/datas/search/ReqSearchParamsObj.d.ts.map +1 -0
  133. package/dist/types/option/HttpServerOption.d.ts +30 -20
  134. package/dist/types/option/HttpServerOption.d.ts.map +1 -1
  135. package/dist/types/proxy/SymbolIntentApiServiceProxy.d.ts +18 -0
  136. package/dist/types/proxy/SymbolIntentApiServiceProxy.d.ts.map +1 -0
  137. package/dist/types/proxy/SymbolIntentApiServiceProxyBase.d.ts +5 -0
  138. package/dist/types/proxy/SymbolIntentApiServiceProxyBase.d.ts.map +1 -0
  139. package/dist/types/proxy/TopicProtocolApiServiceProxy.d.ts +28 -0
  140. package/dist/types/proxy/TopicProtocolApiServiceProxy.d.ts.map +1 -0
  141. package/dist/types/proxy/index.d.ts +4 -0
  142. package/dist/types/proxy/index.d.ts.map +1 -0
  143. package/dist/types/session/SessionManager.d.ts +2 -17
  144. package/dist/types/session/SessionManager.d.ts.map +1 -1
  145. package/dist/types/websocket/WebSocketClient.d.ts +88 -0
  146. package/dist/types/websocket/WebSocketClient.d.ts.map +1 -0
  147. package/dist/types/websocket/WebSocketManager.d.ts +163 -0
  148. package/dist/types/websocket/WebSocketManager.d.ts.map +1 -0
  149. package/dist/types/websocket/index.d.ts +3 -0
  150. package/dist/types/websocket/index.d.ts.map +1 -0
  151. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js +13638 -5146
  152. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js.map +4 -4
  153. package/dist/umd-bundle/websocket-client.umd.js +11194 -0
  154. package/dist/umd-bundle/websocket-client.umd.js.map +7 -0
  155. package/package.json +24 -15
  156. package/src/SimpleBootHttpServer.ts +367 -296
  157. package/src/codes/HttpHeaders.ts +13 -2
  158. package/src/codes/HttpStatus.ts +19 -1
  159. package/src/codes/Mimes.ts +27 -25
  160. package/src/decorators/MethodMapping.ts +6 -3
  161. package/src/endpoints/WebSocketEndPoint.ts +12 -0
  162. package/src/filters/CacheFilter.ts +112 -67
  163. package/src/filters/IntentSchemeFilter.ts +69 -0
  164. package/src/filters/ResourceFilter.ts +7 -1
  165. package/src/filters/TopicProtocolFilter.ts +349 -0
  166. package/src/filters/index.ts +1 -0
  167. package/src/index.ts +12 -12
  168. package/src/models/RequestResponse.ts +113 -240
  169. package/src/models/datas/body/ReqPathData.ts +3 -0
  170. package/src/models/datas/search/ReqSearchParamsObj.ts +3 -0
  171. package/src/option/HttpServerOption.ts +73 -23
  172. package/src/proxy/SymbolIntentApiServiceProxy.ts +120 -0
  173. package/src/proxy/SymbolIntentApiServiceProxyBase.ts +16 -0
  174. package/src/proxy/TopicProtocolApiServiceProxy.ts +328 -0
  175. package/src/proxy/index.ts +3 -0
  176. package/src/resolvers/ResourceResolver.ts +1 -1
  177. package/src/session/SessionManager.ts +3 -3
  178. package/src/websocket/WebSocketClient.ts +637 -0
  179. package/src/websocket/WebSocketManager.ts +713 -0
  180. package/src/websocket/index.ts +2 -0
  181. package/tsconfig.json +3 -1
@@ -1,7 +1,7 @@
1
1
  import { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from 'http';
2
2
  import { HttpHeaders, HttpHeadersType } from '../codes/HttpHeaders';
3
3
  import { Mimes } from '../codes/Mimes';
4
- import { Intent } from '@dooboostore/simple-boot/intent/Intent';
4
+ import { Intent } from '@dooboostore/simple-boot';
5
5
  import { URL, URLSearchParams } from 'url';
6
6
  import { Buffer } from 'buffer';
7
7
  import { MultipartData } from './datas/MultipartData';
@@ -16,45 +16,29 @@ import { HttpServerOption } from '../option/HttpServerOption';
16
16
  import { Blob } from 'node:buffer';
17
17
  import * as fs from 'fs';
18
18
  import * as os from 'os';
19
- import { RandomUtils } from '@dooboostore/core/random/RandomUtils';
20
- import { FileUtils } from '@dooboostore/core-node/file/FileUtils';
21
- import { ConvertUtils as CoreConvertUtils} from '@dooboostore/core/convert/ConvertUtils';
22
- import { ConvertUtils } from '@dooboostore/core-node/convert/ConvertUtils';
23
- // https://masteringjs.io/tutorials/node/http-request
24
- type Config = { sessionManager?: SessionManager, option: HttpServerOption };
25
-
26
- // https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction/
19
+ import { RandomUtils } from '@dooboostore/core';
20
+ import { FileUtils } from '@dooboostore/core-node';
21
+ import { ConvertUtils as CoreConvertUtils } from '@dooboostore/core';
22
+ import { ConvertUtils } from '@dooboostore/core-node';
23
+
24
+ type Config = { sessionManager?: SessionManager; option: HttpServerOption };
25
+
27
26
  export class RequestResponse {
28
27
  protected resWriteChunk: string | Buffer | undefined;
29
28
  protected reqBodyChunk?: Buffer;
30
29
  protected req: IncomingMessage;
31
30
  protected res: ServerResponse;
32
31
  protected config: Config;
33
- // protected sessionManager?: SessionManager;
34
-
35
- // constructor(req: IncomingMessage, res: ServerResponse);
36
- // constructor(req: RequestResponse);
37
- // constructor(req: IncomingMessage, res: ServerResponse, sessionManager?: SessionManager);
38
- // constructor(req: IncomingMessage | RequestResponse, res?: ServerResponse, sessionManager?: SessionManager) {
39
- // // this.req = req;
40
- // // this.res = res;
41
- // if (req instanceof RequestResponse) {
42
- // this.req = req.req;
43
- // this.res = req.res;
44
- // this.sessionManager = req.sessionManager;
45
- // } else {
46
- // this.req = req;
47
- // this.res = res!;
48
- // this.sessionManager = sessionManager;
49
- // }
50
- // }
32
+
33
+ // [아키텍트님의 정석] RequestResponse 객체 고유의 속성 저장소 (트랜잭션 생명주기)
34
+ protected attributes = new Map<string, any>();
35
+
51
36
  constructor(req: IncomingMessage | RequestResponse, res: ServerResponse, config: Config) {
52
- // this.req = req;
53
- // this.res = res;
54
37
  if (req instanceof RequestResponse) {
55
38
  this.req = req.req;
56
39
  this.res = req.res;
57
40
  this.config = config;
41
+ this.attributes = req.attributes;
58
42
  } else {
59
43
  this.req = req;
60
44
  this.res = res!;
@@ -62,6 +46,16 @@ export class RequestResponse {
62
46
  }
63
47
  }
64
48
 
49
+ // --- RequestResponse Attributes (Transaction Life-cycle) ---
50
+
51
+ setAttribute(key: string, value: any): void {
52
+ this.attributes.set(key, value);
53
+ }
54
+
55
+ getAttribute<T = any>(key: string): T | undefined {
56
+ return this.attributes.get(key) as T;
57
+ }
58
+
65
59
  get reqSocket() {
66
60
  return this.req.socket;
67
61
  }
@@ -69,13 +63,16 @@ export class RequestResponse {
69
63
  get reqCookieMap() {
70
64
  let cookies = this.reqHeader(HttpHeaders.Cookie) ?? '';
71
65
  if (Array.isArray(cookies)) {
72
- cookies = cookies.join(';')
66
+ cookies = cookies.join(';');
73
67
  }
74
68
 
75
69
  const map = new Map<string, string>();
76
- cookies.split(';').map(it => it.trim().split('=')).forEach(it => {
77
- map.set(it[0], it[1]);
78
- });
70
+ cookies
71
+ .split(';')
72
+ .map(it => it.trim().split('='))
73
+ .forEach(it => {
74
+ if (it[0]) map.set(it[0], it[1]);
75
+ });
79
76
  return map;
80
77
  }
81
78
 
@@ -95,11 +92,10 @@ export class RequestResponse {
95
92
  }
96
93
 
97
94
  get reqUrlObject(): URL {
98
- return new URL(this.reqUrl, `${this.reqSocket ? 'https://' : 'http'}${this.reqHost ?? 'localhost'}`);
95
+ return new URL(this.reqUrl, `${this.reqSocket ? 'https://' : 'http://'}${this.reqHost ?? 'localhost'}`);
99
96
  }
100
97
 
101
98
  get reqUrlPathName(): string {
102
- // parse(rr.reqUrl ?? '', true)
103
99
  return this.reqUrlObj().pathname ?? '';
104
100
  }
105
101
 
@@ -107,8 +103,8 @@ export class RequestResponse {
107
103
  return this.req.url ?? '';
108
104
  }
109
105
 
110
- reqUrlObj(config?:{scheme?: string, host?: string}): URL {
111
- return new URL(`${config?.scheme??'http' }://${config?.host ? config?.host : (this.reqHeaderFirst(HttpHeaders.Host) ?? 'localhost')}${this.req.url ?? ''}`);
106
+ reqUrlObj(config?: { scheme?: string; host?: string }): URL {
107
+ return new URL(`${config?.scheme ?? 'http'}://${config?.host ? config?.host : (this.reqHeaderFirst(HttpHeaders.Host) ?? 'localhost')}${this.req.url ?? ''}`);
112
108
  }
113
109
 
114
110
  get reqUrlSearchParamTuples(): [string, string][] {
@@ -119,16 +115,14 @@ export class RequestResponse {
119
115
  return this.reqUrlObj().searchParams;
120
116
  }
121
117
 
122
- get reqUrlSearchParamsObj(): {[p: string]: string | string[]} {
118
+ get reqUrlSearchParamsObj(): { [p: string]: string | string[] } {
123
119
  const entries = this.reqUrlObj().searchParams;
124
120
  return CoreConvertUtils.toObject(entries);
125
- // return obj;
126
- // return Object.fromEntries(entries as any)
127
121
  }
128
122
 
129
123
  get reqPathSearchParamUrl(): string {
130
124
  const reqUrlObj = this.reqUrlObj();
131
- return reqUrlObj.pathname + (reqUrlObj.searchParams.toString() ? '?' + reqUrlObj.searchParams.toString() : '')
125
+ return reqUrlObj.pathname + (reqUrlObj.searchParams.toString() ? '?' + reqUrlObj.searchParams.toString() : '');
132
126
  }
133
127
 
134
128
  get reqReadable() {
@@ -151,7 +145,7 @@ export class RequestResponse {
151
145
  return new Promise<Buffer>((resolve, reject) => {
152
146
  if (this.reqReadable) {
153
147
  const data: Uint8Array[] = [];
154
- this.req.on('data', (chunk) => data.push(chunk));
148
+ this.req.on('data', chunk => data.push(chunk));
155
149
  this.req.on('error', err => reject(err));
156
150
  this.req.on('end', () => {
157
151
  this.reqBodyChunk = Buffer.concat(data);
@@ -162,31 +156,29 @@ export class RequestResponse {
162
156
  }
163
157
  });
164
158
  }
165
-
166
- resBodyData(): string | Buffer | undefined{
159
+
160
+ resBodyData(): string | Buffer | undefined {
167
161
  return this.resWriteChunk;
168
162
  }
169
163
 
170
-
171
-
172
164
  async reqBodyMultipartFormDataObject<T>(): Promise<T> {
173
165
  const m = await this.reqBodyMultipartFormData();
174
166
  const formData = {} as any;
175
167
 
176
168
  for (const it of m) {
177
169
  if (it.isFile) {
178
- formData[it.name] = await FileUtils.writeFile(it.value, {originalName: it.filename });
170
+ formData[it.name] = await FileUtils.writeFile(it.value, { originalName: it.filename, etcData: it });
179
171
  } else {
180
172
  const target = formData[it.name];
181
173
  if (Array.isArray(target)) {
182
174
  target.push(it.value);
183
175
  } else if (typeof target === 'string') {
184
- formData[it.name] = [target, it.value]
176
+ formData[it.name] = [target, it.value];
185
177
  } else {
186
178
  formData[it.name] = it.value;
187
179
  }
188
180
  }
189
- };
181
+ }
190
182
  return formData;
191
183
  }
192
184
 
@@ -201,14 +193,14 @@ export class RequestResponse {
201
193
  if (!boundaryMatch) {
202
194
  return reject(new Error('Boundary not found in Content-Type header.'));
203
195
  }
204
- const boundary = boundaryMatch[1] || boundaryMatch[2]; // 따옴표 유무 처리
196
+ const boundary = boundaryMatch[1] || boundaryMatch[2];
205
197
  if (!boundary) {
206
198
  return reject(new Error('Failed to extract boundary.'));
207
199
  }
208
200
 
209
201
  const boundaryBuffer = Buffer.from(`--${boundary}`);
210
202
  const crlfBuffer = Buffer.from('\r\n');
211
- const doubleCrlfBuffer = Buffer.from('\r\n\r\n'); // 헤더와 바디 구분자
203
+ const doubleCrlfBuffer = Buffer.from('\r\n\r\n');
212
204
 
213
205
  const chunks: Buffer[] = [];
214
206
  let totalLength = 0;
@@ -218,65 +210,54 @@ export class RequestResponse {
218
210
  totalLength += chunk.length;
219
211
  });
220
212
 
221
- this.req.on('error', (err) => {
213
+ this.req.on('error', err => {
222
214
  reject(err);
223
215
  });
224
216
 
225
217
  this.req.on('end', () => {
226
218
  if (totalLength === 0) {
227
- return resolve([]); // 빈 요청 처리
219
+ return resolve([]);
228
220
  }
229
221
 
230
222
  const fullBuffer = Buffer.concat(chunks, totalLength);
231
223
  const parsedParts: MultipartData[] = [];
232
224
  let currentPosition = 0;
233
225
 
234
- // 첫 번째 boundary 찾기 (보통 시작 부분에 있음)
235
226
  let boundaryStartIndex = fullBuffer.indexOf(boundaryBuffer, currentPosition);
236
227
  if (boundaryStartIndex === -1) {
237
228
  return reject(new Error('Initial boundary not found.'));
238
229
  }
239
- // boundary 바로 다음 \r\n 건너뛰기
240
230
  currentPosition = boundaryStartIndex + boundaryBuffer.length;
241
231
  if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {
242
232
  currentPosition += crlfBuffer.length;
243
233
  }
244
234
 
245
-
246
235
  while (currentPosition < fullBuffer.length) {
247
- // 다음 boundary 찾기 (파트의 끝)
248
236
  const nextBoundaryIndex = fullBuffer.indexOf(boundaryBuffer, currentPosition);
249
237
  if (nextBoundaryIndex === -1) {
250
- // 마지막 boundary (--)인지 확인 필요하나, 여기서는 단순하게 처리
251
- // console.warn('Next boundary not found, assuming end of data or malformed.');
252
238
  break;
253
239
  }
254
240
 
255
- // 현재 파트 데이터 추출 (boundary 이전까지)
256
- // 실제 파트 데이터는 다음 boundary 바로 앞의 \r\n을 제외해야 함
257
241
  let partEndIndex = nextBoundaryIndex;
258
242
  if (partEndIndex > crlfBuffer.length && fullBuffer.slice(partEndIndex - crlfBuffer.length, partEndIndex).equals(crlfBuffer)) {
259
243
  partEndIndex -= crlfBuffer.length;
260
244
  }
261
245
  const partBuffer = fullBuffer.slice(currentPosition, partEndIndex);
262
246
 
263
- // 헤더와 바디 분리
264
247
  const headerBodySeparatorIndex = partBuffer.indexOf(doubleCrlfBuffer);
265
248
  if (headerBodySeparatorIndex === -1) {
266
- console.warn('Skipping malformed part: no header/body separator found.');
267
249
  currentPosition = nextBoundaryIndex + boundaryBuffer.length;
268
250
  if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {
269
251
  currentPosition += crlfBuffer.length;
270
252
  }
271
- if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') break; // 마지막 boundary
253
+ if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') break;
272
254
  continue;
273
255
  }
274
256
 
275
257
  const headerBuffer = partBuffer.slice(0, headerBodySeparatorIndex);
276
258
  const bodyBuffer = partBuffer.slice(headerBodySeparatorIndex + doubleCrlfBuffer.length);
277
- const headersStr = headerBuffer.toString('utf-8'); // 헤더는 보통 ASCII/UTF-8
259
+ const headersStr = headerBuffer.toString('utf-8');
278
260
 
279
- // 헤더 파싱
280
261
  const headers: { [key: string]: string } = {};
281
262
  headersStr.split('\r\n').forEach(line => {
282
263
  const colonIndex = line.indexOf(':');
@@ -289,7 +270,6 @@ export class RequestResponse {
289
270
 
290
271
  const contentDisposition = headers['content-disposition'];
291
272
  if (!contentDisposition) {
292
- console.warn('Skipping part: no Content-Disposition header.');
293
273
  currentPosition = nextBoundaryIndex + boundaryBuffer.length;
294
274
  if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {
295
275
  currentPosition += crlfBuffer.length;
@@ -306,113 +286,39 @@ export class RequestResponse {
306
286
  const contentType = headers['content-type'] || null;
307
287
 
308
288
  if (name) {
309
-
310
- const isFile = !!filename;
311
- // @ts-ignore
312
- const multipartData:MultipartData = {
313
- name:name,
314
- isFile: isFile, // filename이 있으면 파일로 간주
315
- filename: filename,
316
- contentType: contentType,
317
- value: isFile ? bodyBuffer: bodyBuffer.toString('utf-8'),
289
+ if (filename) {
290
+ parsedParts.push({
291
+ isFile: true,
292
+ name: name,
293
+ filename: filename,
294
+ contentType: contentType ?? 'application/octet-stream',
295
+ value: bodyBuffer
296
+ });
297
+ } else {
298
+ parsedParts.push({
299
+ isFile: false,
300
+ name: name,
301
+ value: bodyBuffer.toString('utf-8')
302
+ });
318
303
  }
319
- parsedParts.push(multipartData);
320
- } else {
321
- console.warn("Skipping part: 'name' not found in Content-Disposition.");
322
304
  }
323
305
 
324
- // 다음 파트 시작 위치로 이동
325
306
  currentPosition = nextBoundaryIndex + boundaryBuffer.length;
326
- // boundary 바로 다음 \r\n 건너뛰기
327
307
  if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {
328
308
  currentPosition += crlfBuffer.length;
329
309
  }
330
310
 
331
- // 마지막 boundary (--)인지 확인하고 루프 종료
332
311
  if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') {
333
312
  break;
334
313
  }
335
314
  }
336
315
  resolve(parsedParts);
337
316
  });
338
- })
339
- // const form = formidable({});
340
- // return new Promise((resolve, reject) => {
341
- // form.parse(this.req, (err, fields, files) => {
342
- // if (err) {
343
- // reject(err);
344
- // return;
345
- // }
346
- //
347
- // console.log('----', files)
348
- // // this.res.set('Content-Type', 'application/json');
349
- // // ctx.status = 200;
350
- // // ctx.state = { fields, files };
351
- // // ctx.body = JSON.stringify(ctx.state, null, 2);
352
- // resolve(' ' as any);
353
- // });
354
- // });
355
-
356
- // return new Promise<MultipartData<any>[]>((resolve, reject) => {
357
- //
358
- //
359
- // const contentType = this.req.headers['content-type'];
360
- // const boundary = contentType.split('boundary=')[1];
361
- //
362
- // let body: Uint8Array[] = [];
363
- // this.req.on('data', chunk => body.push(chunk));
364
- // this.req.on('end', async () => {
365
- // const buffer = Buffer.concat(body);
366
- // // Boundary로 파트 분리
367
- // const parts = buffer.toString().split(`--${boundary}`).slice(1, -1);
368
- // let jsonData = {};
369
- // let fileData = null;
370
- //
371
- // for (let part of parts) {
372
- // const [headerPart, ...bodyParts] = part.split('\r\n\r\n');
373
- // const headers = headerPart.split('\r\n').reduce((acc, line) => {
374
- // const [key, value] = line.split(': ').map(s => s.trim().toLowerCase());
375
- // if (key) acc[key] = value;
376
- // return acc;
377
- // }, {});
378
- //
379
- // const content = bodyParts.join('\r\n\r\n').trim();
380
- // const disposition = headers['content-disposition'];
381
- // const name = disposition?.match(/name="([^"]+)"/)?.[1];
382
- // const filename = disposition?.match(/filename="([^"]+)"/)?.[1];
383
- //
384
- // if (filename) {
385
- // // 파일 데이터 (Blob)
386
- // fileData = { filename, contentType: headers['content-type'], data: Buffer.from(content, 'binary') };
387
- // } else if (name) {
388
- // // 텍스트 데이터
389
- // if (name === 'metadata') jsonData = JSON.parse(content);
390
- // }
391
- // }
392
- //
393
- // // 파일 저장
394
- // if (fileData) {
395
- //
396
- //
397
- //
398
- //
399
- // const uploadPath = this.config.option.fileUploadTempPath || os.tmpdir();
400
- // fs.mkdirSync(uploadPath, { recursive: true }); // 폴더가 없으면 생성
401
- // const saveTempPath = `${uploadPath}/${RandomUtils.uuid4()}${fileData.filename}`;
402
- // console.log('saveTempPathsaveTempPath', saveTempPath)
403
- // await fs.promises.writeFile(saveTempPath, fileData.data);
404
- // this.res.writeHead(200, { 'Content-Type': 'application/json' });
405
- // this.res.end(JSON.stringify({ message: '업로드 성공', jsonData, filename: fileData?.filename }));
406
- // // const uploadPath = this.config.option.fileUploadTempPath ;
407
- // // fs.mkdirSync(uploadPath, { recursive: true }); // 폴더가 없으면 생성
408
- // // await fs.writeFile(`${uploadPath}/${fileData.filename}`, fileData.data);
409
- // }
410
- // });
411
- // });
317
+ });
412
318
  }
413
319
 
414
320
  async reqBodyStringData(): Promise<string> {
415
- const data = (await this.reqBodyData()).toString()
321
+ const data = (await this.reqBodyData()).toString();
416
322
  return data;
417
323
  }
418
324
 
@@ -421,14 +327,14 @@ export class RequestResponse {
421
327
  }
422
328
 
423
329
  async reqBodyFormUrlData<T>(): Promise<T> {
424
- const data = (await this.reqBodyStringData())
330
+ const data = await this.reqBodyStringData();
425
331
  const formData = {} as any;
426
332
  Array.from(new URLSearchParams(data).entries()).forEach(([k, v]) => {
427
333
  const target = formData[k];
428
334
  if (Array.isArray(target)) {
429
335
  target.push(v);
430
336
  } else if (typeof target === 'string') {
431
- formData[k] = [target, v]
337
+ formData[k] = [target, v];
432
338
  } else {
433
339
  formData[k] = v;
434
340
  }
@@ -437,20 +343,16 @@ export class RequestResponse {
437
343
  }
438
344
 
439
345
  async reqBodyReqFormUrlBody() {
440
- const data = await this.reqBodyFormUrlData()
346
+ const data = await this.reqBodyFormUrlData();
441
347
  return Object.assign(new ReqFormUrlBody(), data);
442
348
  }
443
349
 
444
350
  async reqBodyReqJsonBody(): Promise<ReqJsonBody> {
445
- const data = (await this.reqBodyStringData());
446
- return Object.assign(new ReqJsonBody(), data ? JSON.parse(data) : {})
351
+ const data = await this.reqBodyStringData();
352
+ return Object.assign(new ReqJsonBody(), data ? JSON.parse(data) : {});
447
353
  }
448
354
 
449
- // reqBodyReqMultipartFormBody(): Promise<ReqMultipartFormBody> {
450
- // return this.reqBodyMultipartFormData().then(it => new ReqMultipartFormBody(it))
451
- // }
452
-
453
- resBodyJsonData<T>(): (T | null) {
355
+ resBodyJsonData<T>(): T | null {
454
356
  const data = ConvertUtils.toString(this.resBodyData());
455
357
  return data ? JSON.parse(data) : null;
456
358
  }
@@ -464,11 +366,11 @@ export class RequestResponse {
464
366
  }
465
367
 
466
368
  reqHeader(key: keyof typeof HttpHeaders | string) {
467
- return this.req.headers[key.toLowerCase()];
369
+ return this.req.headers[(key as string).toLowerCase()];
468
370
  }
469
371
 
470
372
  get reqHost() {
471
- return this.reqHeaderFirst(HttpHeaders.Host)
373
+ return this.reqHeaderFirst(HttpHeaders.Host);
472
374
  }
473
375
 
474
376
  get reqHeaderObj(): ReqHeader {
@@ -480,7 +382,7 @@ export class RequestResponse {
480
382
  }
481
383
 
482
384
  reqHeaderFirst(key: HttpHeadersType | string, defaultValue?: string) {
483
- const header = this.req.headers[key.toLowerCase()];
385
+ const header = this.req.headers[(key as string).toLowerCase()];
484
386
  if (header && Array.isArray(header)) {
485
387
  return header[0] ?? defaultValue;
486
388
  } else {
@@ -497,9 +399,7 @@ export class RequestResponse {
497
399
  }
498
400
 
499
401
  resStatusCode(code?: undefined): number;
500
- // eslint-disable-next-line no-dupe-class-members
501
402
  resStatusCode(code: number | HttpStatus): RequestResponseChain<number>;
502
- // eslint-disable-next-line no-dupe-class-members
503
403
  resStatusCode(code: number | undefined | HttpStatus): number | RequestResponseChain<number> {
504
404
  if (code) {
505
405
  this.res.statusCode = code;
@@ -510,11 +410,11 @@ export class RequestResponse {
510
410
  }
511
411
 
512
412
  resHeader(key: HttpHeadersType | string) {
513
- return this.res.getHeader(key.toLowerCase());
413
+ return this.res.getHeader((key as string).toLowerCase());
514
414
  }
515
415
 
516
416
  resHeaderFirst(key: HttpHeadersType | string, defaultValue?: string) {
517
- const header = this.res.getHeader(key.toLowerCase());
417
+ const header = this.res.getHeader((key as string).toLowerCase());
518
418
  if (header && Array.isArray(header)) {
519
419
  return header[0] ?? defaultValue;
520
420
  } else {
@@ -524,21 +424,22 @@ export class RequestResponse {
524
424
 
525
425
  async reqSession(): Promise<{ [key: string]: any }> {
526
426
  if (this.config.sessionManager) {
527
- return (await this.config.sessionManager.session(this)).dataSet.data;
427
+ const session = await this.config.sessionManager.session(this);
428
+ session.dataSet.data ??= {};
429
+ return session.dataSet.data;
528
430
  } else {
529
431
  return Promise.reject(new Error('Not SessionManager'));
530
432
  }
531
433
  }
532
434
 
533
- reqSessionSet(key: string, value: any): void {
534
- (this.reqSession as any)[key] = value;
435
+ async reqSessionSet(key: string, value: any): Promise<void> {
436
+ const sessionData = await this.reqSession();
437
+ sessionData[key] = value;
535
438
  }
536
439
 
537
- reqSessionGet<T = any>(key: string): T | undefined {
538
- const session = this.reqSession as any;
539
- if (session) {
540
- return session[key] as T;
541
- }
440
+ async reqSessionGet<T = any>(key: string): Promise<T | undefined> {
441
+ const sessionData = await this.reqSession();
442
+ return sessionData[key] as T;
542
443
  }
543
444
 
544
445
  resSetStatusCode(statusCode: number) {
@@ -546,33 +447,25 @@ export class RequestResponse {
546
447
  return this.createRequestResponseChain(this.res.statusCode);
547
448
  }
548
449
 
549
- // resEnd() {
550
- // this.res.end();
551
- // }
552
-
553
- // eslint-disable-next-line no-undef
554
450
  resWrite(chunk: string | Buffer | any, encoding: BufferEncoding = 'utf8') {
555
451
  this.resWriteChunk = chunk;
556
452
  return this.createRequestResponseChain(this.resWriteChunk);
557
453
  }
558
454
 
559
- // eslint-disable-next-line no-undef
560
455
  resWriteJson(chunk: any, encoding: BufferEncoding = 'utf8') {
561
456
  return this.resWrite(JSON.stringify(chunk), encoding);
562
457
  }
563
458
 
564
459
  resSetHeader(key: HttpHeadersType | string, value: string | string[]) {
565
- return this.createRequestResponseChain(this.res.setHeader(key.toLowerCase(), value));
460
+ this.res.setHeader((key as string).toLowerCase(), value);
461
+ return this.createRequestResponseChain();
566
462
  }
567
463
 
568
464
  resAddHeader(key: HttpHeadersType | string, value: string | string[]) {
569
- const existingValue = this.res.getHeader(key.toLowerCase());
570
- const newValue = Array.isArray(existingValue)
571
- ? existingValue.concat(value)
572
- : existingValue
573
- ? [existingValue.toString(), ...[].concat(value)]
574
- : value;
575
- return this.createRequestResponseChain(this.res.setHeader(key.toLowerCase(), newValue));
465
+ const existingValue = this.res.getHeader((key as string).toLowerCase());
466
+ const newValue = Array.isArray(existingValue) ? existingValue.concat(value) : existingValue ? [existingValue.toString(), ...[].concat(value as any)] : value;
467
+ this.res.setHeader((key as string).toLowerCase(), newValue as any);
468
+ return this.createRequestResponseChain();
576
469
  }
577
470
 
578
471
  resSetHeaders(headers: { [key: string]: string | string[] }) {
@@ -581,15 +474,14 @@ export class RequestResponse {
581
474
  }
582
475
 
583
476
  resAddHeaders(headers: { [key: string]: string | string[] }) {
584
- Object.entries(headers).forEach(([key, value]) => this.resAddHeader(key, value));
585
- return this.createRequestResponseChain();
477
+ Object.entries(headers).forEach(([key, value]) => this.resAddHeader(key, value));
478
+ return this.createRequestResponseChain();
586
479
  }
587
480
 
588
- // 마지막 종료될때 타는거.
589
481
  private async resEndChunk() {
590
482
  const encoding = this.reqHeaderFirst(HttpHeaders.AcceptEncoding);
591
483
  let data = this.resWriteChunk;
592
- if (encoding?.includes('gzip')) {
484
+ if (encoding?.includes('gzip') && data) {
593
485
  data = await gzip(data);
594
486
  this.resSetHeader(HttpHeaders.ContentEncoding, 'gzip');
595
487
  }
@@ -598,27 +490,24 @@ export class RequestResponse {
598
490
 
599
491
  async resEnd(chunk?: string | Buffer | Blob | ArrayBuffer | Response) {
600
492
  if (chunk instanceof Response) {
601
- // 헤더를 직접 설정하여 체이닝 오버헤드 제거
602
493
  chunk.headers.forEach((value, key) => {
603
494
  this.res.setHeader(`ORIGIN-${key}`, value);
604
495
  });
605
496
  if (!this.resHeader(HttpHeaders.ContentType)) {
606
497
  const contentType = chunk.headers.get(HttpHeaders.ContentType);
607
- if (contentType) {
608
- this.res.setHeader(HttpHeaders.ContentType, contentType);
609
- }
498
+ if (contentType) this.res.setHeader(HttpHeaders.ContentType, contentType);
610
499
  }
611
500
  this.res.statusCode = chunk.status;
612
501
  this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());
613
502
  } else if (chunk instanceof Blob) {
614
- this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());
615
- if (!this.resHeader(HttpHeaders.ContentType)) {
616
- this.res.setHeader(HttpHeaders.ContentType, chunk.type);
617
- }
503
+ this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());
504
+ if (!this.resHeader(HttpHeaders.ContentType)) {
505
+ this.res.setHeader(HttpHeaders.ContentType, chunk.type);
506
+ }
618
507
  } else if (chunk instanceof ArrayBuffer) {
619
- this.resWriteChunk = Buffer.from(chunk);
508
+ this.resWriteChunk = Buffer.from(chunk);
620
509
  } else {
621
- this.resWriteChunk = chunk ?? this.resWriteChunk;
510
+ this.resWriteChunk = chunk ?? this.resWriteChunk;
622
511
  }
623
512
 
624
513
  if (this.req.readable) {
@@ -629,28 +518,21 @@ export class RequestResponse {
629
518
  }
630
519
  }
631
520
 
632
- // writeContinue(callback?: () => void) {
633
- // this.res.writeContinue(callback);
634
- // return new RequestResponseChain(this.req, this.res);
635
- // }
636
-
637
- // reqWrite(chunk?: any) {
638
- // this.resWriteChunk = chunk;
639
- // // this.res.write(chunk);
640
- // return this.createRequestResponseChain();
641
- // }
642
-
521
+ resRedirect(statusCode: number, location: string) {
522
+ this.res.statusCode = statusCode;
523
+ this.res.setHeader(HttpHeaders.Location, location);
524
+ this.res.end();
525
+ }
643
526
  resWriteHead(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | { [key: string]: string | string[] }) {
644
- return this.createRequestResponseChain(this.res.writeHead(statusCode, headers));
527
+ return this.createRequestResponseChain(this.res.writeHead(statusCode, headers as any));
645
528
  }
646
529
  resWriteHeadEnd(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | { [key: string]: string | string[] }) {
647
- this.createRequestResponseChain(this.res.writeHead(statusCode, headers));
530
+ this.createRequestResponseChain(this.res.writeHead(statusCode, headers as any));
648
531
  this.res.end();
649
532
  }
650
533
 
651
534
  resIsDone() {
652
535
  return this.res.finished || this.res.writableEnded || this.res.headersSent;
653
- // return new RequestResponseChain(this.req, this.res, this.res.finished || this.res.writableEnded);
654
536
  }
655
537
 
656
538
  createRequestResponseChain<T = any>(data?: T) {
@@ -659,24 +541,15 @@ export class RequestResponse {
659
541
  requestResponseChain.reqBodyChunk = this.reqBodyChunk;
660
542
  return requestResponseChain;
661
543
  }
662
-
663
- // res.on("readable", () => {
664
- // console.log('readable???')
665
- // });
666
- // res.on('complete', function (details) {
667
- // var size = details.req.bytes;
668
- // console.log('complete-->', size)
669
- // });
670
- // res.on('finish', function() {
671
- // console.log('finish??');
672
- // });
673
- // res.on('end', () => {
674
- // console.log('end--?')
675
- // });
676
544
  }
677
545
 
678
546
  export class RequestResponseChain<T> extends RequestResponse {
679
- constructor(req: IncomingMessage, res: ServerResponse, config: Config, public result?: T) {
547
+ constructor(
548
+ req: IncomingMessage,
549
+ res: ServerResponse,
550
+ config: Config,
551
+ public result?: T
552
+ ) {
680
553
  super(req, res, config);
681
554
  }
682
- }
555
+ }