def test_dispatcher(): def null_application(environ, start_response): start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) yield b"NOT FOUND" def dummy_application(environ, start_response): start_response("200 OK", [("Content-Type", "text/plain")]) yield _to_bytes(environ["SCRIPT_NAME"]) app = DispatcherMiddleware( null_application, { "/test1": dummy_application, "/test2/very": dummy_application }, ) tests = { "/test1": ("/test1", "/test1/asfd", "/test1/very"), "/test2/very": ("/test2/very", "/test2/very/long/path/after/script/name"), } for name, urls in tests.items(): for p in urls: environ = create_environ(p) app_iter, status, headers = run_wsgi_app(app, environ) assert status == "200 OK" assert b"".join(app_iter).strip() == _to_bytes(name) app_iter, status, headers = run_wsgi_app(app, create_environ("/missing")) assert status == "404 NOT FOUND" assert b"".join(app_iter).strip() == b"NOT FOUND"
def test_multiple_cookies(): @Request.application def test_app(request): response = Response(repr(sorted(request.cookies.items()))) response.set_cookie("test1", b"foo") response.set_cookie("test2", b"bar") return response client = Client(test_app) resp = client.get("/") assert resp.data == b"[]" resp = client.get("/") assert resp.data == _to_bytes(repr([("test1", "foo"), ("test2", "bar")]), "ascii")
def handle_request(app, event, context=None): # if event.get("source") in ["scf.events", "serverless-plugin-warmup"]: # print("Tencent Cloud Function warming event received, skipping handler") # return {} if "multiValueHeaders" in event: headers = Headers(event["multiValueHeaders"]) else: headers = Headers(event["headers"]) strip_stage_path = os.environ.get("STRIP_STAGE_PATH", "").lower().strip() in [ "yes", "y", "true", "t", "1", ] if ( headers.get("Host", "").endswith(".apigw.tencentcs.com") and not strip_stage_path ): script_name = "/{}".format(event["requestContext"].get("stage", "")) else: script_name = "" # If a user is using a custom domain on API Gateway, they may have a base # path in their URL. This allows us to strip it out via an optional # environment variable. path_info = event["path"] base_path = os.environ.get("API_GATEWAY_BASE_PATH") print(base_path) if base_path: script_name = "/" + base_path if path_info.startswith(script_name): path_info = path_info[len(script_name) :] or "/" if "body" in event: body = event["body"] or "" else: body = "" if event.get("isBase64Encoded", False): body = base64.b64decode(body) if isinstance(body, str): body = _to_bytes(body, charset="utf-8") environ = { "CONTENT_LENGTH": str(len(body)), "CONTENT_TYPE": headers.get("Content-Type", ""), "PATH_INFO": url_unquote(path_info), "QUERY_STRING": encode_query_string(event), "REMOTE_ADDR": event["requestContext"].get("identity", {}).get("sourceIp", ""), "REMOTE_USER": event["requestContext"] .get("authorizer", {}) .get("principalId", ""), "REQUEST_METHOD": event["httpMethod"], "SCRIPT_NAME": script_name, "SERVER_NAME": headers.get("Host", "lambda"), "SERVER_PORT": headers.get("X-Forwarded-Port", "80"), "SERVER_PROTOCOL": "HTTP/1.1", "wsgi.errors": sys.stderr, "wsgi.input": BytesIO(body), "wsgi.multiprocess": False, "wsgi.multithread": False, "wsgi.run_once": False, "wsgi.url_scheme": headers.get("X-Forwarded-Proto", "http"), "wsgi.version": (1, 0), "serverless.authorizer": event["requestContext"].get("authorizer"), "serverless.event": event, "serverless.context": context, # TODO: Deprecate the following entries, as they do not comply with the WSGI # spec. For custom variables, the spec says: # # Finally, the environ dictionary may also contain server-defined variables. # These variables should be named using only lower-case letters, numbers, # dots, and underscores, and should be prefixed with a name that is unique # to the defining server or gateway. "API_GATEWAY_AUTHORIZER": event["requestContext"].get("authorizer"), "event": event, "context": context, } for key, value in environ.items(): if isinstance(value, str): environ[key] = _wsgi_encoding_dance(value) for key, value in headers.items(): key = "HTTP_" + key.upper().replace("-", "_") if key not in ("HTTP_CONTENT_TYPE", "HTTP_CONTENT_LENGTH"): environ[key] = value response = Response.from_app(app, environ) returndict = {"statusCode": response.status_code} if "multiValueHeaders" in event: returndict["multiValueHeaders"] = group_headers(response.headers) else: returndict["headers"] = split_headers(response.headers) if event.get("requestContext").get("elb"): # If the request comes from ALB we need to add a status description returndict["statusDescription"] = "%d %s" % ( response.status_code, HTTP_STATUS_CODES[response.status_code], ) if response.data: mimetype = response.mimetype or "text/plain" if ( mimetype.startswith("text/") or mimetype in TEXT_MIME_TYPES ) and not response.headers.get("Content-Encoding", ""): returndict["body"] = response.get_data(as_text=True) returndict["isBase64Encoded"] = False else: returndict["body"] = base64.b64encode(response.data).decode("utf-8") returndict["isBase64Encoded"] = True return returndict
def __init__(self, key: str, **kwargs): charset = kwargs.get('charset', 'utf-8') key = _to_bytes(key, charset=charset) value = _to_bytes(kwargs.get('value'), charset=charset) path = kwargs.get('path', None) if path is not None: path = iri_to_uri(path, charset) domain = _make_cookie_domain(kwargs.get('domain')) max_age = kwargs.get('max_age', None) if isinstance(max_age, timedelta): max_age = int(max_age.total_seconds()) expires = kwargs.get('expires') if expires is not None: if not isinstance(expires, str): expires = http_date(expires) elif max_age is not None and kwargs.get('sync_expires', False): expires = http_date( datetime.now(tz=datetime.timezone.utc).timestamp() + max_age) same_site = kwargs.get('same_site', None) if same_site is not None: same_site = same_site.title() if same_site not in ['Strict', 'Lax', 'None']: raise ValueError('same site must be one of ') buffer = [key + b'=' + _cookie_quote(value)] cookie_attrs = [ (b'Domain', domain, True), (b'Expires', expires, False), (b'Max-Age', max_age, False), (b'Secure', kwargs.get('secure', False), None), (b'HttpOnly', kwargs.get('http_only', False), None), (b'Path', path, False), (b'SameSite', same_site, False), ] for key, value, f in cookie_attrs: if f is None: if value: buffer.append(key) continue if value is None: continue temp = bytearray(key) if not isinstance(value, (bytes, bytearray)): value = _to_bytes(str(value), charset) if f: value = _cookie_quote(value) temp += b'=' + value buffer.append(bytes(temp)) return_value = b'; '.join(buffer) return_value = return_value.decode('latin1') cookie_size = len(return_value) max_size = kwargs.get('max_size', 4093) if max_size and cookie_size > max_size: value_size = len(value) warnings.warn( f"The {key.decode(charset)!r} cookie is too large: the value was" f" {value_size} bytes but the" f" header required {cookie_size - value_size} extra bytes. The final size" f" was {cookie_size} bytes but the limit is {max_size} bytes. Browsers may" f" silently ignore cookies larger than this.", stacklevel=2, ) self.return_value = return_value
def dummy_application(environ, start_response): start_response("200 OK", [("Content-Type", "text/plain")]) yield _to_bytes(environ["SCRIPT_NAME"])
def inner(environ, start_response): if environ["PATH_INFO"] == "/_getpid": start_response("200 OK", [("Content-Type", "text/plain")]) pid_logger.info("pid=%s", os.getpid()) return [_to_bytes(str(os.getpid()))] return f(environ, start_response)