percent encode characters in path names
authorHiltjo Posthuma <hiltjo@codemadness.org>
Tue, 16 Nov 2021 13:16:46 +0000 (14:16 +0100)
committerHiltjo Posthuma <hiltjo@codemadness.org>
Tue, 16 Nov 2021 13:16:46 +0000 (14:16 +0100)
Paths could contain characters like # (fragment), '?', control-characters, etc.

stagit-index.c
stagit.c

index 84785a9e8395e37aaae68df36908bef26e73a8d5..8a53463d047cc00251f788f93be3fefa382ddb16 100644 (file)
@@ -28,6 +28,28 @@ joinpath(char *buf, size_t bufsiz, const char *path, const char *path2)
                        path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2);
 }
 
+/* Percent-encode, see RFC3986 section 2.1. */
+void
+percentencode(FILE *fp, const char *s, size_t len)
+{
+       static char tab[] = "0123456789ABCDEF";
+       unsigned char uc;
+       size_t i;
+
+       for (i = 0; *s && i < len; s++, i++) {
+               uc = *s;
+               /* NOTE: do not encode '/' for paths */
+               if (uc < '/' || uc >= 127 || (uc >= ':' && uc <= '@') ||
+                   uc == '[' || uc == ']') {
+                       putc('%', fp);
+                       putc(tab[(uc >> 4) & 0x0f], fp);
+                       putc(tab[uc & 0x0f], fp);
+               } else {
+                       putc(uc, fp);
+               }
+       }
+}
+
 /* Escape characters below as HTML 2.0 / XML 1.0. */
 void
 xmlencode(FILE *fp, const char *s, size_t len)
@@ -118,7 +140,7 @@ writelog(FILE *fp)
                        *p = '\0';
 
        fputs("<tr><td><a href=\"", fp);
-       xmlencode(fp, stripped_name, strlen(stripped_name));
+       percentencode(fp, stripped_name, strlen(stripped_name));
        fputs("/log.html\">", fp);
        xmlencode(fp, stripped_name, strlen(stripped_name));
        fputs("</a></td><td>", fp);
index d6376910b4a18855bb0e86c885d2b687cf5decea..07d79293df7cf7489614b59491b80ef76213a39e 100644 (file)
--- a/stagit.c
+++ b/stagit.c
@@ -359,6 +359,28 @@ efopen(const char *filename, const char *flags)
        return fp;
 }
 
+/* Percent-encode, see RFC3986 section 2.1. */
+void
+percentencode(FILE *fp, const char *s, size_t len)
+{
+       static char tab[] = "0123456789ABCDEF";
+       unsigned char uc;
+       size_t i;
+
+       for (i = 0; *s && i < len; s++, i++) {
+               uc = *s;
+               /* NOTE: do not encode '/' for paths */
+               if (uc < '/' || uc >= 127 || (uc >= ':' && uc <= '@') ||
+                   uc == '[' || uc == ']') {
+                       putc('%', fp);
+                       putc(tab[(uc >> 4) & 0x0f], fp);
+                       putc(tab[uc & 0x0f], fp);
+               } else {
+                       putc(uc, fp);
+               }
+       }
+}
+
 /* Escape characters below as HTML 2.0 / XML 1.0. */
 void
 xmlencode(FILE *fp, const char *s, size_t len)
@@ -497,7 +519,7 @@ writeheader(FILE *fp, const char *title)
        fputs("</span></td></tr>", fp);
        if (cloneurl[0]) {
                fputs("<tr class=\"url\"><td></td><td>git clone <a href=\"", fp);
-               xmlencode(fp, cloneurl, strlen(cloneurl));
+               xmlencode(fp, cloneurl, strlen(cloneurl)); /* not percent-encoded */
                fputs("\">", fp);
                xmlencode(fp, cloneurl, strlen(cloneurl));
                fputs("</a></td></tr>", fp);
@@ -570,7 +592,7 @@ printcommit(FILE *fp, struct commitinfo *ci)
                fputs("<b>Author:</b> ", fp);
                xmlencode(fp, ci->author->name, strlen(ci->author->name));
                fputs(" &lt;<a href=\"mailto:", fp);
-               xmlencode(fp, ci->author->email, strlen(ci->author->email));
+               xmlencode(fp, ci->author->email, strlen(ci->author->email)); /* not percent-encoded */
                fputs("\">", fp);
                xmlencode(fp, ci->author->email, strlen(ci->author->email));
                fputs("</a>&gt;\n<b>Date:</b>   ", fp);
@@ -665,11 +687,11 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                patch = ci->deltas[i]->patch;
                delta = git_patch_get_delta(patch);
                fprintf(fp, "<b>diff --git a/<a id=\"h%zu\" href=\"%sfile/", i, relpath);
-               xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));
+               percentencode(fp, delta->old_file.path, strlen(delta->old_file.path));
                fputs(".html\">", fp);
                xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));
                fprintf(fp, "</a> b/<a href=\"%sfile/", relpath);
-               xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));
+               percentencode(fp, delta->new_file.path, strlen(delta->new_file.path));
                fprintf(fp, ".html\">");
                xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));
                fprintf(fp, "</a></b>\n");
@@ -1037,7 +1059,7 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
                        fputs("<tr><td>", fp);
                        fputs(filemode(git_tree_entry_filemode(entry)), fp);
                        fprintf(fp, "</td><td><a href=\"%s", relpath);
-                       xmlencode(fp, filepath, strlen(filepath));
+                       percentencode(fp, filepath, strlen(filepath));
                        fputs("\">", fp);
                        xmlencode(fp, entrypath, strlen(entrypath));
                        fputs("</a></td><td class=\"num\" align=\"right\">", fp);