Skip to content

Commit 78bedea

Browse files
added simple wsgi support (#348)
* added simple wsgi support * simplified path logic in server.py * updated flask-test to reflect WSGI changes * updated lambda-config-test to reflect WSGI changes * added SCRIPT_NAME flask var to set the root of the application to /run/<app-name>. Also added example/wsgi-test with multiple endpoints * Updated server_legacy.py to implement WSGI
1 parent 90f6cbd commit 78bedea

9 files changed

Lines changed: 135 additions & 13 deletions

File tree

‎examples/flask-test/f.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ def page_not_found(e):
66
app = Flask("hi")
77
app.register_error_handler(404, page_not_found)
88

9-
# TODO: modify wrappers so "/" is the root
10-
@app.route("/run/flask-test")
9+
@app.route("/")
1110
def hi():
1211
print("in hi() of flask-test/f.py")
1312
teapot = 418 # I'm a teapot (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418)

‎examples/lambda-config-test/f.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ def page_not_found(e):
66
app = Flask("hi")
77
app.register_error_handler(404, page_not_found)
88

9-
# TODO: modify wrappers so "/" is the root
10-
@app.route("/run/lambda-config-test", methods=["GET", "POST", "PUT", "DELETE"])
9+
@app.route("/", methods=["GET", "POST", "PUT", "DELETE"])
1110
def hi():
1211
print("in hi() of lambda-config-test/f.py")
1312
teapot = 418 # I'm a teapot (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418)

‎examples/wsgi-test/f.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from flask import Flask, render_template, request
2+
3+
def page_not_found(e):
4+
return f"{e}, {request.base_url}, {request.url_root}\n", 404
5+
6+
app = Flask(__name__)
7+
app.register_error_handler(404, page_not_found)
8+
9+
@app.route("/home")
10+
def hi():
11+
return render_template("index.html")
12+
13+
@app.route("/home/button")
14+
def button():
15+
print("Button endpoint hit!")
16+
return "You clicked the button!\n"

‎examples/wsgi-test/requirements.in‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flask==2.3.2
2+
werkzeug==3.0.3
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# This file is autogenerated by pip-compile with Python 3.13
3+
# by the following command:
4+
#
5+
# pip-compile requirements.in
6+
#
7+
blinker==1.6.2
8+
# via flask
9+
click==8.1.7
10+
# via flask
11+
flask==2.3.2
12+
# via -r requirements.in
13+
itsdangerous==2.1.2
14+
# via flask
15+
jinja2==3.1.4
16+
# via flask
17+
markupsafe==2.1.3
18+
# via
19+
# jinja2
20+
# werkzeug
21+
werkzeug==3.0.3
22+
# via
23+
# -r requirements.in
24+
# flask
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Test Website</title>
7+
<style>
8+
body {
9+
font-family: Arial, sans-serif;
10+
background: #f9f9f9;
11+
color: #333;
12+
margin: 0;
13+
padding: 0;
14+
display: flex;
15+
flex-direction: column;
16+
align-items: center;
17+
justify-content: center;
18+
height: 100vh;
19+
}
20+
21+
h1 {
22+
color: #007acc;
23+
margin-bottom: 10px;
24+
}
25+
26+
p {
27+
font-size: 1.1rem;
28+
}
29+
30+
button {
31+
background-color: #007acc;
32+
color: white;
33+
border: none;
34+
padding: 10px 20px;
35+
margin-top: 20px;
36+
font-size: 1rem;
37+
border-radius: 8px;
38+
cursor: pointer;
39+
transition: background-color 0.3s ease;
40+
}
41+
42+
button:hover {
43+
background-color: #005f99;
44+
}
45+
</style>
46+
</head>
47+
<body>
48+
<h1>Welcome to this Test Website </h1>
49+
<p>This is a simple HTML page for testing WSGI</p>
50+
<button onclick="window.location.href='home/button'">Click Me</button>
51+
</body>
52+
</html>
53+

‎go/worker/event/lambdaServer.go‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,10 @@ func (s *LambdaServer) RunLambda(w http.ResponseWriter, r *http.Request) {
5757
// components represent run[0]/<name_of_sandbox>[1]/<extra_things>...
5858
// ergo we want [1] for name of sandbox
5959
urlParts := getURLComponents(r)
60-
if len(urlParts) == 2 {
61-
img := urlParts[1]
62-
s.lambdaMgr.Get(img).Invoke(w, r)
63-
} else {
64-
w.WriteHeader(http.StatusInternalServerError)
65-
w.Write([]byte("expected invocation format: /run/<lambda-name>"))
66-
}
60+
61+
// Send entire path to app
62+
lambdaName := urlParts[1]
63+
s.lambdaMgr.Get(lambdaName).Invoke(w, r)
6764
}
6865
}
6966

‎min-image/runtimes/python/server.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,24 @@ def options(self):
6868

6969

7070
if hasattr(f, "app"):
71+
def path_wrapper(environ, start_response):
72+
path = environ.get("PATH_INFO", "")
73+
# split path to get individual components
74+
parts = path.split("/") # ["", "run", <app-name>]
75+
76+
# set new environment path
77+
# `/run/<func-name>/a/b/c` -> `/a/b/c`
78+
environ["PATH_INFO"] = '/' + '/'.join(parts[3:])
79+
80+
# set the root of the application
81+
app_name = parts[2]
82+
environ["SCRIPT_NAME"] = '/run/' + app_name
83+
84+
return f.app(environ, start_response)
85+
7186
# use WSGI entry
72-
app = tornado.wsgi.WSGIContainer(f.app)
87+
# call wrapper to strip /run/<func-name> from path
88+
app = tornado.wsgi.WSGIContainer(path_wrapper)
7389
else:
7490
# use function entry
7591
app = tornado.web.Application([

‎min-image/runtimes/python/server_legacy.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,24 @@ def options(self):
9292
def lambda_server():
9393
init()
9494
if hasattr(f, "app"):
95+
def path_wrapper(environ, start_response):
96+
path = environ.get("PATH_INFO", "")
97+
# split path to get individual components
98+
parts = path.split("/") # ["", "run", <app-name>]
99+
100+
# set new environment path
101+
# `/run/<func-name>/a/b/c` -> `/a/b/c`
102+
environ["PATH_INFO"] = '/' + '/'.join(parts[3:])
103+
104+
# set the root of the application
105+
app_name = parts[2]
106+
environ["SCRIPT_NAME"] = '/run/' + app_name
107+
108+
return f.app(environ, start_response)
109+
95110
# use WSGI entry
96-
tornado_app = tornado.wsgi.WSGIContainer(f.app)
111+
# call wrapper to strip /run/<func-name> from path
112+
tornado_app = tornado.wsgi.WSGIContainer(path_wrapper)
97113
else:
98114
# use function entry
99115
tornado_app = tornado.web.Application([

0 commit comments

Comments
 (0)