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