/usr/share/pyshared/circuits/web/client.py is in python-circuits 2.1.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse # NOQA
from circuits.web.headers import Headers
from circuits.core import handler, BaseComponent, Event
from circuits.net.sockets import TCPClient, Connect, Write, Close
from circuits.net.protocols.http import HTTP
def parse_url(url):
p = urlparse(url)
if p.hostname:
host = p.hostname
else:
raise ValueError("URL must be absolute")
if p.scheme == "http":
secure = False
port = p.port or 80
elif p.scheme == "https":
secure = True
port = p.port or 443
else:
raise ValueError("Invalid URL scheme")
resource = p.path or "/"
if p.query:
resource += "?" + p.query
return (host, port, resource, secure)
class HTTPException(Exception):
pass
class NotConnected(HTTPException):
pass
class Request(Event):
"""Request Event
This Event is used to initiate a new request.
:param method: HTTP Method (PUT, GET, POST, DELETE)
:type method: str
:param path: Path to resource
:type path: str
"""
def __init__(self, method, path, body=None, headers={}):
"x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
super(Request, self).__init__(method, path, body, headers)
class Client(BaseComponent):
channel = "client"
def __init__(self, url, channel=channel):
super(Client, self).__init__(channel=channel)
self._host, self._port, self._resource, self._secure = parse_url(url)
self._response = None
self._transport = TCPClient(channel=channel).register(self)
HTTP(channel=channel).register(self._transport)
@handler("write")
def write(self, data):
if self._transport.connected:
self.fire(Write(data), self._transport)
@handler("close")
def close(self):
if self._transport.connected:
self.fire(Close(), self._transport)
@handler("connect", filter=True)
def connect(self, host=None, port=None, secure=None):
host = host or self._host
port = port or self._port
secure = secure or self._secure
if not self._transport.connected:
self.fire(Connect(host, port, secure), self._transport)
return True
@handler("request")
def request(self, method, path, body=None, headers={}):
if self._transport.connected:
headers = Headers([(k, v) for k, v in headers.items()])
# Clients MUST include Host header in HTTP/1.1 requests (RFC 2616)
if "Host" not in headers:
headers["Host"] = self._host \
+ (":" + str(self._port)) if self._port else ""
if body is not None:
headers["Content-Length"] = len(body)
command = "%s %s HTTP/1.1" % (method, path)
message = "%s\r\n%s" % (command, headers)
self.fire(Write(message.encode('utf-8')), self._transport)
if body is not None:
self.fire(Write(body), self._transport)
else:
raise NotConnected()
@handler("response")
def _on_response(self, response):
self._response = response
if response.headers.get("Connection") == "Close":
self.fire(Close(), self._transport)
@property
def connected(self):
if hasattr(self, "_transport"):
return self._transport.connected
@property
def response(self):
return getattr(self, "_response", None)
|