Uploaded image for project: 'jclouds'
  1. jclouds
  2. JCLOUDS-1264

Multipart SLO uploads fail if key contains multibyte Unicode characters

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • 2.0.1
    • 2.1.0
    • jclouds-blobstore
    • None
    • Devstack on Ubuntu 14.04

    Description

      If a large object is PUT to a key that contains multibyte Unicode characters, the manifest upload fails because the Content-Length header sent is incorrect.

      A small project that reproduces the issue against the latest Devstack Swift can be found here: https://github.com/UniversityofWarwick/jclouds-highbyte-slo-bug

      In short:

      >> "[{"path":"slo-test/Ni[0xc5][0x9f]an.rar/slo/1491214092.299000/38547913/0/00000001","etag":"58f06dd588d8ffb3beb46ada6309436b","size_bytes":33554432},{"path":"slo-test/Ni[0xc5][0x9f]an.rar/slo/1491214092.299000/38547913/0/00000002","etag":"2b4b81733d0a2e4abe89516639627408","size_bytes":4993481}]"
      >> PUT http://137.205.194.8:8080/v1/AUTH_c7a3e66567ec442080a360d6d23f2dbe/slo-test/Ni%C5%9Fan.rar?multipart-manifest=put HTTP/1.1
      >> Content-Length: 272
      
      14657 ERROR org.jclouds.http.internal.JavaUrlHttpCommandExecutorService error after writing 0/272 bytes to http://137.205.194.8:8080/v1/AUTH_c7a3e66567ec442080a360d6d23f2dbe/slo-test/Ni%C5%9Fan.rar?multipart-manifest=put
      java.io.IOException: too many bytes written
      	at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(HttpURLConnection.java:3505)
      	at com.google.common.io.CountingOutputStream.write(CountingOutputStream.java:53)
      	at com.google.common.io.ByteStreams.copy(ByteStreams.java:179)
      	at org.jclouds.http.internal.JavaUrlHttpCommandExecutorService.writePayloadToConnection(JavaUrlHttpCommandExecutorService.java:298)
      	at org.jclouds.http.internal.JavaUrlHttpCommandExecutorService.convert(JavaUrlHttpCommandExecutorService.java:171)
      	at org.jclouds.http.internal.JavaUrlHttpCommandExecutorService.convert(JavaUrlHttpCommandExecutorService.java:65)
      	at org.jclouds.http.internal.BaseHttpCommandExecutorService.invoke(BaseHttpCommandExecutorService.java:99)
      	at org.jclouds.rest.internal.InvokeHttpMethod.invoke(InvokeHttpMethod.java:90)
      	at org.jclouds.rest.internal.InvokeHttpMethod.apply(InvokeHttpMethod.java:73)
      	at org.jclouds.rest.internal.InvokeHttpMethod.apply(InvokeHttpMethod.java:44)
      	at org.jclouds.reflect.FunctionalReflection$FunctionalInvocationHandler.handleInvocation(FunctionalReflection.java:117)
      	at com.google.common.reflect.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:87)
      	at com.sun.proxy.$Proxy77.replaceManifest(Unknown Source)
      	at org.jclouds.openstack.swift.v1.blobstore.RegionScopedSwiftBlobStore.completeMultipartUpload(RegionScopedSwiftBlobStore.java:522)
      	at uk.ac.warwick.slo.AbstractJCloudsSLOTest.putSLO(AbstractJCloudsSLOTest.java:70)
      	at uk.ac.warwick.slo.AbstractJCloudsSLOTest.assertCanPutAndGetSLO(AbstractJCloudsSLOTest.java:74)
      	at uk.ac.warwick.slo.AbstractJCloudsSLOTest.sloWithHighByteChars(AbstractJCloudsSLOTest.java:91)
      	at uk.ac.warwick.slo.SwiftJCloudsSLOTest.sloWithHighByteChars(SwiftJCloudsSLOTest.java:7)
      

      The cause of this is org.jclouds.openstack.swift.v1.binders.BindManifestToJsonPayload:61, where the ContentLength is set to the length of the JSON String in Java, which is not the same as the String byte length. This is actually unnecessary, as request.setPayload(String) creates a StringPayload, and the constructor here sets the content length to the correct byte length - so I think this code is left-over from a previous version where this isn't the case.

      Attachments

        Activity

          People

            gaul Andrew Gaul
            mmannion Mathew Mannion
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: