3 from cStringIO import StringIO
4 import urlparse, httplib
5 import allmydata # for __full_version__
7 from allmydata.util.encodingutil import quote_output
8 from allmydata.scripts.common import TahoeError
9 from socket import error as socket_error
11 # copied from twisted/web/client.py
12 def parse_url(url, defaultPort=None):
14 parsed = urlparse.urlparse(url)
16 path = urlparse.urlunparse(('','')+parsed[2:])
17 if defaultPort is None:
22 host, port = parsed[1], defaultPort
24 host, port = host.split(':')
28 return scheme, host, port, path
30 class BadResponse(object):
31 def __init__(self, url, err):
33 self.reason = "Error trying to connect to %s: %s" % (url, err)
39 def do_http(method, url, body=""):
40 if isinstance(body, str):
42 elif isinstance(body, unicode):
43 raise TypeError("do_http body must be a bytestring, not unicode")
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"
51 scheme, host, port, path = parse_url(url)
53 c = httplib.HTTPConnection(host, port)
54 elif scheme == "https":
55 c = httplib.HTTPSConnection(host, port)
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")
65 body.seek(0, os.SEEK_END)
68 c.putheader("Content-Length", str(length))
72 except socket_error, err:
73 return BadResponse(url, err)
76 data = body.read(8192)
81 return c.getresponse()
84 def format_http_success(resp):
85 return "%s %s" % (resp.status, quote_output(resp.reason, quotemarks=False))
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))
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)
97 class HTTPError(TahoeError):
98 def __init__(self, msg, resp):
99 TahoeError.__init__(self, format_http_error(msg, resp))