From 8e24a8c97b55bbaaf2c92a496d1cd30b0c008934 Mon Sep 17 00:00:00 2001
From: Alex <alxmorais8@msn.com>
Date: Thu, 20 May 2021 21:38:51 +0200
Subject: [PATCH] fix: UDP url parsing

---
 client.js                 |  2 +-
 lib/client/udp-tracker.js | 15 +--------------
 lib/common.js             | 31 +++++++++++++++++++++++++++++++
 test/client.js            | 24 ++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/client.js b/client.js
index fabbf63f..75bdf26d 100644
--- a/client.js
+++ b/client.js
@@ -86,7 +86,7 @@ class Client extends EventEmitter {
       .map(announceUrl => {
         let parsedUrl
         try {
-          parsedUrl = new URL(announceUrl)
+          parsedUrl = common.parseUrl(announceUrl)
         } catch (err) {
           nextTickWarn(new Error(`Invalid tracker URL: ${announceUrl}`))
           return null
diff --git a/lib/client/udp-tracker.js b/lib/client/udp-tracker.js
index 0f4c0e4f..093ed4c8 100644
--- a/lib/client/udp-tracker.js
+++ b/lib/client/udp-tracker.js
@@ -74,20 +74,7 @@ class UDPTracker extends Tracker {
     const self = this
     if (!opts) opts = {}
 
-    // HACK: Fix for WHATWG URL object not parsing non-standard URL schemes like
-    // 'udp:'. Just replace it with 'http:' since we only need the `hostname`
-    // and `port` properties.
-    //
-    // Note: Only affects Chrome and Firefox. Works fine in Node.js, Safari, and
-    // Edge.
-    //
-    // Note: UDP trackers aren't used in the normal browser build, but they are
-    // used in a Chrome App build (i.e. by Brave Browser).
-    //
-    // Bug reports:
-    // - Chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=734880
-    // - Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1374505
-    let { hostname, port } = new URL(this.announceUrl.replace(/^udp:/, 'http:'))
+    let { hostname, port } = common.parseUrl(this.announceUrl)
     if (port === '') port = 80
 
     let transactionId = genTransactionId()
diff --git a/lib/common.js b/lib/common.js
index 4e0e039f..f6c9f1e5 100644
--- a/lib/common.js
+++ b/lib/common.js
@@ -19,5 +19,36 @@ exports.hexToBinary = function (str) {
   return Buffer.from(str, 'hex').toString('binary')
 }
 
+// HACK: Fix for WHATWG URL object not parsing non-standard URL schemes like
+// 'udp:'. Just replace it with 'http:' since we only need a few properties.
+//
+// Note: Only affects Chrome and Firefox. Works fine in Node.js, Safari, and
+// Edge.
+//
+// Note: UDP trackers aren't used in the normal browser build, but they are
+// used in a Chrome App build (i.e. by Brave Browser).
+//
+// Bug reports:
+// - Chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=734880
+// - Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1374505
+exports.parseUrl = function (str) {
+  const isUDP = str.match(/^udp:/)
+  const parsedUrl = (isUDP) ? new URL(str.replace(/^udp:/, 'http:')) : new URL(str)
+
+  return {
+    hash: parsedUrl.hash,
+    host: parsedUrl.host,
+    hostname: parsedUrl.hostname,
+    href: isUDP ? parsedUrl.href.replace(/^http:/, 'udp:') : parsedUrl.href,
+    origin: isUDP ? parsedUrl.origin.replace(/^http:/, 'udp:') : parsedUrl.origin,
+    password: parsedUrl.password,
+    pathname: parsedUrl.pathname,
+    port: parsedUrl.port,
+    protocol: isUDP ? 'udp:' : parsedUrl.protocol,
+    search: parsedUrl.search,
+    username: parsedUrl.username
+  }
+}
+
 const config = require('./common-node')
 Object.assign(exports, config)
diff --git a/test/client.js b/test/client.js
index 829574d4..c34a27b6 100644
--- a/test/client.js
+++ b/test/client.js
@@ -534,10 +534,34 @@ test('http: invalid tracker port', function (t) {
   testUnsupportedTracker(t, 'http://127.0.0.1:69691337/announce')
 })
 
+test('http: invalid tracker url', function (t) {
+  testUnsupportedTracker(t, 'http:')
+})
+
+test('http: invalid tracker url with slash', function (t) {
+  testUnsupportedTracker(t, 'http://')
+})
+
 test('udp: invalid tracker port', function (t) {
   testUnsupportedTracker(t, 'udp://127.0.0.1:69691337')
 })
 
+test('udp: invalid tracker url', function (t) {
+  testUnsupportedTracker(t, 'udp:')
+})
+
+test('udp: invalid tracker url with slash', function (t) {
+  testUnsupportedTracker(t, 'udp://')
+})
+
 test('ws: invalid tracker port', function (t) {
   testUnsupportedTracker(t, 'ws://127.0.0.1:69691337')
 })
+
+test('ws: invalid tracker url', function (t) {
+  testUnsupportedTracker(t, 'ws:')
+})
+
+test('ws: invalid tracker url with slash', function (t) {
+  testUnsupportedTracker(t, 'ws://')
+})