Esempio n. 1
0
def _call_api(method, uri, params=None, body=None, 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)
    if not cloud_name: raise Exception("Must supply cloud_name")
    api_key = options.pop("api_key", cloudinary.config().api_key)
    if not api_key: raise Exception("Must supply api_key")
    api_secret = options.pop("api_secret", cloudinary.config().api_secret)
    if not cloud_name: raise Exception("Must supply api_secret")
    api_url = "/".join([prefix, "v1_1", cloud_name] + uri)

    processed_params = None
    if isinstance(params, dict):
        processed_params = {}
        for key, value in params.items():
            if isinstance(value, list):
                value_list = {
                    "{}[{}]".format(key, i): i_value
                    for i, i_value in enumerate(value)
                }
                processed_params.update(value_list)
            elif value:
                processed_params[key] = value

    # Add authentication
    req_headers = urllib3.make_headers(basic_auth="{0}:{1}".format(
        api_key, api_secret),
                                       user_agent=cloudinary.get_user_agent())
    if headers is not None:
        req_headers.update(headers)
    kw = {}
    if 'timeout' in options:
        kw['timeout'] = options['timeout']
    if body is not None:
        kw['body'] = body
    try:
        response = _http.request(method.upper(), api_url, processed_params,
                                 req_headers, **kw)
        body = response.data
    except HTTPError as e:
        raise GeneralError("Unexpected error {0}", e.message)
    except socket.error as e:
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        result = json.loads(body.decode('utf-8'))
    except Exception as e:
        # Error is parsing json
        raise GeneralError(
            "Error parsing server response (%d) - %s. Got - %s" %
            (response.status, body, e))

    if "error" in result:
        exception_class = EXCEPTION_CODES.get(response.status) or Exception
        exception_class = exception_class
        raise exception_class("Error {0} - {1}".format(
            response.status, result["error"]["message"]))

    return Response(result, response)
Esempio n. 2
0
    def test_django_user_agent(self):
        agent = cloudinary.get_user_agent()

        six.assertRegex(
            self, agent,
            r'^Django\/\d\.\d+(\.\d+)? CloudinaryPython\/\d\.\d+\.\d+ \(Python \d\.\d+\.\d+\)$'
        )
def fetch_alt_tags(public_id, remote_url):
    """
    A wrapper function that makes a call to the remote URL specified as worker_url and fetches the alt text tag.

    This function expects the response to be in the following JSON format:
    {
        "alt_text": "something"
    }

    It may have any other dictionary along with this value but, alt_text is the only mandatory value.

    :param public_id: Object for which we require the alt-text
    :param remote_url: API endpoint that will be returning the alt-text information

    :return: JSON object that will include the alt-text if one is present
    """
    url = f"{remote_url}{cloudinary.config().cloud_name}/{public_id}"

    req_headers = urllib3.make_headers(
        basic_auth=
        f"{cloudinary.config().api_key}:{cloudinary.config().api_secret}",
        user_agent=cloudinary.get_user_agent())
    logger.debug(f"making a call to {url} with headers {req_headers}")

    client = HttpClient()
    response = client.get_json(url, headers=req_headers)
    return response
Esempio n. 4
0
def call_api(method, uri, params, **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)
    if not cloud_name: raise Exception("Must supply cloud_name")
    api_key = options.pop("api_key", cloudinary.config().api_key)
    if not api_key: raise Exception("Must supply api_key")
    api_secret = options.pop("api_secret", cloudinary.config().api_secret)
    if not cloud_name: raise Exception("Must supply api_secret")

    data = to_bytes(urlencode(params))
    api_url = "/".join([prefix, "v1_1", cloud_name] + uri)
    request = urllib2.Request(api_url, data)
    # Add authentication
    byte_value = to_bytes('%s:%s' % (api_key, api_secret))
    encoded_value = base64.encodebytes(
        byte_value) if PY3 else base64.encodestring(byte_value)
    base64string = to_string(encoded_value).replace('\n', '')
    request.add_header("Authorization", "Basic %s" % base64string)
    request.add_header("User-Agent", cloudinary.get_user_agent())
    request.get_method = lambda: method.upper()

    kw = {}
    if 'timeout' in options:
        kw['timeout'] = options['timeout']
    try:
        response = urllib2.urlopen(request, **kw)
        body = response.read()
    except HTTPError:
        e = sys.exc_info()[1]
        exception_class = EXCEPTION_CODES.get(e.code)
        if exception_class:
            response = e
            body = response.read()
        else:
            raise GeneralError(
                "Server returned unexpected status code - %d - %s" %
                (e.code, e.read()))
    except socket.error:
        e = sys.exc_info()[1]
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        body = to_string(body)
        result = json.loads(body)
    except Exception:
        # Error is parsing json
        e = sys.exc_info()[1]
        raise GeneralError(
            "Error parsing server response (%d) - %s. Got - %s" %
            (response.code, body, e))

    if "error" in result:
        exception_class = exception_class or Exception
        raise exception_class(result["error"]["message"])

    return Response(result, response)
Esempio n. 5
0
def _call_api(method, uri, params=None, body=None, 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)
    if not cloud_name:
        raise Exception("Must supply cloud_name")
    api_key = options.pop("api_key", cloudinary.config().api_key)
    if not api_key:
        raise Exception("Must supply api_key")
    api_secret = options.pop("api_secret", cloudinary.config().api_secret)
    if not cloud_name:
        raise Exception("Must supply api_secret")
    api_url = "/".join([prefix, "v1_1", cloud_name] + uri)

    processed_params = None
    if isinstance(params, dict):
        processed_params = {}
        for key, value in params.items():
            if isinstance(value, list) or isinstance(value, tuple):
                value_list = {"{}[{}]".format(key, i): i_value for i, i_value in enumerate(value)}
                processed_params.update(value_list)
            elif value:
                processed_params[key] = value

    # Add authentication
    req_headers = urllib3.make_headers(
        basic_auth="{0}:{1}".format(api_key, api_secret),
        user_agent=cloudinary.get_user_agent()
    )
    if headers is not None:
        req_headers.update(headers)
    kw = {}
    if 'timeout' in options:
        kw['timeout'] = options['timeout']
    if body is not None:
        kw['body'] = body
    try:
        response = _http.request(method.upper(), api_url, processed_params, req_headers, **kw)
        body = response.data
    except HTTPError as e:
        raise GeneralError("Unexpected error {0}", e.message)
    except socket.error as e:
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        result = json.loads(body.decode('utf-8'))
    except Exception as e:
        # Error is parsing json
        raise GeneralError("Error parsing server response (%d) - %s. Got - %s" % (response.status, body, e))

    if "error" in result:
        exception_class = EXCEPTION_CODES.get(response.status) or Exception
        exception_class = exception_class
        raise exception_class("Error {0} - {1}".format(response.status, result["error"]["message"]))

    return Response(result, response)
Esempio n. 6
0
def call_api(method, uri, params, **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)
    if not cloud_name: raise Exception("Must supply cloud_name")
    api_key = options.pop("api_key", cloudinary.config().api_key)
    if not api_key: raise Exception("Must supply api_key")
    api_secret = options.pop("api_secret", cloudinary.config().api_secret)
    if not cloud_name: raise Exception("Must supply api_secret")

    data = to_bytes(urlencode(params))
    api_url = "/".join([prefix, "v1_1", cloud_name] + uri)
    request = urllib2.Request(api_url, data)
    # Add authentication
    byte_value = to_bytes('%s:%s' % (api_key, api_secret))
    encoded_value = base64.encodebytes(byte_value) if PY3 else base64.encodestring(byte_value)
    base64string = to_string(encoded_value).replace('\n', '')
    request.add_header("Authorization", "Basic %s" % base64string)
    request.add_header("User-Agent", cloudinary.get_user_agent())
    request.get_method = lambda: method.upper()

    kw = {}
    if 'timeout' in options:
        kw['timeout'] = options['timeout']
    try:
        response = urllib2.urlopen(request, **kw)
        body = response.read()
    except HTTPError:
        e = sys.exc_info()[1]
        exception_class = EXCEPTION_CODES.get(e.code)
        if exception_class:
            response = e
            body = response.read()
        else:
            raise GeneralError("Server returned unexpected status code - %d - %s" % (e.code, e.read()))
    except socket.error:
        e = sys.exc_info()[1]
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        body = to_string(body)
        result = json.loads(body)
    except Exception:
        # Error is parsing json
        e = sys.exc_info()[1]
        raise GeneralError("Error parsing server response (%d) - %s. Got - %s" % (response.code, body, e))

    if "error" in result:
        exception_class = exception_class or Exception
        raise exception_class(result["error"]["message"])

    return Response(result, response)
Esempio n. 7
0
def execute_request(http_connector, method, params, headers, auth, api_url,
                    **options):
    # authentication
    key = auth.get("key")
    secret = auth.get("secret")
    oauth_token = auth.get("oauth_token")
    req_headers = urllib3.make_headers(user_agent=cloudinary.get_user_agent())
    if oauth_token:
        req_headers["authorization"] = "Bearer {}".format(oauth_token)
    else:
        req_headers.update(
            urllib3.make_headers(basic_auth="{0}:{1}".format(key, secret)))

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

    kw = {}
    if "timeout" in options:
        kw["timeout"] = options["timeout"]
    if "body" in options:
        kw["body"] = options["body"]

    processed_params = process_params(params)

    api_url = smart_escape(unquote(api_url))

    try:
        response = http_connector.request(method.upper(), api_url,
                                          processed_params, req_headers, **kw)
        body = response.data
    except HTTPError as e:
        raise GeneralError("Unexpected error {0}", e.message)
    except socket.error as e:
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        result = json.loads(body.decode('utf-8'))
    except Exception as e:
        # Error is parsing json
        raise GeneralError(
            "Error parsing server response (%d) - %s. Got - %s" %
            (response.status, body, e))

    if "error" in result:
        exception_class = EXCEPTION_CODES.get(response.status) or Exception
        exception_class = exception_class
        raise exception_class("Error {0} - {1}".format(
            response.status, result["error"]["message"]))

    return Response(result, response)
Esempio n. 8
0
def call_api(method, uri, params, **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)
    if not cloud_name: raise Exception("Must supply cloud_name")
    api_key = options.pop("api_key", cloudinary.config().api_key)
    if not api_key: raise Exception("Must supply api_key")
    api_secret = options.pop("api_secret", cloudinary.config().api_secret)
    if not cloud_name: raise Exception("Must supply api_secret")
    api_url = "/".join([prefix, "v1_1", cloud_name] + uri)
    # Add authentication
    headers = urllib3.make_headers(basic_auth="{0}:{1}".format(
        api_key, api_secret),
                                   user_agent=cloudinary.get_user_agent())

    kw = {}
    if 'timeout' in options:
        kw['timeout'] = options['timeout']
    try:
        response = _http.request(method.upper(), api_url, params, headers,
                                 **kw)
        body = response.data
    except HTTPError as e:
        raise GeneralError("Unexpected error {0}", e.message)
    except socket.error as e:
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        result = json.loads(body.decode('utf-8'))
    except Exception as e:
        # Error is parsing json
        raise GeneralError(
            "Error parsing server response (%d) - %s. Got - %s" %
            (response.status, body, e))

    if "error" in result:
        exception_class = EXCEPTION_CODES.get(response.status) or Exception
        exception_class = exception_class
        raise exception_class("Error {0} - {1}".format(
            response.status, result["error"]["message"]))

    return Response(result, response)
Esempio n. 9
0
def call_api(method, uri, params, **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)
    if not cloud_name: raise Exception("Must supply cloud_name")
    api_key = options.pop("api_key", cloudinary.config().api_key)
    if not api_key: raise Exception("Must supply api_key")
    api_secret = options.pop("api_secret", cloudinary.config().api_secret)
    if not cloud_name: raise Exception("Must supply api_secret")
    api_url = "/".join([prefix, "v1_1", cloud_name] + uri)
    # Add authentication
    headers = urllib3.make_headers(
        basic_auth="{0}:{1}".format(api_key, api_secret),
        user_agent=cloudinary.get_user_agent()
    )

    kw = {}
    if 'timeout' in options:
        kw['timeout'] = options['timeout']
    try:
        response = _http.request(method.upper(), api_url, params, headers, **kw)
        body = response.data
    except HTTPError as e:
        raise GeneralError("Unexpected error {0}", e.message)
    except socket.error as e:
        raise GeneralError("Socket Error: %s" % (str(e)))

    try:
        result = json.loads(body.decode('utf-8'))
    except Exception as e:
        # Error is parsing json
        raise GeneralError("Error parsing server response (%d) - %s. Got - %s" % (response.status, body, e))

    if "error" in result:
        exception_class = EXCEPTION_CODES.get(response.status) or Exception
        exception_class = exception_class
        raise exception_class("Error {0} - {1}".format(response.status, result["error"]["message"]))

    return Response(result, response)
Esempio n. 10
0
def call_api(action,
             params,
             http_headers=None,
             return_error=False,
             unsigned=False,
             file=None,
             timeout=None,
             **options):
    if http_headers is None:
        http_headers = {}
    file_io = None
    try:
        if unsigned:
            params = utils.cleanup_params(params)
        else:
            params = utils.sign_request(params, options)

        param_list = OrderedDict()
        for k, v in params.items():
            if isinstance(v, list):
                for i in range(len(v)):
                    param_list["{0}[{1}]".format(k, i)] = v[i]
            elif v:
                param_list[k] = v

        api_url = utils.cloudinary_api_url(action, **options)
        if file:
            if isinstance(file, string_types):
                if utils.is_remote_url(file):
                    # URL
                    name = None
                    data = file
                else:
                    # file path
                    name = file
                    with open(file, "rb") as opened:
                        data = opened.read()
            elif hasattr(file, 'read') and callable(file.read):
                # stream
                data = file.read()
                name = file.name if hasattr(file, 'name') and isinstance(
                    file.name, str) else "stream"
            elif isinstance(file, tuple):
                name = None
                data = file
            else:
                # Not a string, not a stream
                name = "file"
                data = file

            param_list["file"] = (name, data) if name else data

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

        kw = {}
        if timeout is not None:
            kw['timeout'] = timeout

        code = 200
        try:
            response = _http.request("POST", api_url, param_list, headers,
                                     **kw)
        except HTTPError as e:
            raise Error("Unexpected error - {0!r}".format(e))
        except socket.error as e:
            raise Error("Socket error: {0!r}".format(e))

        try:
            result = json.loads(response.data.decode('utf-8'))
        except Exception as e:
            # Error is parsing json
            raise Error("Error parsing server response (%d) - %s. Got - %s",
                        response.status, response, e)

        if "error" in result:
            if response.status not in [200, 400, 401, 403, 404, 500]:
                code = response.status
            if return_error:
                result["error"]["http_code"] = code
            else:
                raise Error(result["error"]["message"])

        return result
    finally:
        if file_io:
            file_io.close()
Esempio n. 11
0
def call_api(action, params, http_headers={}, return_error=False, unsigned=False, file=None, timeout=None, **options):
    try:
        file_io = None
        if unsigned:
          params = utils.cleanup_params(params)
        else:
          params = utils.sign_request(params, options)
    
        param_list = []
        for k, v in params.items():
            if isinstance(v, list):          
                for vv in v:
                  param_list.append((k+"[]", vv))
            elif v:
                param_list.append((k, v))            
    
        api_url = utils.cloudinary_api_url(action, **options)
    
        global _initialized
        if not _initialized:
            _initialized = True
            # Register the streaming http handlers with urllib2
            register_openers()
    
        datagen, headers = multipart_encode({})
        if file:
            if not isinstance(file, string_types):
                datagen, headers = multipart_encode({'file': file})
            elif not re.match(r'ftp:|https?:|s3:|data:[^;]*;base64,([a-zA-Z0-9\/+\n=]+)$', file):
                file_io = open(file, "rb")
                datagen, headers = multipart_encode({'file': file_io})
            else:
                param_list.append(("file", file))

        if _is_gae():
            # Might not be needed in the future but for now this is needed in GAE
            datagen = "".join(datagen)

        request = urllib2.Request(api_url + "?" + urlencode(param_list), datagen, headers)
        request.add_header("User-Agent", cloudinary.get_user_agent())
        for k, v in http_headers.items():
            request.add_header(k, v)
    
        kw = {}
        if timeout is not None:
            kw['timeout'] = timeout

        code = 200
        try:
            response = urllib2.urlopen(request, **kw).read()
        except HTTPError:
            e = sys.exc_info()[1]
            if not e.code in [200, 400, 500]:
                raise Error("Server returned unexpected status code - %d - %s" % (e.code, e.read()))
            code = e.code
            response = e.read()
        except urllib2.URLError:
            e = sys.exc_info()[1]
            raise Error("Error - %s" % str(e))
        except socket.error:
            e = sys.exc_info()[1]
            raise Error("Socket error: %s" % str(e))
    
        try:
            result = json.loads(to_string(response))
        except Exception:
            e = sys.exc_info()[1]
            # Error is parsing json
            raise Error("Error parsing server response (%d) - %s. Got - %s", code, response, e)
    
        if "error" in result:
            if return_error:
                result["error"]["http_code"] = code
            else:
                raise Error(result["error"]["message"])
    
        return result
    finally:
        if file_io: file_io.close()    
Esempio n. 12
0
def call_api(action,
             params,
             http_headers={},
             return_error=False,
             unsigned=False,
             file=None,
             timeout=None,
             **options):
    try:
        file_io = None
        if unsigned:
            params = utils.cleanup_params(params)
        else:
            params = utils.sign_request(params, options)

        param_list = []
        for k, v in params.items():
            if isinstance(v, list):
                for vv in v:
                    param_list.append((k + "[]", vv))
            elif v:
                param_list.append((k, v))

        api_url = utils.cloudinary_api_url(action, **options)

        global _initialized
        if not _initialized:
            _initialized = True
            # Register the streaming http handlers with urllib2
            register_openers()

        if file:
            if not isinstance(file, string_types):
                param_list.append(("file", file))
            elif not re.match(
                    r'ftp:|https?:|s3:|data:[^;]*;base64,([a-zA-Z0-9\/+\n=]+)$',
                    file):
                file_io = open(file, "rb")
                param_list.append(('file', file_io))
            else:
                param_list.append(("file", file))

        datagen, headers = multipart_encode(param_list)

        if _is_gae():
            # Might not be needed in the future but for now this is needed in GAE
            datagen = "".join(datagen)

        request = urllib2.Request(api_url, datagen, headers)
        request.add_header("User-Agent", cloudinary.get_user_agent())
        for k, v in http_headers.items():
            request.add_header(k, v)

        kw = {}
        if timeout is not None:
            kw['timeout'] = timeout

        code = 200
        try:
            response = urllib2.urlopen(request, **kw).read()
        except HTTPError:
            e = sys.exc_info()[1]
            if not e.code in [200, 400, 500]:
                raise Error(
                    "Server returned unexpected status code - %d - %s" %
                    (e.code, e.read()))
            code = e.code
            response = e.read()
        except urllib2.URLError:
            e = sys.exc_info()[1]
            raise Error("Error - %s" % str(e))
        except socket.error:
            e = sys.exc_info()[1]
            raise Error("Socket error: %s" % str(e))

        try:
            result = json.loads(to_string(response))
        except Exception:
            e = sys.exc_info()[1]
            # Error is parsing json
            raise Error("Error parsing server response (%d) - %s. Got - %s",
                        code, response, e)

        if "error" in result:
            if return_error:
                result["error"]["http_code"] = code
            else:
                raise Error(result["error"]["message"])

        return result
    finally:
        if file_io: file_io.close()
Esempio n. 13
0
def call_api(action,
             params,
             http_headers=None,
             return_error=False,
             unsigned=False,
             file=None,
             timeout=None,
             **options):
    params = utils.cleanup_params(params)

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

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

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

    if oauth_token:
        headers["authorization"] = "Bearer {}".format(oauth_token)
    elif not unsigned:
        params = utils.sign_request(params, options)

    param_list = []
    for k, v in params.items():
        if isinstance(v, list):
            for i in v:
                param_list.append(("{0}[]".format(k), i))
        elif v:
            param_list.append((k, v))

    api_url = utils.cloudinary_api_url(action, **options)

    if file:
        filename = options.get(
            "filename"
        )  # Custom filename provided by user (relevant only for streams and files)

        if isinstance(file, string_types):
            if utils.is_remote_url(file):
                # URL
                name = None
                data = file
            else:
                # file path
                name = filename or file
                with open(file, "rb") as opened:
                    data = opened.read()
        elif hasattr(file, 'read') and callable(file.read):
            # stream
            data = file.read()
            name = filename or (file.name if hasattr(file, 'name')
                                and isinstance(file.name, str) else "stream")
        elif isinstance(file, tuple):
            name, data = file
        else:
            # Not a string, not a stream
            name = filename or "file"
            data = file

        param_list.append(("file", (name, data) if name else data))

    kw = {}
    if timeout is not None:
        kw['timeout'] = timeout

    code = 200
    try:
        response = _http.request("POST", api_url, param_list, headers, **kw)
    except HTTPError as e:
        raise Error("Unexpected error - {0!r}".format(e))
    except socket.error as e:
        raise Error("Socket error: {0!r}".format(e))

    try:
        result = json.loads(response.data.decode('utf-8'))
    except Exception as e:
        # Error is parsing json
        raise Error("Error parsing server response (%d) - %s. Got - %s" %
                    (response.status, response.data, e))

    if "error" in result:
        if response.status not in [200, 400, 401, 403, 404, 500]:
            code = response.status
        if return_error:
            result["error"]["http_code"] = code
        else:
            raise Error(result["error"]["message"])

    return result
Esempio n. 14
0
    def test_django_user_agent(self):
        agent = cloudinary.get_user_agent()

        six.assertRegex(self, agent, r'^Django\/\d\.\d+\.?\d* CloudinaryPython\/\d\.\d+\.\d+ \(Python \d\.\d+\.\d+\)$')
Esempio n. 15
0
def call_api(action, params, http_headers=None, return_error=False, unsigned=False, file=None, timeout=None, **options):
    if http_headers is None:
        http_headers = {}
    file_io = None
    try:
        if unsigned:
            params = utils.cleanup_params(params)
        else:
            params = utils.sign_request(params, options)

        param_list = OrderedDict()
        for k, v in params.items():
            if isinstance(v, list):
                for i in range(len(v)):
                    param_list["{0}[{1}]".format(k, i)] = v[i]
            elif v:
                param_list[k] = v

        api_url = utils.cloudinary_api_url(action, **options)
        if file:
            if isinstance(file, string_types):
                if re.match(r'ftp:|https?:|s3:|data:[^;]*;base64,([a-zA-Z0-9\/+\n=]+)$', file):
                    # URL
                    name = None
                    data = file
                else:
                    # file path
                    name = file
                    with open(file, "rb") as opened:
                        data = opened.read()
            elif hasattr(file, 'read') and callable(file.read):
                # stream
                data = file.read()
                name = file.name if hasattr(file, 'name') else "stream"
            elif isinstance(file, tuple):
                name = None
                data = file
            else:
                # Not a string, not a stream
                name = "file"
                data = file

            param_list["file"] = (name, data) if name else data

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

        kw = {}
        if timeout is not None:
            kw['timeout'] = timeout

        code = 200
        try:
            response = _http.request("POST", api_url, param_list, headers, **kw)
        except HTTPError as e:
            raise Error("Unexpected error - {0!r}".format(e))
        except socket.error as e:
            raise Error("Socket error: {0!r}".format(e))

        try:
            result = json.loads(response.data.decode('utf-8'))
        except Exception as e:
            # Error is parsing json
            raise Error("Error parsing server response (%d) - %s. Got - %s", response.status, response, e)

        if "error" in result:
            if response.status not in [200, 400, 401, 403, 404, 500]:
                code = response.status
            if return_error:
                    result["error"]["http_code"] = code
            else:
                raise Error(result["error"]["message"])

        return result
    finally:
        if file_io: file_io.close()