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 |