Загрузить на s3 с помощью curl, используя предварительно подписанный URL (получая 403)

Я использую curl для вызова API Java ReST для получения URL. Затем Java генерирует предварительно подписанный URL-адрес для загрузки S3, используя мои учетные данные S3, и возвращает его в ответе ReST. Curl берет URL-адрес и использует его для загрузки на S3, но S3 возвращает 403 «Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи. Проверьте свой ключ и метод подписи».

Вот код, который я использую для создания предварительно подписанного URL:

public class S3Util {
    static final AmazonS3 s3 = new AmazonS3Client( new AWSCredentials() {
        @Override
        public String getAWSAccessKeyId() {
            return "XXXXXXX";
        }
        @Override
        public String getAWSSecretKey() {
            return "XXXXXXXXXXXXXX";
        }
    });
    static final String BUCKET = "XXXXXXXXXXXXXXXXXXXXXXXXXXX";

    static public URL getMediaChunkURL( MediaChunk mc, HttpMethod method ) {
        String key = ...
        //way in the future (for testing)...
        Date expiration = new Date( System.currentTimeMillis() + CalendarUtil.ONE_MINUTE_IN_MILLISECONDS*60*1000 );

        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, method);
        req.setExpiration(expiration);
        req.addRequestParameter("Content-Type", "application/octet-stream");

        //this gets passed to the end user:
        return s3.generatePresignedUrl(req);
    }
}

и в curl, запустить из Bash, я выполняю это:

echo Will try to upload chunk to ${location}
curl -i -X POST \
        -F 'Content-Type=application/octet-stream' \
        -F "file=@${fileName}" \
        ${location} || (echo upload chunk failed. ; exit 1 )

Помимо прочего, я попробовал PUT и «Content-type» (строчная буква T). Я понимаю, что упускаю что-то (или что-то) очевидное, но после прочтения соответствующих документов, поиска в Google и просмотра множества похожих вопросов я не уверен, что это такое. Я вижу много подсказок о необходимых заголовках, но я думал, что отказавшийся URL-адрес должен был устранить эти потребности. Возможно, нет?

ТИА!

Обновить:

Просто чтобы быть ясно, я протестировал загрузки, и это прекрасно работает.

Java выглядит так:

GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(BUCKET, key, HttpMethod.GET);
req.setExpiration(expiration);

а curl это просто:

curl -i ${location}

Ответы на вопрос(4)

Ваш ответ на вопрос