1

I wrote a small program to download assets from GitHub releases:

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class GitTest
{
    public static void main(String[] args) throws IOException
    {
        String assetUrlString = "https://api.github.com/repos/YuryMalyshev/SnakeGameWithProcessing/releases/assets/24010211";
        String token = "Bearer My_Secret_GitHub_Personal_Access_Token";
        String filename = "test.txt";
    
        URL assetURL = new URL(assetUrlString);
        HttpURLConnection downloadconnection = (HttpURLConnection) assetURL.openConnection();
        downloadconnection.setConnectTimeout(0);
        downloadconnection.addRequestProperty("Accept", "application/octet-stream");
        downloadconnection.addRequestProperty("Authorization", token);
        downloadconnection.connect();
        
        // to partially mitigate the problem, we can put the problematic code
        // into try-catch to get redirect URL
        try
        {
            // throws IOException with message 
            //"Server returned HTTP response code: 400 for URL: ... if ran on Linux"
            InputStream inStream = downloadconnection.getInputStream(); 
            Files.copy(inStream, Paths.get(filename), StandardCopyOption.REPLACE_EXISTING);
        }
        catch(IOException e)
        {
            String responseMsg = e.getMessage();
            if(responseMsg.contains("Server returned HTTP response code: 400 for URL"))
            {
                URL redirectURL = new URL(responseMsg.substring(responseMsg.indexOf("https://")));
                HttpURLConnection redirectconnection = (HttpURLConnection)redirectURL.openConnection();
                redirectconnection.connect();
                InputStream inStream = redirectconnection.getInputStream(); 
                Files.copy(inStream, Paths.get(filename), StandardCopyOption.REPLACE_EXISTING);
                redirectconnection.disconnect();
            }
        }
        downloadconnection.disconnect();
    }
}

StackTrace:

Exception in thread "main" java.io.IOException: Server returned HTTP response code: 400 for URL: https://github-production-release-asset-2e65be.s3.amazonaws.com/251348046/ca3bbd00-e0b0-11ea-8d30-49e495660664?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20200817%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200817T145454Z&X-Amz-Expires=300&X-Amz-Signature=16f08a48455394dccdb94b91da32e4814885ae66c17d6f942ec814448b51975a&X-Amz-SignedHeaders=host&actor_id=49309415&repo_id=251348046&response-content-disposition=attachment%3B%20filename%3DTest.txt&response-content-type=application%2Foctet-stream
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at GitTest.main(GitTest.java:24)

Error Stream when getting Code 400

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>InvalidArgument</Code>
    <Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message>
    <ArgumentName>Authorization</ArgumentName>
    <ArgumentValue>Bearer My_Secret_GitHub_Personal_Access_Token</ArgumentValue>
    <RequestId>5C8A004BD481B671</RequestId>
    <HostId>geSe0mXTd5ZFCskr7WK+9iI/RDx+mTTO/tgt25uGTK9v+fmUeM8qx6bkTSjPI3rgxPO4aNRrHEM=</HostId>
</Error>

It works fine on my Windows 10 machine, but when I try to execute it on Linux (RPi OS) the exception is thrown.

If I take the URL from the exception message and paste it into the browser (on Linux), then the file downloads just fine as well.

I tried to execute the program with sudo but the result is the same.


I guess one way would be to retrieve URL from the exception since I don't really know how it is generated, and use Runtime to execute cURL command. But I'd like to avoid it Just use redirect URL and continue with it.


Edit 1: cURL request would have the next form: curl -L -H "Accept: application/octet-stream" -H "Authorization: Bearer <token>" <url_to_the_asset> --output <name_of_the_file>


Edit 2: Added content of ErrorStream and partial solution

Yorick1257
  • 11
  • 1
  • 2
  • 1
    Hello and welcome. What exception is thrown? What part of the code generates it? – Federico klez Culloca Aug 17 '20 at 14:11
  • Please [edit] your question to provide a [mre] demonstrating the problem and the full [stack trace](https://stackoverflow.com/questions/3988788/) of the exception(s). – Slaw Aug 17 '20 at 14:28
  • @FedericoklezCulloca line 7, below the comment - `InputStream inStream = downloadconnection.getInputStream(); `. It's IOException with a message "Server returned HTTP response code: 400 for URL: ..." – Yorick1257 Aug 17 '20 at 14:36
  • If it works from the browser you should try and reproduce the request as closely as possible. In particular I suspect you're missing some headers that the server expects to be there. – Federico klez Culloca Aug 17 '20 at 14:53
  • I've updated the post, though it won't work directly since I'm not sure if posting my OAuth2 Git token is safe. @FedericoklezCulloca do you know, maybe there is a better way of downloading files in Java? Because at this point I have no idea what could be missing. – Yorick1257 Aug 17 '20 at 15:06
  • Last ditch effort: try with `setRequestProperty` instead of `addRequestProperty`. Then I'm out of ideas. – Federico klez Culloca Aug 17 '20 at 15:21
  • @FedericoklezCulloca Unfortunately, nothing. I'm thinking the problem is with OS itself since cURL doesn't download files if I run it from Java either at the moment... Anyway, thanks! – Yorick1257 Aug 17 '20 at 15:29

1 Answers1

0

The difference of your code and the cURL example is Bearer ...

So, try something kile this:

 downloadconnection.addRequestProperty("Authorization", "Bearer " + token);
Usagi Miyamoto
  • 6,196
  • 1
  • 19
  • 33