def set_cookie(name, _, *args): cookie = SimpleCookie() cookie[name] = base64.b64encode(":".join(args)) cookie[name]['path'] = "/" cookie[name]["expires"] = _expiration(5) # 5 minutes from now logger.debug("Cookie expires: %s", cookie[name]["expires"]) return tuple(cookie.output().split(": ", 1))
def set_cookie(name, _, *args): cookie = SimpleCookie() cookie[name] = base64.b64encode(":".join(args)) cookie[name]['path'] = "/" cookie[name]["expires"] = _expiration(5) # 5 minutes from now logger.debug("Cookie expires: %s", cookie[name]["expires"]) return tuple(cookie.output().split(": ", 1))
def make_cookie(name, load, seed, expire=0, domain="", path="", timestamp=""): """ Create and return a cookie :param name: Cookie name :param load: Cookie load :param seed: A seed for the HMAC function :param expire: Number of minutes before this cookie goes stale :param domain: The domain of the cookie :param path: The path specification for the cookie :return: A tuple to be added to headers """ cookie = SimpleCookie() if not timestamp: timestamp = str(int(time.mktime(time.gmtime()))) signature = cookie_signature(seed, load, timestamp) cookie[name] = "|".join([load, timestamp, signature]) if path: cookie[name]["path"] = path if domain: cookie[name]["domain"] = domain if expire: cookie[name]["expires"] = _expiration(expire, "%a, %d-%b-%Y %H:%M:%S GMT") return tuple(cookie.output().split(": ", 1))
def build_wsgi_environ(self, method, path, body, content_type, cookies=None, **kw): # NOTE that in Pando (request.py make_franken_headers) only headers # beginning with ``HTTP`` are included in the request - and those are # changed to no longer include ``HTTP``. There are currently 2 # exceptions to this: ``'CONTENT_TYPE'``, ``'CONTENT_LENGTH'`` which # are explicitly checked for. if isinstance(cookies, dict) and not isinstance(cookies, SimpleCookie): cookies, d = SimpleCookie(), cookies for k, v in d.items(): cookies[str(k)] = str(v) typecheck(path, (bytes, text_type), method, text_type, content_type, bytes, body, bytes) environ = {} environ[b'CONTENT_TYPE'] = content_type if cookies is not None: environ[b'HTTP_COOKIE'] = cookies.output(header='', sep='; ') environ[b'HTTP_HOST'] = b'localhost' environ[b'PATH_INFO'] = path.encode( 'ascii') if type(path) != bytes else path environ[b'REMOTE_ADDR'] = b'0.0.0.0' environ[b'REQUEST_METHOD'] = method.encode('ascii') environ[b'SERVER_PROTOCOL'] = b'HTTP/1.1' environ[b'wsgi.input'] = BytesIO(body) environ[b'HTTP_CONTENT_LENGTH'] = str(len(body)).encode('ascii') environ.update((k.encode('ascii'), v) for k, v in kw.items()) return environ
def make_cookie(name, load, seed, expire=0, domain="", path="", timestamp=""): """ Create and return a cookie :param name: Cookie name :param load: Cookie load :param seed: A seed for the HMAC function :param expire: Number of minutes before this cookie goes stale :param domain: The domain of the cookie :param path: The path specification for the cookie :return: A tuple to be added to headers """ cookie = SimpleCookie() if not timestamp: timestamp = str(int(time.mktime(time.gmtime()))) signature = cookie_signature(seed, load, timestamp) cookie[name] = "|".join([load, timestamp, signature]) if path: cookie[name]["path"] = path if domain: cookie[name]["domain"] = domain if expire: cookie[name]["expires"] = _expiration(expire, "%a, %d-%b-%Y %H:%M:%S GMT") return tuple(cookie.output().split(": ", 1))
def build_wsgi_environ(self, method, path, body, content_type, cookies=None, **kw): # NOTE that in Pando (request.py make_franken_headers) only headers # beginning with ``HTTP`` are included in the request - and those are # changed to no longer include ``HTTP``. There are currently 2 # exceptions to this: ``'CONTENT_TYPE'``, ``'CONTENT_LENGTH'`` which # are explicitly checked for. if isinstance(cookies, dict) and not isinstance(cookies, SimpleCookie): cookies, d = SimpleCookie(), cookies for k, v in d.items(): cookies[str(k)] = str(v) typecheck(path, (bytes, text_type), method, text_type, content_type, bytes, body, bytes) environ = {} environ[b'CONTENT_TYPE'] = content_type if cookies is not None: environ[b'HTTP_COOKIE'] = cookies.output(header='', sep='; ') environ[b'HTTP_HOST'] = b'localhost' environ[b'PATH_INFO'] = path.encode('ascii') if type(path) != bytes else path environ[b'REMOTE_ADDR'] = b'0.0.0.0' environ[b'REQUEST_METHOD'] = method.encode('ascii') environ[b'SERVER_PROTOCOL'] = b'HTTP/1.1' environ[b'wsgi.input'] = BytesIO(body) environ[b'HTTP_CONTENT_LENGTH'] = str(len(body)).encode('ascii') environ.update((k.encode('ascii'), v) for k, v in kw.items()) return environ
def set_cookie(self, user): uid = rndstr(32) self.uid2user[uid] = user cookie = SimpleCookie() cookie[self.cookie_name] = uid cookie[self.cookie_name]["path"] = "/" cookie[self.cookie_name]["expires"] = _expiration(480) logger.debug("Cookie expires: %s", cookie[self.cookie_name]["expires"]) return cookie.output().split(": ", 1)
def set_cookie(self, user): uid = rndstr(32) self.uid2user[uid] = user cookie = SimpleCookie() cookie[self.cookie_name] = uid cookie[self.cookie_name]['path'] = "/" cookie[self.cookie_name]["expires"] = _expiration(480) logger.debug("Cookie expires: %s", cookie[self.cookie_name]["expires"]) return cookie.output().encode("UTF-8").split(": ", 1)
def delete_cookie(environ, name): kaka = environ.get("HTTP_COOKIE", "") logger.debug("delete KAKA: %s", kaka) if kaka: cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name, None) cookie = SimpleCookie() cookie[name] = "" cookie[name]["path"] = "/" logger.debug("Expire: %s", morsel) cookie[name]["expires"] = _expiration("dawn") return tuple(cookie.output().split(": ", 1)) return None
def delete_cookie(environ, name): kaka = environ.get("HTTP_COOKIE", '') logger.debug("delete KAKA: %s", kaka) if kaka: cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name, None) cookie = SimpleCookie() cookie[name] = "" cookie[name]['path'] = "/" logger.debug("Expire: %s", morsel) cookie[name]["expires"] = _expiration("dawn") return tuple(cookie.output().split(": ", 1)) return None
def delete_cookie(self, environ): cookie = environ.get("HTTP_COOKIE", '') logger.debug("delete cookie: %s", cookie) if cookie: _name = self.cookie_name cookie_obj = SimpleCookie(cookie) morsel = cookie_obj.get(_name, None) cookie = SimpleCookie() cookie[_name] = "" cookie[_name]['path'] = "/" logger.debug("Expire: %s", morsel) cookie[_name]["expires"] = _expiration("now") return cookie.output().split(": ", 1) return None
def delete_cookie(self, environ): cookie = environ.get("HTTP_COOKIE", "") logger.debug("delete cookie: %s", cookie) if cookie: _name = self.cookie_name cookie_obj = SimpleCookie(cookie) morsel = cookie_obj.get(_name, None) cookie = SimpleCookie() cookie[_name] = "" cookie[_name]["path"] = "/" logger.debug("Expire: %s", morsel) cookie[_name]["expires"] = _expiration("now") return cookie.output().split(": ", 1) return None
def set_cookie(name, _, *args): cookie = SimpleCookie() data = ":".join(args) if not isinstance(data, six.binary_type): data = data.encode("ascii") data64 = base64.b64encode(data) if not isinstance(data64, six.string_types): data64 = data64.decode("ascii") cookie[name] = data64 cookie[name]["path"] = "/" cookie[name]["expires"] = _expiration(5) # 5 minutes from now logger.debug("Cookie expires: %s", cookie[name]["expires"]) return tuple(cookie.output().split(": ", 1))
def request(self, sitename, path, method='GET', data=None): url = self.base_url + '/' + sitename + path path = '/' + sitename + path if isinstance(data, dict): for k in data.keys(): if data[k] is None: del data[k] if web.config.debug: web.ctx.infobase_req_count = 1 + web.ctx.get( 'infobase_req_count', 0) a = time.time() _path = path _data = data headers = {} if data: if isinstance(data, dict): data = dict( (web.safestr(k), web.safestr(v)) for k, v in data.items()) data = urlencode(data) headers['Content-Type'] = 'application/x-www-form-urlencoded' if method == 'GET': path += '?' + data data = None stats.begin("infobase", path=path, method=method, data=data) conn = HTTPConnection(self.base_url) env = web.ctx.get('env') or {} if self.auth_token: c = SimpleCookie() c['infobase_auth_token'] = quote(self.auth_token) cookie = c.output(header='').strip() headers['Cookie'] = cookie # pass the remote ip to the infobase server headers['X-REMOTE-IP'] = web.ctx.get('ip') try: conn.request(method, path, data, headers=headers) response = conn.getresponse() stats.end() except socket.error: stats.end(error=True) logger.error("Unable to connect to infobase server", exc_info=True) raise ClientException("503 Service Unavailable", "Unable to connect to infobase server") cookie = response.getheader('Set-Cookie') if cookie: c = SimpleCookie() c.load(cookie) if 'infobase_auth_token' in c: auth_token = c['infobase_auth_token'].value # The auth token will be in urlquoted form, unquote it before use. # Otherwise, it will be quoted twice this value is set as cookie. auth_token = auth_token and unquote(auth_token) self.set_auth_token(auth_token) if web.config.debug: b = time.time() print("%.02f (%s):" % (round(b - a, 2), web.ctx.infobase_req_count), response.status, method, _path, _data, file=web.debug) if response.status == 200: return response.read() else: self.handle_error("%d %s" % (response.status, response.reason), response.read())
class Response(object): """An HTTP Response, including status, headers, and body.""" status = '' """The HTTP Status-Code and Reason-Phrase.""" header_list = [] """ A list of the HTTP response headers as (name, value) tuples. In general, you should use response.headers (a dict) instead. This attribute is generated from response.headers and is not valid until after the finalize phase.""" headers = httputil.HeaderMap() """ A dict-like object containing the response headers. Keys are header names (in Title-Case format); however, you may get and set them in a case-insensitive manner. That is, headers['Content-Type'] and headers['content-type'] refer to the same value. Values are header values (decoded according to :rfc:`2047` if necessary). .. seealso:: classes :class:`HeaderMap`, :class:`HeaderElement` """ cookie = SimpleCookie() """See help(Cookie).""" body = ResponseBody() """The body (entity) of the HTTP response.""" time = None """The value of time.time() when created. Use in HTTP dates.""" stream = False """If False, buffer the response body.""" def __init__(self): self.status = None self.header_list = None self._body = [] self.time = time.time() self.headers = httputil.HeaderMap() # Since we know all our keys are titled strings, we can # bypass HeaderMap.update and get a big speed boost. dict.update(self.headers, { 'Content-Type': 'text/html', 'Server': 'CherryPy/' + cherrypy.__version__, 'Date': httputil.HTTPDate(self.time), }) self.cookie = SimpleCookie() def collapse_body(self): """Collapse self.body to a single string; replace it and return it.""" if isinstance(self.body, text_or_bytes): return self.body newbody = [] for chunk in self.body: if six.PY3 and not isinstance(chunk, bytes): raise TypeError("Chunk %s is not of type 'bytes'." % repr(chunk)) newbody.append(chunk) newbody = b''.join(newbody) self.body = newbody return newbody def finalize(self): """Transform headers (and cookies) into self.header_list. (Core)""" try: code, reason, _ = httputil.valid_status(self.status) except ValueError: raise cherrypy.HTTPError(500, sys.exc_info()[1].args[0]) headers = self.headers self.status = '%s %s' % (code, reason) self.output_status = ntob(str(code), 'ascii') + \ b' ' + headers.encode(reason) if self.stream: # The upshot: wsgiserver will chunk the response if # you pop Content-Length (or set it explicitly to None). # Note that lib.static sets C-L to the file's st_size. if dict.get(headers, 'Content-Length') is None: dict.pop(headers, 'Content-Length', None) elif code < 200 or code in (204, 205, 304): # "All 1xx (informational), 204 (no content), # and 304 (not modified) responses MUST NOT # include a message-body." dict.pop(headers, 'Content-Length', None) self.body = b'' else: # Responses which are not streamed should have a Content-Length, # but allow user code to set Content-Length if desired. if dict.get(headers, 'Content-Length') is None: content = self.collapse_body() dict.__setitem__(headers, 'Content-Length', len(content)) # Transform our header dict into a list of tuples. self.header_list = h = headers.output() cookie = self.cookie.output() if cookie: for line in cookie.split('\r\n'): name, value = line.split(': ', 1) if isinstance(name, six.text_type): name = name.encode('ISO-8859-1') if isinstance(value, six.text_type): value = headers.encode(value) h.append((name, value))
class HTTP(object): HTTPError = HTTPError def __init__(self, script): self.script = script if script: # For testing purposes self.logger = PrefixLoggerAdapter(script.logger, "http") self.headers = {} self.cookies = None self.session_started = False self.request_id = 1 self.session_id = None self.request_middleware = None if self.script: # For testing purposes self.setup_middleware() def get_url(self, path): address = self.script.credentials["address"] port = self.script.credentials.get("http_port") if port: address += ":%s" % port proto = self.script.credentials.get("http_protocol", "http") return "%s://%s%s" % (proto, address, path) def get(self, path, headers=None, cached=False, json=False, eof_mark=None, use_basic=False): """ Perform HTTP GET request :param path: URI :param headers: Dict of additional headers :param cached: Cache result :param json: Decode json if set to True :param eof_mark: Waiting eof_mark in stream for end session (perhaps device return length 0) :param use_basic: Use basic authentication """ self.ensure_session() self.request_id += 1 self.logger.debug("GET %s", path) if cached: cache_key = "get_%s" % path r = self.script.root.http_cache.get(cache_key) if r is not None: self.logger.debug("Use cached result") return r user, password = None, None if use_basic: user = self.script.credentials.get("user") password = self.script.credentials.get("password") # Apply GET middleware url = self.get_url(path) hdr = self._get_effective_headers(headers) if self.request_middleware: for mw in self.request_middleware: url, _, hdr = mw.process_get(url, "", hdr) code, headers, result = fetch_sync( url, headers=hdr, request_timeout=60, follow_redirects=True, allow_proxy=False, validate_cert=False, eof_mark=eof_mark, user=user, password=password, ) if not 200 <= code <= 299: raise HTTPError(msg="HTTP Error (%s)" % result[:256], code=code) self._process_cookies(headers) if json: try: result = ujson.loads(result) except ValueError as e: raise HTTPError("Failed to decode JSON: %s", e) self.logger.debug("Result: %r", result) if cached: self.script.root.http_cache[cache_key] = result return result def post(self, path, data, headers=None, cached=False, json=False, eof_mark=None, use_basic=False): """ Perform HTTP GET request :param path: URI :param headers: Dict of additional headers :param cached: Cache result :param json: Decode json if set to True :param eof_mark: Waiting eof_mark in stream for end session (perhaps device return length 0) :param use_basic: Use basic authentication """ self.ensure_session() self.request_id += 1 self.logger.debug("POST %s %s", path, data) if cached: cache_key = "post_%s" % path r = self.script.root.http_cache.get(cache_key) if r is not None: self.logger.debug("Use cached result") return r user, password = None, None if use_basic: user = self.script.credentials.get("user") password = self.script.credentials.get("password") # Apply POST middleware url = self.get_url(path) hdr = self._get_effective_headers(headers) if self.request_middleware: for mw in self.request_middleware: url, data, hdr = mw.process_post(url, data, hdr) code, headers, result = fetch_sync( url, method="POST", body=data, headers=hdr, request_timeout=60, follow_redirects=True, allow_proxy=False, validate_cert=False, eof_mark=eof_mark, user=user, password=password, ) if not 200 <= code <= 299: raise HTTPError(msg="HTTP Error (%s)" % result[:256], code=code) self._process_cookies(headers) if json: try: return ujson.loads(result) except ValueError as e: raise HTTPError(msg="Failed to decode JSON: %s" % e) self.logger.debug("Result: %r", result) if cached: self.script.root.http_cache[cache_key] = result return result def close(self): if self.session_started: self.shutdown_session() def _process_cookies(self, headers): """ Process and store cookies from response headers :param headers: :return: """ cdata = headers.get("Set-Cookie") if not cdata: return if not self.cookies: self.cookies = SimpleCookie() self.cookies.load(cdata) def get_cookie(self, name): """ Get cookie name by value :param name: :return: Morsel object or None """ if not self.cookies: return None return self.cookies.get(name) def _get_effective_headers(self, headers): """ Append session headers when necessary. Apply effective cookies :param headers: :return: """ if self.headers: if headers: headers = headers.copy() else: headers = {} headers.update(self.headers) elif not headers and self.cookies: headers = {} if self.cookies: headers["Cookie"] = self.cookies.output(header="").lstrip() return headers def set_header(self, name, value): """ Set HTTP header to be set with all following requests :param name: :param value: :return: """ self.logger.debug("Set header: %s = %s", name, value) self.headers[name] = str(value) def set_session_id(self, session_id): """ Set session_id to be reused by middleware :param session_id: :return: None """ if session_id is not None: self.session_id = session_id else: self.session_id = None def ensure_session(self): if not self.session_started: self.session_started = True self.setup_session() def setup_session(self): if self.script.profile.setup_http_session: self.logger.debug("Setup http session") self.script.profile.setup_http_session(self.script) def shutdown_session(self): if self.script.profile.shutdown_http_session: self.logger.debug("Shutdown http session") self.script.profile.shutdown_http_session(self.script) def setup_middleware(self): mw_list = self.script.profile.get_http_request_middleware(self.script) if not mw_list: return self.request_middleware = [] for mw_cfg in mw_list: if isinstance(mw_cfg, tuple): name, cfg = mw_cfg else: name, cfg = mw_cfg, {} if "." in name: # Handler mw_cls = get_handler(name) assert mw_cls assert issubclass(mw_cls, BaseMiddleware) else: # Middleware name mw_cls = loader.get_class(name) self.request_middleware += [mw_cls(self, **cfg)]
def update_cookies(base_value, cookies): cookie = SimpleCookie(base_value) for k, v in cookies.items(): cookie[k] = v return str(cookie.output(header='', sep=';').lstrip())
def update_cookies(base_value, cookies): cookie = SimpleCookie(base_value) for k, v in cookies.items(): cookie[k] = v return cookie.output(header='', sep=';').lstrip()
class Response(object): """An HTTP Response, including status, headers, and body.""" status = '' """The HTTP Status-Code and Reason-Phrase.""" header_list = [] """ A list of the HTTP response headers as (name, value) tuples. In general, you should use response.headers (a dict) instead. This attribute is generated from response.headers and is not valid until after the finalize phase.""" headers = httputil.HeaderMap() """ A dict-like object containing the response headers. Keys are header names (in Title-Case format); however, you may get and set them in a case-insensitive manner. That is, headers['Content-Type'] and headers['content-type'] refer to the same value. Values are header values (decoded according to :rfc:`2047` if necessary). .. seealso:: classes :class:`HeaderMap`, :class:`HeaderElement` """ cookie = SimpleCookie() """See help(Cookie).""" body = ResponseBody() """The body (entity) of the HTTP response.""" time = None """The value of time.time() when created. Use in HTTP dates.""" stream = False """If False, buffer the response body.""" def __init__(self): self.status = None self.header_list = None self._body = [] self.time = time.time() self.headers = httputil.HeaderMap() # Since we know all our keys are titled strings, we can # bypass HeaderMap.update and get a big speed boost. dict.update(self.headers, { 'Content-Type': 'text/html', 'Server': 'CherryPy/' + cherrypy.__version__, 'Date': httputil.HTTPDate(self.time), }) self.cookie = SimpleCookie() def collapse_body(self): """Collapse self.body to a single string; replace it and return it.""" if isinstance(self.body, text_or_bytes): return self.body newbody = [] for chunk in self.body: if six.PY3 and not isinstance(chunk, bytes): raise TypeError("Chunk %s is not of type 'bytes'." % repr(chunk)) newbody.append(chunk) newbody = b''.join(newbody) self.body = newbody return newbody def _flush_body(self): """ Discard self.body but consume any generator such that any finalization can occur, such as is required by caching.tee_output(). """ consume(iter(self.body)) def finalize(self): """Transform headers (and cookies) into self.header_list. (Core)""" try: code, reason, _ = httputil.valid_status(self.status) except ValueError: raise cherrypy.HTTPError(500, sys.exc_info()[1].args[0]) headers = self.headers self.status = '%s %s' % (code, reason) self.output_status = ntob(str(code), 'ascii') + \ b' ' + headers.encode(reason) if self.stream: # The upshot: wsgiserver will chunk the response if # you pop Content-Length (or set it explicitly to None). # Note that lib.static sets C-L to the file's st_size. if dict.get(headers, 'Content-Length') is None: dict.pop(headers, 'Content-Length', None) elif code < 200 or code in (204, 205, 304): # "All 1xx (informational), 204 (no content), # and 304 (not modified) responses MUST NOT # include a message-body." dict.pop(headers, 'Content-Length', None) self._flush_body() self.body = b'' else: # Responses which are not streamed should have a Content-Length, # but allow user code to set Content-Length if desired. if dict.get(headers, 'Content-Length') is None: content = self.collapse_body() dict.__setitem__(headers, 'Content-Length', len(content)) # Transform our header dict into a list of tuples. self.header_list = h = headers.output() cookie = self.cookie.output() if cookie: for line in cookie.split('\r\n'): name, value = line.split(': ', 1) if isinstance(name, six.text_type): name = name.encode('ISO-8859-1') if isinstance(value, six.text_type): value = headers.encode(value) h.append((name, value))