def test_login(app_url, uuid): r = requests.post(app_url + '/phone/send', json={'phone': '+380711234567'}) assert r.ok otp_id = r.json()['verification_id'] otps = requests.get( 'https://twilio/2010-04-01/Accounts/123456/Messages.json', verify=False) otp = otps.json()[0]['Body'] print(otp) r = requests.post(app_url + '/phone/login', json={ 'otp_id': otp_id, 'otp': otp }) assert r.ok assert r.headers['access'] is not None assert r.headers['Set-Cookie'] is not None cookie = SimpleCookie() cookie.load(r.headers['Set-Cookie']) assert cookie.get('refresh_token') is not None assert verify_jwt(r.headers['access'], cookie.get('refresh_token').value, BASE_URL + '/phone-pwless-jwk-file/jwk', ['RS256'], uuid, 'Aureole Server') requests.delete('https://twilio/2010-04-01/Accounts/123456/Messages.json', verify=False)
def test_login(app_url, uuid): login_resp = requests.post(app_url + '/login', json={ 'email': '*****@*****.**', 'password': '******' }) assert login_resp.ok assert login_resp.headers['access'] is not None cookie = SimpleCookie() cookie.load(login_resp.headers['Set-Cookie']) assert cookie.get('refresh_token') is not None assert verify_jwt(login_resp.headers['access'], cookie.get('refresh_token').value, app_url + '/gen-keys/jwk', ['ES256'], uuid, 'Aureole Server') refresh_resp = requests.post(app_url + '/refresh', cookies=login_resp.cookies) assert refresh_resp.ok assert refresh_resp.headers['access'] is not None assert verify_jwt(refresh_resp.headers['access'], cookie.get('refresh_token').value, app_url + '/gen-keys/jwk', ['ES256'], uuid, 'Aureole Server')
def test_facebook_login(app_url, uuid): r = requests.get(app_url + '/oauth2/facebook', verify=False) print(r.text) assert r.ok assert r.headers['access'] is not None cookie = SimpleCookie() cookie.load(r.headers['Set-Cookie']) assert cookie.get('refresh_token') is not None assert verify_jwt(r.headers['access'], cookie.get('refresh_token').value, app_url + '/social-auth-jwk-file/jwk', ['RS256'], uuid, 'Aureole Server')
def do_CONNECT(self, initial_data): print("In do_Connect") global secret_key global pamenabled cookies = SimpleCookie(self.headers.get('Cookie')) path = self.path if pamenabled == True: try: cookie = cookies.get("p_auth").value clientip = self.client_address[0] if clientip == "127.0.0.1": if not self.headers.get("x-forwarded-for") == "": clientip = self.headers.get("x-forwarded-for") result = validateCookie(secret_key, cookie, clientip) except: result = False if result == False: self.send_response(302) self.send_header("Location", "/authentication_services") self.end_headers() return None temp = "CONNECT " + self.path + " " + "HTTP/1.1\r\n" cookie = cookies.get("p_auth").value data = cookie.split("username="******"&")[0] else: username = "******" for x in self.headers: if x.lower() == "remote_user": print("Skipping " + x.lower()) elif x.lower() == "cookie": cookietemp = self.headers.get(x).split("=")[0] if cookietemp.lower() == "p_auth": print("Skipping " + x.lower()) else: temp = temp + x + ": " + self.headers.get(x) + "\r\n" else: temp = temp + x + ": " + self.headers.get(x) + "\r\n" temp = temp + "remote_user: "******"\r\n\r\n" #print(temp) self.dataConnectorCONNECT(0, temp, remotehost, int(remoteport))
def parse_cookie(name, seed, kaka): """Parses and verifies a cookie value :param seed: A seed used for the HMAC signature :param kaka: The cookie :return: A tuple consisting of (payload, timestamp) """ if not kaka: return None cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name) if morsel: parts = morsel.value.split("|") if len(parts) != 3: return None # verify the cookie signature sig = cookie_signature(seed, parts[0], parts[1]) if sig != parts[2]: raise SAMLError("Invalid cookie signature") try: return parts[0].strip(), parts[1] except KeyError: return None else: return None
def getSession(self): """Return the existing session or a new session""" if self.session is not None: return self.session # Get value of cookie header that was sent cookie_str = self.headers.get('Cookie') if cookie_str: cookie_obj = SimpleCookie(cookie_str) sid_morsel = cookie_obj.get(self.SESSION_COOKIE_NAME, None) if sid_morsel is not None: sid = sid_morsel.value else: sid = None else: sid = None # If a session id was not set, create a new one if sid is None: sid = randomString(16, '0123456789abcdef') session = None else: session = self.server.sessions.get(sid) # If no session exists for this session ID, create one if session is None: session = self.server.sessions[sid] = {} session['id'] = sid self.session = session return session
def __init__(self, path, query_string, cookie, method, post, url_scheme, host): self._routes = dict() self.pattern_url = "" self.path = path self.full_path = path self.query_string = query_string self.method = method self.post = post self.url_scheme = url_scheme self.host = host self.matchdict = {} self.reinit() if settings.SQLITE_DBNAME: self.db = db.Database(settings.SQLITE_DBNAME) if cookie: request_cookie = SimpleCookie(cookie) if request_cookie.get("session"): session_id = request_cookie["session"].value if session_id: self.session_id = session_id if not self.session_id: self.session_id = uuid.uuid4().hex self.db.insert_session(self.session_id) session = self.db.get_session(self.session_id) self.session, self.session_expires = session if self.session_expires > datetime.datetime.utcnow().replace( tzinfo=datetime.timezone.utc) - timedelta(days=1): cookie = SimpleCookie() cookie["session"] = self.session_id cookie["session"]["expires"] = settings.SESSION_LENGTH self.set_cookie = tuple(cookie.output().split(": ", 1)) self.user = self.db.get_user_by_session(self.session_id)
def upload(env, start_response): form = cgi.FieldStorage(fp=env['wsgi.input'], environ=env, keep_blank_values=True) image = form['image'].value HTTP_COOKIE = env.get('HTTP_COOKIE', '') cookie = SimpleCookie(HTTP_COOKIE) username = cookie.get('username').value file_type = os.path.splitext(form['image'].filename)[-1] file_name = getDigest(username) path = '/home/ubuntu/sources/demo0/images/' + file_name + file_type f = open(path, mode='wb+') f.write(image) db = getDBConn('test_db') cursor = db.cursor() sql = "UPDATE user_db SET profile_image=%s WHERE username=%s;" cursor.execute(sql, [file_name + file_type, username]) db.commit() db.close() image_url = image_url_prefix + file_name + file_type start_response('200 OK', [('Content-type', 'text/html')]) return getTemplate('yagra/profile.html')\ .render(image = image_url, tag = False, username = username)\ .encode('utf-8')
def cookie_parts(name, kaka): cookie_obj = SimpleCookie(text_type(kaka)) morsel = cookie_obj.get(name) if morsel: return morsel.value.split("|") else: return None
def cookie_parts(name, kaka): cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(name) if morsel: return morsel.value.split("|") else: return None
def get_cookie(self, key): cookie_string = self.req_env.get('HTTP_COOKIE', None) if cookie_string is None: return cookie = SimpleCookie() cookie.load(cookie_string) return cookie.get(key, None).value
def _initialize_consent(self): """ Set a consent cookie if not yet present in the cookie jar, and in the request headers as a result. If a pending consent cookie is there, accept it to avoid the blocking page. """ # Make a first request to get initial cookies, in case none were passed # as argument (or failed to load) # TODO perhaps this needs to be done once in a while for very long # running sessions. req = Request('https://www.youtube.com/', headers=self.headers) cookies = SimpleCookie(req.get_header('Cookie')) if cookies.get('__Secure-3PSID'): return consent_id = None consent = cookies.get('CONSENT') if consent: if 'YES' in consent.value: return consent_id = re.search(r'PENDING\+(\d+)', consent.value) if not consent_id: consent_id = randint(100, 999) domain = '.youtube.com' cookie = Cookie( 0, # version 'CONSENT', # name 'YES+cb.20210328-17-p0.en+F+%s' % consent_id, # value None, # port False, # port_specified domain, # domain True, # domain_specified domain.startswith('.'), # domain_initial_dot '/', # path True, # path_specified False, # secure None, # expires False, # discard None, # comment None, # comment_url {} # rest ) self.cookie_jar.set_cookie(cookie)
def cookie_parts(name, kaka): if not isinstance(kaka, SimpleCookie): cookie_obj = SimpleCookie(str(kaka)) else: cookie_obj = kaka morsel = cookie_obj.get(name) if morsel: return morsel.value.split("|") else: return None
def onConnect(self, request): from http.cookies import SimpleCookie s = SimpleCookie(request.headers["cookie"]) val = s.get(app.session_cookie_name).value self.cookies = {app.session_cookie_name: val} ss = seFactory.open_session(app, self) print(ss.get("test")) print(request.params) return None
def get_sid(): """ Returns the real SID value """ cookie = SimpleCookie() cookie_string = environ.get('HTTP_COOKIE', '') cookie.load(cookie_string) sid = 0 if not SessionAnomalyChecker.is_not_sid else cookie.get('__PYSESSION__SID') sid = cookie['__PYSESSION__SID'].value if '__PYSESSION__SID' in cookie else '0' return SessionsHelper.clear(sid)
def _loadSessionFromCookie(self, environ): """ Attempt to load the associated session using the identifier from the cookie. """ C = SimpleCookie(environ.get('HTTP_COOKIE')) morsel = C.get(self._cookieName, None) if morsel is not None: self._session = self._store.checkOutSession(morsel.value) self._expired = self._session is None
def __call__(self, req): cookie = req.headers.get('HTTP_COOKIE') action = req.GET_params.get('action') session_token = None if cookie: parsed_cookie = SimpleCookie(cookie) session_token = parsed_cookie.get('session') if action and action == 'logout': # Because particular session id was removed - next # condition won't trigger and we wil be redirected to # home in logout state, previous session id cookie will # not be valid if session_token and session_token.value in self.sessions: self.sessions.remove(session_token.value) with FlashManager() as f_mng: # logged-in state if session_token and session_token.value in self.sessions: requested_path = req.GET_params.get('path') create_dir_action = req.POST_params.get('dir_name_create') cur_client = self.current_users[session_token.value] # path wants to be deleted if requested_path and action: self.handle_remove(requested_path, action, cur_client, f_mng) # if make dir required elif create_dir_action: pseudo_dir_name = create_dir_action[0] self.handle_make_dir(pseudo_dir_name, cur_client, f_mng) # if upload required elif req.file: self.handle_upload_file(cur_client, req, f_mng) # if some path requested in query string and no # specific action requested elif requested_path and not action: # requested path - file if self.is_file(cur_client.u_name, requested_path): return self.handle_download_file(cur_client.u_name, requested_path) # requested path - directory else: cur_client.cwd = requested_path dir_view = cur_client.get_dir_view() return render_template('main.html', dir_view=dir_view, flash_messages=f_mng.get_flashes()) return self.app.redirect(self.app.url_for(req, '/'))
def test_set_cookie(clean_manager, default_data): token = clean_manager.create_access_token(data=default_data) response = Response() clean_manager.set_cookie(response, token) cookie = SimpleCookie(response.headers['set-cookie']) cookie_value = cookie.get(clean_manager.cookie_name) assert cookie_value is not None assert cookie_value["httponly"] is True assert cookie_value["samesite"] == "lax" assert cookie_value.value == token assert cookie_value.key == clean_manager.cookie_name
def __call__(self, req): cookie = req.headers.get('HTTP_COOKIE') if cookie: parsed_cookie = SimpleCookie(cookie) session_token = parsed_cookie.get('session') if session_token and session_token.value in self.sessions: return self.app.redirect( self.app.url_for(req, 'main') ) return render_template('index.html')
def test_login(app_url, uuid): r = requests.post(app_url + '/email-link/send', json={'email': '*****@*****.**'}) assert r.ok emails = requests.get('http://smtp:1080/api/emails') link = emails.json()[0]['text'] r = requests.get(link) assert r.ok assert r.headers['access'] is not None assert r.headers['Set-Cookie'] is not None cookie = SimpleCookie() cookie.load(r.headers['Set-Cookie']) assert cookie.get('refresh_token') is not None assert verify_jwt(r.headers['access'], cookie.get('refresh_token').value, BASE_URL + '/email-pwless-jwk-file/jwk', ['RS256'], uuid, 'Aureole Server') requests.delete('http://smtp:1080/api/emails')
def kaka2user(self, kaka): logger.debug("KAKA: %s" % kaka) if kaka: cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get(self.cookie_name, None) if morsel: try: return self.uid2user[morsel.value] except KeyError: return None else: logger.debug("No spauthn cookie") 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 get_session_id(self, headers): cookie_header = headers.get('cookie') if not cookie_header: return None cookie = SimpleCookie() cookie.load(cookie_header) session_id_cookie = cookie.get(SESSION_COOKIE_NAME) if not session_id_cookie: return None return session_id_cookie.value
def parse_cookie(cookie): if cookie == '': return {} try: c = SimpleCookie() c.load(cookie) except CookieError: # Invalid cookie return {} cookiedict = {} for key in list(c.keys()): cookiedict[key] = c.get(key).value return cookiedict
def info_from_cookie(kaka): logger.debug("KAKA: %s" % kaka) if kaka: cookie_obj = SimpleCookie(kaka) morsel = cookie_obj.get("idpauthn", None) if morsel: try: key, ref = base64.b64decode(morsel.value).split(":") return IDP.cache.uid2user[key], ref except KeyError: return None, None else: logger.debug("No idpauthn cookie") return None, None
class Request: NONE_COOKIE = object() def __init__(self, HTTPRequest: BaseHTTPRequestHandler): self.req = HTTPRequest self.path = self.req.path self.headers = self.req.headers self.server = self.req.server self.addr = self.req.client_address self.type = self.req.command self.cookie = SimpleCookie() # Generate cookies c = self.get_header('Cookie') if c is not None: self.cookie.load(c) # Search for GET query self.get_query = None q = self.path.split('?') if len(q) > 1: self.get_query = parse_qs(q[1]) self.path = q[0] # Generate POST vals self.post_vals = None if self.type == 'POST': content_len = int(self.get_header('content-length')) post_body = self.req.rfile.read(content_len) self.post_vals = parse_qs(post_body.decode(ENCODING)) # Generate client object (now done in handlers.py) # self.client = client.ClientObj(self.addr[0], self.get_cookie('user_token')) def get_header(self, key): return self.headers.get(key.lower()) def get_cookie(self, key): v = self.cookie.get(key, Morsel()).value return None if v is '_none' else v def get_post(self, key): v = self.post_vals.get(key) if v is None: return if len(v) == 1: return v[0] return v def read(self): return self.req.rfile.read()
def oauth2_code(event, context): token_url = f"{api_url}/tradeshift/auth/token" print(event) oauth_state = '' headers = event.get('headers', {}) cookie = SimpleCookie() cookie.load(rawdata=headers.get('Cookie', '')) requestContext = event.get('requestContext') path = requestContext.get('path') domain_name = requestContext.get('domainName') callback_url = f"https://{domain_name}{path}" code = event.get('queryStringParameters', {}).get('code', '') if SESSION_COOKIE_KEY in cookie: key = cookie.get(SESSION_COOKIE_KEY).value saved_session = engine.get(SessionObject, key=key) oauth_state = saved_session.state tradeshift = f(client_id, state=oauth_state) print(f"code: {code}") print(f"oauth_state: {oauth_state}") print(f"callback_url: {callback_url}") print(f"token_url: {token_url}") auth = HTTPBasicAuth(client_id, client_secret) client = BackendApplicationClient(client_id=client_id) tradeshift = OAuth2Session(client=client) token = tradeshift.fetch_token(token_url=token_url, code=code, auth=auth) # https://ef0ymjxyc8.execute-api.eu-west-1.amazonaws.com/dev/oauth2/callback/ # token = tradeshift.fetch_token(token_url, authorization_response=callback_url, client_secret=client_secret, headers=authorization_header) #, include_client_id=True, client_id=client_i<d<) body = { "message": "oauth2_code called", "input": event, "token": token } response = { "statusCode": 200, "body": json.dumps(body) } return response
def _do_cookieguard(self, override=None): do_cg = override if do_cg is None: do_cg = getattr(self, 'pox_cookieguard', True) if not do_cg: return True requested = self.raw_requestline.split()[1].decode("latin-1") cookies = SimpleCookie(self.headers.get('Cookie')) cgc = cookies.get(self._pox_cookieguard_cookie_name) if cgc and cgc.value == self._get_cookieguard_cookie(): if requested.startswith(self._pox_cookieguard_bouncer + "?"): log.debug("POX CookieGuard cookie is valid -- bouncing") qs = requested.split("?", 1)[1] self._cookieguard_maybe_consume_post() self.send_response(307, "Temporary Redirect") self.send_header("Location", unquote_plus(qs)) self.end_headers() return False log.debug("POX CookieGuard cookie is valid") return True else: # No guard cookie or guard cookie is wrong if requested.startswith(self._pox_cookieguard_bouncer + "?"): # Client probably didn't save cookie qs = requested.split("?", 1)[1] target = unquote_plus(qs) bad_qs = quote_plus(target) != qs if bad_qs or self.command != "GET": log.warn( "Bad POX CookieGuard bounce; possible attack " "(method:%s cookie:%s qs:%s)", self.command, "bad" if cgc else "missing", "bad" if bad_qs else "okay") self.send_response(400, "Bad Request") self.end_headers() return False self._do_cookieguard_explict_continuation(requested, target) return False if cgc: log.debug( "POX CookieGuard got wrong cookie -- setting new one") else: log.debug("POX CookieGuard got no cookie -- setting one") self._do_cookieguard_set_cookie(requested, bool(cgc)) return False
def cookie_parts(name, kaka): """ Give me the parts of the cookie payload :param name: A name of a cookie object :param kaka: The cookie :return: A list of parts or None if there is no cookie object with the given name """ cookie_obj = SimpleCookie(as_unicode(kaka)) morsel = cookie_obj.get(name) if morsel: return morsel.value.split("|") else: return None
def load_session(self, cookies): from http.cookies import SimpleCookie from beaker.session import Session from pyload.webui.interface import session cookies = SimpleCookie(cookies) sid = cookies.get(session.options['key']) if not sid: return None s = Session({}, use_cookies=False, id=sid.value, **session.options) if s.is_new: return None return s
def _websocket_auth(self, queue_events_data: Dict[str, Dict[str, str]], cookies: SimpleCookie) -> Generator[str, str, None]: message = { "req_id": self._get_request_id(), "type": "auth", "request": { "csrf_token": cookies.get(settings.CSRF_COOKIE_NAME), "queue_id": queue_events_data['queue_id'], "status_inquiries": [] } } auth_frame_str = ujson.dumps(message) self.ws.write_message(ujson.dumps([auth_frame_str])) response_ack = yield self.ws.read_message() response_message = yield self.ws.read_message() raise gen.Return([response_ack, response_message])
def init_session(self): cookie = SimpleCookie(self.headers.get("Cookie")) sid = cookie.get("_ldapauthd_sess", None) if sid: self.session_id = sid.value self.session = sessions[self.session_id] if self.session: # session_id is valid log.debug("Got valid session with id %s", self.session_id) return True log.debug("Got invalid session with id %s", self.session_id) (self.session_id, self.session) = sessions.new_session() log.debug("Initialized new session with id %s", self.session_id) return False
def _websocket_auth(self, ws: Any, queue_events_data: Dict[str, Dict[str, str]], cookies: SimpleCookie) -> Generator[str, str, None]: auth_queue_id = ':'.join((queue_events_data['response']['queue_id'], '0')) message = { "req_id": auth_queue_id, "type": "auth", "request": { "csrf_token": cookies.get('csrftoken').coded_value, "queue_id": queue_events_data['response']['queue_id'], "status_inquiries": [] } } auth_frame_str = ujson.dumps(message) ws.write_message(ujson.dumps([auth_frame_str])) response_ack = yield ws.read_message() response_message = yield ws.read_message() raise gen.Return([response_ack, response_message])
def parse_cookie(cookie): """Parse an `HTTP cookie`_ string. Return a dictionary of cookie name/values. """ if not cookie: return {} if not isinstance(cookie, BaseCookie): try: c = SimpleCookie() c.load(cookie) except CookieError: # pragma nocover # Invalid cookie return {} else: c = cookie cookiedict = {} for key in c.keys(): cookiedict[key] = c.get(key).value return cookiedict
def _load_from_cookie(self, environ): cookie = SimpleCookie(environ.get("HTTP_COOKIE")) if not cookie: return morsel = cookie.get(COOKIE_KEY) if not morsel: return val = self._converter.decode(morsel.value) if not val: return assert isinstance(val, dict) if val['__creation'] + self._max_age < time.time(): # Session has expired val = {} self.clear() self.update(val) self._changed = False
def query_server(self, filename): conn = self.module.ICAPConnection(**self.conn_kwargs) conn.request('REQMOD', filename, read_content=False, **self.req_kwargs) resp = conn.getresponse() conn.close() # look for the headers defined inside # the RFC Draft for ICAP Extensions threat = resp.get_icap_header('X-Violations-Found') # multiple threats? try to parse the header values if threat is not None: try: values = threat.split('\n') # only read the human readable descriptions threats = [s.strip() for idx, s in enumerate(values[1:]) if idx % 4 == 1] threat = '%s threat(s) found: %s' % \ (threats[0].strip(), ', '.join(threats)) except: threat = 'Multiple threats found: %s' % threat if threat is None: # only a description threat = resp.get_icap_header('X-Virus-ID') if threat is not None: threat = 'Threat found: %s' % threat if threat is None: threat = resp.get_icap_header('X-Infection-Found') if threat is not None: # only return the human readable threat name cookie = SimpleCookie(threat) kv = cookie.get('Threat') if kv is not None: threat = kv.value if threat is not None: threat = 'Threat found: %s' % threat return threat
def parse_cookies(self): cookie_data = self.environ.get('HTTP_COOKIE', '') cookies = SimpleCookie() if cookie_data: cookies.load(cookie_data) return {key: cookies.get(key).value for key in cookies.keys()}
class StreamResponse(HeadersMixin): def __init__(self, *, status=200, reason=None, headers=None): self._body = None self._keep_alive = None self._chunked = False self._chunk_size = None self._compression = False self._compression_force = False self._headers = CIMultiDict() self._cookies = SimpleCookie() self._req = None self._resp_impl = None self._eof_sent = False self._task = None if headers is not None: # TODO: optimize CIMultiDict extending self._headers.extend(headers) self._headers.setdefault(hdrs.CONTENT_TYPE, 'application/octet-stream') self.set_status(status, reason) @property def prepared(self): return self._resp_impl is not None @property def started(self): warnings.warn('use Response.prepared instead', DeprecationWarning) return self.prepared @property def task(self): return self._task @property def status(self): return self._status @property def chunked(self): return self._chunked @property def compression(self): return self._compression @property def reason(self): return self._reason def set_status(self, status, reason=None): if self.prepared: raise RuntimeError("Cannot change the response status code after " "the headers have been sent") self._status = int(status) if reason is None: reason = ResponseImpl.calc_reason(status) self._reason = reason @property def keep_alive(self): return self._keep_alive def force_close(self): self._keep_alive = False @property def body_length(self): return self._resp_impl.body_length @property def output_length(self): return self._resp_impl.output_length def enable_chunked_encoding(self, chunk_size=None): """Enables automatic chunked transfer encoding.""" self._chunked = True self._chunk_size = chunk_size def enable_compression(self, force=None): """Enables response compression encoding.""" # Backwards compatibility for when force was a bool <0.17. if type(force) == bool: force = ContentCoding.deflate if force else ContentCoding.identity elif force is not None: assert isinstance(force, ContentCoding), ("force should one of " "None, bool or " "ContentEncoding") self._compression = True self._compression_force = force @property def headers(self): return self._headers @property def cookies(self): return self._cookies def set_cookie(self, name, value, *, expires=None, domain=None, max_age=None, path='/', secure=None, httponly=None, version=None): """Set or update response cookie. Sets new cookie or updates existent with new value. Also updates only those params which are not None. """ old = self._cookies.get(name) if old is not None and old.coded_value == '': # deleted cookie self._cookies.pop(name, None) self._cookies[name] = value c = self._cookies[name] if expires is not None: c['expires'] = expires elif c.get('expires') == 'Thu, 01 Jan 1970 00:00:00 GMT': del c['expires'] if domain is not None: c['domain'] = domain if max_age is not None: c['max-age'] = max_age elif 'max-age' in c: del c['max-age'] c['path'] = path if secure is not None: c['secure'] = secure if httponly is not None: c['httponly'] = httponly if version is not None: c['version'] = version def del_cookie(self, name, *, domain=None, path='/'): """Delete cookie. Creates new empty expired cookie. """ # TODO: do we need domain/path here? self._cookies.pop(name, None) self.set_cookie(name, '', max_age=0, expires="Thu, 01 Jan 1970 00:00:00 GMT", domain=domain, path=path) @property def content_length(self): # Just a placeholder for adding setter return super().content_length @content_length.setter def content_length(self, value): if value is not None: value = int(value) # TODO: raise error if chunked enabled self.headers[hdrs.CONTENT_LENGTH] = str(value) else: self.headers.pop(hdrs.CONTENT_LENGTH, None) @property def content_type(self): # Just a placeholder for adding setter return super().content_type @content_type.setter def content_type(self, value): self.content_type # read header values if needed self._content_type = str(value) self._generate_content_type_header() @property def charset(self): # Just a placeholder for adding setter return super().charset @charset.setter def charset(self, value): ctype = self.content_type # read header values if needed if ctype == 'application/octet-stream': raise RuntimeError("Setting charset for application/octet-stream " "doesn't make sense, setup content_type first") if value is None: self._content_dict.pop('charset', None) else: self._content_dict['charset'] = str(value).lower() self._generate_content_type_header() @property def last_modified(self, _LAST_MODIFIED=hdrs.LAST_MODIFIED): """The value of Last-Modified HTTP header, or None. This header is represented as a `datetime` object. """ httpdate = self.headers.get(_LAST_MODIFIED) if httpdate is not None: timetuple = parsedate(httpdate) if timetuple is not None: return datetime.datetime(*timetuple[:6], tzinfo=datetime.timezone.utc) return None @last_modified.setter def last_modified(self, value): if value is None: self.headers.pop(hdrs.LAST_MODIFIED, None) elif isinstance(value, (int, float)): self.headers[hdrs.LAST_MODIFIED] = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(math.ceil(value))) elif isinstance(value, datetime.datetime): self.headers[hdrs.LAST_MODIFIED] = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", value.utctimetuple()) elif isinstance(value, str): self.headers[hdrs.LAST_MODIFIED] = value @property def tcp_nodelay(self): resp_impl = self._resp_impl if resp_impl is None: raise RuntimeError("Cannot get tcp_nodelay for " "not prepared response") return resp_impl.transport.tcp_nodelay def set_tcp_nodelay(self, value): resp_impl = self._resp_impl if resp_impl is None: raise RuntimeError("Cannot set tcp_nodelay for " "not prepared response") resp_impl.transport.set_tcp_nodelay(value) @property def tcp_cork(self): resp_impl = self._resp_impl if resp_impl is None: raise RuntimeError("Cannot get tcp_cork for " "not prepared response") return resp_impl.transport.tcp_cork def set_tcp_cork(self, value): resp_impl = self._resp_impl if resp_impl is None: raise RuntimeError("Cannot set tcp_cork for " "not prepared response") resp_impl.transport.set_tcp_cork(value) def _generate_content_type_header(self, CONTENT_TYPE=hdrs.CONTENT_TYPE): params = '; '.join("%s=%s" % i for i in self._content_dict.items()) if params: ctype = self._content_type + '; ' + params else: ctype = self._content_type self.headers[CONTENT_TYPE] = ctype def _start_pre_check(self, request): if self._resp_impl is not None: if self._req is not request: raise RuntimeError( "Response has been started with different request.") else: return self._resp_impl else: return None def _do_start_compression(self, coding): if coding != ContentCoding.identity: self.headers[hdrs.CONTENT_ENCODING] = coding.value self._resp_impl.add_compression_filter(coding.value) self.content_length = None def _start_compression(self, request): if self._compression_force: self._do_start_compression(self._compression_force) else: accept_encoding = request.headers.get( hdrs.ACCEPT_ENCODING, '').lower() for coding in ContentCoding: if coding.value in accept_encoding: self._do_start_compression(coding) return def start(self, request): warnings.warn('use .prepare(request) instead', DeprecationWarning) resp_impl = self._start_pre_check(request) if resp_impl is not None: return resp_impl return self._start(request) @asyncio.coroutine def prepare(self, request): resp_impl = self._start_pre_check(request) if resp_impl is not None: return resp_impl yield from request._prepare_hook(self) return self._start(request) def _start(self, request, HttpVersion10=HttpVersion10, HttpVersion11=HttpVersion11, CONNECTION=hdrs.CONNECTION, DATE=hdrs.DATE, SERVER=hdrs.SERVER, SET_COOKIE=hdrs.SET_COOKIE, TRANSFER_ENCODING=hdrs.TRANSFER_ENCODING): self._req = request keep_alive = self._keep_alive if keep_alive is None: keep_alive = request.keep_alive self._keep_alive = keep_alive version = request.version resp_impl = self._resp_impl = ResponseImpl( request._writer, self._status, version, not keep_alive, self._reason) headers = self.headers for cookie in self._cookies.values(): value = cookie.output(header='')[1:] headers.add(SET_COOKIE, value) if self._compression: self._start_compression(request) if self._chunked: if request.version != HttpVersion11: raise RuntimeError("Using chunked encoding is forbidden " "for HTTP/{0.major}.{0.minor}".format( request.version)) resp_impl.chunked = True if self._chunk_size: resp_impl.add_chunking_filter(self._chunk_size) headers[TRANSFER_ENCODING] = 'chunked' else: resp_impl.length = self.content_length headers.setdefault(DATE, request.time_service.strtime()) headers.setdefault(SERVER, resp_impl.SERVER_SOFTWARE) if CONNECTION not in headers: if keep_alive: if version == HttpVersion10: headers[CONNECTION] = 'keep-alive' else: if version == HttpVersion11: headers[CONNECTION] = 'close' resp_impl.headers = headers self._send_headers(resp_impl) self._task = request._task return resp_impl def _send_headers(self, resp_impl): # Durty hack required for # https://github.com/KeepSafe/aiohttp/issues/1093 # File sender may override it resp_impl.send_headers() def write(self, data): assert isinstance(data, (bytes, bytearray, memoryview)), \ "data argument must be byte-ish (%r)" % type(data) if self._eof_sent: raise RuntimeError("Cannot call write() after write_eof()") if self._resp_impl is None: raise RuntimeError("Cannot call write() before start()") if data: return self._resp_impl.write(data) else: return () @asyncio.coroutine def drain(self): if self._resp_impl is None: raise RuntimeError("Response has not been started") yield from self._resp_impl.transport.drain() @asyncio.coroutine def write_eof(self): if self._eof_sent: return if self._resp_impl is None: raise RuntimeError("Response has not been started") yield from self._resp_impl.write_eof() self._eof_sent = True def __repr__(self): if self.started: info = "{} {} ".format(self._req.method, self._req.path) else: info = "not started" return "<{} {} {}>".format(self.__class__.__name__, self.reason, info)
class StreamResponse(collections.MutableMapping, HeadersMixin): _length_check = True def __init__(self, *, status=200, reason=None, headers=None): self._body = None self._keep_alive = None self._chunked = False self._compression = False self._compression_force = False self._cookies = SimpleCookie() self._req = None self._payload_writer = None self._eof_sent = False self._body_length = 0 self._state = {} if headers is not None: self._headers = CIMultiDict(headers) else: self._headers = CIMultiDict() self.set_status(status, reason) @property def prepared(self): return self._payload_writer is not None @property def task(self): return getattr(self._req, 'task', None) @property def status(self): return self._status @property def chunked(self): return self._chunked @property def compression(self): return self._compression @property def reason(self): return self._reason def set_status(self, status, reason=None, _RESPONSES=RESPONSES): assert not self.prepared, \ 'Cannot change the response status code after ' \ 'the headers have been sent' self._status = int(status) if reason is None: try: reason = _RESPONSES[self._status][0] except Exception: reason = '' self._reason = reason @property def keep_alive(self): return self._keep_alive def force_close(self): self._keep_alive = False @property def body_length(self): return self._body_length @property def output_length(self): warnings.warn('output_length is deprecated', DeprecationWarning) return self._payload_writer.buffer_size def enable_chunked_encoding(self, chunk_size=None): """Enables automatic chunked transfer encoding.""" self._chunked = True if hdrs.CONTENT_LENGTH in self._headers: raise RuntimeError("You can't enable chunked encoding when " "a content length is set") if chunk_size is not None: warnings.warn('Chunk size is deprecated #1615', DeprecationWarning) def enable_compression(self, force=None): """Enables response compression encoding.""" # Backwards compatibility for when force was a bool <0.17. if type(force) == bool: force = ContentCoding.deflate if force else ContentCoding.identity elif force is not None: assert isinstance(force, ContentCoding), ("force should one of " "None, bool or " "ContentEncoding") self._compression = True self._compression_force = force @property def headers(self): return self._headers @property def cookies(self): return self._cookies def set_cookie(self, name, value, *, expires=None, domain=None, max_age=None, path='/', secure=None, httponly=None, version=None): """Set or update response cookie. Sets new cookie or updates existent with new value. Also updates only those params which are not None. """ old = self._cookies.get(name) if old is not None and old.coded_value == '': # deleted cookie self._cookies.pop(name, None) self._cookies[name] = value c = self._cookies[name] if expires is not None: c['expires'] = expires elif c.get('expires') == 'Thu, 01 Jan 1970 00:00:00 GMT': del c['expires'] if domain is not None: c['domain'] = domain if max_age is not None: c['max-age'] = max_age elif 'max-age' in c: del c['max-age'] c['path'] = path if secure is not None: c['secure'] = secure if httponly is not None: c['httponly'] = httponly if version is not None: c['version'] = version def del_cookie(self, name, *, domain=None, path='/'): """Delete cookie. Creates new empty expired cookie. """ # TODO: do we need domain/path here? self._cookies.pop(name, None) self.set_cookie(name, '', max_age=0, expires="Thu, 01 Jan 1970 00:00:00 GMT", domain=domain, path=path) @property def content_length(self): # Just a placeholder for adding setter return super().content_length @content_length.setter def content_length(self, value): if value is not None: value = int(value) if self._chunked: raise RuntimeError("You can't set content length when " "chunked encoding is enable") self._headers[hdrs.CONTENT_LENGTH] = str(value) else: self._headers.pop(hdrs.CONTENT_LENGTH, None) @property def content_type(self): # Just a placeholder for adding setter return super().content_type @content_type.setter def content_type(self, value): self.content_type # read header values if needed self._content_type = str(value) self._generate_content_type_header() @property def charset(self): # Just a placeholder for adding setter return super().charset @charset.setter def charset(self, value): ctype = self.content_type # read header values if needed if ctype == 'application/octet-stream': raise RuntimeError("Setting charset for application/octet-stream " "doesn't make sense, setup content_type first") if value is None: self._content_dict.pop('charset', None) else: self._content_dict['charset'] = str(value).lower() self._generate_content_type_header() @property def last_modified(self, _LAST_MODIFIED=hdrs.LAST_MODIFIED): """The value of Last-Modified HTTP header, or None. This header is represented as a `datetime` object. """ httpdate = self.headers.get(_LAST_MODIFIED) if httpdate is not None: timetuple = parsedate(httpdate) if timetuple is not None: return datetime.datetime(*timetuple[:6], tzinfo=datetime.timezone.utc) return None @last_modified.setter def last_modified(self, value): if value is None: self.headers.pop(hdrs.LAST_MODIFIED, None) elif isinstance(value, (int, float)): self.headers[hdrs.LAST_MODIFIED] = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(math.ceil(value))) elif isinstance(value, datetime.datetime): self.headers[hdrs.LAST_MODIFIED] = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", value.utctimetuple()) elif isinstance(value, str): self.headers[hdrs.LAST_MODIFIED] = value def _generate_content_type_header(self, CONTENT_TYPE=hdrs.CONTENT_TYPE): params = '; '.join("%s=%s" % i for i in self._content_dict.items()) if params: ctype = self._content_type + '; ' + params else: ctype = self._content_type self.headers[CONTENT_TYPE] = ctype def _do_start_compression(self, coding): if coding != ContentCoding.identity: self.headers[hdrs.CONTENT_ENCODING] = coding.value self._payload_writer.enable_compression(coding.value) # Compressed payload may have different content length, # remove the header self._headers.popall(hdrs.CONTENT_LENGTH, None) def _start_compression(self, request): if self._compression_force: self._do_start_compression(self._compression_force) else: accept_encoding = request.headers.get( hdrs.ACCEPT_ENCODING, '').lower() for coding in ContentCoding: if coding.value in accept_encoding: self._do_start_compression(coding) return async def prepare(self, request): if self._eof_sent: return if self._payload_writer is not None: return self._payload_writer await request._prepare_hook(self) return self._start(request) def _start(self, request, HttpVersion10=HttpVersion10, HttpVersion11=HttpVersion11, CONNECTION=hdrs.CONNECTION, DATE=hdrs.DATE, SERVER=hdrs.SERVER, CONTENT_TYPE=hdrs.CONTENT_TYPE, CONTENT_LENGTH=hdrs.CONTENT_LENGTH, SET_COOKIE=hdrs.SET_COOKIE, SERVER_SOFTWARE=SERVER_SOFTWARE, TRANSFER_ENCODING=hdrs.TRANSFER_ENCODING): self._req = request keep_alive = self._keep_alive if keep_alive is None: keep_alive = request.keep_alive self._keep_alive = keep_alive version = request.version writer = self._payload_writer = request._payload_writer headers = self._headers for cookie in self._cookies.values(): value = cookie.output(header='')[1:] headers.add(SET_COOKIE, value) if self._compression: self._start_compression(request) if self._chunked: if version != HttpVersion11: raise RuntimeError( "Using chunked encoding is forbidden " "for HTTP/{0.major}.{0.minor}".format(request.version)) writer.enable_chunking() headers[TRANSFER_ENCODING] = 'chunked' if CONTENT_LENGTH in headers: del headers[CONTENT_LENGTH] elif self._length_check: writer.length = self.content_length if writer.length is None: if version >= HttpVersion11: writer.enable_chunking() headers[TRANSFER_ENCODING] = 'chunked' if CONTENT_LENGTH in headers: del headers[CONTENT_LENGTH] else: keep_alive = False headers.setdefault(CONTENT_TYPE, 'application/octet-stream') headers.setdefault(DATE, rfc822_formatted_time()) headers.setdefault(SERVER, SERVER_SOFTWARE) # connection header if CONNECTION not in headers: if keep_alive: if version == HttpVersion10: headers[CONNECTION] = 'keep-alive' else: if version == HttpVersion11: headers[CONNECTION] = 'close' # status line status_line = 'HTTP/{}.{} {} {}\r\n'.format( version[0], version[1], self._status, self._reason) writer.write_headers(status_line, headers) return writer async def write(self, data): assert isinstance(data, (bytes, bytearray, memoryview)), \ "data argument must be byte-ish (%r)" % type(data) if self._eof_sent: raise RuntimeError("Cannot call write() after write_eof()") if self._payload_writer is None: raise RuntimeError("Cannot call write() before prepare()") await self._payload_writer.write(data) async def drain(self): assert not self._eof_sent, "EOF has already been sent" assert self._payload_writer is not None, \ "Response has not been started" warnings.warn("drain method is deprecated, use await resp.write()", DeprecationWarning, stacklevel=2) await self._payload_writer.drain() async def write_eof(self, data=b''): assert isinstance(data, (bytes, bytearray, memoryview)), \ "data argument must be byte-ish (%r)" % type(data) if self._eof_sent: return assert self._payload_writer is not None, \ "Response has not been started" await self._payload_writer.write_eof(data) self._eof_sent = True self._req = None self._body_length = self._payload_writer.output_size self._payload_writer = None def __repr__(self): if self._eof_sent: info = "eof" elif self.prepared: info = "{} {} ".format(self._req.method, self._req.path) else: info = "not prepared" return "<{} {} {}>".format(self.__class__.__name__, self.reason, info) def __getitem__(self, key): return self._state[key] def __setitem__(self, key, value): self._state[key] = value def __delitem__(self, key): del self._state[key] def __len__(self): return len(self._state) def __iter__(self): return iter(self._state) def __hash__(self): return hash(id(self))