summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions/docs/server2/patch_servlet.py
blob: 8207e1d0d4f4414487b6fb8b039ddec7098505f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from fnmatch import fnmatch
import logging
from urlparse import urlparse

from appengine_url_fetcher import AppEngineUrlFetcher
from appengine_wrappers import IsDevServer
from caching_file_system import CachingFileSystem
from caching_rietveld_patcher import CachingRietveldPatcher
from chained_compiled_file_system import ChainedCompiledFileSystem
from compiled_file_system import  CompiledFileSystem
from host_file_system_creator import HostFileSystemCreator
from instance_servlet import InstanceServlet
from render_servlet import RenderServlet
from rietveld_patcher import RietveldPatcher, RietveldPatcherError
from object_store_creator import ObjectStoreCreator
from patched_file_system import PatchedFileSystem
from server_instance import ServerInstance
from servlet import Request, Response, Servlet
import svn_constants
import url_constants

class _PatchServletDelegate(RenderServlet.Delegate):
  def __init__(self, issue, delegate):
    self._issue = issue
    self._delegate = delegate

  def CreateServerInstance(self):
    object_store_creator = ObjectStoreCreator(start_empty=False)
    branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
    host_file_system_creator = self._delegate.CreateHostFileSystemCreator(
        object_store_creator)
    # TODO(fj): Use OfflineFileSystem here once all json/idl files in api/
    # are pulled into data store by cron jobs.
    base_file_system = CachingFileSystem(host_file_system_creator.Create(),
                                         object_store_creator)
    base_compiled_fs_factory = CompiledFileSystem.Factory(base_file_system,
                                                          object_store_creator)

    rietveld_patcher = CachingRietveldPatcher(
        RietveldPatcher(svn_constants.EXTENSIONS_PATH,
                        self._issue,
                        AppEngineUrlFetcher(url_constants.CODEREVIEW_SERVER)),
        object_store_creator)
    patched_file_system = PatchedFileSystem(base_file_system,
                                            rietveld_patcher)
    patched_compiled_fs_factory = CompiledFileSystem.Factory(
        patched_file_system, object_store_creator)

    compiled_fs_factory = ChainedCompiledFileSystem.Factory(
        [(patched_compiled_fs_factory, patched_file_system),
         (base_compiled_fs_factory, base_file_system)])

    return ServerInstance(object_store_creator,
                          patched_file_system,
                          self._delegate.CreateAppSamplesFileSystem(
                              object_store_creator),
                          '/_patch/%s' % self._issue,
                          compiled_fs_factory,
                          branch_utility,
                          host_file_system_creator)

class PatchServlet(Servlet):
  '''Servlet which renders patched docs.
  '''
  def __init__(self, request, delegate=None):
    self._request = request
    self._delegate = delegate or InstanceServlet.Delegate()

  def Get(self):
    if (not IsDevServer() and
        not fnmatch(urlparse(self._request.host).netloc, '*.appspot.com')):
      # Only allow patches on appspot URLs; it doesn't matter if appspot.com is
      # XSS'ed, but it matters for chrome.com.
      redirect_host = 'https://chrome-apps-doc.appspot.com'
      logging.info('Redirecting from XSS-able host %s to %s' % (
          self._request.host, redirect_host))
      return Response.Redirect(
          '%s/_patch/%s' % (redirect_host, self._request.path))

    path_with_issue = self._request.path.lstrip('/')
    if '/' in path_with_issue:
      issue, path_without_issue = path_with_issue.split('/', 1)
    else:
      return Response.NotFound('Malformed URL. It should look like ' +
          'https://developer.chrome.com/_patch/12345/extensions/...')

    try:
      response = RenderServlet(
          Request(path_without_issue,
                  self._request.host,
                  self._request.headers),
          _PatchServletDelegate(issue, self._delegate)).Get()
      # Disable cache for patched content.
      response.headers.pop('cache-control', None)
    except RietveldPatcherError as e:
      response = Response.NotFound(e.message, {'Content-Type': 'text/plain'})

    redirect_url, permanent = response.GetRedirect()
    if redirect_url is not None:
      response = Response.Redirect('/_patch/%s%s' % (issue, redirect_url),
                                   permanent)
    return response