| #!/usr/bin/python |
| # Copyright 2011 Google Inc. All Rights Reserved. |
| # |
| """A command-line tool for uploading to gfiber-dropbox.appspot.com.""" |
| |
| __author__ = 'apenwarr@google.com (Avery Pennarun)' |
| |
| import httplib |
| import os.path |
| import signal |
| import sys |
| import time |
| import urllib |
| import zlib |
| import options |
| |
| |
| optspec = """ |
| upload-logs [options...] <filenames...> |
| -- |
| s,server= The server URL [https://gfiber-dropbox.appspot.com] |
| k,key= Add a key/value pair (format "-k key=value") |
| stdin= Also upload stdin, with the given virtual filename |
| """ |
| |
| |
| class HttpError(Exception): |
| def __init__(self, result): |
| self.status = result.status |
| self.reason = result.reason |
| Exception.__init__(self, str(self)) |
| |
| def __str__(self): |
| return 'http status %d: %s' % (self.status, self.reason) |
| |
| |
| def UrlSplit(url): |
| proto, rest = urllib.splittype(url) |
| hostport, rest = urllib.splithost(rest) |
| path, query = urllib.splitquery(rest) |
| return proto, hostport, path, query |
| |
| |
| def HttpDo(method, url, content, headers): |
| """Make an HTTP request and return the result.""" |
| proto, hostport, path, query = UrlSplit(url) |
| assert proto.lower() in ('http', 'https') |
| connection = httplib.HTTPConnection(hostport) |
| if query: |
| path += '?' + query |
| connection.request(method, path, content, headers) |
| result = connection.getresponse() |
| if result.status != 200: |
| raise HttpError(result) |
| return result.read() |
| |
| |
| def UploadFile(url, filename, fileobj, keys): |
| """Actually upload the given file to the server.""" |
| while filename.startswith('/'): |
| filename = filename[1:] |
| start_url = os.path.join(url, 'upload', filename) |
| if keys: |
| start_url += '?' + urllib.urlencode(keys) |
| upload_url = HttpDo('GET', start_url, None, headers={}) |
| |
| splitter = 'foo-splitter-%f' % time.time() |
| content_type = 'multipart/form-data; boundary=%s' % splitter |
| |
| basecontent = zlib.compress(fileobj.read()) |
| attachment = ('--%(splitter)s\r\n' |
| 'Content-Disposition: form-data; name="file";' |
| ' filename="%(filename)s"\r\n' |
| '\r\n' |
| '%(data)s' |
| '\r\n' |
| '--%(splitter)s--\r\n' |
| '\r\n' |
| % dict(splitter=splitter, |
| filename=filename, |
| data=basecontent)) |
| |
| try: |
| HttpDo('POST', upload_url, attachment, |
| headers={'Content-Type': content_type, |
| 'Content-Length': len(attachment)}) |
| except HttpError, e: |
| if e.status == 302: |
| pass |
| else: |
| raise |
| else: |
| raise Exception('expected http response code 302') |
| |
| |
| def main(): |
| # set an alarm, in case our HTTP client (or anything else) hangs |
| # for any reason |
| signal.alarm(60) |
| |
| o = options.Options(optspec) |
| (opt, flags, extra) = o.parse(sys.argv[1:]) #pylint: disable-msg=W0612 |
| if not extra and not opt.stdin: |
| o.fatal('at least one filename and/or --stdin expected') |
| keys = [] |
| for k, v in flags: |
| if k in ('-k', '--key'): |
| keys.append(tuple(v.split('=', 1))) |
| |
| if opt.stdin: |
| UploadFile(opt.server, opt.stdin, sys.stdin, keys) |
| for filename in extra: |
| UploadFile(opt.server, filename, open(filename), keys) |
| |
| |
| if __name__ == '__main__': |
| main() |