xref: /aosp_15_r20/external/perfetto/infra/perfetto.dev/appengine/main.py (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1#!/usr/bin/env python3
2# Copyright (C) 2021 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import flask
17import os
18
19from google.cloud import storage
20
21BUCKET_NAME = 'perfetto.dev'
22
23app = flask.Flask(__name__)
24bucket = None
25is_local_testing_instance = False
26
27
28@app.route('/_ah/<path:path>')
29def ignore_app_engine_lifecycle(path):
30  return flask.abort(404)
31
32
33@app.route('/docs')
34def docs_redirect():
35  return flask.redirect('/docs/', code=301)
36
37
38# Serve the requests from the GCS bucket.
39@app.route('/', methods=['GET'])
40@app.route('/<path:path>', methods=['GET'])
41def main(path=''):
42  # Force redirect HTTP -> HTTPS.
43  if not flask.request.is_secure and not is_local_testing_instance:
44    https_url = flask.request.url.replace('http://', 'https://', 1)
45    return flask.redirect(https_url, code=301)
46  if flask.request.host == 'www.perfetto.dev':
47    return flask.redirect(
48        flask.request.url.replace('www.perfetto.dev', 'perfetto.dev'))
49  if flask.request.host == 'docs.perfetto.dev':
50    return flask.redirect('https://perfetto.dev/docs/')
51
52  path = '/' + path
53  path += 'index.html' if path.endswith('/') else ''
54  global bucket
55  if bucket is None:
56    bucket = storage.Client().get_bucket(BUCKET_NAME)
57  blob = bucket.get_blob(path[1:])
58  if blob is None:
59    return flask.abort(404)
60  data = blob.download_as_bytes()
61  resp = flask.Response(data)
62  resp.headers['Content-Type'] = blob.content_type
63  resp.headers['Content-Length'] = len(data)
64  resp.headers['Content-Encoding'] = blob.content_encoding
65  if os.path.splitext(path)[1] in ('.png', '.svg'):
66    resp.headers['Cache-Control'] = 'public, max-age=86400'  # 1 Day
67  else:
68    resp.headers['Cache-Control'] = 'public, max-age=600'  # 10 min
69  return resp
70
71
72def get_credentials_for_local_testing():
73  from google_auth_oauthlib import flow
74  flow = flow.InstalledAppFlow.from_client_config(
75      client_config={
76          'installed': {
77              # These aren't secret. Copied from gsutil's apitools sources.
78              'client_id': '1042881264118.apps.googleusercontent.com',
79              'client_secret': 'x_Tw5K8nnjoRAqULM9PFAC2b',
80              'redirect_uris': ['urn:ietf:wg:oauth:2.0:oob'],
81              'auth_uri': 'https://accounts.google.com/o/oauth2/auth',
82              'token_uri': 'https://accounts.google.com/o/oauth2/token'
83          }
84      },
85      scopes=['https://www.googleapis.com/auth/devstorage.read_only'])
86  creds = flow.run_console()
87  return creds
88
89
90if __name__ == '__main__':
91  # This is used when running locally only.
92  creds = get_credentials_for_local_testing()
93  storage_client = storage.Client(project='perfetto-site', credentials=creds)
94  bucket = storage_client.bucket(BUCKET_NAME)
95  is_local_testing_instance = True
96  app.run(host='127.0.0.1', port=8082, debug=False)
97