def test_get_binary_support_binary_custom_text_with_gzip_content_encoding( self, simple_app, text_content_type): simple_app.handler = make_lambda_handler( simple_app, binary_support=True, non_binary_content_type_prefixes= CUSTOM_NON_BINARY_CONTENT_TYPE_PREFIXES, ) simple_app.headers = [ ("Content-Type", text_content_type), ("Content-Encoding", "gzip"), ] simple_app.response = b"\x13\x37" response = simple_app.handler(make_v2_event(), None) assert response == { "statusCode": 200, "cookies": [], "headers": { "content-type": text_content_type, "content-encoding": "gzip", }, "isBase64Encoded": True, "body": b64encode(b"\x13\x37").decode("utf-8"), }
def __init__( self, headers: list[tuple[str, str]], response: bytes, exc_info: _ExcInfoType, ) -> None: self.headers = headers self.response = response self.exc_info = exc_info self.handler = make_lambda_handler(self)
def test_get_binary_support_default_text_content_types(simple_app, text_content_type): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [("Content-Type", text_content_type)] response = simple_app.handler(make_event(), None) assert response == { "statusCode": 200, "headers": {"Content-Type": text_content_type}, "body": "Hello World\n", }
def test_empty_and_uncloseable_content(self): def app(environ, start_response): start_response("200 OK", [], None) return [b"Hi", b"", b" there!", b""] handler = make_lambda_handler(app) event = make_v2_event() response = handler(event, None) assert response["body"] == b64encode(b"Hi there!").decode("utf-8")
def simple_app(): def app(environ, start_response): app.environ = environ start_response('200 OK', app.headers, app.exc_info) return BytesIO(app.response) app.headers = [('Content-Type', 'text/plain')] app.response = b'Hello World\n' app.handler = make_lambda_handler(app) app.exc_info = None yield app
def simple_app(): def app(environ, start_response): app.environ = environ start_response("200 OK", app.headers, app.exc_info) return BytesIO(app.response) app.headers = [("Content-Type", "text/plain")] app.response = b"Hello World\n" app.handler = make_lambda_handler(app) app.exc_info = None yield app
def test_get_binary_support_text(simple_app): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) response = simple_app.handler(make_event(), None) assert response == { 'statusCode': 200, 'headers': { 'Content-Type': 'text/plain' }, 'body': 'Hello World\n', }
def test_get_binary_support_text(simple_app): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) response = simple_app.handler(make_event(), None) assert response == { "statusCode": 200, "headers": { "Content-Type": "text/plain" }, "body": "Hello World\n", }
def test_post_binary_support(simple_app): simple_app.handler = make_lambda_handler(simple_app) event = make_event(method="POST", body="dogfood", binary=True) response = simple_app.handler(event, None) assert simple_app.environ["wsgi.input"].read() == b"dogfood" assert simple_app.environ["CONTENT_LENGTH"] == str(len(b"dogfood")) assert response == { "statusCode": 200, "headers": {"Content-Type": "text/plain"}, "body": "Hello World\n", }
def test_override_wsgi_errors(simple_app): class customLogger: def write(self, data): pass def flush(self): pass errorsTo = customLogger() simple_app.handler = make_lambda_handler(simple_app, wsgi_errors=errorsTo) simple_app.handler(make_event(), None) assert simple_app.environ["wsgi.errors"] == errorsTo
def lambda_handler(event, context): """Entry point for web requests""" global _real_handler if _real_handler is None: install_secrets() from apig_wsgi import make_lambda_handler from django.core.wsgi import get_wsgi_application application = get_wsgi_application() _real_handler = make_lambda_handler(application) return _real_handler(event, context)
def test_get_binary_support_binary(simple_app): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [("Content-Type", "application/octet-stream")] simple_app.response = b"\x13\x37" response = simple_app.handler(make_event(), None) assert response == { "statusCode": 200, "headers": {"Content-Type": "application/octet-stream"}, "body": b64encode(b"\x13\x37").decode("utf-8"), "isBase64Encoded": True, }
def test_get_binary_support_no_content_type(simple_app): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [] simple_app.response = b'\x13\x37' response = simple_app.handler(make_event(), None) assert response == { 'statusCode': 200, 'headers': {}, 'body': b64encode(b'\x13\x37').decode('utf-8'), 'isBase64Encoded': True, }
def test_get_binary_support_no_content_type(simple_app): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [] simple_app.response = b"\x13\x37" response = simple_app.handler(make_event(), None) assert response == { "statusCode": 200, "multiValueHeaders": {}, "body": b64encode(b"\x13\x37").decode("utf-8"), "isBase64Encoded": True, }
def test_get_binary_support_custom_text_content_types(simple_app, text_content_type): simple_app.handler = make_lambda_handler( simple_app, binary_support=True, non_binary_content_type_prefixes=CUSTOM_NON_BINARY_CONTENT_TYPE_PREFIXES, ) simple_app.headers = [("Content-Type", text_content_type)] response = simple_app.handler(make_event(), None) assert response == { "statusCode": 200, "headers": {"Content-Type": text_content_type}, "body": "Hello World\n", }
def test_get_binary_support_default_text_content_types( self, simple_app, text_content_type): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [("Content-Type", text_content_type)] response = simple_app.handler(make_v1_event(), None) assert response == { "statusCode": 200, "multiValueHeaders": { "Content-Type": [text_content_type] }, "isBase64Encoded": False, "body": "Hello World\n", }
def test_get_binary_support_binary(simple_app): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [('Content-Type', 'application/octet-stream')] simple_app.response = b'\x13\x37' response = simple_app.handler(make_event(), None) assert response == { 'statusCode': 200, 'headers': { 'Content-Type': 'application/octet-stream' }, 'body': b64encode(b'\x13\x37').decode('utf-8'), 'isBase64Encoded': True, }
def test_post_binary_support(simple_app): simple_app.handler = make_lambda_handler(simple_app) event = make_event(method='POST', body='dogfood', binary=True) response = simple_app.handler(event, None) assert simple_app.environ['wsgi.input'].read() == b'dogfood' assert simple_app.environ['CONTENT_LENGTH'] == str(len(b'dogfood')) assert response == { 'statusCode': 200, 'headers': { 'Content-Type': 'text/plain' }, 'body': 'Hello World\n', }
def test_get_binary_support_default_text_content_types( self, simple_app: App, text_content_type: str) -> None: simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [("Content-Type", text_content_type)] response = simple_app.handler(make_v2_event(), None) assert response == { "statusCode": 200, "cookies": [], "headers": { "content-type": text_content_type }, "isBase64Encoded": False, "body": "Hello World\n", }
def test_get_binary_support_binary_default_text_with_gzip_content_encoding( simple_app, text_content_type ): simple_app.handler = make_lambda_handler(simple_app, binary_support=True) simple_app.headers = [ ("Content-Type", text_content_type), ("Content-Encoding", "gzip"), ] simple_app.response = b"\x13\x37" response = simple_app.handler(make_event(), None) assert response == { "statusCode": 200, "headers": {"Content-Type": text_content_type, "Content-Encoding": "gzip"}, "body": b64encode(b"\x13\x37").decode("utf-8"), "isBase64Encoded": True, }
def test_get_binary_support_custom_text_content_types( self, simple_app: App, text_content_type: str) -> None: simple_app.handler = make_lambda_handler( simple_app, binary_support=True, non_binary_content_type_prefixes= CUSTOM_NON_BINARY_CONTENT_TYPE_PREFIXES, ) simple_app.headers = [("Content-Type", text_content_type)] response = simple_app.handler(make_v1_event(), None) assert response == { "statusCode": 200, "multiValueHeaders": { "Content-Type": [text_content_type] }, "isBase64Encoded": False, "body": "Hello World\n", }
import os from apig_wsgi import make_lambda_handler from application import create_app app = create_app() def proxied_app(environ, start_response): environ["SCRIPT_NAME"] = os.environ["stage_mount_point"] return app(environ, start_response) lambda_handler = make_lambda_handler(proxied_app)
from hmalib.common.logging import get_logger from .action_rules_api import get_action_rules_api from .actions_api import get_actions_api from .content import get_content_api from .datasets_api import get_datasets_api from .matches import get_matches_api from .stats import get_stats_api from .submit import get_submit_api # Set to 10MB for images bottle.BaseRequest.MEMFILE_MAX = 10 * 1024 * 1024 app = bottle.default_app() apig_wsgi_handler = make_lambda_handler(app) logger = get_logger(__name__) s3_client = boto3.client("s3") dynamodb = boto3.resource("dynamodb") THREAT_EXCHANGE_DATA_BUCKET_NAME = os.environ["THREAT_EXCHANGE_DATA_BUCKET_NAME"] THREAT_EXCHANGE_DATA_FOLDER = os.environ["THREAT_EXCHANGE_DATA_FOLDER"] THREAT_EXCHANGE_PDQ_FILE_EXTENSION = os.environ["THREAT_EXCHANGE_PDQ_FILE_EXTENSION"] HMA_CONFIG_TABLE = os.environ["HMA_CONFIG_TABLE"] DYNAMODB_TABLE = os.environ["DYNAMODB_TABLE"] IMAGE_BUCKET_NAME = os.environ["IMAGE_BUCKET_NAME"] IMAGE_FOLDER_KEY = os.environ[ "IMAGE_FOLDER_KEY" ] # Misnamed, this is a prefix, not a key, if renaming, use IMAGE_PREFIX
"tuckboxes": "Card Tuckboxes", } flask_app = Flask(__name__) bootstrap = Bootstrap(flask_app) secret_key = os.environ["FLASK_SECRET_KEY"] assert secret_key, "Need secret key specified in env" flask_app.config["SECRET_KEY"] = secret_key flask_app.config["UPLOADS_DEFAULT_DEST"] = "/tmp" flask_app.config["UPLOADED_FILES_ALLOW"] = IMAGES logger = logging.getLogger("bgtools_logger") logger.setLevel(int(os.environ.get("LOG_LEVEL", logging.INFO))) apig_wsgi_handler = apig_wsgi.make_lambda_handler(flask_app, binary_support=True) if os.environ.get("DEBUG"): apig_wsgi_handler_helper = apig_wsgi_handler def apig_wsgi_handler(event, context): logger.info("in apig handler") print(json.dumps(event, indent=2, sort_keys=True)) response = apig_wsgi_handler_helper(event, context) print(json.dumps(response, indent=2, sort_keys=True)) return response def get_pages(): return {url_for(p): n for p, n in PAGES.items()}
def bottle_init_once() -> t.Tuple[bottle.AppStack, t.Callable[ [t.Dict[str, t.Any], t.Any], t.Dict[str, t.Any]]]: """ Meant to be called once per lambda instance. Returns a bottle app and an api_wsgi_handler that can be plugged into a lambda handler. The method also serves as a closure for all dependencies that need to be resolved at startup. """ app = bottle.default_app() # Initialize hmaconfig at module level. Mounted SubApps need not initialize # their own HMAConfigs. HMAConfig.initialize(HMA_CONFIG_TABLE) functionality_mapping = get_pytx_functionality_mapping() @app.get("/root/") def root(): """ root endpoint to make sure the API is live and check when it was last updated """ context = bottle.request.environ.get("apig_wsgi.context") invoked_function_arn = context.invoked_function_arn client = boto3.client("lambda") last_modified = client.get_function_configuration( FunctionName=invoked_function_arn)["LastModified"] return { "message": "Welcome to the HMA API!", "last_modified": last_modified, } app.mount( "/action-rules/", get_action_rules_api(hma_config_table=HMA_CONFIG_TABLE), ) app.mount( "/matches/", get_matches_api( datastore_table=dynamodb.Table(DYNAMODB_TABLE), hma_config_table=HMA_CONFIG_TABLE, indexes_bucket_name=INDEXES_BUCKET_NAME, writeback_queue_url=WRITEBACK_QUEUE_URL, bank_table=dynamodb.Table(BANKS_TABLE), signal_type_mapping=functionality_mapping.signal_and_content, ), ) app.mount( "/content/", get_content_api( dynamodb_table=dynamodb.Table(DYNAMODB_TABLE), image_bucket=IMAGE_BUCKET_NAME, image_prefix=IMAGE_PREFIX, signal_type_mapping=functionality_mapping.signal_and_content, ), ) app.mount( "/submit/", get_submit_api( dynamodb_table=dynamodb.Table(DYNAMODB_TABLE), image_bucket=IMAGE_BUCKET_NAME, image_prefix=IMAGE_PREFIX, submissions_queue_url=SUBMISSIONS_QUEUE_URL, hash_queue_url=HASHES_QUEUE_URL, signal_type_mapping=functionality_mapping.signal_and_content, ), ) app.mount( "/datasets/", get_datasets_api( hma_config_table=HMA_CONFIG_TABLE, datastore_table=dynamodb.Table(DYNAMODB_TABLE), threat_exchange_data_bucket_name=THREAT_EXCHANGE_DATA_BUCKET_NAME, threat_exchange_data_folder=THREAT_EXCHANGE_DATA_FOLDER, ), ) app.mount("/stats/", get_stats_api(counts_table=dynamodb.Table(COUNTS_TABLE_NAME))) app.mount( "/actions/", get_actions_api(hma_config_table=HMA_CONFIG_TABLE), ) app.mount( "/banks/", get_bank_api( bank_table=dynamodb.Table(BANKS_TABLE), bank_user_media_bucket=BANKS_MEDIA_BUCKET_NAME, submissions_queue_url=SUBMISSIONS_QUEUE_URL, signal_type_mapping=functionality_mapping.signal_and_content, ), ) app.mount( "/indexes/", get_indexes_api( indexes_bucket_name=INDEXES_BUCKET_NAME, indexer_function_name=INDEXER_FUNCTION_NAME, ), ) app.mount( "/lcc/", get_lcc_api( storage_path=LCC_DURABLE_FS_PATH, signal_type_mapping=functionality_mapping.signal_and_content, ), ) apig_wsgi_handler = make_lambda_handler(app) return (app, apig_wsgi_handler)
import json import os from django.core.wsgi import get_wsgi_application from apig_wsgi import make_lambda_handler os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings") application = get_wsgi_application() apig_wsgi_handler = make_lambda_handler(application, binary_support=True) def lambda_handler(event, context): print(json.dumps(event, indent=2, sort_keys=True)) response = apig_wsgi_handler(event, context) print(json.dumps(response, indent=2, sort_keys=True)) return response
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True app.url_map.redirect_defaults = False preview_app = Flask("Preview") if GITHUB_APP_ID and GITHUB_APP_KEY and GITHUB_APP_SECRET: preview_app.config['GITHUBAPP_ID'] = int(GITHUB_APP_ID) preview_app.config['GITHUBAPP_KEY'] = reformat_ssh_key_to_pem_bytes(GITHUB_APP_KEY) preview_app.config['GITHUBAPP_SECRET'] = GITHUB_APP_SECRET app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {'/preview': preview_app}) else: preview_app.config['GITHUBAPP_ID'] = 0 preview_app.config['GITHUBAPP_KEY'] = None preview_app.config['GITHUBAPP_SECRET'] = False github_app = GitHubApp(preview_app) handler = make_lambda_handler(app.wsgi_app) @app.route('/') def index(): return render_template('index.html', stack="/" + os.getenv('BUCKET_PATH') if os.getenv('BUCKET_PATH') else '') @app.route('/swagger.yml') def swagger(): return render_template('swagger.yml', local_url=f"- url: {os.getenv('API_URL')}" if os.getenv('API_URL') else '') @app.route('/plugins/index') def plugin_index() -> Response: return jsonify(get_index())
def assign_lambda_handler(module_name: str, wsgi_app, wrap_handler: WrapAwsHandlerFunc = None): """Defines the global `handler` function in the loaded module named `module_name`. If the module is not loaded, does nothing. If the module already has `handler`, does nothing. Otherwise the `handler` is initialized with a function ready to process AWS Lambda requests. The requests will be processed with `app`. """ # # When we programmatically call `ric_main` with `basename.handler` # argument, it will try to import file `basename.py` as module # `basename`, and then use the `handler` defined there. # # The easiest way is just declare the `handler` function inside the # `basename.py`. # # ``` # def handler(event, context): # pass # ``` # # # PROBLEM 1 # --------- # # We want to keep `basename.py` as simple as possible. We # assume, it contains only # # ``` # start(app) # app is Flask # ``` # # It means, we have to detect the module, from which the `start` # is called (it's `basename`) and dynamically assign the handler # to it. # # # PROBLEM 2 # --------- # # We also assume, that the `basename.py` is the entrypoint: # the Dockerfile runs it as ENTRYPOINT ["python", "basename.py"]. # # So when it executed for the first time (as entrypoint), the # `basename.py` has name "__main__". Then ric_main will re-import # the same file under name "basename". # # We have to assign the `handler` to the `basename` module only # when it is re-imported by the `ric_main`. Defining `handler` on # `__main__` will have to effect. if module_name not in sys.modules: return module = sys.modules.get(module_name) if not module: return if 'handler' in module.__dict__: print(f'{module} already has the `handler` defined') return # noinspection PyTypeChecker aws_handler: AwsHandlerFunc = make_lambda_handler(wsgi_app, binary_support=True) # todo unit test if wrap_handler is not None: aws_handler = wrap_handler(aws_handler) module.__dict__['handler'] = aws_handler
import logging from apig_wsgi import make_lambda_handler from aws_xray_sdk.ext.flask.middleware import XRayMiddleware from aws_xray_sdk.core import xray_recorder from bc_lambda import bc_lambda import project _app = project.create_app() xray_recorder.configure(service='ProjectName') XRayMiddleware(_app, xray_recorder) _decorator = bc_lambda(level=logging.INFO, service='ProjectName') handler = _decorator(make_lambda_handler(_app))
import os from apig_wsgi import make_lambda_handler from django.core.wsgi import get_wsgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testapp.settings') application = get_wsgi_application() lambda_handler = make_lambda_handler(application)