Browse Source

Ensure external urls are encoded properly. (Issue #158).

-   BREAKING:  While this change will correct the weird encoding
    behavior, this also changes the way `xxx_url` macros work.
-   Do not encode the url bases (`base_url`, `media_url`). Only
    the path component needs to be encoded.
main
Lakshmi Vyasarajan 11 years ago
parent
commit
2480012b3d
6 changed files with 53 additions and 32 deletions
  1. +13
    -3
      CHANGELOG.rst
  2. +1
    -1
      README.rst
  3. +19
    -21
      hyde/site.py
  4. +3
    -2
      hyde/tests/ext/test_textlinks.py
  5. +16
    -4
      hyde/tests/test_site.py
  6. +1
    -1
      hyde/version.py

+ 13
- 3
CHANGELOG.rst View File

@@ -1,11 +1,21 @@
Version 0.8.7a9
============================================================

* Ensure external urls are encoded properly. (Issue #158).

- BREAKING: While this change will correct the weird encoding
behavior, this also changes the way `xxx_url` macros work.
- Do not encode the url bases (`base_url`, `media_url`). Only
the path component needs to be encoded.

Version 0.8.7a8 Version 0.8.7a8
============================================================ ============================================================


* Fix subfolders for root paths on windows. (Issue #167). * Fix subfolders for root paths on windows. (Issue #167).


- Using subfolders for `layout_root`, `content_root`,
`media_root` and `deploy_root` now works reliably
on windows.
- Ensure that subfolders for `layout_root`, `content_root`,
`media_root` and `deploy_root` works reliably
on windows. Use `fully_expanded_path` for all path components.




Version 0.8.7a7 Version 0.8.7a7


+ 1
- 1
README.rst View File

@@ -1,4 +1,4 @@
Version 0.8.7a8
Version 0.8.7a9


A brand new **hyde** A brand new **hyde**
==================== ====================


+ 19
- 21
hyde/site.py View File

@@ -383,6 +383,13 @@ class RootNode(Node):
if dont_ignore(afile.name): if dont_ignore(afile.name):
self.add_resource(afile) self.add_resource(afile)



def _encode_path(base, path, safe):
base = base.strip().replace(os.sep, '/').encode('utf-8')
path = path.strip().replace(os.sep, '/').encode('utf-8')
path = quote(path, safe) if safe is not None else quote(path)
return base.rstrip('/') + '/' + path.lstrip('/')

class Site(object): class Site(object):
""" """
Represents the site to be generated. Represents the site to be generated.
@@ -425,35 +432,28 @@ class Site(object):
""" """
self.content.load() self.content.load()


def _safe_chars(self, safe=None):
if safe is not None:
return safe
elif self.config.encode_safe is not None:
return self.config.encode_safe
else:
return None

def content_url(self, path, safe=None): def content_url(self, path, safe=None):
""" """
Returns the content url by appending the base url from the config Returns the content url by appending the base url from the config
with the given path. The return value is url encoded. with the given path. The return value is url encoded.
""" """
fpath = Folder(self.config.base_url) \
.child(path) \
.replace(os.sep, '/').encode("utf-8")
if safe is not None:
return quote(fpath, safe)
elif self.config.encode_safe is not None:
return quote(fpath, self.config.encode_safe)
else:
return quote(fpath)
return _encode_path(self.config.base_url, path, self._safe_chars(safe))



def media_url(self, path, safe=None): def media_url(self, path, safe=None):
""" """
Returns the media url by appending the media base url from the config Returns the media url by appending the media base url from the config
with the given path. The return value is url encoded. with the given path. The return value is url encoded.
""" """
fpath = Folder(self.config.media_url) \
.child(path) \
.replace(os.sep, '/').encode("utf-8")
if safe is not None:
return quote(fpath, safe)
elif self.config.encode_safe is not None:
return quote(fpath, self.config.encode_safe)
else:
return quote(fpath)
return _encode_path(self.config.media_url, path, self._safe_chars(safe))


def full_url(self, path, safe=None): def full_url(self, path, safe=None):
""" """
@@ -461,11 +461,9 @@ class Site(object):
configuration and returns the appropriate url. The return value configuration and returns the appropriate url. The return value
is url encoded. is url encoded.
""" """
if safe is None and self.config.encode_safe is not None:
safe = self.config.encode_safe
if urlparse.urlparse(path)[:2] != ("",""): if urlparse.urlparse(path)[:2] != ("",""):
return path return path

if self.is_media(path): if self.is_media(path):
relative_path = File(path).get_relative_path( relative_path = File(path).get_relative_path(
Folder(self.config.media_root)) Folder(self.config.media_root))


+ 3
- 2
hyde/tests/ext/test_textlinks.py View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
""" """
Use nose Use nose
`$ pip install nose` `$ pip install nose`
@@ -49,6 +48,7 @@ class TestTextlinks(object):
site.config.media_url = '/media' site.config.media_url = '/media'
tlink = File(site.content.source_folder.child('tlink.html')) tlink = File(site.content.source_folder.child('tlink.html'))
tlink.write(text % d) tlink.write(text % d)
print tlink.read_all()
gen = Generator(site) gen = Generator(site)
gen.generate_all() gen.generate_all()
f = File(site.config.deploy_root_path.child(tlink.name)) f = File(site.config.deploy_root_path.child(tlink.name))
@@ -56,5 +56,6 @@ class TestTextlinks(object):
html = f.read_all() html = f.read_all()
assert html assert html
for name, path in d.items(): for name, path in d.items():
assert quote(site.config.base_url + path) in html

assert site.config.base_url + quote(path) in html
assert '/media/img/hyde-logo.png' in html assert '/media/img/hyde-logo.png' in html

+ 16
- 4
hyde/tests/test_site.py View File

@@ -60,9 +60,19 @@ def test_node_full_url():
r = RootNode(TEST_SITE_ROOT.child_folder('content'), s) r = RootNode(TEST_SITE_ROOT.child_folder('content'), s)
assert not r.module assert not r.module
n = r.add_node(TEST_SITE_ROOT.child_folder('content/blog')) n = r.add_node(TEST_SITE_ROOT.child_folder('content/blog'))
assert n.full_url == quote('http://localhost/blog')
assert n.full_url == 'http://localhost/blog'
c = r.add_node(TEST_SITE_ROOT.child_folder('content/blog/2010/december')) c = r.add_node(TEST_SITE_ROOT.child_folder('content/blog/2010/december'))
assert c.full_url == quote('http://localhost/blog/2010/december')
assert c.full_url == 'http://localhost/blog/2010/december'

def test_node_full_url_quoted():
s = Site(TEST_SITE_ROOT)
s.config.base_url = 'http://localhost'
r = RootNode(TEST_SITE_ROOT.child_folder('content'), s)
assert not r.module
n = r.add_node(TEST_SITE_ROOT.child_folder('content/blo~g'))
assert n.full_url == 'http://localhost/' + quote('blo~g')
c = r.add_node(TEST_SITE_ROOT.child_folder('content/blo~g/2010/december'))
assert c.full_url == 'http://localhost/' + quote('blo~g/2010/december')


def test_node_relative_path(): def test_node_relative_path():
s = Site(TEST_SITE_ROOT) s = Site(TEST_SITE_ROOT)
@@ -200,13 +210,15 @@ class TestSiteWithConfig(object):
s = Site(self.SITE_PATH, config=self.config) s = Site(self.SITE_PATH, config=self.config)
s.load() s.load()
path = '".jpg' path = '".jpg'
assert s.content_url(path) == quote("/" + path)
assert s.content_url(path) == "/" + quote(path)


def test_content_url_encoding_safe(self): def test_content_url_encoding_safe(self):
s = Site(self.SITE_PATH, config=self.config) s = Site(self.SITE_PATH, config=self.config)
s.load() s.load()
path = '".jpg/abc' path = '".jpg/abc'
assert s.content_url(path, "") == quote("/" + path, "")
print s.content_url(path, "")
print "/" + quote(path, "")
assert s.content_url(path, "") == "/" + quote(path, "")


def test_media_url(self): def test_media_url(self):
s = Site(self.SITE_PATH, config=self.config) s = Site(self.SITE_PATH, config=self.config)


+ 1
- 1
hyde/version.py View File

@@ -2,4 +2,4 @@
""" """
Handles hyde version. Handles hyde version.
""" """
__version__ = '0.8.7a8'
__version__ = '0.8.7a9'

Loading…
Cancel
Save