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