cloudinary / pycloudinary

Python package for cloudinary
https://cloudinary.com/documentation/django_integration
Other
254 stars 138 forks source link

transformation name with spaces causes 400 error #42

Open oppianmatt opened 9 years ago

oppianmatt commented 9 years ago

Making a call to get transformations, some of them come back with spaces in the name like this:

 {u'allowed_for_strict': False,
  u'name': u'fl_progressive,t_primary/t_t_primary@2x jpg.t_primary@2x jpg.display@2x',
  u'used': False},

Now trying to use that (ignoring issue #41 for now), generates a 400 server error:

In [10]: name = 'fl_progressive,t_primary/t_t_primary@2x jpg.t_primary@2x jpg.display@2x'

In [11]: cloudinary.api.transformation(name)
---------------------------------------------------------------------------
GeneralError                              Traceback (most recent call last)
<ipython-input-11-031ddf1dde0b> in <module>()
----> 1 cloudinary.api.transformation(name)

.../venv/lib/python2.7/site-packages/cloudinary/api.pyc in transformation(transformation, **options)
    129 def transformation(transformation, **options):
    130     uri = ["transformations", transformation_string(transformation)]
--> 131     return call_api("get", uri, only(options, "max_results"), **options)
    132
    133 def delete_transformation(transformation, **options):

.../venv/lib/python2.7/site-packages/cloudinary/api.pyc in call_api(method, uri, params, **options)
    225         # Error is parsing json
    226         e = sys.exc_info()[1]
--> 227         raise GeneralError("Error parsing server response (%d) - %s. Got - %s" % (response.code, body, e))
    228
    229     if "error" in result:

GeneralError: Error parsing server response (400) - . Got - No JSON object could be decoded

The fix it seems is to renencode the name using url encoding:

In [12]: name = 'fl_progressive,t_primary/t_t_primary@2x%20jpg.t_primary@2x%20jpg.display@2x'

In [13]: cloudinary.api.transformation(name)
Out[13]:
{u'allowed_for_strict': False,
 u'derived': [],
 u'info': [{u'flags': [u'progressive'], u'transformation': [u'primary']},
  {u'transformation': [u't_primary@2x jpg', u'display@2x']}],
 u'name': u'fl_progressive,t_primary/t_t_primary@2x jpg.t_primary@2x jpg.display@2x',
 u'used': False}
oppianmatt commented 9 years ago

Not just transformation name, public ids as well. I had a public_id that ended in a slash and it threw the same errors. Needed to urllib.quote(public_id, '') before sending it. Also public_id (and transformations also) have unicode issues so the full line to fix a public_id is:

public_id = urllib.quote(str(public_id.encode('utf-8')), '')

EXCEPT fetch urls have public ids that you don't escape.

idobarnoam commented 7 years ago

Hi @oppianmatt

I see that the last response is from a while back. Are you still experiencing the issue?

aidanlister commented 5 years ago

@idobarnoam we're experiencing the issue, it's really painful!

                cached_version = cache.get(f'cloudinary_version-preview-{file.key}')
                preview_image = cloudinary.CloudinaryImage(
                    os.path.join(settings.MEDIA_CLOUDINARY_PREFIX, file.key),
                    version=cached_version,
                )
                preview_image.url_options.update({
                    'width': 2500,
                    'height': 2500,
                    'crop': 'limit',
                    'flags': 'attachment',
                })
                file_dict.update({
                    'url': preview_image.url,  # here we replace `url`. remove this when react-keyed-file-browser is updated
                    'preview_url': preview_image.url,
                })

This produces a URL like; https://images.onuptick.com/image/upload/s--sQ2RlW0s--/c_limit,fl_attachment,h_2500,w_2500/v1/tesg/properties/40956/public/Annual%20Certification/2018/E%26E%203.JPG

That causes a 400 error,

x-cld-error: public_id (tesg/properties/40956/public/Annual Certification/2018/E&E 3) is invalid
x-request-id: d005f3099039b94b
x-ua-compatible: IE=Edge,chrome=1

The file in S3 is named properties/40956/public/Annual Certification/2018/E&E 4.JPG

aidanlister commented 5 years ago

Soooo this might not be a problem with escaping the spaces, it's a problem with the & symbol ... eg this works, https://images.onuptick.com/image/upload/v1/tesg/properties/40956/public/Annual%20Certification/2018/E_E%204.JPG

There's a few symbols that aren't valid and if it's not a valid public_id it won't auto-upload from the source bucket. I'll go via a support ticket instead as it's not really pycloudinary's problem.

https://support.cloudinary.com/hc/en-us/articles/115001317409--Legal-naming-conventions

FYI We get a little closer double escaping, eg %2526 is escaped back to %26 which is an escaped & - it's just a remote bucket fetching problem :|

The other non allowed chars are: '?&#\%<>'