| OLD | NEW |
| 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 import logging | 5 import logging |
| 6 import mimetypes | 6 import mimetypes |
| 7 import posixpath | 7 import posixpath |
| 8 import traceback | 8 import traceback |
| 9 | 9 |
| 10 from compiled_file_system import SingleFile | 10 from compiled_file_system import SingleFile |
| 11 from directory_zipper import DirectoryZipper | 11 from directory_zipper import DirectoryZipper |
| 12 from docs_server_utils import ToUnicode | 12 from docs_server_utils import ToUnicode |
| 13 from file_system import FileNotFoundError | 13 from file_system import FileNotFoundError |
| 14 from future import All, Future | 14 from future import All, Future |
| 15 from path_canonicalizer import PathCanonicalizer | 15 from path_canonicalizer import PathCanonicalizer |
| 16 from path_util import AssertIsValid, IsDirectory, Join, ToDirectory | 16 from path_util import AssertIsValid, IsDirectory, Join, ToDirectory |
| 17 from special_paths import SITE_VERIFICATION_FILE | 17 from special_paths import SITE_VERIFICATION_FILE |
| 18 from third_party.handlebar import Handlebar | |
| 19 from third_party.markdown import markdown | 18 from third_party.markdown import markdown |
| 19 from third_party.motemplate import Motemplate |
| 20 | 20 |
| 21 | 21 |
| 22 _MIMETYPE_OVERRIDES = { | 22 _MIMETYPE_OVERRIDES = { |
| 23 # SVG is not supported by mimetypes.guess_type on AppEngine. | 23 # SVG is not supported by mimetypes.guess_type on AppEngine. |
| 24 '.svg': 'image/svg+xml', | 24 '.svg': 'image/svg+xml', |
| 25 } | 25 } |
| 26 | 26 |
| 27 | 27 |
| 28 class ContentAndType(object): | 28 class ContentAndType(object): |
| 29 '''Return value from ContentProvider.GetContentAndType. | 29 '''Return value from ContentProvider.GetContentAndType. |
| 30 ''' | 30 ''' |
| 31 | 31 |
| 32 def __init__(self, content, content_type, version): | 32 def __init__(self, content, content_type, version): |
| 33 self.content = content | 33 self.content = content |
| 34 self.content_type = content_type | 34 self.content_type = content_type |
| 35 self.version = version | 35 self.version = version |
| 36 | 36 |
| 37 | 37 |
| 38 class ContentProvider(object): | 38 class ContentProvider(object): |
| 39 '''Returns file contents correctly typed for their content-types (in the HTTP | 39 '''Returns file contents correctly typed for their content-types (in the HTTP |
| 40 sense). Content-type is determined from Python's mimetype library which | 40 sense). Content-type is determined from Python's mimetype library which |
| 41 guesses based on the file extension. | 41 guesses based on the file extension. |
| 42 | 42 |
| 43 Typically the file contents will be either str (for binary content) or | 43 Typically the file contents will be either str (for binary content) or |
| 44 unicode (for text content). However, HTML files *may* be returned as | 44 unicode (for text content). However, HTML files *may* be returned as |
| 45 Handlebar templates (if |supports_templates| is True on construction), in | 45 Motemplate templates (if |supports_templates| is True on construction), in |
| 46 which case the caller will presumably want to Render them. | 46 which case the caller will presumably want to Render them. |
| 47 | 47 |
| 48 Zip file are automatically created and returned for .zip file extensions if | 48 Zip file are automatically created and returned for .zip file extensions if |
| 49 |supports_zip| is True. | 49 |supports_zip| is True. |
| 50 | 50 |
| 51 |default_extensions| is a list of file extensions which are queried when no | 51 |default_extensions| is a list of file extensions which are queried when no |
| 52 file extension is given to GetCanonicalPath/GetContentAndType. Typically | 52 file extension is given to GetCanonicalPath/GetContentAndType. Typically |
| 53 this will include .html. | 53 this will include .html. |
| 54 ''' | 54 ''' |
| 55 | 55 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 82 def _CompileContent(self, path, text): | 82 def _CompileContent(self, path, text): |
| 83 assert text is not None, path | 83 assert text is not None, path |
| 84 _, ext = posixpath.splitext(path) | 84 _, ext = posixpath.splitext(path) |
| 85 mimetype = _MIMETYPE_OVERRIDES.get(ext, mimetypes.guess_type(path)[0]) | 85 mimetype = _MIMETYPE_OVERRIDES.get(ext, mimetypes.guess_type(path)[0]) |
| 86 if ext == '.md': | 86 if ext == '.md': |
| 87 # See http://pythonhosted.org/Markdown/extensions | 87 # See http://pythonhosted.org/Markdown/extensions |
| 88 # for details on "extensions=". | 88 # for details on "extensions=". |
| 89 content = markdown(ToUnicode(text), | 89 content = markdown(ToUnicode(text), |
| 90 extensions=('extra', 'headerid', 'sane_lists')) | 90 extensions=('extra', 'headerid', 'sane_lists')) |
| 91 if self._supports_templates: | 91 if self._supports_templates: |
| 92 content = Handlebar(content, name=path) | 92 content = Motemplate(content, name=path) |
| 93 mimetype = 'text/html' | 93 mimetype = 'text/html' |
| 94 elif mimetype is None: | 94 elif mimetype is None: |
| 95 content = text | 95 content = text |
| 96 mimetype = 'text/plain' | 96 mimetype = 'text/plain' |
| 97 elif mimetype == 'text/html': | 97 elif mimetype == 'text/html': |
| 98 content = ToUnicode(text) | 98 content = ToUnicode(text) |
| 99 if self._supports_templates: | 99 if self._supports_templates: |
| 100 content = Handlebar(content, name=path) | 100 content = Motemplate(content, name=path) |
| 101 elif (mimetype.startswith('text/') or | 101 elif (mimetype.startswith('text/') or |
| 102 mimetype in ('application/javascript', 'application/json')): | 102 mimetype in ('application/javascript', 'application/json')): |
| 103 content = ToUnicode(text) | 103 content = ToUnicode(text) |
| 104 else: | 104 else: |
| 105 content = text | 105 content = text |
| 106 return ContentAndType(content, | 106 return ContentAndType(content, |
| 107 mimetype, | 107 mimetype, |
| 108 self.file_system.Stat(path).version) | 108 self.file_system.Stat(path).version) |
| 109 | 109 |
| 110 def GetCanonicalPath(self, path): | 110 def GetCanonicalPath(self, path): |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 futures.append(self.GetContentAndType(Join(root, f))) | 203 futures.append(self.GetContentAndType(Join(root, f))) |
| 204 # Also cache the extension-less version of the file if needed. | 204 # Also cache the extension-less version of the file if needed. |
| 205 base, ext = posixpath.splitext(f) | 205 base, ext = posixpath.splitext(f) |
| 206 if f != SITE_VERIFICATION_FILE and ext in self._default_extensions: | 206 if f != SITE_VERIFICATION_FILE and ext in self._default_extensions: |
| 207 futures.append(self.GetContentAndType(Join(root, base))) | 207 futures.append(self.GetContentAndType(Join(root, base))) |
| 208 # TODO(kalman): Cache .zip files for each directory (if supported). | 208 # TODO(kalman): Cache .zip files for each directory (if supported). |
| 209 return All(futures, except_pass=Exception, except_pass_log=True) | 209 return All(futures, except_pass=Exception, except_pass_log=True) |
| 210 | 210 |
| 211 def __repr__(self): | 211 def __repr__(self): |
| 212 return 'ContentProvider of <%s>' % repr(self.file_system) | 212 return 'ContentProvider of <%s>' % repr(self.file_system) |
| OLD | NEW |