Skip to content

Commit 63e3b49

Browse files
authored
Replace depricated url.parse with the WHATWG URL API (#1387)
close #1380
1 parent b620877 commit 63e3b49

4 files changed

Lines changed: 61 additions & 14 deletions

File tree

src/http.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { NtlmClient } from 'axios-ntlm';
88
import { randomUUID } from 'crypto';
99
import debugBuilder from 'debug';
1010
import { ReadStream } from 'fs';
11-
import * as url from 'url';
1211
import { MIMEType } from 'whatwg-mimetype';
1312
import { gzipSync } from 'zlib';
1413
import { IExOptions, IHeaders, IHttpClient, IOptions } from './types';
@@ -24,6 +23,13 @@ export interface IAttachment {
2423
body: NodeJS.ReadableStream;
2524
}
2625

26+
function getPortFromUrl(url: URL): string {
27+
if (url.port) return url.port;
28+
if (url.protocol.toLowerCase() === 'https:') return '443';
29+
if (url.protocol.toLowerCase() === 'http:') return '80';
30+
return '';
31+
}
32+
2733
/**
2834
* A class representing the http client
2935
* @param {Object} [options] Options object. It allows the customization of
@@ -50,18 +56,19 @@ export class HttpClient implements IHttpClient {
5056
* @returns {Object} The http request object for the `request` module
5157
*/
5258
public buildRequest(rurl: string, data: any, exheaders?: IHeaders, exoptions: IExOptions = {}): any {
53-
const curl = url.parse(rurl);
59+
const curl = new URL(rurl);
5460
const method = data ? 'POST' : 'GET';
5561

5662
const host = curl.hostname;
57-
const port = parseInt(curl.port, 10);
63+
64+
const port = getPortFromUrl(curl);
5865
const headers: IHeaders = {
5966
'User-Agent': 'node-soap/' + version,
6067
'Accept': 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8',
6168
'Accept-Encoding': 'none',
6269
'Accept-Charset': 'utf-8',
6370
...(exoptions.forever && { Connection: 'keep-alive' }),
64-
'Host': host + (isNaN(port) ? '' : ':' + port),
71+
'Host': host + (port ? ':' + port : ''),
6572
};
6673
const mergeOptions = ['headers'];
6774

src/server.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55

66
import { EventEmitter } from 'events';
77
import * as http from 'http';
8-
import * as url from 'url';
98
import { IOneWayOptions, IServerOptions, IServerlessRequest, IServerlessResponse, IServices, ISoapFault, ISoapServiceMethod } from './types';
109
import { WSDL } from './wsdl';
1110
import { BindingElement, IPort } from './wsdl/elements';
1211
import zlib from 'zlib';
1312

14-
interface IExpressApp {
13+
interface IExpressApp extends http.Server {
1514
route;
1615
use;
1716
}
1817

1918
export type ServerType = http.Server | IExpressApp;
19+
2020
type Request = http.IncomingMessage & { body?: any };
2121
type Response = http.ServerResponse;
2222

@@ -35,6 +35,32 @@ function getDateString(d) {
3535
return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z';
3636
}
3737

38+
function getServerBaseUrl(server: ServerType): string {
39+
if (!server) {
40+
return `http://localhost:8080`;
41+
}
42+
43+
if (typeof server.address !== 'function') {
44+
return `http://${server.address}`;
45+
}
46+
47+
const address = server.address();
48+
49+
if (address === null) {
50+
return `http://localhost:8080`;
51+
}
52+
53+
if (typeof address === 'string') {
54+
return `http://${address}`;
55+
}
56+
57+
if (address.family.toLowerCase() === 'ipv6') {
58+
return `http://localhost:${address.port}`;
59+
}
60+
61+
return `http://${address.address}:${address.port}`;
62+
}
63+
3864
//eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
3965
export interface Server {
4066
emit(event: 'request', request: any, methodName: string): boolean;
@@ -78,6 +104,7 @@ export class Server extends EventEmitter {
78104
private enableChunkedEncoding: boolean;
79105
private soapHeaders: any[];
80106
private callback?: (err: any, res: any) => void;
107+
private baseUrl: string;
81108

82109
constructor(server: ServerType | null, path: string | RegExp, services: IServices, wsdl: WSDL, options?: IServerOptions) {
83110
super();
@@ -94,6 +121,7 @@ export class Server extends EventEmitter {
94121
this.onewayOptions = (options && options.oneWay) || {};
95122
this.enableChunkedEncoding = options.enableChunkedEncoding === undefined ? true : !!options.enableChunkedEncoding;
96123
this.callback = options.callback ? options.callback : () => {};
124+
this.baseUrl = getServerBaseUrl(server);
97125
if (typeof path === 'string' && path[path.length - 1] !== '/') {
98126
path += '/';
99127
} else if (path instanceof RegExp && path.source[path.source.length - 1] !== '/') {
@@ -127,7 +155,7 @@ export class Server extends EventEmitter {
127155
return;
128156
}
129157
}
130-
let reqPath = url.parse(req.url).pathname;
158+
let reqPath = new URL(req.url, this.baseUrl).pathname;
131159
if (reqPath[reqPath.length - 1] !== '/') {
132160
reqPath += '/';
133161
}
@@ -285,7 +313,7 @@ export class Server extends EventEmitter {
285313
}
286314

287315
private _requestListener(req: Request, res: Response) {
288-
const reqParse = url.parse(req.url);
316+
const reqParse = new URL(req.url, this.baseUrl);
289317
const reqQuery = reqParse.search;
290318

291319
if (typeof this.log === 'function') {
@@ -343,7 +371,7 @@ export class Server extends EventEmitter {
343371
}
344372

345373
private _process(input, req: Request, res: Response, cb: (result: any, statusCode?: number) => any) {
346-
const pathname = url.parse(req.url).pathname.replace(/\/$/, '');
374+
const pathname = new URL(req.url, this.baseUrl).pathname.replace(/\/$/, '');
347375
const obj = this.wsdl.xmlToObject(input);
348376
const body = obj.Body ? obj.Body : obj;
349377
const headers = obj.Header;
@@ -387,7 +415,7 @@ export class Server extends EventEmitter {
387415
for (name in ports) {
388416
portName = name;
389417
const port = ports[portName];
390-
const portPathname = url.parse(port.location).pathname.replace(/\/$/, '');
418+
const portPathname = new URL(port.location, 'http://localhost').pathname.replace(/\/$/, '');
391419

392420
if (typeof this.log === 'function') {
393421
this.log('info', 'Trying ' + portName + ' from path ' + portPathname, req);

src/wsdl/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import * as fs from 'fs';
1111
import { isPlainObject, mergeWith } from '../utils';
1212
import * as path from 'path';
1313
import * as sax from 'sax';
14-
import * as url from 'url';
1514
import { HttpClient } from '../http';
1615
import { NamespaceContext } from '../nscontext';
1716
import { IOptions } from '../types';
@@ -1230,7 +1229,15 @@ export class WSDL {
12301229
includePath = path.resolve(path.dirname(this.uri), include.location);
12311230
}
12321231
} else {
1233-
includePath = url.resolve(this.uri || '', include.location);
1232+
if (/^https?:/i.test(include.location)) {
1233+
includePath = include.location;
1234+
} else {
1235+
try {
1236+
includePath = new URL(include.location, this.uri || '').toString();
1237+
} catch {
1238+
includePath = include.location;
1239+
}
1240+
}
12341241
}
12351242

12361243
const options = Object.assign({}, this.options);

test/client-test.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,13 @@ var fs = require('fs'),
508508
client.MyOperation(
509509
{},
510510
function () {
511-
assert.ok(client.lastRequestHeaders.Host.indexOf(':443') > -1);
512-
done();
511+
try {
512+
assert.ok(client.lastRequestHeaders.Host.indexOf(':443') > -1);
513+
done();
514+
} catch (err) {
515+
done(err);
516+
throw err;
517+
}
513518
},
514519
null,
515520
{ 'test-header': 'test' },

0 commit comments

Comments
 (0)