Skip to content

Commit c9dbc80

Browse files
authored
Merge pull request #7 from neerajshukla1911/reverse-proxy-with-https
Reverse proxy with https support
2 parents cb729b6 + 37e90bb commit c9dbc80

24 files changed

+1323
-485
lines changed

.eslintrc.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ module.exports = {
1616
"indent": ["error", 2],
1717
"linebreak-style": [ "error", "unix"],
1818
"semi": ["error", "always"],
19-
"eol-last": ["error", "always"]
19+
"eol-last": ["error", "always"],
20+
"keyword-spacing": [1],
21+
"no-trailing-spaces": ["error", { "skipBlankLines": true }]
2022
},
2123
"overrides": [{
2224
"files": ["src/requestsDebugger.js", "src/commandLine.js", "test/**/*.test.js"],

.github/workflows/unit-tests.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: 'unit-tests'
2+
on:
3+
pull_request:
4+
paths:
5+
- './**'
6+
- '.github/workflows/unit-tests*'
7+
push:
8+
paths:
9+
- './**'
10+
- '.github/workflows/unit-tests*'
11+
12+
jobs:
13+
unit-tests:
14+
runs-on: ${{ matrix.operating-system }}
15+
strategy:
16+
matrix:
17+
operating-system: [ubuntu-latest, macos-latest]
18+
steps:
19+
- uses: actions/checkout@v2
20+
21+
- name: Set Node.js 4.9.1
22+
uses: actions/setup-node@master
23+
with:
24+
node-version: 4.9.1
25+
26+
- name: npm install
27+
working-directory: ./
28+
run: npm install
29+
30+
- name: Lint and Unit tests
31+
working-directory: ./
32+
run: npm run test

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,9 @@ dist
108108
RequestsDebugger-Mac
109109
RequestsDebugger.exe
110110
RequestsDebugger-Linux*
111+
112+
# VS code settings
113+
.vscode/
114+
115+
# Others
116+
.DS_Store

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
## Requests Debugger
2+
3+
<p align="center">
4+
<a href="https://browserstack.com"><img alt="BrowserStack Logo" src="https://d98b8t1nnulk5.cloudfront.net/production/images/layout/logo-invoice.svg"></a>
5+
</p>
6+
7+
<p align="center">
8+
<a href="https://github.com/browserstack/requests-debugger/actions?query=workflow%3Aunit-tests"><img alt="unit-tests build status" src="https://github.com/browserstack/requests-debugger/workflows/unit-tests/badge.svg"></a>
9+
</p>
10+
211
### Tool for debugging client side failure of requests, leading to requests getting dropped or not reaching BrowserStack.
312

413
## Features
5-
- Proxy Server to intercept requests fired by client bindings to keep track of their flow.
14+
- Server to intercept requests fired by client bindings to keep track of their flow.
615
- Connectivity Checker : To check for the reachability of BrowserStack components, i.e. Rails & Hub.
716
- Multi-Platform Stats Compatibility : Ability to collect stats of CPU, Network & Memory Stats.
817
- Retry Mechanism in case a request fails at the client side
@@ -13,6 +22,8 @@
1322
- Start Requests Debugger with the required arguments: `npm run start -- <args>`.
1423
- Supported `args`:
1524
- `--port <port>`: Port on which the Requests Debugger Tool's Proxy will run. Default: 9687
25+
- `--reverse-proxy-port <port>`: Port on which the Requests Debugger Tool's Reverse Proxy will run. Default: 9688
26+
- `--scheme <https/http>`: Scheme for requests to browserstack. Default: https
1627
- `--proxy-host <hostname>`: Hostname of the Upstream Proxy
1728
- `--proxy-port <port>`: Port of the Upstream Proxy. Default: 3128 (if hostname is provided)
1829
- `--proxy-user <username>`: Username for auth of the Upstream Proxy
@@ -30,7 +41,8 @@
3041
- Windows: `RequestsDebugger.exe <args>`
3142

3243
## How to use
33-
- Since the tool acts like a proxy, you will have to set the proxy to be used by your client binding to `localhost:9687`. i.e.
44+
- To use tool as reverse proxy, you will have to replace `hub-cloud.browserstack.com` in hub url with `localhost:9688`.
45+
- To use tool as a proxy, you will have to set the proxy to be used by your client binding to `localhost:9687`. i.e.
3446
- For Java:
3547
- ```
3648
System.getProperties().put("http.proxyHost", "localhost");
@@ -40,7 +52,7 @@
4052
- Set your system's env variable `http_proxy=localhost:9687` and Ruby's Selenium Client Binding will pick the value. Or,
4153
- Run you test by giving the environment variable to your command itself, i.e. `http_proxy=localhost:9687 ruby <your_script.rb>`
4254
- Similarly, you can also set proxy for other client bindings.
43-
55+
4456
## Steps to build the executables
4557
- Linux
4658
- `npm run build:linux`

config/constants.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
module.exports.VERSION = '1.0.0';
2-
module.exports.HUB_STATUS_URL = 'http://hub-cloud.browserstack.com/wd/hub/status';
3-
module.exports.RAILS_AUTOMATE = 'http://automate.browserstack.com';
1+
module.exports.VERSION = '1.1.0';
2+
module.exports.BS_DOMAIN = 'browserstack.com';
3+
module.exports.HUB_HOST = 'hub-cloud.' + this.BS_DOMAIN;
4+
module.exports.RAILS_HOST = 'automate.' + this.BS_DOMAIN;
5+
module.exports.HUB_STATUS_PATH = '/wd/hub/status';
6+
module.exports.HUB_STATUS_URL = 'http://' + this.HUB_HOST + this.HUB_STATUS_PATH;
7+
module.exports.HUB_STATUS_URL_HTTPS = 'https://' + this.HUB_HOST + this.HUB_STATUS_PATH;
8+
module.exports.RAILS_AUTOMATE = 'http://' + this.RAILS_HOST;
9+
module.exports.RAILS_AUTOMATE_HTTPS = 'https://' + this.RAILS_HOST;
410
module.exports.CONNECTIVITY_REQ_TIMEOUT = 30000;
511
module.exports.DEFAULT_PROXY_PORT = 3128;
612
module.exports.CUSTOM_ERROR_RESPONSE_CODE = 502;
@@ -10,6 +16,8 @@ module.exports.PORTS = {
1016
MAX: 65535,
1117
MIN: 1
1218
};
19+
20+
module.exports.LINE_LENGTH = 70;
1321
module.exports.PROTOCOL_REGEX = /(^\w+:|^)\/\//;
1422

1523
module.exports.LOGS = Object.freeze({
@@ -23,13 +31,15 @@ module.exports.LOGS = Object.freeze({
2331

2432
module.exports.RdGlobalConfig = {
2533
RETRY_DELAY: 1000, // in ms
26-
RD_HANDLER_PORT: process.env.NODE_ENV === 'test' ? 8787 : 9687,
34+
RD_HANDLER_PROXY_PORT: process.env.NODE_ENV === 'test' ? 8787 : 9687,
35+
RD_HANDLER_REVERSE_PROXY_PORT: process.env.NODE_ENV === 'test' ? 8788 : 9688,
2736
CLIENT_REQ_TIMEOUT: 260000, // in ms
37+
SCHEME: 'https'
2838
};
2939

3040
module.exports.COMMON = Object.freeze({
31-
PING_HUB: 'ping -c 5 hub-cloud.browserstack.com',
32-
PING_AUTOMATE: 'ping -c 5 automate.browserstack.com'
41+
PING_HUB: 'ping -c 5 ' + this.HUB_HOST,
42+
PING_AUTOMATE: 'ping -c 5 ' + this.RAILS_HOST
3343
});
3444

3545
module.exports.MAC = Object.freeze({
@@ -49,8 +59,8 @@ module.exports.WIN = Object.freeze({
4959
NETSTAT_ROUTING_TABLE: 'netstat -r',
5060
IPCONFIG_ALL: 'ipconfig /all',
5161
SWAP_USAGE: 'pagefile get AllocatedBaseSize, CurrentUsage', // this is a WMIC command. Prefix with WMIC Path
52-
PING_HUB: 'ping -n 5 hub-cloud.browserstack.com',
53-
PING_AUTOMATE: 'ping -n 5 automate.browserstack.com',
62+
PING_HUB: 'ping -n 5 ' + this.HUB_HOST,
63+
PING_AUTOMATE: 'ping -n 5 ' + this.RAILS_HOST,
5464
LOAD_PERCENTAGE: 'cpu get loadpercentage', // prefix wmic path
5565
});
5666

@@ -78,8 +88,10 @@ module.exports.STATIC_MESSAGES = Object.freeze({
7888
CHECK_NETWORK_STATS: 'Stats : Checking Network Stats',
7989
CHECK_MEMORY_STATS: 'Stats : Checking Memory Stats',
8090
CHECK_CONNECTIVITY: 'Checks : Checking Connectivity With BrowserStack',
81-
ERR_STARTING_TOOL: 'Error in starting Requests Debugger Tool Proxy: ',
82-
TOOL_STARTED_ON_PORT: 'Requests Debugger Tool Proxy Started on Port: ',
91+
ERR_STARTING_TOOL_PROXY: 'Error in starting Requests Debugger Tool Proxy: ',
92+
ERR_STARTING_TOOL_REVERSE_PROXY: 'Error in starting Requests Debugger Tool Reverse Proxy: ',
93+
TOOL_PROXY_STARTED_ON_PORT: 'Requests Debugger Tool Proxy Server Started on Port: ',
94+
TOOL_REVESE_PROXY_STARTED_ON_PORT: 'Requests Debugger Tool Reverse Proxy Server Started on Port: ',
8395
CPU_STATS_COLLECTED: 'Stats : Initial CPU Stats Collected',
8496
NETWORK_STATS_COLLECTED: 'Stats : Initial Network Stats Collected',
8597
MEMORY_STATS_COLLECTED: 'Stats : Initial Memory Stats Collected',

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"start": "NODE_ENV=prod node src/requestsDebugger.js",
88
"lint": "./node_modules/.bin/eslint 'src/*' 'test/*' 'config/*.js'",
9-
"test": "npm run lint; NODE_ENV=test nyc --reporter=html ./node_modules/mocha/bin/mocha 'test/**/*.test.js'",
9+
"test": "npm run lint; NODE_ENV=test ./node_modules/nyc/bin/nyc.js --reporter=html ./node_modules/mocha/bin/mocha 'test/**/*.test.js'",
1010
"build:mac": "npm install; ./node_modules/pkg/lib-es5/bin.js -t node4-macos-x64 src/requestsDebugger.js; mv requestsDebugger RequestsDebugger-Mac",
1111
"build:linux-x86": "npm install; ./node_modules/pkg/lib-es5/bin.js -t node4-linux-x86 src/requestsDebugger.js; mv requestsDebugger RequestsDebugger-Linux-x86",
1212
"build:linux-x64": "npm install; ./node_modules/pkg/lib-es5/bin.js -t node4-linux-x64 src/requestsDebugger.js; mv requestsDebugger RequestsDebugger-Linux-x64",
@@ -34,6 +34,8 @@
3434
"sinon": "7.5.0"
3535
},
3636
"dependencies": {
37+
"http-proxy-agent": "^2.1.0",
38+
"https-proxy-agent": "^2.1.0",
3739
"uuid": "3.4.0",
3840
"winston": "2.4.4"
3941
},

src/commandLine.js

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
* Command Line Manager to parse the command line arguments
33
* and set the necessary fields in RdGlobalConfig.
44
*/
5-
65
var constants = require('../config/constants');
6+
77
var RdGlobalConfig = constants.RdGlobalConfig;
88

99
var CommandLineManager = {
@@ -13,21 +13,25 @@ var CommandLineManager = {
1313
+ "\n"
1414
+ "Usage: RequestsDebugger [ARGUMENTS]\n\n"
1515
+ "ARGUMENTS:\n"
16-
+ " --port <port> : Port on which the Requests Debugger Tool's Proxy will run\n"
17-
+ " Default: " + RdGlobalConfig.RD_HANDLER_PORT + "\n"
18-
+ " --proxy-host <hostname> : Hostname of the Upstream Proxy\n"
19-
+ " --proxy-port <port> : Port of the Upstream Proxy. Default: " + constants.DEFAULT_PROXY_PORT + " (if hostname is provided)\n"
20-
+ " --proxy-user <username> : Username for auth of the Upstream Proxy\n"
21-
+ " --proxy-pass <password> : Password for auth of the Upstream Proxy\n"
22-
+ " --retry-delay <milliseconds> : Delay for the retry of a failed request. Default: " + RdGlobalConfig.RETRY_DELAY + "ms\n"
23-
+ " --request-timeout <milliseconds> : Hard timeout for the requests being fired by the tool before receiving any response\n"
24-
+ " Default: " + RdGlobalConfig.CLIENT_REQ_TIMEOUT + "ms\n"
25-
+ " --logs-path <relative/absolute path> : Directory where the '" + constants.LOGS_FOLDER + "' folder will be created\n"
26-
+ " for storing logs. Default: Current Working Directory\n"
27-
+ " --del-logs : Deletes any existing logs from the " + constants.LOGS_FOLDER + "/ directory and initializes\n"
28-
+ " new files for logging\n"
29-
+ " --help : Help for Requests Debugger Tool\n"
30-
+ " --version : Version of the Requests Debugger Tool\n";
16+
+ " --proxy-port <port> : Port on which the Requests Debugger Tool's Proxy will run\n"
17+
+ " Default: " + RdGlobalConfig.RD_HANDLER_PROXY_PORT + "\n"
18+
+ " --reverse-proxy-port <port> : Port on which the Requests Debugger Tool's Reverse Proxy will run\n"
19+
+ " Default: " + RdGlobalConfig.RD_HANDLER_REVERSE_PROXY_PORT + "\n"
20+
+ " --scheme <https/http> : Scheme for requests to browserstack.\n"
21+
+ " Default: " + RdGlobalConfig.SCHEME + "\n"
22+
+ " --proxy-host <hostname> : Hostname of the Upstream Proxy\n"
23+
+ " --proxy-port <port> : Port of the Upstream Proxy. Default: " + constants.DEFAULT_PROXY_PORT + " (if hostname is provided)\n"
24+
+ " --proxy-user <username> : Username for auth of the Upstream Proxy\n"
25+
+ " --proxy-pass <password> : Password for auth of the Upstream Proxy\n"
26+
+ " --retry-delay <milliseconds> : Delay for the retry of a failed request. Default: " + RdGlobalConfig.RETRY_DELAY + "ms\n"
27+
+ " --request-timeout <milliseconds> : Hard timeout for the requests being fired by the tool before receiving any response\n"
28+
+ " Default: " + RdGlobalConfig.CLIENT_REQ_TIMEOUT + "ms\n"
29+
+ " --logs-path <relative/absolute path> : Directory where the '" + constants.LOGS_FOLDER + "' folder will be created\n"
30+
+ " for storing logs. Default: Current Working Directory\n"
31+
+ " --del-logs : Deletes any existing logs from the " + constants.LOGS_FOLDER + "/ directory and initializes\n"
32+
+ " new files for logging\n"
33+
+ " --help : Help for Requests Debugger Tool\n"
34+
+ " --version : Version of the Requests Debugger Tool\n";
3135

3236
console.log(helpOutput);
3337
},
@@ -38,7 +42,7 @@ var CommandLineManager = {
3842

3943
/**
4044
* Processes the args from the given input array and sets the global config.
41-
* @param {Array<String>} argv
45+
* @param {Array<String>} argv
4246
*/
4347
processArgs: function (argv) {
4448

@@ -67,7 +71,7 @@ var CommandLineManager = {
6771
if (CommandLineManager.validArgValue(argv[index + 1])) {
6872
var probablePort = parseInt(argv[index + 1]);
6973
if (!isNaN(probablePort) && (probablePort <= constants.PORTS.MAX) && (probablePort >= constants.PORTS.MIN)) {
70-
RdGlobalConfig.RD_HANDLER_PORT = probablePort;
74+
RdGlobalConfig.RD_HANDLER_PROXY_PORT = probablePort;
7175
} else {
7276
console.log("\nPort can only range from:", constants.PORTS.MIN, "to:", constants.PORTS.MAX);
7377
invalidArgs.add('--port');
@@ -79,6 +83,24 @@ var CommandLineManager = {
7983
}
8084
}
8185

86+
// port for Requests Debugger Reverse Proxy
87+
index = argv.indexOf('--reverse-proxy-port');
88+
if (index !== -1) {
89+
if (CommandLineManager.validArgValue(argv[index + 1])) {
90+
var probableReverseProxyPort = parseInt(argv[index + 1]);
91+
if (!isNaN(probableReverseProxyPort) && (probableReverseProxyPort <= constants.PORTS.MAX) && (probableReverseProxyPort >= constants.PORTS.MIN)) {
92+
RdGlobalConfig.RD_HANDLER_REVERSE_PROXY_PORT = probableReverseProxyPort;
93+
} else {
94+
console.log("\nPort can only range from:", constants.PORTS.MIN, "to:", constants.PORTS.MAX);
95+
invalidArgs.add('--reverse-proxy-port');
96+
}
97+
argv.splice(index, 2);
98+
} else {
99+
invalidArgs.add('--reverse-proxy-port');
100+
argv.splice(index, 1);
101+
}
102+
}
103+
82104
// delay for retries in case of request failures
83105
index = argv.indexOf('--retry-delay');
84106
if (index !== -1) {
@@ -115,12 +137,34 @@ var CommandLineManager = {
115137
}
116138
}
117139

140+
// process proxy host
141+
index = argv.indexOf('--scheme');
142+
if (index !== -1) {
143+
if (CommandLineManager.validArgValue(argv[index + 1])) {
144+
var scheme = argv[index + 1];
145+
if (!(scheme === 'http' || scheme === 'https')){
146+
console.log("\nScheme can only be http/https");
147+
invalidArgs.add('--scheme');
148+
argv.splice(index, 2);
149+
}
150+
else {
151+
RdGlobalConfig.SCHEME = scheme;
152+
argv.splice(index, 2);
153+
}
154+
} else {
155+
invalidArgs.add('--scheme');
156+
argv.splice(index, 1);
157+
}
158+
}
159+
118160
// process proxy host
119161
index = argv.indexOf('--proxy-host');
120162
if (index !== -1) {
121163
if (CommandLineManager.validArgValue(argv[index + 1])) {
122164
var host = argv[index + 1];
123-
host = host.replace(constants.PROTOCOL_REGEX, '');
165+
if (host.lastIndexOf("http") !== 0){
166+
host = 'http://' + host;
167+
}
124168
RdGlobalConfig.proxy = RdGlobalConfig.proxy || {};
125169
RdGlobalConfig.proxy.host = host;
126170
argv.splice(index, 2);
@@ -151,7 +195,7 @@ var CommandLineManager = {
151195
argv.splice(index, 1);
152196
}
153197
}
154-
198+
155199
// if proxy port value in invalid or doesn't exist and host exists, set the default value
156200
if (RdGlobalConfig.proxy && RdGlobalConfig.proxy.host && (invalidArgs.has('--proxy-port') || !RdGlobalConfig.proxy.port)) {
157201
console.log('\nSetting Default Proxy Port:', constants.DEFAULT_PROXY_PORT, '\n');
@@ -190,7 +234,7 @@ var CommandLineManager = {
190234
argv.splice(index, 1);
191235
}
192236
}
193-
237+
194238
// if proxy pass is invalid or doesn't exist and username exists, set the password as empty
195239
if (RdGlobalConfig.proxy && RdGlobalConfig.proxy.username && (invalidArgs.has('--proxy-pass') || !RdGlobalConfig.proxy.password)) {
196240
console.log('Setting Proxy Password as Empty\n');

0 commit comments

Comments
 (0)