| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
import os |
|---|
| 25 |
import urllib |
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
import tools |
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
sep = "/" |
|---|
| 33 |
|
|---|
| 34 |
class NotUnderRoot(Exception): |
|---|
| 35 |
pass |
|---|
| 36 |
|
|---|
| 37 |
def _is_file_system_root(path): |
|---|
| 38 |
r""" |
|---|
| 39 |
Return `True` if `path` is a file system root directory, else |
|---|
| 40 |
`False`. |
|---|
| 41 |
|
|---|
| 42 |
Under Posix, the file system root directory is "/", under |
|---|
| 43 |
Windows, it's r"x:\", where x is any drive letter. |
|---|
| 44 |
""" |
|---|
| 45 |
path = tools.normalize_path(path) |
|---|
| 46 |
drive, rest = os.path.splitdrive(path) |
|---|
| 47 |
return rest == os.sep |
|---|
| 48 |
|
|---|
| 49 |
def is_safe_path(root, path): |
|---|
| 50 |
""" |
|---|
| 51 |
Return `True` if the `path` is a subdirectory of or a file |
|---|
| 52 |
under the document root directory `root`, else return `False`. |
|---|
| 53 |
""" |
|---|
| 54 |
root = tools.normalize_path(root) |
|---|
| 55 |
path = tools.normalize_path(path) |
|---|
| 56 |
if root == path: |
|---|
| 57 |
return True |
|---|
| 58 |
if _is_file_system_root(root): |
|---|
| 59 |
return path.startswith(root) |
|---|
| 60 |
else: |
|---|
| 61 |
return path.startswith(root + os.sep) |
|---|
| 62 |
|
|---|
| 63 |
def to_url(root, path): |
|---|
| 64 |
r""" |
|---|
| 65 |
Return an absolute URL (starting with a slash, without host and |
|---|
| 66 |
port part) which is derived from the absolute file system path |
|---|
| 67 |
`path`. The argument `root` is the document root (a file system |
|---|
| 68 |
path) to take into account. |
|---|
| 69 |
|
|---|
| 70 |
Trailing path separators on the `root` or `path` are ignored. |
|---|
| 71 |
|
|---|
| 72 |
If the `path` isn't part of the `root`, raise a `NotUnderRoot` |
|---|
| 73 |
exception. |
|---|
| 74 |
""" |
|---|
| 75 |
if not is_safe_path(root, path): |
|---|
| 76 |
raise NotUnderRoot('path "%s" isn\'t under root directory "%s"' % |
|---|
| 77 |
(path, root)) |
|---|
| 78 |
root = tools.normalize_path(root) |
|---|
| 79 |
path = tools.normalize_path(path) |
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
reduced_path = path.replace(root, "", 1) |
|---|
| 83 |
if root == path: |
|---|
| 84 |
return "/" |
|---|
| 85 |
if _is_file_system_root(root): |
|---|
| 86 |
reduced_path = "/" + reduced_path |
|---|
| 87 |
url = reduced_path.replace(os.sep, sep) |
|---|
| 88 |
return urllib.quote(url) |
|---|
| 89 |
|
|---|
| 90 |
def to_file_system(root, url): |
|---|
| 91 |
r""" |
|---|
| 92 |
Return a file system path (with the proper separator for the used |
|---|
| 93 |
platform) derived from `root` and `url`. The `root` argument is |
|---|
| 94 |
the document root directory while `url` is an absolute URL (with |
|---|
| 95 |
leading slash, without host name). |
|---|
| 96 |
|
|---|
| 97 |
Trailing path separators on the `root` or `url` are ignored. |
|---|
| 98 |
|
|---|
| 99 |
If the `path` isn't part of the `root`, raise a `NotUnderRoot` |
|---|
| 100 |
exception. |
|---|
| 101 |
""" |
|---|
| 102 |
root = tools.normalize_path(root) |
|---|
| 103 |
url = urllib.unquote(url) |
|---|
| 104 |
reduced_path = url.replace(sep, os.sep) |
|---|
| 105 |
path = os.path.join(root, reduced_path[1:]) |
|---|
| 106 |
path = tools.normalize_path(path) |
|---|
| 107 |
if not is_safe_path(root, path): |
|---|
| 108 |
raise NotUnderRoot('path "%s" isn\'t under root directory "%s"' % |
|---|
| 109 |
(path, root)) |
|---|
| 110 |
return path |
|---|
| 111 |
|
|---|