title: Upload a file to AWS S3 pre-signed URL using Retrofit2
body: <p>I'm trying to upload a file to Amazon's S3 using a pre-signed URL.  I get the URL from a server which generates the URL &amp; sends it to me as part of a JSON object.  I get the URL as a String, something like this:</p>
  
  <p><a href="https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/ImageName?X-Amz-Security-Token=xxfooxx%2F%2F%2F%2F%2F%2F%2F%2F%2F%2Fxxbarxx%3D&amp;X-Amz-Algorithm=xxAlgoxx&amp;X-Amz-Date=20170831T090152Z&amp;X-Amz-SignedHeaders=host&amp;X-Amz-Expires=3600&amp;X-Amz-Credential=xxcredxx&amp;X-Amz-Signature=xxsignxx" rel="noreferrer">https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/ImageName?X-Amz-Security-Token=xxfooxx%2F%2F%2F%2F%2F%2F%2F%2F%2F%2Fxxbarxx%3D&amp;X-Amz-Algorithm=xxAlgoxx&amp;X-Amz-Date=20170831T090152Z&amp;X-Amz-SignedHeaders=host&amp;X-Amz-Expires=3600&amp;X-Amz-Credential=xxcredxx&amp;X-Amz-Signature=xxsignxx</a></p>
  
  <p>Unfortunately, when I pass this to Retrofit2, it modifies the String attempting to make it into a URL. I've set <code>encoding=true</code> which took care of most of the problem but not completely. I know the String works as it is.  I've tried it in Postman &amp; get a successful response.</p>
  
  <p>1st I tried just putting the String (except for what I cut out as baseUrl) as a whole into the Path</p>
  
  <pre><code>public interface UpdateImageInterface {
      @PUT("{url}")
      Call&lt;Void&gt; updateImage(@Path(value="url", encoded=true) String url, Body RequestBody image);
  }
  </code></pre>
  
  <p>The calling code:</p>
  
  <pre><code>    Retrofit retrofit = new Retrofit.Builder()
              .baseUrl("https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/")
              .build();
  
      UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
      // imageUrl is "ImageName..."
      Call&lt;Void&gt; call = imageInterface.updateImage(imageUrl, requestFile);
  </code></pre>
  
  <p>This works mostly except the the '?' (after "ImageName") get converted to "%3F".  This causes a Bad Request / 400.</p>
  
  <p>My next attempt was to create a query with Retrofit2 but then dump the whole String (with multiple queries) into the query.  </p>
  
  <pre><code>public interface UpdateImageInterface {
      @PUT("ImageName")
      Call&lt;Void&gt; updateProfilePhoto(@Query(value="X-Amz-Security-Token", encoded = true) String token, @Body RequestBody image);
  }
  </code></pre>
  
  <p>The calling code:</p>
  
  <pre><code>    Retrofit retrofit = new Retrofit.Builder()
              .baseUrl("https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/")
              .build();
  
      UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
      // imageUrl is "xxfooxx..."
      Call&lt;Void&gt; call = imageInterface.updateImage(imageUrl, requestFile);
  </code></pre>
  
  <p>This gets the '?' rendered correctly but all of the '&amp;' get changed to "%26"    </p>
  
  <p>Lastly I tried passing the whole String in <code>baseUrl()</code> but that gives an IllegalArgumentException for not having '/' on the end.</p>
  
  <p>I know that I could parse the pre-signed URL to make multiple queries &amp; assemble them in Retrofit2 as queries should be done but I'd like to avoid that processing.  </p>
  
  <p>To restate the question:</p>
  
  <p>Is there a way to easily (without heavy String parsing) upload a file to S3 with a pre-signed URL using Retrofit2?</p>