- add sources.
[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_file_system import CachingFileSystem
11 from caching_rietveld_patcher import CachingRietveldPatcher
12 from chained_compiled_file_system import ChainedCompiledFileSystem
13 from compiled_file_system import  CompiledFileSystem
14 from environment import IsDevServer
15 from host_file_system_provider import HostFileSystemProvider
16 from instance_servlet import InstanceServlet
17 from render_servlet import RenderServlet
18 from rietveld_patcher import RietveldPatcher, RietveldPatcherError
19 from object_store_creator import ObjectStoreCreator
20 from patched_file_system import PatchedFileSystem
21 from server_instance import ServerInstance
22 from servlet import Request, Response, Servlet
23 import svn_constants
24 import url_constants
25
26 class _PatchServletDelegate(RenderServlet.Delegate):
27   def __init__(self, issue, delegate):
28     self._issue = issue
29     self._delegate = delegate
30
31   def CreateServerInstance(self):
32     # start_empty=False because a patch can rely on files that are already in
33     # SVN repository but not yet pulled into data store by cron jobs (a typical
34     # example is to add documentation for an existing API).
35     object_store_creator = ObjectStoreCreator(start_empty=False)
36
37     unpatched_file_system = self._delegate.CreateHostFileSystemProvider(
38         object_store_creator).GetTrunk()
39
40     rietveld_patcher = CachingRietveldPatcher(
41         RietveldPatcher(svn_constants.EXTENSIONS_PATH,
42                         self._issue,
43                         AppEngineUrlFetcher(url_constants.CODEREVIEW_SERVER)),
44         object_store_creator)
45
46     patched_file_system = PatchedFileSystem(unpatched_file_system,
47                                             rietveld_patcher)
48
49     patched_host_file_system_provider = (
50         self._delegate.CreateHostFileSystemProvider(
51             object_store_creator,
52             # The patched file system needs to be online otherwise it'd be
53             # impossible to add files in the patches.
54             offline=False,
55             # The trunk file system for this creator should be the patched one.
56             default_trunk_instance=patched_file_system))
57
58     combined_compiled_fs_factory = ChainedCompiledFileSystem.Factory(
59         [unpatched_file_system], object_store_creator)
60
61     branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
62
63     return ServerInstance(object_store_creator,
64                           combined_compiled_fs_factory,
65                           branch_utility,
66                           patched_host_file_system_provider,
67                           self._delegate.CreateGithubFileSystemProvider(
68                               object_store_creator),
69                           base_path='/_patch/%s/' % self._issue)
70
71 class PatchServlet(Servlet):
72   '''Servlet which renders patched docs.
73   '''
74   def __init__(self, request, delegate=None):
75     self._request = request
76     self._delegate = delegate or InstanceServlet.Delegate()
77
78   def Get(self):
79     if (not IsDevServer() and
80         not fnmatch(urlparse(self._request.host).netloc, '*.appspot.com')):
81       # Only allow patches on appspot URLs; it doesn't matter if appspot.com is
82       # XSS'ed, but it matters for chrome.com.
83       redirect_host = 'https://chrome-apps-doc.appspot.com'
84       logging.info('Redirecting from XSS-able host %s to %s' % (
85           self._request.host, redirect_host))
86       return Response.Redirect(
87           '%s/_patch/%s' % (redirect_host, self._request.path))
88
89     path_with_issue = self._request.path.lstrip('/')
90     if '/' in path_with_issue:
91       issue, path_without_issue = path_with_issue.split('/', 1)
92     else:
93       return Response.NotFound('Malformed URL. It should look like ' +
94           'https://developer.chrome.com/_patch/12345/extensions/...')
95
96     try:
97       response = RenderServlet(
98           Request(path_without_issue,
99                   self._request.host,
100                   self._request.headers),
101           _PatchServletDelegate(issue, self._delegate)).Get()
102       # Disable cache for patched content.
103       response.headers.pop('cache-control', None)
104     except RietveldPatcherError as e:
105       response = Response.NotFound(e.message, {'Content-Type': 'text/plain'})
106
107     redirect_url, permanent = response.GetRedirect()
108     if redirect_url is not None:
109       response = Response.Redirect('/_patch/%s%s' % (issue, redirect_url),
110                                    permanent)
111     return response