1 # Copyright (C) 2018 The Android Open Source Project 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 from google.appengine.api import memcache 16 from google.appengine.api import urlfetch 17 18 import re 19 import webapp2 20 21 MEMCACHE_TTL_SEC= 60 * 60 * 24 22 BASE = 'https://catapult-project.github.io/perfetto/%s' 23 HEADERS = {'last-modified', 'content-type', 24 'content-length', 'content-encoding', 'etag'} 25 26 27 class MainHandler(webapp2.RequestHandler): 28 def get(self): 29 handler = GithubMirrorHandler() 30 handler.initialize(self.request, self.response) 31 return handler.get("index.html") 32 33 34 class GithubMirrorHandler(webapp2.RequestHandler): 35 def get(self, resource): 36 if not re.match('^[a-zA-Z0-9-_./]*$', resource): 37 self.response.set_status(403) 38 return 39 40 url = BASE % resource 41 cache = memcache.get(url) 42 if not cache or self.request.get('reload'): 43 result = urlfetch.fetch(url) 44 if result.status_code != 200: 45 memcache.delete(url) 46 self.response.set_status(result.status_code) 47 self.response.write(result.content) 48 return 49 cache = {'content-type': 'text/html'} 50 for k, v in result.headers.iteritems(): 51 k = k.lower() 52 if k in HEADERS: 53 cache[k] = v 54 cache['content'] = result.content 55 memcache.set(url, cache, time=MEMCACHE_TTL_SEC) 56 57 for k, v in cache.iteritems(): 58 if k != 'content': 59 self.response.headers[k] = v 60 self.response.headers['cache-control'] = 'public,max-age=600' 61 self.response.write(cache['content']) 62 63 64 app = webapp2.WSGIApplication([ 65 ('/', MainHandler), 66 ('/(.+)', GithubMirrorHandler), 67 ], debug=True) 68