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

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

Issue 14273035: Docserver: refactor the Handler/ServerInstance relationship into a servlet (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 7 months 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
(Empty)
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 import mimetypes
8 import os
9 import traceback
10
11 from appengine_wrappers import IsDevServer
12 from branch_utility import BranchUtility
13 from file_system import FileNotFoundError
14 from server_instance import ServerInstance
15 from servlet import Servlet
16 import svn_constants
17
18 _DEFAULT_CHANNEL = 'stable'
19
20 _ALWAYS_ONLINE = IsDevServer()
21
22 def _IsBinaryMimetype(mimetype):
23 return any(mimetype.startswith(prefix)
24 for prefix in ['audio', 'image', 'video'])
25
26 def AlwaysOnline(fn):
27 '''A function decorator which forces the rendering to be always online rather
28 than the default offline behaviour. Useful for testing.
29 '''
30 def impl(*args, **optargs):
31 global _ALWAYS_ONLINE
32 was_always_online = _ALWAYS_ONLINE
33 try:
34 _ALWAYS_ONLINE = True
35 return fn(*args, **optargs)
36 finally:
37 _ALWAYS_ONLINE = was_always_online
38 return impl
39
40 class RenderServlet(Servlet):
41 '''Servlet which renders templates.
42 '''
43 def Get(self, server_instance=None):
44 path, request, response = (self._path, self._request, self._response)
45
46 # Redirect "extensions" and "extensions/" to "extensions/index.html", etc.
47 if os.path.splitext(path)[1] == '' and path.find('/') == -1:
48 path += '/'
49 if path.endswith('/'):
50 self.Redirect(path + 'index.html')
51 return
52
53 channel_name, real_path = BranchUtility.SplitChannelNameFromPath(path)
54
55 if channel_name == _DEFAULT_CHANNEL:
56 self.Redirect('/%s' % real_path)
57 return
58
59 if channel_name is None:
60 channel_name = _DEFAULT_CHANNEL
61
62 # AppEngine instances should never need to call out to SVN. That should
63 # only ever be done by the cronjobs, which then write the result into
64 # DataStore, which is as far as instances look. To enable this, crons can
65 # pass a custom (presumably online) ServerInstance into Get().
66 #
67 # Why? SVN is slow and a bit flaky. Cronjobs failing is annoying but
68 # temporary. Instances failing affects users, and is really bad.
69 #
70 # Anyway - to enforce this, we actually don't give instances access to SVN.
71 # If anything is missing from datastore, it'll be a 404. If the cronjobs
72 # don't manage to catch everything - uhoh. On the other hand, we'll figure
73 # it out pretty soon, and it also means that legitimate 404s are caught
74 # before a round trip to SVN.
75 if not server_instance:
76 # The ALWAYS_ONLINE thing is for tests and preview.py that shouldn't need
77 # to run the cron before rendering things.
78 constructor = (ServerInstance.CreateOnline if _ALWAYS_ONLINE else
79 ServerInstance.GetOrCreateOffline)
80 server_instance = constructor(channel_name)
81
82 canonical_path = server_instance.path_canonicalizer.Canonicalize(real_path)
83 if real_path != canonical_path:
84 if channel_name is None:
85 self.Redirect(canonical_path);
86 else:
87 self.Redirect('%s/%s' % (channel_name, canonical_path))
88 return
89
90 templates = server_instance.template_data_source_factory.Create(request,
方觉(Fang Jue) 2013/04/29 12:14:15 These code (and below) will also be shared by Patc
not at google - send to devlin 2013/04/29 16:09:13 As they say, composition over inheritance - compos
91 path)
92
93 content = None
94 try:
95 if fnmatch(path, 'extensions/examples/*.zip'):
96 content = server_instance.example_zipper.Create(
97 path[len('extensions/'):-len('.zip')])
98 response.headers['content-type'] = 'application/zip'
99 elif path.startswith('extensions/examples/'):
100 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
101 content = server_instance.content_cache.GetFromFile(
102 '%s/%s' % (svn_constants.DOCS_PATH, path[len('extensions/'):]),
103 binary=_IsBinaryMimetype(mimetype))
104 response.headers['content-type'] = 'text/plain'
105 elif path.startswith('static/'):
106 mimetype = mimetypes.guess_type(path)[0] or 'text/plain'
107 content = server_instance.content_cache.GetFromFile(
108 ('%s/%s' % (svn_constants.DOCS_PATH, path)),
109 binary=_IsBinaryMimetype(mimetype))
110 response.headers['content-type'] = mimetype
111 elif path.endswith('.html'):
112 content = templates.Render(path)
113 except FileNotFoundError as e:
114 logging.warning(traceback.format_exc())
115 content = None
116
117 response.headers['x-frame-options'] = 'sameorigin'
118 if content is None:
119 response.set_status(404);
120 response.out.write(templates.Render('404'))
121 else:
122 if not content:
123 logging.error('%s had empty content' % path)
124 response.headers['cache-control'] = 'max-age=300'
125 response.out.write(content)
OLDNEW
« no previous file with comments | « chrome/common/extensions/docs/server2/preview.py ('k') | chrome/common/extensions/docs/server2/server_instance.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698