9f55d978f0a8202d78eeeb5ec3c8dfce858b5e69
[platform/framework/web/crosswalk.git] / src / chrome / common / extensions / docs / server2 / patch_servlet.py
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.
4
5 from fnmatch import fnmatch
6 import logging
7 from urlparse import urlparse
8
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
21 import url_constants
22
23
24 class _PatchServletDelegate(RenderServlet.Delegate):
25   def __init__(self, issue, delegate):
26     self._issue = issue
27     self._delegate = delegate
28
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)
34
35     unpatched_file_system = self._delegate.CreateHostFileSystemProvider(
36         object_store_creator).GetTrunk()
37
38     rietveld_patcher = CachingRietveldPatcher(
39         RietveldPatcher(self._issue,
40                         AppEngineUrlFetcher(url_constants.CODEREVIEW_SERVER)),
41         object_store_creator)
42
43     patched_file_system = PatchedFileSystem(unpatched_file_system,
44                                             rietveld_patcher)
45
46     patched_host_file_system_provider = (
47         self._delegate.CreateHostFileSystemProvider(
48             object_store_creator,
49             # The patched file system needs to be online otherwise it'd be
50             # impossible to add files in the patches.
51             offline=False,
52             # The trunk file system for this creator should be the patched one.
53             default_trunk_instance=patched_file_system))
54
55     combined_compiled_fs_factory = ChainedCompiledFileSystem.Factory(
56         [unpatched_file_system], object_store_creator)
57
58     branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
59
60     server_instance = ServerInstance(
61         object_store_creator,
62         combined_compiled_fs_factory,
63         branch_utility,
64         patched_host_file_system_provider,
65         self._delegate.CreateGithubFileSystemProvider(object_store_creator),
66         base_path='/_patch/%s/' % self._issue)
67
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()
73
74     return server_instance
75
76 class PatchServlet(Servlet):
77   '''Servlet which renders patched docs.
78   '''
79   def __init__(self, request, delegate=None):
80     self._request = request
81     self._delegate = delegate or InstanceServlet.Delegate()
82
83   def Get(self):
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))
93
94     path_with_issue = self._request.path.lstrip('/')
95     if '/' in path_with_issue:
96       issue, path_without_issue = path_with_issue.split('/', 1)
97     else:
98       return Response.NotFound('Malformed URL. It should look like ' +
99           'https://developer.chrome.com/_patch/12345/extensions/...')
100
101     try:
102       response = RenderServlet(
103           Request(path_without_issue,
104                   self._request.host,
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'})
111
112     redirect_url, permanent = response.GetRedirect()
113     if redirect_url is not None:
114       response = Response.Redirect('/_patch/%s%s' % (issue, redirect_url),
115                                    permanent)
116     return response