Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload binary files to an existing release #56

Closed
AntonioFasano opened this issue Dec 14, 2016 · 6 comments
Closed

Upload binary files to an existing release #56

AntonioFasano opened this issue Dec 14, 2016 · 6 comments

Comments

@AntonioFasano
Copy link

I would like to a upload binary file to an existing release on GitHub, using the API published here.

developer.github.com/v3/repos/releases

Is it possible to upload a binary with a gh() POST?

In the meantime, I have tried with the R curl package. Assuming RELEASEID is the release ID to upload to, I might use:

library(curl)
h=new_handle()
handle_setheaders(h, Authorization="token XXXXX",
                               "Content-Type" = "application/x-dosexec",
                               "User-Agent" = "curl")

handle_setform(h, app=form_file("app.exe", "application/x-dosexec"))
url="https://uploads.github.com/repos/:OWNER/:REPO/releases/:RELEASEID/assets?name=app.exe"
curl_fetch_memory(url, handle=h)

The upload appears to succeed, but, when I download the file app.exe, it is corrupted.
I do not experience problems with other MIME types, e.g. PDFs.
Also, using curl.exe from the shell, app.exe does not break.

@gaborcsardi
Copy link
Member

Yes, this is somewhat cumbersome in gh, but possible, nevertheless. It goes like this:

library(gh)

## Get a list of releases
## https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository

rels <- gh(
  "/repos/:owner/:repo/releases",
  owner = "gh-testing",
  repo = "myrepo"
)

## Get a single release
## https://developer.github.com/v3/repos/releases/#get-a-single-release

rel <- gh(
  "/repos/:owner/:repo/releases/:id",
  owner = "gh-testing",
  repo = "myrepo",
  id = rels[[1]]$id
)

## Extract the upload url, we don't support URI templates (yet),
## so you need to handle the {} part manually.

upload_url <- gsub("\\{[^\\}]+}", "", rel$upload_url)

## Upload a file
## https://developer.github.com/v3/repos/releases/#upload-a-release-asset

cat("This will be uploaded\n", file = "asset.txt")

gh(
  paste0("POST ", upload_url, "?name=asset.txt"),
  readBin("asset.txt", raw(), file.info("asset.txt")$size),
  .send_headers = c("Content-Type" = "text/plain")
)

@AntonioFasano
Copy link
Author

AntonioFasano commented Dec 16, 2016

Unfortunately, I experience the same problems.
The upload appears to succeed, but, when I download the binary file, it is corrupted.

I tried to upload the binary with the following MIME types:

  • application/x-dosexec,
  • application/octet-stream,
  • text/plain.

With my code I was able to upload and open a PDF using the MIME type application/pdf; now the PDF download results in a corrupted file too.

Just like before, the size of the upload shown in GitHub and downloaded is larger: my test 93K binary increases to 128K. file.info correctly reports the size anyway.

Not really important, but for the sake of reproducibility, I uploaded to a draft release.
I am using x64 Windows 10 .

@gaborcsardi
Copy link
Member

gaborcsardi commented Dec 16, 2016

It seems that the exe file is encoded (probably base64 or sg similar), and it is not decoded at the server.

What's your curl.exe command line?

@AntonioFasano
Copy link
Author

Using MSYS2 zsh:

upload=$(echo $upload | cut -d "\"" -f4 | cut -d "{" -f1)
upload="$upload?name=$theAsset"
succ=$(curl -H "Authorization: token $GITHUB_PAT" \
     -H "Content-Type: $(file -b --mime-type $theAsset)" \
     --data-binary @$theAsset $upload)

where:

$(file -b --mime-type $theAsset)

gives application/x-dosexec

Note that I have tried with a number of different test files.
As a small reference file, I used DriverView.exe binary in driverview-x64.zip from NirSoft.

@gaborcsardi
Copy link
Member

Finally this is now fixed. E.g.

binary <- "~/Downloads/clipboard.exe"

gh(
  paste0("POST https://uploads.github.com/repos/gaborcsardi/playground/releases/233390/assets",
         "?name=clipboard.exe"),
  readBin(binary, raw(), file.info(binary)$size),
  .send_headers = c("Content-Type" = "application/vnd.microsoft.portable-executable")
)

@AntonioFasano
Copy link
Author

Finally I was able to check your code. I confirm it works for me too.
Also, by inspecting gh(), the naked version (based only on curl) is:

## Customise this with your OWNER/REPO, Release ID and binary 
binary <- "~/Downloads/clipboard.exe"
url <- "https://uploads.github.com/repos/gaborcsardi/playground/releases/233390/assets?name=clipboard.exe"
perstoken <- "XXXXX"
 
 
library(curl)
h <- new_handle()
handle_setopt(h, .list = list(
                     post=TRUE, postfieldsize= file.info(binary)$size, 
                     postfields= readBin(binary, raw(), file.info(binary)$size)))
 
handle_setheaders(h, Authorization=paste0("token ", perstoken),
                  "Content-Type" = "application/x-dosexec")
 
req <- curl_fetch_memory(url, handle = h)

So it seems that handle_setform() should be avoided in favour of manually loading the file as a post field via readBin().
One can enrich the headers with the "User-Agent", "Accept" = "application/vnd.github.v3+json" or use
application/vnd.microsoft.portable-executable as content type.

R code was executed in Linux and the download test was executed in Windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants