Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from fnmatch import fnmatch | 5 from fnmatch import fnmatch |
| 6 import mimetypes | 6 import mimetypes |
| 7 import os | 7 import os |
| 8 | 8 |
| 9 from api_data_source import APIDataSource | |
| 10 from api_list_data_source import APIListDataSource | |
| 11 from appengine_blobstore import AppEngineBlobstore | |
| 12 from appengine_url_fetcher import AppEngineUrlFetcher | |
| 13 from branch_utility import BranchUtility | |
| 14 from compiled_file_system import CompiledFileSystem | |
| 15 from example_zipper import ExampleZipper | |
| 9 from file_system import FileNotFoundError | 16 from file_system import FileNotFoundError |
| 10 import compiled_file_system as compiled_fs | 17 from github_file_system import GithubFileSystem |
| 11 | 18 from in_memory_object_store import InMemoryObjectStore |
| 12 STATIC_DIR_PREFIX = 'docs' | 19 from intro_data_source import IntroDataSource |
| 13 DOCS_PATH = 'docs' | 20 from local_file_system import LocalFileSystem |
| 21 from caching_file_system import CachingFileSystem | |
| 22 from object_store_creator import ObjectStoreCreator | |
| 23 from path_canonicalizer import PathCanonicalizer | |
| 24 from reference_resolver import ReferenceResolver | |
| 25 from samples_data_source import SamplesDataSource | |
| 26 from sidenav_data_source import SidenavDataSource | |
| 27 from subversion_file_system import SubversionFileSystem | |
| 28 import svn_constants | |
| 29 from template_data_source import TemplateDataSource | |
| 30 from third_party.json_schema_compiler.model import UnixName | |
| 31 import url_constants | |
| 14 | 32 |
| 15 def _IsBinaryMimetype(mimetype): | 33 def _IsBinaryMimetype(mimetype): |
| 16 return any(mimetype.startswith(prefix) | 34 return any(mimetype.startswith(prefix) |
| 17 for prefix in ['audio', 'image', 'video']) | 35 for prefix in ['audio', 'image', 'video']) |
| 18 | 36 |
| 19 class ServerInstance(object): | 37 class ServerInstance(object): |
| 20 """This class is used to hold a data source and fetcher for an instance of a | 38 '''Per-instance per-branch state. |
| 21 server. Each new branch will get its own ServerInstance. | 39 ''' |
| 22 """ | 40 _instances = {} |
| 23 def __init__(self, | 41 |
| 24 template_data_source_factory, | 42 branch_utility = None |
| 25 example_zipper, | 43 github_file_system = None |
| 26 cache_factory): | 44 |
| 27 self._template_data_source_factory = template_data_source_factory | 45 @staticmethod |
| 28 self._example_zipper = example_zipper | 46 def GetOrCreate(channel): |
| 29 self._cache = cache_factory.Create(lambda _, x: x, compiled_fs.STATIC) | 47 branch_utility = ServerInstance.branch_utility |
|
cduvall
2013/04/08 07:09:24
is it necessary to assign ServerInstance.branch_ut
not at google - send to devlin
2013/04/08 12:21:21
Done. For GithubFileSystem too.
| |
| 48 if branch_utility is None: | |
| 49 branch_utility = BranchUtility(url_constants.OMAHA_PROXY_URL, | |
| 50 AppEngineUrlFetcher()) | |
| 51 ServerInstance.branch_utility = branch_utility | |
| 52 | |
| 53 branch = branch_utility.GetBranchNumberForChannelName(channel) | |
| 54 | |
| 55 # Use the branch as the key to |_instances| since the branch data is | |
| 56 # predictable while the channel data (channels can swich branches) isn't. | |
| 57 instance = ServerInstance._instances.get(branch) | |
| 58 if instance is None: | |
| 59 instance = ServerInstance._CreateForProduction(channel, branch) | |
| 60 ServerInstance._instances[branch] = instance | |
| 61 return instance | |
| 62 | |
| 63 @staticmethod | |
| 64 def _CreateForProduction(channel, branch): | |
| 65 if branch == 'trunk': | |
| 66 svn_url = '/'.join((url_constants.SVN_TRUNK_URL, | |
| 67 'src', | |
| 68 svn_constants.EXTENSIONS_PATH)) | |
| 69 else: | |
| 70 svn_url = '/'.join((url_constants.SVN_BRANCH_URL, | |
| 71 branch, | |
| 72 'src', | |
| 73 svn_constants.EXTENSIONS_PATH)) | |
| 74 | |
| 75 viewvc_url = svn_url.replace(url_constants.SVN_URL, | |
| 76 url_constants.VIEWVC_URL) | |
| 77 | |
| 78 svn_file_system = CachingFileSystem( | |
| 79 SubversionFileSystem(AppEngineUrlFetcher(svn_url), | |
| 80 AppEngineUrlFetcher(viewvc_url))) | |
| 81 | |
| 82 github_file_system = ServerInstance.github_file_system | |
| 83 if github_file_system is None: | |
| 84 github_file_system = GithubFileSystem( | |
| 85 AppEngineUrlFetcher(url_constants.GITHUB_URL), | |
| 86 AppEngineBlobstore()) | |
| 87 ServerInstance.github_file_system = github_file_system | |
| 88 | |
| 89 return ServerInstance(channel, svn_file_system, github_file_system) | |
| 90 | |
| 91 @staticmethod | |
| 92 def CreateForTest(file_system): | |
| 93 return ServerInstance('test', file_system, None) | |
| 94 | |
| 95 def __init__(self, channel, svn_file_system, github_file_system): | |
| 96 self.svn_file_system = svn_file_system | |
| 97 | |
| 98 self.github_file_system = github_file_system | |
| 99 | |
| 100 self.compiled_fs_factory = CompiledFileSystem.Factory(svn_file_system) | |
| 101 | |
| 102 self.api_list_data_source_factory = APIListDataSource.Factory( | |
| 103 self.compiled_fs_factory, | |
| 104 svn_constants.API_PATH, | |
| 105 svn_constants.PUBLIC_TEMPLATE_PATH) | |
| 106 | |
| 107 self.api_data_source_factory = APIDataSource.Factory( | |
| 108 self.compiled_fs_factory, | |
| 109 svn_constants.API_PATH) | |
| 110 | |
| 111 self.ref_resolver_factory = ReferenceResolver.Factory( | |
| 112 self.api_data_source_factory, | |
| 113 self.api_list_data_source_factory) | |
| 114 | |
| 115 self.api_data_source_factory.SetReferenceResolverFactory( | |
| 116 self.ref_resolver_factory) | |
| 117 | |
| 118 self.samples_data_source_factory = SamplesDataSource.Factory( | |
| 119 channel, | |
| 120 self.svn_file_system, | |
| 121 ServerInstance.github_file_system, | |
| 122 self.ref_resolver_factory, | |
| 123 svn_constants.EXAMPLES_PATH) | |
| 124 | |
| 125 self.api_data_source_factory.SetSamplesDataSourceFactory( | |
| 126 self.samples_data_source_factory) | |
| 127 | |
| 128 self.intro_data_source_factory = IntroDataSource.Factory( | |
| 129 self.compiled_fs_factory, | |
| 130 self.ref_resolver_factory, | |
| 131 [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH]) | |
| 132 | |
| 133 self.sidenav_data_source_factory = SidenavDataSource.Factory( | |
| 134 self.compiled_fs_factory, | |
| 135 svn_constants.JSON_PATH) | |
| 136 | |
| 137 self.template_data_source_factory = TemplateDataSource.Factory( | |
| 138 channel, | |
| 139 self.api_data_source_factory, | |
| 140 self.api_list_data_source_factory, | |
| 141 self.intro_data_source_factory, | |
| 142 self.samples_data_source_factory, | |
| 143 self.sidenav_data_source_factory, | |
| 144 self.compiled_fs_factory, | |
| 145 self.ref_resolver_factory, | |
| 146 svn_constants.PUBLIC_TEMPLATE_PATH, | |
| 147 svn_constants.PRIVATE_TEMPLATE_PATH) | |
| 148 | |
| 149 self.example_zipper = ExampleZipper( | |
| 150 self.svn_file_system, | |
| 151 self.compiled_fs_factory, | |
| 152 svn_constants.DOCS_PATH) | |
| 153 | |
| 154 self.path_canonicalizer = PathCanonicalizer( | |
| 155 channel, | |
| 156 self.compiled_fs_factory) | |
| 157 | |
| 158 self.content_cache = self.compiled_fs_factory.GetOrCreateIdentity() | |
| 30 | 159 |
| 31 def _FetchStaticResource(self, path, response): | 160 def _FetchStaticResource(self, path, response): |
| 32 """Fetch a resource in the 'static' directory. | 161 """Fetch a resource in the 'static' directory. |
| 33 """ | 162 """ |
| 34 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' | 163 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' |
| 35 try: | 164 try: |
| 36 result = self._cache.GetFromFile(STATIC_DIR_PREFIX + '/' + path, | 165 result = self.content_cache.GetFromFile( |
| 37 binary=_IsBinaryMimetype(mimetype)) | 166 svn_constants.DOCS_PATH + '/' + path, |
| 167 binary=_IsBinaryMimetype(mimetype)) | |
| 38 except FileNotFoundError: | 168 except FileNotFoundError: |
| 39 return None | 169 return None |
| 40 response.headers['content-type'] = mimetype | 170 response.headers['content-type'] = mimetype |
| 41 return result | 171 return result |
| 42 | 172 |
| 43 def Get(self, path, request, response): | 173 def Get(self, path, request, response): |
| 44 # TODO(cduvall): bundle up all the request-scoped data into a single object. | 174 templates = self.template_data_source_factory.Create(request, path) |
| 45 templates = self._template_data_source_factory.Create(request, path) | 175 |
| 176 if path.rsplit('/', 1)[-1] in ('favicon.ico', 'robots.txt'): | |
| 177 response.set_status(404) | |
| 178 response.out.write(templates.Render('404')) | |
| 179 return | |
| 46 | 180 |
| 47 content = None | 181 content = None |
| 48 if fnmatch(path, 'extensions/examples/*.zip'): | 182 if fnmatch(path, 'extensions/examples/*.zip'): |
| 49 try: | 183 try: |
| 50 content = self._example_zipper.Create( | 184 content = self.example_zipper.Create( |
| 51 path[len('extensions/'):-len('.zip')]) | 185 path[len('extensions/'):-len('.zip')]) |
| 52 response.headers['content-type'] = 'application/zip' | 186 response.headers['content-type'] = 'application/zip' |
| 53 except FileNotFoundError: | 187 except FileNotFoundError: |
| 54 content = None | 188 content = None |
| 55 elif path.startswith('extensions/examples/'): | 189 elif path.startswith('extensions/examples/'): |
| 56 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' | 190 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' |
| 57 try: | 191 try: |
| 58 content = self._cache.GetFromFile( | 192 content = self.content_cache.GetFromFile( |
| 59 '%s/%s' % (DOCS_PATH, path[len('extensions/'):]), | 193 '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]), |
| 60 binary=_IsBinaryMimetype(mimetype)) | 194 binary=_IsBinaryMimetype(mimetype)) |
| 61 response.headers['content-type'] = 'text/plain' | 195 response.headers['content-type'] = 'text/plain' |
| 62 except FileNotFoundError: | 196 except FileNotFoundError: |
| 63 content = None | 197 content = None |
| 64 elif path.startswith('static/'): | 198 elif path.startswith('static/'): |
| 65 content = self._FetchStaticResource(path, response) | 199 content = self._FetchStaticResource(path, response) |
| 66 elif path.endswith('.html'): | 200 elif path.endswith('.html'): |
| 67 content = templates.Render(path) | 201 content = templates.Render(path) |
| 68 | 202 |
| 69 response.headers['x-frame-options'] = 'sameorigin' | 203 response.headers['x-frame-options'] = 'sameorigin' |
| 70 if content: | 204 if content: |
| 71 response.headers['cache-control'] = 'max-age=300' | 205 response.headers['cache-control'] = 'max-age=300' |
| 72 response.out.write(content) | 206 response.out.write(content) |
| 73 else: | 207 else: |
| 74 response.set_status(404); | 208 response.set_status(404); |
| 75 response.out.write(templates.Render('404')) | 209 response.out.write(templates.Render('404')) |
| OLD | NEW |