Escape URLs according to RFC3986.

Previously, we weren't escaping parentheses when generating directory listings.

Pointed out by: Wijatmoko U. Prayitno
This commit is contained in:
Emil Mikulic 2015-05-19 22:02:12 +10:00
parent c4c0034242
commit 1c5fdb5607
2 changed files with 16 additions and 17 deletions

View File

@ -1675,25 +1675,24 @@ static void cleanup_sorted_dirlist(struct dlent **list, const ssize_t size) {
} }
} }
/* Should this character be urlencoded? (according to RFC1738) /* Is this an unreserved character according to
* Contributed by nf. * https://tools.ietf.org/html/rfc3986#section-2.3
*/ */
static int needs_urlencoding(const unsigned char c) { static int is_unreserved(const unsigned char c) {
unsigned int i; if (c >= 'a' && c <= 'z') return 1;
static const char bad[] = "<>\"%{}|^~[]`\\;:/?@#=&"; if (c >= 'A' && c <= 'Z') return 1;
if (c >= '0' && c <= '9') return 1;
/* Non-US-ASCII characters */ switch (c) {
if ((c <= 0x1F) || (c >= 0x7F)) case '-':
case '.':
case '_':
case '~':
return 1; return 1;
}
for (i = 0; i < sizeof(bad) - 1; i++)
if (c == bad[i])
return 1;
return 0; return 0;
} }
/* Encode string to be an RFC1738-compliant URL part. /* Encode string to be an RFC3986-compliant URL part.
* Contributed by nf. * Contributed by nf.
*/ */
static void urlencode(const char *src, char *dest) { static void urlencode(const char *src, char *dest) {
@ -1701,7 +1700,7 @@ static void urlencode(const char *src, char *dest) {
int i, j; int i, j;
for (i = j = 0; src[i] != '\0'; i++) { for (i = j = 0; src[i] != '\0'; i++) {
if (needs_urlencoding((unsigned char)src[i])) { if (!is_unreserved((unsigned char)src[i])) {
dest[j++] = '%'; dest[j++] = '%';
dest[j++] = hex[(src[i] >> 4) & 0xF]; dest[j++] = hex[(src[i] >> 4) & 0xF];
dest[j++] = hex[ src[i] & 0xF]; dest[j++] = hex[ src[i] & 0xF];

View File

@ -151,7 +151,7 @@ class TestHelper(unittest.TestCase):
class TestDirList(TestHelper): class TestDirList(TestHelper):
def setUp(self): def setUp(self):
self.fn = WWWROOT+"/escape#this" self.fn = WWWROOT+"/escape(this)name"
open(self.fn, "w").write("x"*12345) open(self.fn, "w").write("x"*12345)
def tearDown(self): def tearDown(self):
@ -161,7 +161,7 @@ class TestDirList(TestHelper):
resp = self.get("/") resp = self.get("/")
status, hdrs, body = parse(resp) status, hdrs, body = parse(resp)
self.assertEquals(ord("#"), 0x23) self.assertEquals(ord("#"), 0x23)
self.assertContains(body, "escape%23this", "12345") self.assertContains(body, "escape%28this%29name", "12345")
class TestCases(TestHelper): class TestCases(TestHelper):
pass # these get autogenerated in setUpModule() pass # these get autogenerated in setUpModule()