Skip to content

Commit c7d148c

Browse files
authored
Add proxy support (#518)
1 parent 2aad22f commit c7d148c

File tree

13 files changed

+172
-5
lines changed

13 files changed

+172
-5
lines changed

lib-es5/api_client/execute_request.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ var Q = require('q');
88
var url = require('url');
99
var utils = require("../utils");
1010
var ensureOption = require('../utils/ensureOption').defaults(config());
11+
var ProxyAgent = utils.optionalRequire('proxy-agent');
1112

1213
var extend = utils.extend,
13-
includes = utils.includes;
14+
includes = utils.includes,
15+
isEmpty = utils.isEmpty;
1416

1517

1618
function execute_request(method, params, auth, api_url, callback) {
@@ -56,6 +58,18 @@ function execute_request(method, params, auth, api_url, callback) {
5658
if (options.agent != null) {
5759
request_options.agent = options.agent;
5860
}
61+
62+
var proxy = options.api_proxy || config().api_proxy;
63+
if (!isEmpty(proxy)) {
64+
if (!request_options.agent) {
65+
if (ProxyAgent === null) {
66+
throw new Error("Proxy value is set, but `proxy-agent` is not installed, please install `proxy-agent` module.");
67+
}
68+
request_options.agent = new ProxyAgent(proxy);
69+
} else {
70+
console.warn("Proxy is set, but request uses a custom agent, proxy is ignored.");
71+
}
72+
}
5973
if (method !== "GET") {
6074
request_options.headers['Content-Length'] = Buffer.byteLength(query_params);
6175
}

lib-es5/config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var extend = require("lodash/extend");
1515
var isObject = require("lodash/isObject");
1616
var isString = require("lodash/isString");
1717
var isUndefined = require("lodash/isUndefined");
18+
var isEmpty = require("lodash/isEmpty");
1819
var entries = require('./utils/entries');
1920

2021
var cloudinary_config = void 0;
@@ -117,13 +118,17 @@ module.exports = function (new_config, new_value) {
117118

118119
var CLOUDINARY_ENV_URL = process.env.CLOUDINARY_URL;
119120
var CLOUDINARY_ENV_ACCOUNT_URL = process.env.CLOUDINARY_ACCOUNT_URL;
121+
var CLOUDINARY_API_PROXY = process.env.CLOUDINARY_API_PROXY;
120122

121123
if (CLOUDINARY_ENV_URL && !CLOUDINARY_ENV_URL.toLowerCase().startsWith('cloudinary://')) {
122124
throw new Error("Invalid CLOUDINARY_URL protocol. URL should begin with 'cloudinary://'");
123125
}
124126
if (CLOUDINARY_ENV_ACCOUNT_URL && !CLOUDINARY_ENV_ACCOUNT_URL.toLowerCase().startsWith('account://')) {
125127
throw new Error("Invalid CLOUDINARY_ACCOUNT_URL protocol. URL should begin with 'account://'");
126128
}
129+
if (!isEmpty(CLOUDINARY_API_PROXY)) {
130+
extendCloudinaryConfig({ api_proxy: CLOUDINARY_API_PROXY }, cloudinary_config);
131+
}
127132

128133
[CLOUDINARY_ENV_URL, CLOUDINARY_ENV_ACCOUNT_URL].forEach(function (ENV_URL) {
129134
if (ENV_URL) {

lib-es5/uploader.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ var Cache = require('./cache');
3434
var utils = require("./utils");
3535
var UploadStream = require('./upload_stream');
3636
var config = require("./config");
37+
var ProxyAgent = utils.optionalRequire('proxy-agent');
3738
var ensureOption = require('./utils/ensureOption').defaults(config());
3839

3940
var build_upload_params = utils.build_upload_params,
4041
extend = utils.extend,
4142
includes = utils.includes,
43+
isEmpty = utils.isEmpty,
4244
isObject = utils.isObject,
4345
isRemoteUrl = utils.isRemoteUrl,
4446
merge = utils.merge,
@@ -671,6 +673,18 @@ function post(url, post_data, boundary, file, callback, options) {
671673
if (options.agent != null) {
672674
post_options.agent = options.agent;
673675
}
676+
var proxy = options.api_proxy || config().api_proxy;
677+
if (!isEmpty(proxy)) {
678+
if (!post_options.agent) {
679+
if (ProxyAgent === null) {
680+
throw new Error("Proxy value is set, but `proxy-agent` is not installed, please install `proxy-agent` module.");
681+
}
682+
post_options.agent = new ProxyAgent(proxy);
683+
} else {
684+
console.warn("Proxy is set, but request uses a custom agent, proxy is ignored.");
685+
}
686+
}
687+
674688
var post_request = https.request(post_options, callback);
675689
var upload_stream = new UploadStream({ boundary });
676690
upload_stream.pipe(post_request);

lib-es5/utils/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,19 @@ function jsonArrayParam(data, modifier) {
16331633
return JSON.stringify(data);
16341634
}
16351635

1636+
function optionalRequire(moduleName) {
1637+
var module = void 0;
1638+
try {
1639+
module = require(moduleName);
1640+
return module;
1641+
} catch (e) {
1642+
if (e.code === "MODULE_NOT_FOUND") {
1643+
return null;
1644+
}
1645+
throw e;
1646+
}
1647+
}
1648+
16361649
/**
16371650
* Empty function - do nothing
16381651
*
@@ -1690,6 +1703,7 @@ exports.jsonArrayParam = jsonArrayParam;
16901703
exports.download_folder = download_folder;
16911704
exports.base_api_url = base_api_url;
16921705
exports.download_backedup_asset = download_backedup_asset;
1706+
exports.optionalRequire = optionalRequire;
16931707

16941708
// was exported before, so kept for backwards compatibility
16951709
exports.DEFAULT_POSTER_OPTIONS = DEFAULT_POSTER_OPTIONS;

lib/api_client/execute_request.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ const Q = require('q');
66
const url = require('url');
77
const utils = require("../utils");
88
const ensureOption = require('../utils/ensureOption').defaults(config());
9+
const ProxyAgent = utils.optionalRequire('proxy-agent');
910

10-
const { extend, includes } = utils;
11+
const { extend, includes, isEmpty } = utils;
1112

1213
function execute_request(method, params, auth, api_url, callback, options = {}) {
1314
method = method.toUpperCase();
@@ -49,6 +50,18 @@ function execute_request(method, params, auth, api_url, callback, options = {})
4950
if (options.agent != null) {
5051
request_options.agent = options.agent;
5152
}
53+
54+
let proxy = options.api_proxy || config().api_proxy;
55+
if (!isEmpty(proxy)) {
56+
if (!request_options.agent) {
57+
if (ProxyAgent === null) {
58+
throw new Error("Proxy value is set, but `proxy-agent` is not installed, please install `proxy-agent` module.")
59+
}
60+
request_options.agent = new ProxyAgent(proxy);
61+
} else {
62+
console.warn("Proxy is set, but request uses a custom agent, proxy is ignored.");
63+
}
64+
}
5265
if (method !== "GET") {
5366
request_options.headers['Content-Length'] = Buffer.byteLength(query_params);
5467
}

lib/config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const extend = require("lodash/extend");
1111
const isObject = require("lodash/isObject");
1212
const isString = require("lodash/isString");
1313
const isUndefined = require("lodash/isUndefined");
14+
const isEmpty = require("lodash/isEmpty");
1415
const entries = require('./utils/entries');
1516

1617
let cloudinary_config = void 0;
@@ -95,13 +96,17 @@ module.exports = function (new_config, new_value) {
9596

9697
let CLOUDINARY_ENV_URL = process.env.CLOUDINARY_URL;
9798
let CLOUDINARY_ENV_ACCOUNT_URL = process.env.CLOUDINARY_ACCOUNT_URL;
98-
99+
let CLOUDINARY_API_PROXY = process.env.CLOUDINARY_API_PROXY;
100+
99101
if (CLOUDINARY_ENV_URL && !CLOUDINARY_ENV_URL.toLowerCase().startsWith('cloudinary://')) {
100102
throw new Error("Invalid CLOUDINARY_URL protocol. URL should begin with 'cloudinary://'");
101103
}
102104
if (CLOUDINARY_ENV_ACCOUNT_URL && !CLOUDINARY_ENV_ACCOUNT_URL.toLowerCase().startsWith('account://')) {
103105
throw new Error("Invalid CLOUDINARY_ACCOUNT_URL protocol. URL should begin with 'account://'");
104106
}
107+
if (!isEmpty(CLOUDINARY_API_PROXY)) {
108+
extendCloudinaryConfig({ api_proxy: CLOUDINARY_API_PROXY }, cloudinary_config);
109+
}
105110

106111
[CLOUDINARY_ENV_URL, CLOUDINARY_ENV_ACCOUNT_URL].forEach((ENV_URL) => {
107112
if (ENV_URL) {

lib/uploader.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ const Cache = require('./cache');
1414
const utils = require("./utils");
1515
const UploadStream = require('./upload_stream');
1616
const config = require("./config");
17+
const ProxyAgent = utils.optionalRequire('proxy-agent');
1718
const ensureOption = require('./utils/ensureOption').defaults(config());
1819

1920
const {
2021
build_upload_params,
2122
extend,
2223
includes,
24+
isEmpty,
2325
isObject,
2426
isRemoteUrl,
2527
merge,
@@ -569,6 +571,18 @@ function post(url, post_data, boundary, file, callback, options) {
569571
if (options.agent != null) {
570572
post_options.agent = options.agent;
571573
}
574+
let proxy = options.api_proxy || config().api_proxy;
575+
if (!isEmpty(proxy)) {
576+
if (!post_options.agent) {
577+
if (ProxyAgent === null) {
578+
throw new Error("Proxy value is set, but `proxy-agent` is not installed, please install `proxy-agent` module.")
579+
}
580+
post_options.agent = new ProxyAgent(proxy);
581+
} else {
582+
console.warn("Proxy is set, but request uses a custom agent, proxy is ignored.");
583+
}
584+
}
585+
572586
let post_request = https.request(post_options, callback);
573587
let upload_stream = new UploadStream({ boundary });
574588
upload_stream.pipe(post_request);

lib/utils/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,19 @@ function jsonArrayParam(data, modifier) {
14991499
return JSON.stringify(data);
15001500
}
15011501

1502+
function optionalRequire(moduleName) {
1503+
let module;
1504+
try {
1505+
module = require(moduleName)
1506+
return module;
1507+
} catch (e) {
1508+
if (e.code === "MODULE_NOT_FOUND") {
1509+
return null;
1510+
}
1511+
throw e;
1512+
}
1513+
}
1514+
15021515
/**
15031516
* Empty function - do nothing
15041517
*
@@ -1554,6 +1567,7 @@ exports.jsonArrayParam = jsonArrayParam;
15541567
exports.download_folder = download_folder;
15551568
exports.base_api_url = base_api_url;
15561569
exports.download_backedup_asset = download_backedup_asset;
1570+
exports.optionalRequire = optionalRequire;
15571571

15581572
// was exported before, so kept for backwards compatibility
15591573
exports.DEFAULT_POSTER_OPTIONS = DEFAULT_POSTER_OPTIONS;

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@
6868
"test-es5": "tools/scripts/test.es5.sh",
6969
"docs": "tools/scripts/docs.sh"
7070
},
71-
"optionalDependencies": {},
71+
"optionalDependencies": {
72+
"proxy-agent": "^4.0.1"
73+
},
7274
"engines": {
7375
"node": ">=0.6"
7476
}

test/integration/api/admin/api_spec.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const sinon = require('sinon');
22
const formatDate = require("date-fns").format;
33
const subDate = require("date-fns").sub;
4+
const https = require('https');
5+
const ProxyAgent = require('proxy-agent');
46
const ClientRequest = require('_http_client').ClientRequest;
57
const Q = require('q');
68
const cloudinary = require("../../../../cloudinary");
@@ -124,7 +126,7 @@ describe("api", function () {
124126
]).finally(function () {});
125127
});
126128
after(function () {
127-
var config = cloudinary.config();
129+
var config = cloudinary.config(true);
128130
this.timeout(TIMEOUT.LONG);
129131
if (config.keep_test_products) {
130132
return Promise.resolve();
@@ -1335,4 +1337,29 @@ describe("api", function () {
13351337
expect(resource.access_mode).to.be('public');
13361338
}));
13371339
});
1340+
describe("proxy support", function () {
1341+
const mocked = helper.mockTest();
1342+
it("should support proxy for api calls", function () {
1343+
cloudinary.config({api_proxy: "https://myuser:[email protected]"});
1344+
cloudinary.v2.api.resources({});
1345+
sinon.assert.calledWith(mocked.request, sinon.match(
1346+
arg => arg.agent instanceof ProxyAgent
1347+
));
1348+
});
1349+
it("should prioritize custom agent", function () {
1350+
cloudinary.config({api_proxy: "https://myuser:[email protected]"});
1351+
const custom_agent = https.Agent()
1352+
cloudinary.v2.api.resources({agent: custom_agent});
1353+
sinon.assert.calledWith(mocked.request, sinon.match(
1354+
arg => arg.agent === custom_agent
1355+
));
1356+
});
1357+
it("should support api_proxy as options key", function () {
1358+
cloudinary.config({});
1359+
cloudinary.v2.api.resources({api_proxy: "https://myuser:[email protected]"});
1360+
sinon.assert.calledWith(mocked.request, sinon.match(
1361+
arg => arg.agent instanceof ProxyAgent
1362+
));
1363+
});
1364+
})
13381365
});

0 commit comments

Comments
 (0)