Skip to content

Commit 5a6e22a

Browse files
committed
ui: add gae internal server code
This is the internal Google extension server. Very simple, just serving straight out of a GCS bucket.
1 parent 9b86a57 commit 5a6e22a

File tree

5 files changed

+71
-0
lines changed

5 files changed

+71
-0
lines changed

infra/gae-internal/.gcloudignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# This file specifies files that are *not* uploaded to Google Cloud
2+
# using gcloud. It follows the same syntax as .gitignore, with the addition of
3+
# "#!include" directives (which insert the entries of the given .gitignore-style
4+
# file at that point).
5+
#
6+
# For more information, run:
7+
# $ gcloud topic gcloudignore
8+
#
9+
.gcloudignore
10+
# If you would like to upload your .git directory, .gitignore file or files
11+
# from your .gitignore file, remove the corresponding line
12+
# below:
13+
.git
14+
.gitignore
15+
16+
# Python pycache:
17+
__pycache__/
18+
# Ignored by the build system
19+
/setup.cfg

infra/gae-internal/app.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
runtime: python312
2+
3+
entrypoint: gunicorn -b :$PORT main:app
4+
5+
instance_class: F1
6+
7+
automatic_scaling:
8+
max_instances: 2

infra/gae-internal/deploy

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
gcloud app deploy app.yaml --project google.com:perfetto-gae-internal
3+

infra/gae-internal/main.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import posixpath
2+
3+
from flask import Flask, Response, abort
4+
from flask_cors import CORS
5+
from google.cloud import storage
6+
7+
app = Flask(__name__)
8+
CORS(app, origins=["https://ui.perfetto.dev", "http://localhost:10000"], supports_credentials=True)
9+
10+
BUCKET_NAME = "perfetto-ui-internal"
11+
BASE_PREFIX = "extension-server-v1"
12+
13+
gcs_client = storage.Client()
14+
bucket = gcs_client.bucket(BUCKET_NAME)
15+
16+
17+
@app.route("/", defaults={"path": ""})
18+
@app.route("/<path:path>")
19+
def serve(path):
20+
# Normalize and reject any path traversal attempts.
21+
normalized = posixpath.normpath(path) if path else ""
22+
if normalized.startswith("..") or "/../" in normalized or normalized.startswith("/"):
23+
abort(403)
24+
25+
blob_path = f"{BASE_PREFIX}/{normalized}" if normalized else BASE_PREFIX + "/"
26+
27+
blob = bucket.blob(blob_path)
28+
if not blob.exists():
29+
abort(404)
30+
31+
data = blob.download_as_bytes()
32+
content_type = blob.content_type or "application/octet-stream"
33+
return Response(data, content_type=content_type)
34+
35+
36+
if __name__ == "__main__":
37+
app.run(host="127.0.0.1", port=8080, debug=True)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Flask==3.0.0
2+
Flask-Cors==4.0.0
3+
google-cloud-storage==2.14.0
4+
gunicorn==21.2.0

0 commit comments

Comments
 (0)