#!/usr/bin/python

import os, sys, httplib, locale, datetime, hashlib, hmac, base64

def s3request(accesskey, secretkey, httpverb, host, bucket_and_file, body=None):
    locale.setlocale(locale.LC_TIME, "C")
    date = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")

    string_to_sign = (httpverb + "\n" +
                      "\n" + # content-md5
                      "\n" + # content-type
                      date + "\n" +
                      bucket_and_file)
    sha1_hmac = hmac.new(secretkey, string_to_sign, hashlib.sha1);
    auth = "AWS " + accesskey + ":" + base64.b64encode(sha1_hmac.digest())

    http = httplib.HTTPSConnection(host)
    http.request(httpverb, bucket_and_file, body,
                 {"Date": date, "Authorization": auth})

    return http.getresponse()

def usage():
    sys.exit("Usage: s3file.py <GET|PUT|DELETE> <host> /bucket/file [<local file>]")


if len(sys.argv) < 4 or len(sys.argv) > 5:
    usage()

httpverb = sys.argv[1]
host = sys.argv[2]
bucket_and_file = sys.argv[3]
local_file = sys.argv[4] if len(sys.argv) == 5 else None

accesskey = os.getenv("S3ACCESSKEY")
if accesskey is None:
    sys.exit("no S3ACCESSKEY environment variable")

secretkey = os.getenv("S3SECRETKEY")
if secretkey is None:
    sys.exit("no S3SECRETKEY environment variable")

if httpverb == "GET":
    body = None
    expected_response = 200
elif httpverb == "PUT":
    body = sys.stdin if local_file is None else open(local_file)
    output = sys.stdout
    expected_response = 200
elif httpverb == "DELETE":
    if not local_file is None:
        usage()
    body = None
    output = sys.stdout
    expected_response = 204
else:
    usage()

response = s3request(accesskey, secretkey, httpverb, host, bucket_and_file, body)
if response.status != expected_response:
    sys.exit(str(response.status) + " " + response.reason)

content_length = response.getheader("Content-Length")
if content_length is None:
    sys.stderr.write("warning: no Content-Length\n")

if httpverb == "GET":
    output = sys.stdout if local_file is None else open(local_file, "w")

CHUNK_LENGTH = 10 * 1024 * 1024
read_bytes = 0

while True:
    chunk = response.read(CHUNK_LENGTH)
    output.write(chunk)
    read_bytes += len(chunk)
    if len(chunk) != CHUNK_LENGTH:
        break

if not content_length is None and str(read_bytes) != content_length:
    sys.exit("expected %sB, got %i" % (content_length, read_bytes))
