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
8 from caching_rietveld_patcher
import CachingRietveldPatcher
9 from chained_compiled_file_system
import ChainedCompiledFileSystem
10 from environment
import IsDevServer
11 from environment_wrappers
import CreateUrlFetcher
12 from extensions_paths
import CONTENT_PROVIDERS
13 from instance_servlet
import InstanceServlet
14 from render_servlet
import RenderServlet
15 from rietveld_patcher
import RietveldPatcher
, RietveldPatcherError
16 from object_store_creator
import ObjectStoreCreator
17 from patched_file_system
import PatchedFileSystem
18 from server_instance
import ServerInstance
19 from servlet
import Request
, Response
, Servlet
21 from gcs_file_system_provider
import CloudStorageFileSystemProvider
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 # the Git repository but not yet pulled into data store by cron jobs (a
32 # typical 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
).GetMaster()
38 rietveld_patcher
= CachingRietveldPatcher(
39 RietveldPatcher(self
._issue
,
40 CreateUrlFetcher(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 master file system for this creator should be the patched one.
53 default_master_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 CloudStorageFileSystemProvider(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
.Refresh().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(self
._request
.host
, '*.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
= '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 'https://%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
),