Home | History | Annotate | Download | only in server2
      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
    117