]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/common_http.py
Flesh out "tahoe magic-folder status" command
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / common_http.py
1
2 import os
3 from cStringIO import StringIO
4 import urlparse, httplib
5 import allmydata # for __full_version__
6
7 from allmydata.util.encodingutil import quote_output
8 from allmydata.scripts.common import TahoeError
9 from socket import error as socket_error
10
11 # copied from twisted/web/client.py
12 def parse_url(url, defaultPort=None):
13     url = url.strip()
14     parsed = urlparse.urlparse(url)
15     scheme = parsed[0]
16     path = urlparse.urlunparse(('','')+parsed[2:])
17     if defaultPort is None:
18         if scheme == 'https':
19             defaultPort = 443
20         else:
21             defaultPort = 80
22     host, port = parsed[1], defaultPort
23     if ':' in host:
24         host, port = host.split(':')
25         port = int(port)
26     if path == "":
27         path = "/"
28     return scheme, host, port, path
29
30 class BadResponse(object):
31     def __init__(self, url, err):
32         self.status = -1
33         self.reason = "Error trying to connect to %s: %s" % (url, err)
34         self.error = err
35     def read(self):
36         return ""
37
38
39 def do_http(method, url, body=""):
40     if isinstance(body, str):
41         body = StringIO(body)
42     elif isinstance(body, unicode):
43         raise TypeError("do_http body must be a bytestring, not unicode")
44     else:
45         # We must give a Content-Length header to twisted.web, otherwise it
46         # seems to get a zero-length file. I suspect that "chunked-encoding"
47         # may fix this.
48         assert body.tell
49         assert body.seek
50         assert body.read
51     scheme, host, port, path = parse_url(url)
52     if scheme == "http":
53         c = httplib.HTTPConnection(host, port)
54     elif scheme == "https":
55         c = httplib.HTTPSConnection(host, port)
56     else:
57         raise ValueError("unknown scheme '%s', need http or https" % scheme)
58     c.putrequest(method, path)
59     c.putheader("Hostname", host)
60     c.putheader("User-Agent", allmydata.__full_version__ + " (tahoe-client)")
61     c.putheader("Accept", "text/plain, application/octet-stream")
62     c.putheader("Connection", "close")
63
64     old = body.tell()
65     body.seek(0, os.SEEK_END)
66     length = body.tell()
67     body.seek(old)
68     c.putheader("Content-Length", str(length))
69
70     try:
71         c.endheaders()
72     except socket_error, err:
73         return BadResponse(url, err)
74
75     while True:
76         data = body.read(8192)
77         if not data:
78             break
79         c.send(data)
80
81     return c.getresponse()
82
83
84 def format_http_success(resp):
85     return "%s %s" % (resp.status, quote_output(resp.reason, quotemarks=False))
86
87 def format_http_error(msg, resp):
88     return "%s: %s %s\n%s" % (msg, resp.status, quote_output(resp.reason, quotemarks=False),
89                               quote_output(resp.read(), quotemarks=False))
90
91 def check_http_error(resp, stderr):
92     if resp.status < 200 or resp.status >= 300:
93         print >>stderr, format_http_error("Error during HTTP request", resp)
94         return 1
95
96
97 class HTTPError(TahoeError):
98     def __init__(self, msg, resp):
99         TahoeError.__init__(self, format_http_error(msg, resp))