| Index: chrome/common/extensions/docs/server2/render_servlet.py
|
| diff --git a/chrome/common/extensions/docs/server2/render_servlet.py b/chrome/common/extensions/docs/server2/render_servlet.py
|
| index 25b6d3ded6c869c0d5778e87beb888d559412c24..093f64d808a589c1b74eea78a56290b38df6e5f3 100644
|
| --- a/chrome/common/extensions/docs/server2/render_servlet.py
|
| +++ b/chrome/common/extensions/docs/server2/render_servlet.py
|
| @@ -5,20 +5,30 @@
|
| from fnmatch import fnmatch
|
| import logging
|
| import mimetypes
|
| +import posixpath
|
| +import traceback
|
| from urlparse import urlsplit
|
|
|
| from data_source_registry import CreateDataSources
|
| from file_system import FileNotFoundError
|
| +from redirector import Redirector
|
| from servlet import Servlet, Response
|
| from svn_constants import DOCS_PATH, PUBLIC_TEMPLATE_PATH
|
| +from third_party.handlebar import Handlebar
|
| +
|
| +
|
| +def _MakeHeaders(content_type):
|
| + return {
|
| + 'x-frame-options': 'sameorigin',
|
| + 'content-type': content_type,
|
| + 'cache-control': 'max-age=300',
|
| + }
|
|
|
| -def _IsBinaryMimetype(mimetype):
|
| - return any(
|
| - mimetype.startswith(prefix) for prefix in ['audio', 'image', 'video'])
|
|
|
| class RenderServlet(Servlet):
|
| '''Servlet which renders templates.
|
| '''
|
| +
|
| class Delegate(object):
|
| def CreateServerInstance(self):
|
| raise NotImplementedError(self.__class__)
|
| @@ -33,82 +43,61 @@ class RenderServlet(Servlet):
|
| # TODO(kalman): a consistent path syntax (even a Path class?) so that we
|
| # can stop being so conservative with stripping and adding back the '/'s.
|
| path = self._request.path.lstrip('/')
|
| -
|
| - if path.split('/')[-1] == 'redirects.json':
|
| - return Response.Ok('')
|
| -
|
| server_instance = self._delegate.CreateServerInstance()
|
|
|
| - redirect = server_instance.redirector.Redirect(self._request.host, path)
|
| - if redirect is not None:
|
| - return Response.Redirect(redirect)
|
| -
|
| - canonical_result = server_instance.path_canonicalizer.Canonicalize(path)
|
| - redirect = canonical_result.path.lstrip('/')
|
| - if path != redirect:
|
| - return Response.Redirect('/' + redirect,
|
| - permanent=canonical_result.permanent)
|
| -
|
| - trunk_fs = server_instance.host_file_system_provider.GetTrunk()
|
| - template_renderer = server_instance.template_renderer
|
| - template_cache = server_instance.compiled_fs_factory.ForTemplates(trunk_fs)
|
| -
|
| - content = None
|
| - content_type = None
|
| -
|
| try:
|
| - # At this point, any valid paths ending with '/' have been redirected.
|
| - # Therefore, the response should be a 404 Not Found.
|
| - if path.endswith('/'):
|
| - pass
|
| - elif fnmatch(path, 'extensions/examples/*.zip'):
|
| - zip_path = DOCS_PATH + path[len('extensions'):-len('.zip')]
|
| - content = server_instance.directory_zipper.Zip(zip_path).Get()
|
| - content_type = 'application/zip'
|
| - elif path.startswith('extensions/examples/'):
|
| - mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
|
| - content = trunk_fs.ReadSingle(
|
| - '%s/%s' % (DOCS_PATH, path[len('extensions/'):]),
|
| - binary=_IsBinaryMimetype(mimetype)).Get()
|
| - content_type = mimetype
|
| - elif path.startswith('static/'):
|
| - mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
|
| - content = trunk_fs.ReadSingle(
|
| - '%s/%s' % (DOCS_PATH, path),
|
| - binary=_IsBinaryMimetype(mimetype)).Get()
|
| - content_type = mimetype
|
| - elif path.endswith('.html'):
|
| - content = template_renderer.Render(
|
| - template_cache.GetFromFile(
|
| - '%s/%s' % (PUBLIC_TEMPLATE_PATH, path)).Get(),
|
| - self._request)
|
| - content_type = 'text/html'
|
| - else:
|
| - content = None
|
| + return self._GetSuccessResponse(path, server_instance)
|
| except FileNotFoundError:
|
| - content = None
|
| -
|
| - headers = {'x-frame-options': 'sameorigin'}
|
| - if content is None:
|
| - def render_template_or_none(path):
|
| + # Maybe it didn't find the file because its canonical location is
|
| + # somewhere else; this is distinct from "redirects", which are typically
|
| + # explicit. This is implicit.
|
| + canonical_result = server_instance.path_canonicalizer.Canonicalize(path)
|
| + redirect = canonical_result.path.lstrip('/')
|
| + if path != redirect:
|
| + return Response.Redirect('/' + redirect,
|
| + permanent=canonical_result.permanent)
|
| +
|
| + # Not found for reals. Find the closest 404.html file and serve that;
|
| + # e.g. if the path is extensions/manifest/typo.html then first look for
|
| + # extensions/manifest/404.html, then extensions/404.html, then 404.html.
|
| + #
|
| + # Failing that just print 'Not Found' but that should preferrably never
|
| + # happen, because it would look really bad.
|
| + path_components = path.split('/')
|
| + for i in xrange(len(path_components) - 1, -1, -1):
|
| try:
|
| - return template_renderer.Render(
|
| - template_cache.GetFromFile(
|
| - '%s/%s' % (PUBLIC_TEMPLATE_PATH, path)).Get(),
|
| - self._request)
|
| - except FileNotFoundError:
|
| - return None
|
| - content = (render_template_or_none('%s/404.html' %
|
| - path.split('/', 1)[0]) or
|
| - render_template_or_none('extensions/404.html') or
|
| - 'Not found')
|
| - return Response.NotFound(content, headers=headers)
|
| -
|
| - if not content:
|
| + path_404 = posixpath.join(*(path_components[0:i] + ['404.html']))
|
| + response = self._GetSuccessResponse(path_404, server_instance)
|
| + return Response.NotFound(response.content.ToString(),
|
| + headers=response.headers)
|
| + except FileNotFoundError: continue
|
| + logging.error('No 404.html found in %s' % path)
|
| + return Response.NotFound('Not Found', headers=_MakeHeaders('text/plain'))
|
| +
|
| + def _GetSuccessResponse(self, path, server_instance):
|
| + '''Returns the Response from trying to render |path| with
|
| + |server_instance|. If |path| isn't found then a FileNotFoundError will be
|
| + raised, such that the only responses that will be returned from this method
|
| + are Ok and Redirect.
|
| + '''
|
| + content_provider, path = (
|
| + server_instance.content_providers.GetByServlet(path))
|
| + assert content_provider, 'No ContentProvider found for %s' % path
|
| +
|
| + redirect = Redirector(
|
| + server_instance.compiled_fs_factory,
|
| + content_provider.file_system).Redirect(self._request.host, path)
|
| + if redirect is not None:
|
| + return Response.Redirect(redirect, permanent=False)
|
| +
|
| + content_info = content_provider.GetContentInfo(
|
| + self._request.host, path).Get()
|
| + if not content_info.content:
|
| logging.error('%s had empty content' % path)
|
|
|
| - headers.update({
|
| - 'content-type': content_type,
|
| - 'cache-control': 'max-age=300',
|
| - })
|
| - return Response.Ok(content, headers=headers)
|
| + if isinstance(content_info.content, Handlebar):
|
| + content_info.content = server_instance.template_renderer.Render(
|
| + content_info.content, self._request)
|
| +
|
| + return Response.Ok(content_info.content,
|
| + headers=_MakeHeaders(content_info.content_type))
|
|
|