Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(729)

Side by Side Diff: chrome/common/extensions/docs/server2/server_instance.py

Issue 14125010: Docserver: Add support for viewing docs with a codereview patch applied (Closed) Base URL: https://src.chromium.org/svn/trunk/src/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 logging 6 import logging
7 import mimetypes 7 import mimetypes
8 import traceback 8 import traceback
9 import os 9 import os
10 10
11 from api_data_source import APIDataSource 11 from api_data_source import APIDataSource
12 from api_list_data_source import APIListDataSource 12 from api_list_data_source import APIListDataSource
13 from appengine_blobstore import AppEngineBlobstore 13 from appengine_blobstore import AppEngineBlobstore
14 from appengine_url_fetcher import AppEngineUrlFetcher 14 from appengine_url_fetcher import AppEngineUrlFetcher
15 from appengine_wrappers import GetAppVersion, IsDevServer 15 from appengine_wrappers import GetAppVersion, IsDevServer
16 from branch_utility import BranchUtility 16 from branch_utility import BranchUtility
17 from caching_file_system import CachingFileSystem 17 from caching_file_system import CachingFileSystem
18 from compiled_file_system import CompiledFileSystem 18 from compiled_file_system import CompiledFileSystem
19 from empty_dir_file_system import EmptyDirFileSystem 19 from empty_dir_file_system import EmptyDirFileSystem
20 from example_zipper import ExampleZipper 20 from example_zipper import ExampleZipper
21 from file_system import FileNotFoundError 21 from file_system import FileNotFoundError
22 from github_file_system import GithubFileSystem 22 from github_file_system import GithubFileSystem
23 from intro_data_source import IntroDataSource 23 from intro_data_source import IntroDataSource
24 from local_file_system import LocalFileSystem 24 from local_file_system import LocalFileSystem
25 from object_store_creator import ObjectStoreCreator 25 from object_store_creator import ObjectStoreCreator
26 from offline_file_system import OfflineFileSystem 26 from offline_file_system import OfflineFileSystem
27 from patched_file_system import PatchedFileSystem
27 from path_canonicalizer import PathCanonicalizer 28 from path_canonicalizer import PathCanonicalizer
28 from reference_resolver import ReferenceResolver 29 from reference_resolver import ReferenceResolver
30 from rietveld_file_system import RietveldFileSystem
31 from rietveld_utility import RietveldUtility
29 from samples_data_source import SamplesDataSource 32 from samples_data_source import SamplesDataSource
30 from sidenav_data_source import SidenavDataSource 33 from sidenav_data_source import SidenavDataSource
31 from subversion_file_system import SubversionFileSystem 34 from subversion_file_system import SubversionFileSystem
32 import svn_constants 35 import svn_constants
33 from template_data_source import TemplateDataSource 36 from template_data_source import TemplateDataSource
34 from third_party.json_schema_compiler.memoize import memoize 37 from third_party.json_schema_compiler.memoize import memoize
35 from third_party.json_schema_compiler.model import UnixName 38 from third_party.json_schema_compiler.model import UnixName
36 import url_constants 39 import url_constants
37 40
38 def _IsBinaryMimetype(mimetype): 41 def _IsBinaryMimetype(mimetype):
39 return any(mimetype.startswith(prefix) 42 return any(mimetype.startswith(prefix)
40 for prefix in ['audio', 'image', 'video']) 43 for prefix in ['audio', 'image', 'video'])
41 44
42 def _IsSamplesDisabled(): 45 def _IsSamplesDisabled():
43 return IsDevServer() 46 return IsDevServer()
44 47
45 class ServerInstance(object): 48 class ServerInstance(object):
46 # Lazily create so we don't create github file systems unnecessarily in 49 # Lazily create so we don't create github file systems unnecessarily in
47 # tests. 50 # tests.
48 branch_utility = None 51 branch_utility = None
52 rietveld_utility = None
49 github_file_system = None 53 github_file_system = None
50 54
51 @staticmethod 55 @staticmethod
52 @memoize 56 @memoize
53 def GetOrCreateOffline(channel): 57 def GetOrCreateOffline(channel):
54 '''Gets/creates a local ServerInstance, meaning that only resources local to 58 '''Gets/creates a local ServerInstance, meaning that only resources local to
55 the server - memcache, object store, etc, are queried. This amounts to not 59 the server - memcache, object store, etc, are queried. This amounts to not
56 setting up the subversion nor github file systems. 60 setting up the subversion nor github file systems.
57 ''' 61 '''
58 branch_utility = ServerInstance._GetOrCreateBranchUtility() 62 branch_utility = ServerInstance._GetOrCreateBranchUtility()
59 branch = branch_utility.GetBranchNumberForChannelName(channel) 63 branch = branch_utility.GetBranchNumberForChannelName(channel)
60 object_store_creator_factory = ObjectStoreCreator.Factory(GetAppVersion(), 64 object_store_creator_factory = ObjectStoreCreator.Factory(GetAppVersion(),
61 branch) 65 branch)
62 # No svn nor github file systems. Rely on the crons to fill the caches, and 66 # No svn nor github file systems. Rely on the crons to fill the caches, and
63 # for the caches to exist. 67 # for the caches to exist.
64 return ServerInstance( 68 return ServerInstance(
65 channel, 69 channel,
66 object_store_creator_factory, 70 object_store_creator_factory,
67 CachingFileSystem(OfflineFileSystem(SubversionFileSystem), 71 CachingFileSystem(OfflineFileSystem(SubversionFileSystem),
68 object_store_creator_factory), 72 object_store_creator_factory),
69 # TODO(kalman): convert GithubFileSystem to be wrappable in a 73 # TODO(kalman): convert GithubFileSystem to be wrappable in a
70 # CachingFileSystem so that it can be replaced with an 74 # CachingFileSystem so that it can be replaced with an
71 # OfflineFileSystem. Currently GFS doesn't set the child versions of 75 # OfflineFileSystem. Currently GFS doesn't set the child versions of
72 # stat requests so it doesn't. 76 # stat requests so it doesn't.
73 ServerInstance._GetOrCreateGithubFileSystem()) 77 ServerInstance._GetOrCreateGithubFileSystem())
74 78
75 @staticmethod 79 @staticmethod
76 def CreateOnline(channel): 80 def CreateOnline(channel, issue=None):
77 '''Creates/creates an online server instance, meaning that both local and 81 '''Creates/creates an online server instance, meaning that both local and
78 subversion/github resources are queried. 82 subversion/github resources are queried.
79 ''' 83 '''
80 branch_utility = ServerInstance._GetOrCreateBranchUtility() 84 branch_utility = ServerInstance._GetOrCreateBranchUtility()
81 branch = branch_utility.GetBranchNumberForChannelName(channel) 85 branch = branch_utility.GetBranchNumberForChannelName(channel)
82 86
83 if branch == 'trunk': 87 if branch == 'trunk':
84 svn_url = '/'.join((url_constants.SVN_TRUNK_URL, 88 svn_url = '/'.join((url_constants.SVN_TRUNK_URL,
85 'src', 89 'src',
86 svn_constants.EXTENSIONS_PATH)) 90 svn_constants.EXTENSIONS_PATH))
87 else: 91 else:
88 svn_url = '/'.join((url_constants.SVN_BRANCH_URL, 92 svn_url = '/'.join((url_constants.SVN_BRANCH_URL,
89 branch, 93 branch,
90 'src', 94 'src',
91 svn_constants.EXTENSIONS_PATH)) 95 svn_constants.EXTENSIONS_PATH))
92 96
93 viewvc_url = svn_url.replace(url_constants.SVN_URL, 97 viewvc_url = svn_url.replace(url_constants.SVN_URL,
94 url_constants.VIEWVC_URL) 98 url_constants.VIEWVC_URL)
95 99
100 if issue is not None:
101 rietveld_utility = ServerInstance._GetOrCreateRietveldUtility()
102 patchset = rietveld_utility.GetPatchsetFromIssue(issue)
103 if patchset is None:
104 issue is None
not at google - send to devlin 2013/04/26 23:53:53 I don't think "issue is None" means anything as a
105
96 object_store_creator_factory = ObjectStoreCreator.Factory(GetAppVersion(), 106 object_store_creator_factory = ObjectStoreCreator.Factory(GetAppVersion(),
97 branch, 107 branch,
98 start_empty=True) 108 start_empty=True)
99 109
100 svn_file_system = CachingFileSystem( 110 svn_file_system = CachingFileSystem(
101 SubversionFileSystem(AppEngineUrlFetcher(svn_url), 111 SubversionFileSystem(AppEngineUrlFetcher(svn_url),
102 AppEngineUrlFetcher(viewvc_url)), 112 AppEngineUrlFetcher(viewvc_url)),
103 object_store_creator_factory) 113 object_store_creator_factory)
114 if issue is not None:
115 (patched_files, changes) = rietveld_utility.GetPatchsetDetails(
116 issue, patchset)
not at google - send to devlin 2013/04/26 23:53:53 patched files... changes... everything should be p
117 patched_object_store_creator_factory = ObjectStoreCreator.Factory(
118 GetAppVersion(),
119 branch,
120 True, # start_empty
not at google - send to devlin 2013/04/26 23:53:53 use start_empty=True
方觉(Fang Jue) 2013/04/29 12:46:23 Done.
121 issue,
122 patchset)
not at google - send to devlin 2013/04/26 23:53:53 it's nice to spell out optional arguments explicit
方觉(Fang Jue) 2013/04/29 12:46:23 Done.
123 rietveld_file_system = CachingFileSystem(
124 RietveldFileSystem(issue,
125 patchset,
126 patched_files,
127 AppEngineUrlFetcher(
128 url_constants.CODEREVIEW_SERVER)),
129 patched_object_store_creator_factory)
130 patched_file_system = PatchedFileSystem(patched_files,
131 svn_file_system,
132 rietveld_file_system)
133 else:
134 patched_object_store_creator_factory = None
135 patched_file_system = None
136 changes = None
104 137
105 return ServerInstance(channel, 138 return ServerInstance(channel,
106 object_store_creator_factory, 139 object_store_creator_factory,
107 svn_file_system, 140 svn_file_system,
not at google - send to devlin 2013/04/26 23:53:53 I hope that it's possible to inject patched_file_s
方觉(Fang Jue) 2013/04/27 00:24:34 I was trying to reuse existing cached content for
not at google - send to devlin 2013/04/27 00:45:30 patched_file_system delegates to svn_file_system,
方觉(Fang Jue) 2013/04/27 01:02:48 SubversionFileSystem will get all the caching but
not at google - send to devlin 2013/04/27 01:07:48 Ah I see what you mean. Eh, re-compiling all that
方觉(Fang Jue) 2013/04/29 12:46:23 Then complicated and messy changes below are no lo
108 ServerInstance._GetOrCreateGithubFileSystem()) 141 ServerInstance._GetOrCreateGithubFileSystem(),
142 patched_object_store_creator_factory,
143 patched_file_system,
144 changes)
109 145
110 @staticmethod 146 @staticmethod
111 def CreateForTest(file_system): 147 def CreateForTest(file_system):
112 return ServerInstance('test', 148 return ServerInstance('test',
113 ObjectStoreCreator.TestFactory(), 149 ObjectStoreCreator.TestFactory(),
114 file_system, 150 file_system,
115 None) 151 None)
116 152
117 @staticmethod 153 @staticmethod
118 def _GetOrCreateBranchUtility(): 154 def _GetOrCreateBranchUtility():
119 if ServerInstance.branch_utility is None: 155 if ServerInstance.branch_utility is None:
120 ServerInstance.branch_utility = BranchUtility( 156 ServerInstance.branch_utility = BranchUtility(
121 url_constants.OMAHA_PROXY_URL, 157 url_constants.OMAHA_PROXY_URL,
122 AppEngineUrlFetcher()) 158 AppEngineUrlFetcher())
123 return ServerInstance.branch_utility 159 return ServerInstance.branch_utility
124 160
125 @staticmethod 161 @staticmethod
162 def _GetOrCreateRietveldUtility():
163 if ServerInstance.rietveld_utility is None:
164 ServerInstance.rietveld_utility = RietveldUtility(
165 AppEngineUrlFetcher(url_constants.CODEREVIEW_SERVER))
166 return ServerInstance.rietveld_utility
not at google - send to devlin 2013/04/26 23:53:53 this would probably end up getting owned by PatchS
167
168 @staticmethod
126 def _GetOrCreateGithubFileSystem(): 169 def _GetOrCreateGithubFileSystem():
127 # Initialising github is pointless if samples are disabled, since it's only 170 # Initialising github is pointless if samples are disabled, since it's only
128 # used for apps samples. 171 # used for apps samples.
129 if ServerInstance.github_file_system is None: 172 if ServerInstance.github_file_system is None:
130 if _IsSamplesDisabled(): 173 if _IsSamplesDisabled():
131 ServerInstance.github_file_system = EmptyDirFileSystem() 174 ServerInstance.github_file_system = EmptyDirFileSystem()
132 else: 175 else:
133 ServerInstance.github_file_system = GithubFileSystem( 176 ServerInstance.github_file_system = GithubFileSystem(
134 AppEngineUrlFetcher(url_constants.GITHUB_URL), 177 AppEngineUrlFetcher(url_constants.GITHUB_URL),
135 AppEngineBlobstore()) 178 AppEngineBlobstore())
136 return ServerInstance.github_file_system 179 return ServerInstance.github_file_system
137 180
181 def _GetCompiledFileSystemFactory(self, deps=[]):
182 for dep in deps:
183 if self.changes.get(dep):
184 return self.compiled_fs_factory
185 return self.unpatched_compiled_fs_factory
186
138 def __init__(self, 187 def __init__(self,
not at google - send to devlin 2013/04/26 23:53:53 As above - I think most of __init__ can stay the s
方觉(Fang Jue) 2013/04/29 12:46:23 Done.
139 channel, 188 channel,
140 object_store_creator_factory, 189 unpatched_object_store_creator_factory,
141 svn_file_system, 190 svn_file_system,
142 github_file_system): 191 github_file_system,
143 self.svn_file_system = svn_file_system 192 patched_object_store_creator_factory=None,
193 patched_file_system=None,
194 changes=None):
195 if changes is None:
196 changes = {}
197 self.changes = changes
198 logging.info(changes)
144 199
145 self.github_file_system = github_file_system 200 self.github_file_system = github_file_system
146 201
147 self.compiled_fs_factory = CompiledFileSystem.Factory( 202 self.unpatched_compiled_fs_factory = CompiledFileSystem.Factory(
148 svn_file_system, 203 svn_file_system,
149 object_store_creator_factory) 204 unpatched_object_store_creator_factory)
205 if patched_object_store_creator_factory is None:
206 patched_object_store_creator_factory = (
207 unpatched_object_store_creator_factory)
208 self.compiled_fs_factory = self.unpatched_compiled_fs_factory
209 else:
210 self.compiled_fs_factory = CompiledFileSystem.Factory(
211 patched_file_system,
212 patched_object_store_creator_factory)
150 213
151 self.api_list_data_source_factory = APIListDataSource.Factory( 214 self.api_list_data_source_factory = APIListDataSource.Factory(
152 self.compiled_fs_factory, 215 self._GetCompiledFileSystemFactory([
216 svn_constants.API_PATH,
217 svn_constants.PUBLIC_TEMPLATE_PATH]),
153 svn_constants.API_PATH, 218 svn_constants.API_PATH,
154 svn_constants.PUBLIC_TEMPLATE_PATH) 219 svn_constants.PUBLIC_TEMPLATE_PATH)
155 220
156 self.api_data_source_factory = APIDataSource.Factory( 221 self.api_data_source_factory = APIDataSource.Factory(
157 self.compiled_fs_factory, 222 self._GetCompiledFileSystemFactory([svn_constants.API_PATH]),
158 svn_constants.API_PATH) 223 svn_constants.API_PATH)
159 224
160 self.ref_resolver_factory = ReferenceResolver.Factory( 225 self.unpatched_ref_resolver_factory = ReferenceResolver.Factory(
226 APIDataSource.Factory(
227 self.compiled_fs_factory,
228 svn_constants.API_PATH),
229 APIListDataSource.Factory(
230 self.compiled_fs_factory,
231 svn_constants.API_PATH,
232 svn_constants.PUBLIC_TEMPLATE_PATH),
233 unpatched_object_store_creator_factory)
234 if (changes.get(svn_constants.API_PATH) or
235 changes.get(svn_constants.PUBLIC_TEMPLATE_PATH)):
236 self.ref_resolver_factory = ReferenceResolver.Factory(
161 self.api_data_source_factory, 237 self.api_data_source_factory,
162 self.api_list_data_source_factory, 238 self.api_list_data_source_factory,
163 object_store_creator_factory) 239 patched_object_store_creator_factory)
240 else:
241 self.ref_resolver_factory = self.unpatched_ref_resolver_factory
164 242
165 self.api_data_source_factory.SetReferenceResolverFactory( 243 self.api_data_source_factory.SetReferenceResolverFactory(
166 self.ref_resolver_factory) 244 self.ref_resolver_factory)
167 245
168 # Note: samples are super slow in the dev server because it doesn't support 246 # Note: samples are super slow in the dev server because it doesn't support
169 # async fetch, so disable them. If you actually want to test samples, then 247 # async fetch, so disable them. If you actually want to test samples, then
170 # good luck, and modify _IsSamplesDisabled at the top. 248 # good luck, and modify _IsSamplesDisabled at the top.
171 if _IsSamplesDisabled(): 249 if _IsSamplesDisabled():
172 svn_fs_for_samples = EmptyDirFileSystem() 250 svn_fs_for_samples = EmptyDirFileSystem()
173 else: 251 else:
174 svn_fs_for_samples = self.svn_file_system 252 svn_fs_for_samples = svn_file_system
175 self.samples_data_source_factory = SamplesDataSource.Factory( 253 self.samples_data_source_factory = SamplesDataSource.Factory(
176 channel, 254 channel,
177 svn_fs_for_samples, 255 svn_fs_for_samples,
178 self.github_file_system, 256 self.github_file_system,
179 self.ref_resolver_factory, 257 self.unpatched_ref_resolver_factory,
180 object_store_creator_factory, 258 unpatched_object_store_creator_factory,
181 svn_constants.EXAMPLES_PATH) 259 svn_constants.EXAMPLES_PATH)
182 260
183 self.api_data_source_factory.SetSamplesDataSourceFactory( 261 self.api_data_source_factory.SetSamplesDataSourceFactory(
184 self.samples_data_source_factory) 262 self.samples_data_source_factory)
185 263
186 self.intro_data_source_factory = IntroDataSource.Factory( 264 self.intro_data_source_factory = IntroDataSource.Factory(
187 self.compiled_fs_factory, 265 self._GetCompiledFileSystemFactory([
266 svn_constants.INTRO_PATH,
267 svn_constants.ARTICLE_PATH]),
188 self.ref_resolver_factory, 268 self.ref_resolver_factory,
189 [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH]) 269 [svn_constants.INTRO_PATH, svn_constants.ARTICLE_PATH])
190 270
191 self.sidenav_data_source_factory = SidenavDataSource.Factory( 271 self.sidenav_data_source_factory = SidenavDataSource.Factory(
192 self.compiled_fs_factory, 272 self._GetCompiledFileSystemFactory([svn_constants.JSON_PATH]),
193 svn_constants.JSON_PATH) 273 svn_constants.JSON_PATH)
194 274
195 self.template_data_source_factory = TemplateDataSource.Factory( 275 self.template_data_source_factory = TemplateDataSource.Factory(
196 channel, 276 channel,
197 self.api_data_source_factory, 277 self.api_data_source_factory,
198 self.api_list_data_source_factory, 278 self.api_list_data_source_factory,
199 self.intro_data_source_factory, 279 self.intro_data_source_factory,
200 self.samples_data_source_factory, 280 self.samples_data_source_factory,
201 self.sidenav_data_source_factory, 281 self.sidenav_data_source_factory,
202 self.compiled_fs_factory, 282 self.compiled_fs_factory,
203 self.ref_resolver_factory, 283 self.ref_resolver_factory,
204 svn_constants.PUBLIC_TEMPLATE_PATH, 284 svn_constants.PUBLIC_TEMPLATE_PATH,
205 svn_constants.PRIVATE_TEMPLATE_PATH) 285 svn_constants.PRIVATE_TEMPLATE_PATH)
206 286
207 self.example_zipper = ExampleZipper( 287 self.example_zipper = ExampleZipper(
208 self.compiled_fs_factory, 288 self.unpatched_compiled_fs_factory,
209 svn_constants.DOCS_PATH) 289 svn_constants.DOCS_PATH)
210 290
211 self.path_canonicalizer = PathCanonicalizer( 291 self.path_canonicalizer = PathCanonicalizer(
212 channel, 292 channel,
213 self.compiled_fs_factory) 293 self.unpatched_compiled_fs_factory)
214 294
215 self.content_cache = self.compiled_fs_factory.GetOrCreateIdentity() 295 self.unpatched_content_cache = (self.unpatched_compiled_fs_factory.
296 GetOrCreateIdentity())
297 if changes.get(svn_constants.STATIC_PATH):
298 self.content_cache = (self.patched_compiled_fs_factory.
299 GetOrCreateIdentity())
300 else:
301 self.content_cache = self.unpatched_content_cache
216 302
217 def _FetchStaticResource(self, path, response): 303 def _FetchStaticResource(self, path, response):
218 """Fetch a resource in the 'static' directory. 304 """Fetch a resource in the 'static' directory.
219 """ 305 """
220 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' 306 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
221 result = self.content_cache.GetFromFile( 307 result = self.content_cache.GetFromFile(
222 svn_constants.DOCS_PATH + '/' + path, 308 svn_constants.DOCS_PATH + '/' + path,
223 binary=_IsBinaryMimetype(mimetype)) 309 binary=_IsBinaryMimetype(mimetype))
224 response.headers['content-type'] = mimetype 310 response.headers['content-type'] = mimetype
225 return result 311 return result
226 312
227 def Get(self, path, request, response): 313 def Get(self, path, request, response):
228 templates = self.template_data_source_factory.Create(request, path) 314 templates = self.template_data_source_factory.Create(request, path)
229 315
230 content = None 316 content = None
231 try: 317 try:
232 if fnmatch(path, 'extensions/examples/*.zip'): 318 if fnmatch(path, 'extensions/examples/*.zip'):
233 content = self.example_zipper.Create( 319 content = self.example_zipper.Create(
234 path[len('extensions/'):-len('.zip')]) 320 path[len('extensions/'):-len('.zip')])
235 response.headers['content-type'] = 'application/zip' 321 response.headers['content-type'] = 'application/zip'
236 elif path.startswith('extensions/examples/'): 322 elif path.startswith('extensions/examples/'):
237 mimetype = mimetypes.guess_type(path)[0] or 'text/plain' 323 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
238 content = self.content_cache.GetFromFile( 324 content = self.unpatched_content_cache.GetFromFile(
239 '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]), 325 '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]),
240 binary=_IsBinaryMimetype(mimetype)) 326 binary=_IsBinaryMimetype(mimetype))
241 response.headers['content-type'] = 'text/plain' 327 response.headers['content-type'] = 'text/plain'
242 elif path.startswith('static/'): 328 elif path.startswith('static/'):
243 content = self._FetchStaticResource(path, response) 329 content = self._FetchStaticResource(path, response)
244 elif path.endswith('.html'): 330 elif path.endswith('.html'):
245 content = templates.Render(path) 331 content = templates.Render(path)
246 except FileNotFoundError as e: 332 except FileNotFoundError as e:
247 logging.warning(traceback.format_exc()) 333 logging.warning(traceback.format_exc())
248 334
249 response.headers['x-frame-options'] = 'sameorigin' 335 response.headers['x-frame-options'] = 'sameorigin'
250 if content is None: 336 if content is None:
251 response.set_status(404); 337 response.set_status(404);
252 response.out.write(templates.Render('404')) 338 response.out.write(templates.Render('404'))
253 else: 339 else:
254 if not content: 340 if not content:
255 logging.error('%s had empty content' % path) 341 logging.error('%s had empty content' % path)
256 response.headers['cache-control'] = 'max-age=300' 342 response.headers['cache-control'] = 'max-age=300'
257 response.out.write(content) 343 response.out.write(content)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698