This is as far as I got before giving up due to libcurl's low level interface (std.net.curl doesn't have a way to upload a file with extra fields, if it did this would have been amazingly simple):
#!/usr/bin/rdmd
import std.stdio, std.net.curl, std.string, std.json, std.conv;
import etc.c.curl;
void main(string[] args)
{
write("GitHub username: ");
auto username = readln().chomp();
write("GitHub password: ");
auto password = readln().chomp();
write("GitHub repo: ");
auto repo = readln().chomp();
write("Description: ");
auto desc = readln().chomp();
write("MIME type: ");
auto mime = readln().chomp();
auto client = HTTP();
client.setAuthentication(username, password);
~ "/downloads";
auto create_json = format(
q"#{ "name": "%s", "size": %d, "description": "%s",
"content_type": "%s" }#",
args[1], File(args[1]).size(), desc, mime);
auto create_response = post(create_url, create_json, client);
auto cj = parseJSON(create_response);
Curl curl;
curl.initialize();
curl.set(CurlOption.url, cj["s3_url"].str);
// missing from etc.c.curl
enum CURLFORM_COPYNAME = 1;
enum CURLFORM_COPYCONTENTS = 4;
enum CURLFORM_FILE = 10;
enum CURLFORM_CONTENTTYPE = 14;
enum CURLFORM_END = 17;
curl_httppost *post=null;
curl_httppost *last=null;
void formadd(string key, string value) {
curl_formadd(&post, &last, CURLFORM_COPYNAME, key.toStringz(),
CURLFORM_COPYCONTENTS, value.toStringz(), CURLFORM_END);
}
formadd("key", cj["path"].str);
formadd("acl", cj["acl"].str);
formadd("success_action_status", "201");
formadd("Filename", cj["name"].str);
formadd("AWSAccessKeyId", cj["accesskeyid"].str);
formadd("Policy", cj["policy"].str);
formadd("Signature", cj["signature"].str);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "Content-Type",
CURLFORM_CONTENTTYPE, cj["mime_type"].str.toStringz(),
CURLFORM_END);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, args[1].toStringz(),
CURLFORM_END);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "name",
CURLFORM_COPYCONTENTS, cj["name"].str.toStringz(),
CURLFORM_END);
curl.set(CurlOption.httppost, post);
curl.onProgress = delegate int(size_t dltotal, size_t dlnow, size_t ultotal,
size_t ulnow)
{
writeln("Progress: uploaded bytes ", ulnow, " of ", ultotal);
return 0;
};
curl.perform();
curl_formfree(post);
}