def _serialize(self, data): vin = self._tunnel._version vtar = self._target_version vout = vtar if vtar is not None else vin serializer = json.Serializer(indent=2, force_unicode=True, source_ver=vin, target_ver=vout) self._headers["user-agent"] = http.compose_user_agent(FEAT_IDENT, vout) return serializer.convert(data)
def _update_peer_version(self, response): vser = None server_header = response.headers.get("server", None) if server_header is not None: server_name, server_ver = http.parse_user_agent(server_header) if (server_name != FEAT_IDENT or len(server_ver) != 1 or not isinstance(server_ver[0], int)): raise TunnelError("Unsupported server %r" % server_header) vser = server_ver[0] vin = self._tunnel._version vout = vser if vser is not None and vser < vin else vin self._peer_version = vser self._target_version = vout self._headers["user-agent"] = http.compose_user_agent(FEAT_IDENT, vout) return response
def __init__(self, tunnel, key, security_policy=None): # Overriding default factory timeouts plus a small margin if tunnel.response_timeout is not None: self.response_timeout = tunnel.response_timeout if tunnel.idle_timeout is not None: self.idle_timeout = tunnel.idle_timeout _scheme, host, port = key httpclient.Connection.__init__(self, host, port=port, security_policy=security_policy, logger=tunnel) self._tunnel = tunnel self._key = key self._peer_version = None self._target_version = None self._headers = {} self._headers["host"] = "%s:%d" % (host, port) self._headers["content-type"] = "application/json" ver = tunnel._version self._headers["user-agent"] = http.compose_user_agent(FEAT_IDENT, ver)
def onAllContentReceived(self): vout = self.channel.owner._version ctype = self.get_received_header("content-type") if ctype != "application/json": self._error(http.Status.UNSUPPORTED_MEDIA_TYPE, "Message content type not supported, " "only application/json is.") return agent_header = self.get_received_header("user-agent") if agent_header is None: self._error(http.Status.BAD_REQUEST, "No user agent specified.") return agent_name, agent_ver = http.parse_user_agent(agent_header) if ((agent_name != FEAT_IDENT) or len(agent_ver) != 1 or not isinstance(agent_ver[0], int)): self._error(http.Status.BAD_REQUEST, "User agent not supported.") return vcli = agent_ver[0] if self.method is http.Methods.HEAD: vin = vcli if vcli is not None and vcli < vout else vout server_header = http.compose_user_agent(FEAT_IDENT, vin) self.set_header("server", server_header) self.set_length(0) self.finish() return if self.method is http.Methods.POST: if vcli is not None and vcli > vout: # not safe, better fail self._error(http.Status.UNSUPPORTED_MEDIA_TYPE, "Message version not supported.") return host_header = self.get_received_header("host") if host_header is None: self._error(http.Status.BAD_REQUEST, "Message without host header.") return scheme = self.channel.owner._scheme host, port = http.parse_host(host_header, scheme) uri = http.compose(self.uri, host=host, port=port, scheme=scheme) vin = vcli if vcli is not None else vout unserializer = json.Unserializer(registry=self._registry, source_ver=vin, target_ver=vout) body = "".join(self._buffer) try: data = unserializer.convert(body) except Exception as e: msg = "Error while unserializing tunnel message" error.handle_exception(self, e, msg) self._error(http.Status.BAD_REQUEST, "Invalid message, unserialization failed.") return self.channel.owner._dispatch(uri, data) self.set_response_code(http.Status.OK) server_header = http.compose_user_agent(FEAT_IDENT, vin) self.set_header("server", server_header) self.set_length(0) self.finish() return self.set_response_code(http.Status.NOT_ALLOWED) self.set_header("content-type", "plain/text") self.write("Method not allowed, only POST and HEAD.") self.finish()