Skip to content

Commit

Permalink
Add support for extra_headers option in Upload and Admin API
Browse files Browse the repository at this point in the history
  • Loading branch information
rnamba-cloudinary authored Apr 2, 2023
1 parent 7af5e33 commit 78b18d4
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 4 deletions.
5 changes: 4 additions & 1 deletion cloudinary/api_client/call_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def call_api(method, uri, params, **options):
return _call_api(method, uri, params=params, **options)


def _call_api(method, uri, params=None, body=None, headers=None, **options):
def _call_api(method, uri, params=None, body=None, headers=None, extra_headers=None, **options):
prefix = options.pop("upload_prefix",
cloudinary.config().upload_prefix) or "https://api.cloudinary.com"
cloud_name = options.pop("cloud_name", cloudinary.config().cloud_name)
Expand All @@ -50,6 +50,9 @@ def _call_api(method, uri, params=None, body=None, headers=None, **options):
if body is not None:
options["body"] = body

if extra_headers is not None:
headers.update(extra_headers)

return execute_request(http_connector=_http,
method=method,
params=params,
Expand Down
6 changes: 5 additions & 1 deletion cloudinary/uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,14 +472,18 @@ def call_cacheable_api(action, params, http_headers=None, return_error=False, un
return result


def call_api(action, params, http_headers=None, return_error=False, unsigned=False, file=None, timeout=None, **options):
def call_api(action, params, http_headers=None, return_error=False, unsigned=False, file=None, timeout=None,
extra_headers=None, **options):
params = utils.cleanup_params(params)

headers = {"User-Agent": cloudinary.get_user_agent()}

if http_headers is not None:
headers.update(http_headers)

if extra_headers is not None:
headers.update(extra_headers)

oauth_token = options.get("oauth_token", cloudinary.config().oauth_token)

if oauth_token:
Expand Down
15 changes: 14 additions & 1 deletion test/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import cloudinary
from cloudinary import api, uploader, utils
from cloudinary.utils import fq_public_id
from test.helper_test import SUFFIX, TEST_IMAGE, get_uri, get_params, get_list_param, get_param, TEST_DOC, get_method, \
from test.helper_test import SUFFIX, TEST_IMAGE, get_uri, get_headers, get_params, get_list_param, get_param, TEST_DOC, get_method, \
UNIQUE_TAG, api_response_mock, ignore_exception, cleanup_test_resources_by_tag, cleanup_test_transformation, \
cleanup_test_resources, UNIQUE_TEST_FOLDER, EVAL_STR, get_json_body
from cloudinary.exceptions import BadRequest, NotFound
Expand Down Expand Up @@ -284,6 +284,19 @@ def test06b_resources_direction(self, mocker):
self.assertTrue(get_uri(args).endswith('/resources/image/tags/{}'.format(API_TEST_TAG)))
self.assertEqual(get_params(args)['direction'], 'desc')

@patch('urllib3.request.RequestMethods.request')
@unittest.skipUnless(cloudinary.config().api_secret, "requires api_key/api_secret")
def test_extra_headers(self, mocker):
"""Should support extra headers"""
mocker.return_value = MOCK_RESPONSE
uploader.upload(TEST_IMAGE, extra_headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/58.0.3029.110 Safari/537.3'})
headers = get_headers(mocker.call_args[0])
self.assertEqual(headers.get('User-Agent'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/58.0.3029.110 Safari/537.3')

@unittest.skipUnless(cloudinary.config().api_secret, "requires api_key/api_secret")
def test07_resource_metadata(self):
""" should allow get resource metadata """
Expand Down
15 changes: 14 additions & 1 deletion test/test_uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from cloudinary.cache.adapter.key_value_cache_adapter import KeyValueCacheAdapter
from cloudinary.compat import urlparse, parse_qs
from test.cache.storage.dummy_cache_storage import DummyCacheStorage
from test.helper_test import uploader_response_mock, SUFFIX, TEST_IMAGE, get_params, TEST_ICON, TEST_DOC, \
from test.helper_test import uploader_response_mock, SUFFIX, TEST_IMAGE, get_params, get_headers, TEST_ICON, TEST_DOC, \
REMOTE_TEST_IMAGE, UTC, populate_large_file, TEST_UNICODE_IMAGE, get_uri, get_method, get_param, \
cleanup_test_resources_by_tag, cleanup_test_transformation, cleanup_test_resources, EVAL_STR
from test.test_utils import TEST_ID, TEST_FOLDER
Expand Down Expand Up @@ -514,6 +514,19 @@ def test_header(self):
uploader.upload(TEST_IMAGE, headers=["Link: 1"], tags=[UNIQUE_TAG])
uploader.upload(TEST_IMAGE, headers={"Link": "1"}, tags=[UNIQUE_TAG])

@patch('urllib3.request.RequestMethods.request')
@unittest.skipUnless(cloudinary.config().api_secret, "requires api_key/api_secret")
def test_extra_headers(self, mocker):
"""Should support extra headers"""
mocker.return_value = MOCK_RESPONSE
uploader.upload(TEST_IMAGE, extra_headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/58.0.3029.110 Safari/537.3'})
headers = get_headers(mocker.call_args[0])
self.assertEqual(headers.get('User-Agent'), 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/58.0.3029.110 Safari/537.3')

@unittest.skipUnless(cloudinary.config().api_secret, "requires api_key/api_secret")
def test_text(self):
"""Should successfully generate text image """
Expand Down

0 comments on commit 78b18d4

Please sign in to comment.