summaryrefslogtreecommitdiff
path: root/url.c
diff options
context:
space:
mode:
authorVincent Douillet <vincent@vdouillet.fr>2024-09-11 11:20:31 +0200
committerVincent Douillet <vincent@vdouillet.fr>2024-09-11 11:20:31 +0200
commit19e47daa9c1fb55f2cb9e639d5a6ef16b5bc4e88 (patch)
tree2b98ac0700a11cb142625d8355019c44b49c1850 /url.c
parent4e921ffa31fdca2425d326efda1c6d9ad190359a (diff)
url: fix encoding for use in http context
Diffstat (limited to 'url.c')
-rw-r--r--url.c80
1 files changed, 69 insertions, 11 deletions
diff --git a/url.c b/url.c
index adcc95d..977edea 100644
--- a/url.c
+++ b/url.c
@@ -28,13 +28,18 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/types.h>
+
#include <assert.h>
#include <limits.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <kcgi.h>
#include <string.h>
#include "config.h"
+#include "str.h"
#include "url.h"
bool
@@ -74,20 +79,35 @@ check_request_path(const char *path, const char *suffix)
return true;
}
+char *
+url_encode(const char *str)
+{
+ char *result;
+
+ if ((result = khttp_urlencode(str)) == NULL)
+ return NULL;
+
+ str_replace(result, '+', ' ');
+ return result;
+}
+
size_t
-url_build(char *dst, size_t dst_size,...)
+url_build(char *dst, size_t dst_sz,...)
{
va_list path_list;
- const char *path;
- size_t w_size;
+ char p [PATH_MAX];
+ char *encoded, *path, *slash;
+ size_t c_len, p_len, w_len;
dst[0] = '\0';
- w_size = 0;
- va_start(path_list, dst_size);
+ w_len = 0;
+ va_start(path_list, dst_sz);
while ((path = va_arg(path_list, char *)) != NULL) {
/* no more space in dst buffer */
- if (w_size >= dst_size)
- break;
+ if (w_len >= dst_sz) {
+ w_len = 0;
+ goto end;
+ }
if (path[0] == '\0')
continue;
@@ -95,12 +115,50 @@ url_build(char *dst, size_t dst_size,...)
if (path[0] == '.' && path[1] == '\0')
continue;
- if (path[0] != '/' && w_size > 0 && dst[w_size - 1] != '/')
- strlcat(dst, "/", dst_size);
+ while (path[0] != '\0') {
+ /* no more space in dst buffer */
+ if (w_len >= dst_sz) {
+ w_len = 0;
+ goto end;
+ }
+
+ /* skip heading slashes */
+ slash = strchr(path, '/');
+ if (slash == path) {
+ path++;
+ continue;
+ }
+
+ /* copy string to encode into buffer
+ * if no slash found, copy everything, otherwise stop
+ * before the slash */
+ c_len = slash == NULL ? strlen(path) :
+ (size_t) (slash - path);
+ if (c_len >= PATH_MAX) {
+ w_len = 0;
+ goto end;
+ }
+ p_len = strlcpy(p, path, c_len + 1);
+ if (p_len < c_len) {
+ w_len = 0;
+ goto end;
+ }
+
+ /* encode string */
+ if ((encoded = url_encode(p)) == NULL) {
+ w_len = 0;
+ goto end;
+ }
- w_size = strlcat(dst, path, dst_size);
+ /* append it to the path */
+ strlcat(dst, "/", dst_sz);
+ w_len = strlcat(dst, encoded, dst_sz);
+ free(encoded);
+ path += c_len;
+ }
}
+end:
va_end(path_list);
- return w_size;
+ return w_len;
}