Skip to content

Commit 286925c

Browse files
committed
wip fixing test suite
1 parent c09c42c commit 286925c

File tree

4 files changed

+140
-199
lines changed

4 files changed

+140
-199
lines changed

src/Application.ts

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -41,103 +41,19 @@ export class Application extends EventEmitter implements express.Application {
4141

4242
protected init() {
4343
this.uWSApp.any("/*", async (uwsResponse, uwsRequest) => {
44-
const url = uwsRequest.getUrl();
45-
4644
const req = new IncomingMessage(uwsRequest, uwsResponse, [], this);
4745
const res = new ServerResponse(uwsResponse, req, this);
4846

4947
uwsResponse.onAborted(onAbort.bind(undefined, req, res));
5048

51-
// read body data!
52-
if (req.headers['content-length']) {
53-
try {
54-
await req['readBody']();
55-
} catch (e) {
56-
console.warn("uWebSockets-express: failed reading request body at", url);
57-
}
58-
}
49+
// read body data first!
50+
await req._readBody();
5951

52+
// @ts-ignore
6053
this.handle(req, res);
6154
});
6255
}
6356

64-
// public engine(ext: string, fn: EngineCallback) {
65-
// application.engine.apply(this, arguments);
66-
// }
67-
68-
// public set(setting, val) {
69-
// return application.set.apply(this, arguments);
70-
// }
71-
72-
// public enable(setting: string) {
73-
// return application.enable.call(this, setting);
74-
// }
75-
76-
// public enabled(setting: string) {
77-
// return application.enabled.call(this, setting);
78-
// }
79-
80-
// public render(name: string, options: any, callback: RenderCallback) {
81-
// return application.render.apply(this, arguments);
82-
// }
83-
84-
// public use(handler: RequestHandler)
85-
// public use(path: string, handler: RequestHandler)
86-
// public use(path: string, router: express.Router)
87-
// public use(path: string, ...handlers: Array<express.Router | RequestHandler>)
88-
// public use(path: string, any: any)
89-
// public use(any: any)
90-
// public use(pathOrHandler: string | RequestHandler, ...handlersOrRouters: Array<RequestHandler | express.Router>) {
91-
// express.application.use.apply(this, arguments);
92-
// return this;
93-
// }
94-
95-
// public get(path: string, ...handlers: RequestHandler[]) {
96-
// return express.application.get.apply(this, arguments);
97-
// }
98-
99-
// public post(path: string, ...handlers: RequestHandler[]) {
100-
// express.application.post.apply(this, arguments);
101-
// return this;
102-
// }
103-
104-
// public patch(path: string, ...handlers: RequestHandler[]) {
105-
// express.application.patch.apply(this, arguments);
106-
// return this;
107-
// }
108-
109-
// public options(path: string, ...handlers: RequestHandler[]) {
110-
// express.application.options.apply(this, arguments);
111-
// return this;
112-
// }
113-
114-
// public put(path: string, ...handlers: RequestHandler[]) {
115-
// express.application.put.apply(this, arguments);
116-
// return this;
117-
// }
118-
119-
// /**
120-
// * @deprecated
121-
// */
122-
// public del(path: string, ...handlers: RequestHandler[]) {
123-
// return this.delete.apply(this, arguments);
124-
// }
125-
126-
// public delete(path: string, ...handlers: RequestHandler[]) {
127-
// express.application.delete.apply(this, arguments);
128-
// return this;
129-
// }
130-
131-
// public head(path: string, ...handlers: RequestHandler[]) {
132-
// express.application.head.apply(this, arguments);
133-
// return this;
134-
// }
135-
136-
// public all(path: string, ...handlers: RequestHandler[]) {
137-
// express.application.all.apply(this, arguments);
138-
// return this;
139-
// }
140-
14157
// @ts-ignore
14258
public listen(port?: number, cb?: () => void) {
14359
this.uWSApp.listen(port, (listenSocket: any) => {

src/IncomingMessage.ts

Lines changed: 68 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,20 @@ export class IncomingMessage extends EventEmitter implements http.IncomingMessag
1313
public method: string;
1414

1515
// public query: querystring.ParsedUrlQuery;
16+
public headers: http.IncomingHttpHeaders = {};
17+
public body: any;
18+
public finished: boolean = false;
1619

1720
// private _url: string;
1821
// private _path: string;
1922
private _baseUrl: string = "";
2023
private _rawquery: string;
2124
private _query: querystring.ParsedUrlQuery;
22-
private _headers: http.IncomingHttpHeaders = {};
2325
private _params: {[name: string]: string};
24-
private _bodydata: any;
25-
private _rawbody: any;
2626
private _remoteAddress: ArrayBuffer;
2727
private _readableState = { pipes: [] };
2828
private _readBodyMaxTime = 500;
29+
private _rawbody?: Buffer;
2930

3031
public aborted: boolean;
3132

@@ -42,14 +43,11 @@ export class IncomingMessage extends EventEmitter implements http.IncomingMessag
4243
) {
4344
super();
4445

45-
this._headers = {};
4646
this.req.forEach((key, value) => {
47-
this._headers[key] = value;
47+
this.headers[key] = value;
4848

4949
// workaround: also consider 'referrer'
50-
if (key === "referer") {
51-
this._headers['referrer'] = value;
52-
}
50+
if (key === "referer") { this.headers['referrer'] = value; }
5351
});
5452

5553
this.url = this.req.getUrl();
@@ -67,58 +65,66 @@ export class IncomingMessage extends EventEmitter implements http.IncomingMessag
6765
if (this.app.opts?.readBodyMaxTime) {
6866
this._readBodyMaxTime = this.app.opts.readBodyMaxTime;
6967
}
70-
}
71-
72-
get ip () {
73-
return Buffer.from(this._remoteAddress).toString();
74-
}
7568

76-
set body (_body: any) {
77-
this._bodydata = _body;
78-
}
69+
// Define getters as own properties to prevent Express from shadowing them
70+
// This ensures the getters are called even if Express tries to set them as properties
7971

80-
get body () {
81-
return this._bodydata || this._rawbody?.toString();
82-
}
83-
84-
get headers (): http.IncomingHttpHeaders {
85-
return this._headers;
86-
}
87-
88-
set params (value) {
89-
this._params = value;
90-
}
91-
92-
get params(): { [name: string]: string } {
93-
if (!this._params) {
94-
this._params = {};
95-
for (let i = 0; i < this.parameterNames.length; i++) {
96-
const paramName = this.parameterNames[i];
97-
this._params[paramName] = this.req.getParameter(i);
98-
}
99-
}
100-
101-
return this._params;
102-
}
72+
Object.defineProperty(this, 'ip', {
73+
get: () => {
74+
return Buffer.from(this._remoteAddress).toString();
75+
},
76+
enumerable: true,
77+
configurable: true
78+
});
10379

104-
get query (): querystring.ParsedUrlQuery {
105-
if(!this._query) this._query = querystring.parse(this._rawquery);
106-
return this._query;
107-
}
80+
Object.defineProperty(this, 'params', {
81+
get: (): { [name: string]: string } => {
82+
if (!this._params) {
83+
this._params = {};
84+
for (let i = 0; i < this.parameterNames.length; i++) {
85+
const paramName = this.parameterNames[i];
86+
this._params[paramName] = this.req.getParameter(i);
87+
}
88+
}
89+
return this._params;
90+
},
91+
set: (value) => {
92+
this._params = value;
93+
},
94+
enumerable: true,
95+
configurable: true
96+
});
10897

109-
get baseUrl() {
110-
return this._baseUrl;
111-
}
98+
Object.defineProperty(this, 'query', {
99+
get: (): querystring.ParsedUrlQuery => {
100+
if(!this._query) this._query = querystring.parse(this._rawquery);
101+
return this._query;
102+
},
103+
enumerable: true,
104+
configurable: true
105+
});
112106

113-
set baseUrl(baseUrl) {
114-
this._baseUrl = baseUrl;
115-
}
107+
Object.defineProperty(this, 'baseUrl', {
108+
get: () => {
109+
return this._baseUrl;
110+
},
111+
set: (baseUrl) => {
112+
this._baseUrl = baseUrl;
113+
},
114+
enumerable: true,
115+
configurable: true
116+
});
116117

117-
get path(): string {
118-
const path = this.#_originalUrlParsed.pathname.replace(this._baseUrl, "");
119-
return (!path.startsWith("/"))
120-
? `/${path}`
121-
: path;
118+
Object.defineProperty(this, 'path', {
119+
get: (): string => {
120+
const path = this.#_originalUrlParsed.pathname.replace(this._baseUrl, "");
121+
return (!path.startsWith("/"))
122+
? `/${path}`
123+
: path;
124+
},
125+
enumerable: true,
126+
configurable: true
127+
});
122128
}
123129

124130
get(name: string) {
@@ -127,7 +133,7 @@ export class IncomingMessage extends EventEmitter implements http.IncomingMessag
127133

128134
header(name: string) {
129135
name = name.toLowerCase();
130-
return this._headers[name] || undefined;
136+
return this.headers[name] || undefined;
131137
}
132138

133139
accepts(...args: any[]): string | false {
@@ -153,7 +159,7 @@ export class IncomingMessage extends EventEmitter implements http.IncomingMessag
153159
return this;
154160
}
155161

156-
protected readBody () {
162+
public _readBody () {
157163
return new Promise<boolean>((resolve, reject) => {
158164
let body: Buffer;
159165

@@ -162,23 +168,25 @@ export class IncomingMessage extends EventEmitter implements http.IncomingMessag
162168
// https://github.com/endel/uWebSockets-express/issues/9
163169
//
164170
const rejectionTimeout = setTimeout(() => {
165-
if (body) {
166-
this._rawbody = body;
167-
this.headers['content-length'] = String(body.length);
168-
}
171+
this.emit('error');
169172
reject();
170173
}, this._readBodyMaxTime);
171174

172175
this.res.onData((arrayBuffer, isLast) => {
176+
this.emit('data', new Uint8Array(arrayBuffer));
177+
173178
const chunk = Buffer.from(arrayBuffer);
174179
body = (body && body.length !== 0) ? Buffer.concat([body, chunk]) : Buffer.concat([chunk]);
175180

176181
if (isLast) {
177182
clearTimeout(rejectionTimeout);
178183
this._rawbody = body;
184+
this.body = body.toString('utf8');
185+
this.emit('end');
179186
resolve(body.length > 0);
180187
}
181188
});
189+
182190
})
183191
}
184192

src/ServerResponse.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class ServerResponse extends OutgoingMessage {
7171
return this;
7272
}
7373

74-
this.setHeader = (name: string, value: string) => {
74+
this.setHeader = (name: string, value: string | string[]) => {
7575
let headers = this[kOutHeaders];
7676

7777
if (!headers) {
@@ -88,6 +88,27 @@ export class ServerResponse extends OutgoingMessage {
8888
return this;
8989
}
9090

91+
// Override hasHeader to work with our lowercase header storage
92+
this.hasHeader = (name: string) => {
93+
const headers = this[kOutHeaders];
94+
if (!headers) return false;
95+
return name.toLowerCase() in headers;
96+
}
97+
98+
// Override getHeader to work with our lowercase header storage
99+
this.getHeader = (name: string) => {
100+
const headers = this[kOutHeaders];
101+
if (!headers) return undefined;
102+
return headers[name.toLowerCase()];
103+
}
104+
105+
// Override removeHeader to work with our lowercase header storage
106+
this.removeHeader = (name: string) => {
107+
const headers = this[kOutHeaders];
108+
if (!headers) return;
109+
delete headers[name.toLowerCase()];
110+
}
111+
91112
// @ts-ignore
92113
this.writeHead = (code: number, headers: { [name: string]: string | string[] } = this[kOutHeaders]) => {
93114
if (this._headerSent) {
@@ -102,9 +123,8 @@ export class ServerResponse extends OutgoingMessage {
102123
// write headers
103124
for (const name in headers) {
104125
if (Array.isArray(headers[name])) {
105-
for (const headerValue of headers[name]) {
106-
this.res.writeHeader(name, headerValue?.toString());
107-
}
126+
// Join array values with comma and space (RFC 7230)
127+
this.res.writeHeader(name, headers[name].map(v => v?.toString()).join(', '));
108128
} else {
109129
this.res.writeHeader(name, headers[name]?.toString());
110130
}

0 commit comments

Comments
 (0)