1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 from fnmatch
import fnmatch
7 from urlparse
import urlparse
9 from appengine_url_fetcher
import AppEngineUrlFetcher
10 from caching_rietveld_patcher
import CachingRietveldPatcher
11 from chained_compiled_file_system
import ChainedCompiledFileSystem
12 from environment
import IsDevServer
13 from extensions_paths
import CONTENT_PROVIDERS
14 from instance_servlet
import InstanceServlet
15 from render_servlet
import RenderServlet
16 from rietveld_patcher
import RietveldPatcher
, RietveldPatcherError
17 from object_store_creator
import ObjectStoreCreator
18 from patched_file_system
import PatchedFileSystem
19 from server_instance
import ServerInstance
20 from servlet
import Request
, Response
, Servlet
24 class _PatchServletDelegate(RenderServlet
.Delegate
):
25 def __init__(self
, issue
, delegate
):
27 self
._delegate
= delegate
29 def CreateServerInstance(self
):
30 # start_empty=False because a patch can rely on files that are already in
31 # SVN repository but not yet pulled into data store by cron jobs (a typical
32 # example is to add documentation for an existing API).
33 object_store_creator
= ObjectStoreCreator(start_empty
=False)
35 unpatched_file_system
= self
._delegate
.CreateHostFileSystemProvider(
36 object_store_creator
).GetTrunk()
38 rietveld_patcher
= CachingRietveldPatcher(
39 RietveldPatcher(self
._issue
,
40 AppEngineUrlFetcher(url_constants
.CODEREVIEW_SERVER
)),
43 patched_file_system
= PatchedFileSystem(unpatched_file_system
,
46 patched_host_file_system_provider
= (
47 self
._delegate
.CreateHostFileSystemProvider(
49 # The patched file system needs to be online otherwise it'd be
50 # impossible to add files in the patches.
52 # The trunk file system for this creator should be the patched one.
53 default_trunk_instance
=patched_file_system
))
55 combined_compiled_fs_factory
= ChainedCompiledFileSystem
.Factory(
56 [unpatched_file_system
], object_store_creator
)
58 branch_utility
= self
._delegate
.CreateBranchUtility(object_store_creator
)
60 server_instance
= ServerInstance(
62 combined_compiled_fs_factory
,
64 patched_host_file_system_provider
,
65 self
._delegate
.CreateGithubFileSystemProvider(object_store_creator
),
66 base_path
='/_patch/%s/' % self
._issue
)
68 # HACK: if content_providers.json changes in this patch then the cron needs
69 # to be re-run to pull in the new configuration.
70 _
, _
, modified
= rietveld_patcher
.GetPatchedFiles()
71 if CONTENT_PROVIDERS
in modified
:
72 server_instance
.content_providers
.Cron().Get()
74 return server_instance
76 class PatchServlet(Servlet
):
77 '''Servlet which renders patched docs.
79 def __init__(self
, request
, delegate
=None):
80 self
._request
= request
81 self
._delegate
= delegate
or InstanceServlet
.Delegate()
84 if (not IsDevServer() and
85 not fnmatch(urlparse(self
._request
.host
).netloc
, '*.appspot.com')):
86 # Only allow patches on appspot URLs; it doesn't matter if appspot.com is
87 # XSS'ed, but it matters for chrome.com.
88 redirect_host
= 'https://chrome-apps-doc.appspot.com'
89 logging
.info('Redirecting from XSS-able host %s to %s' % (
90 self
._request
.host
, redirect_host
))
91 return Response
.Redirect(
92 '%s/_patch/%s' % (redirect_host
, self
._request
.path
))
94 path_with_issue
= self
._request
.path
.lstrip('/')
95 if '/' in path_with_issue
:
96 issue
, path_without_issue
= path_with_issue
.split('/', 1)
98 return Response
.NotFound('Malformed URL. It should look like ' +
99 'https://developer.chrome.com/_patch/12345/extensions/...')
102 response
= RenderServlet(
103 Request(path_without_issue
,
105 self
._request
.headers
),
106 _PatchServletDelegate(issue
, self
._delegate
)).Get()
107 # Disable cache for patched content.
108 response
.headers
.pop('cache-control', None)
109 except RietveldPatcherError
as e
:
110 response
= Response
.NotFound(e
.message
, {'Content-Type': 'text/plain'})
112 redirect_url
, permanent
= response
.GetRedirect()
113 if redirect_url
is not None:
114 response
= Response
.Redirect('/_patch/%s%s' % (issue
, redirect_url
),