Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: chrome/common/extensions/docs/server2/render_servlet.py

Issue 54603010: Docserver: Implement the content providers infrastructure, where a (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from fnmatch import fnmatch 5 from fnmatch import fnmatch
6 import logging 6 import logging
7 import mimetypes 7 import mimetypes
8 import posixpath
9 import traceback
8 from urlparse import urlsplit 10 from urlparse import urlsplit
9 11
10 from data_source_registry import CreateDataSources 12 from data_source_registry import CreateDataSources
11 from file_system import FileNotFoundError 13 from file_system import FileNotFoundError
14 from redirector import Redirector
12 from servlet import Servlet, Response 15 from servlet import Servlet, Response
13 from svn_constants import DOCS_PATH, PUBLIC_TEMPLATE_PATH 16 from svn_constants import DOCS_PATH, PUBLIC_TEMPLATE_PATH
17 from third_party.handlebar import Handlebar
14 18
15 def _IsBinaryMimetype(mimetype): 19
16 return any( 20 def _MakeHeaders(content_type):
17 mimetype.startswith(prefix) for prefix in ['audio', 'image', 'video']) 21 return {
22 'x-frame-options': 'sameorigin',
23 'content-type': content_type,
24 'cache-control': 'max-age=300',
25 }
26
18 27
19 class RenderServlet(Servlet): 28 class RenderServlet(Servlet):
20 '''Servlet which renders templates. 29 '''Servlet which renders templates.
21 ''' 30 '''
31
22 class Delegate(object): 32 class Delegate(object):
23 def CreateServerInstance(self): 33 def CreateServerInstance(self):
24 raise NotImplementedError(self.__class__) 34 raise NotImplementedError(self.__class__)
25 35
26 def __init__(self, request, delegate): 36 def __init__(self, request, delegate):
27 Servlet.__init__(self, request) 37 Servlet.__init__(self, request)
28 self._delegate = delegate 38 self._delegate = delegate
29 39
30 def Get(self): 40 def Get(self):
31 ''' Render the page for a request. 41 ''' Render the page for a request.
32 ''' 42 '''
33 # TODO(kalman): a consistent path syntax (even a Path class?) so that we 43 # TODO(kalman): a consistent path syntax (even a Path class?) so that we
34 # can stop being so conservative with stripping and adding back the '/'s. 44 # can stop being so conservative with stripping and adding back the '/'s.
35 path = self._request.path.lstrip('/') 45 path = self._request.path.lstrip('/')
36
37 if path.split('/')[-1] == 'redirects.json':
38 return Response.Ok('')
39
40 server_instance = self._delegate.CreateServerInstance() 46 server_instance = self._delegate.CreateServerInstance()
41 47
42 redirect = server_instance.redirector.Redirect(self._request.host, path) 48 try:
49 return self._GetSuccessResponse(path, server_instance)
50 except FileNotFoundError:
51 # Maybe it didn't find the file because its canonical location is
52 # somewhere else; this is distinct from "redirects", which are typically
53 # explicit. This is implicit.
54 canonical_result = server_instance.path_canonicalizer.Canonicalize(path)
55 redirect = canonical_result.path.lstrip('/')
56 if path != redirect:
57 return Response.Redirect('/' + redirect,
58 permanent=canonical_result.permanent)
59
60 # Not found for reals. Find the closest 404.html file and serve that;
61 # e.g. if the path is extensions/manifest/typo.html then first look for
62 # extensions/manifest/404.html, then extensions/404.html, then 404.html.
63 #
64 # Failing that just print 'Not Found' but that should preferrably never
65 # happen, because it would look really bad.
66 path_components = path.split('/')
67 for i in xrange(len(path_components) - 1, -1, -1):
68 try:
69 path_404 = posixpath.join(*(path_components[0:i] + ['404.html']))
70 response = self._GetSuccessResponse(path_404, server_instance)
71 return Response.NotFound(response.content.ToString(),
72 headers=response.headers)
73 except FileNotFoundError: continue
74 logging.error('No 404.html found in %s' % path)
75 return Response.NotFound('Not Found', headers=_MakeHeaders('text/plain'))
76
77 def _GetSuccessResponse(self, path, server_instance):
78 '''Returns the Response from trying to render |path| with
79 |server_instance|. If |path| isn't found then a FileNotFoundError will be
80 raised, such that the only responses that will be returned from this method
81 are Ok and Redirect.
82 '''
83 content_provider, path = (
84 server_instance.content_providers.GetByServeFrom(path))
85 assert content_provider, 'No ContentProvider found for %s' % path
86
87 redirect = Redirector(
88 server_instance.compiled_fs_factory,
89 content_provider.file_system).Redirect(self._request.host, path)
43 if redirect is not None: 90 if redirect is not None:
44 return Response.Redirect(redirect) 91 return Response.Redirect(redirect, permanent=False)
45 92
46 canonical_result = server_instance.path_canonicalizer.Canonicalize(path) 93 content_and_type = content_provider.GetContentAndType(
47 redirect = canonical_result.path.lstrip('/') 94 self._request.host, path).Get()
48 if path != redirect: 95 if not content_and_type.content:
49 return Response.Redirect('/' + redirect,
50 permanent=canonical_result.permanent)
51
52 trunk_fs = server_instance.host_file_system_provider.GetTrunk()
53 template_renderer = server_instance.template_renderer
54 template_cache = server_instance.compiled_fs_factory.ForTemplates(trunk_fs)
55
56 content = None
57 content_type = None
58
59 try:
60 # At this point, any valid paths ending with '/' have been redirected.
61 # Therefore, the response should be a 404 Not Found.
62 if path.endswith('/'):
63 pass
64 elif fnmatch(path, 'extensions/examples/*.zip'):
65 zip_path = DOCS_PATH + path[len('extensions'):-len('.zip')]
66 content = server_instance.directory_zipper.Zip(zip_path).Get()
67 content_type = 'application/zip'
68 elif path.startswith('extensions/examples/'):
69 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
70 content = trunk_fs.ReadSingle(
71 '%s/%s' % (DOCS_PATH, path[len('extensions/'):]),
72 binary=_IsBinaryMimetype(mimetype)).Get()
73 content_type = mimetype
74 elif path.startswith('static/'):
75 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
76 content = trunk_fs.ReadSingle(
77 '%s/%s' % (DOCS_PATH, path),
78 binary=_IsBinaryMimetype(mimetype)).Get()
79 content_type = mimetype
80 elif path.endswith('.html'):
81 content = template_renderer.Render(
82 template_cache.GetFromFile(
83 '%s/%s' % (PUBLIC_TEMPLATE_PATH, path)).Get(),
84 self._request)
85 content_type = 'text/html'
86 else:
87 content = None
88 except FileNotFoundError:
89 content = None
90
91 headers = {'x-frame-options': 'sameorigin'}
92 if content is None:
93 def render_template_or_none(path):
94 try:
95 return template_renderer.Render(
96 template_cache.GetFromFile(
97 '%s/%s' % (PUBLIC_TEMPLATE_PATH, path)).Get(),
98 self._request)
99 except FileNotFoundError:
100 return None
101 content = (render_template_or_none('%s/404.html' %
102 path.split('/', 1)[0]) or
103 render_template_or_none('extensions/404.html') or
104 'Not found')
105 return Response.NotFound(content, headers=headers)
106
107 if not content:
108 logging.error('%s had empty content' % path) 96 logging.error('%s had empty content' % path)
109 97
110 headers.update({ 98 if isinstance(content_and_type.content, Handlebar):
111 'content-type': content_type, 99 content_and_type.content = server_instance.template_renderer.Render(
112 'cache-control': 'max-age=300', 100 content_and_type.content, self._request)
113 }) 101
114 return Response.Ok(content, headers=headers) 102 return Response.Ok(content_and_type.content,
103 headers=_MakeHeaders(content_and_type.content_type))
OLDNEW
« no previous file with comments | « chrome/common/extensions/docs/server2/redirector_test.py ('k') | chrome/common/extensions/docs/server2/render_servlet_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698