summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/afb-hreq.c127
-rw-r--r--src/afb-hreq.h2
-rw-r--r--src/afb-hswitch.c2
3 files changed, 111 insertions, 20 deletions
diff --git a/src/afb-hreq.c b/src/afb-hreq.c
index ab174e2f..a325fd4f 100644
--- a/src/afb-hreq.c
+++ b/src/afb-hreq.c
@@ -390,24 +390,24 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *hreq, int dirfd, const char *f
/* serve directory */
if (S_ISDIR(st.st_mode)) {
- static const char *indexes[] = { "index.html", NULL };
- int i = 0;
- rc = 0;
- while (indexes[i] != NULL) {
- if (faccessat(fd, indexes[i], R_OK, 0) == 0) {
- if (hreq->url[hreq->lenurl - 1] != '/') {
- /* the redirect is needed for reliability of relative path */
- char *tourl = alloca(hreq->lenurl + 2);
- memcpy(tourl, hreq->url, hreq->lenurl);
- tourl[hreq->lenurl] = '/';
- tourl[hreq->lenurl + 1] = 0;
- rc = afb_hreq_redirect_to(hreq, tourl);
- } else {
+ if (hreq->url[hreq->lenurl - 1] != '/') {
+ /* the redirect is needed for reliability of relative path */
+ char *tourl = alloca(hreq->lenurl + 2);
+ memcpy(tourl, hreq->url, hreq->lenurl);
+ tourl[hreq->lenurl] = '/';
+ tourl[hreq->lenurl + 1] = 0;
+ rc = afb_hreq_redirect_to(hreq, tourl, 1);
+ } else {
+ static const char *indexes[] = { "index.html", NULL };
+ int i = 0;
+ rc = 0;
+ while (indexes[i] != NULL) {
+ if (faccessat(fd, indexes[i], R_OK, 0) == 0) {
rc = afb_hreq_reply_file_if_exist(hreq, fd, indexes[i]);
+ break;
}
- break;
+ i++;
}
- i++;
}
close(fd);
return rc;
@@ -472,12 +472,103 @@ int afb_hreq_reply_file(struct afb_hreq *hreq, int dirfd, const char *filename)
return 1;
}
-int afb_hreq_redirect_to(struct afb_hreq *hreq, const char *url)
+struct _mkq_ {
+ int count;
+ size_t length;
+ size_t alloc;
+ char *text;
+};
+
+static void _mkq_add_(struct _mkq_ *mkq, char value)
+{
+ char *text = mkq->text;
+ if (text != NULL) {
+ if (mkq->length == mkq->alloc) {
+ mkq->alloc += 100;
+ text = realloc(text, mkq->alloc);
+ if (text == NULL) {
+ free(mkq->text);
+ mkq->text = NULL;
+ return;
+ }
+ mkq->text = text;
+ }
+ text[mkq->length++] = value;
+ }
+}
+
+static void _mkq_add_hex_(struct _mkq_ *mkq, char value)
+{
+ _mkq_add_(mkq, (char)(value < 10 ? value + '0' : value + 'A' - 10));
+}
+
+static void _mkq_add_esc_(struct _mkq_ *mkq, char value)
+{
+ _mkq_add_(mkq, '%');
+ _mkq_add_hex_(mkq, (char)((value >> 4) & 15));
+ _mkq_add_hex_(mkq, (char)(value & 15));
+}
+
+static void _mkq_add_char_(struct _mkq_ *mkq, char value)
+{
+ if (value <= ' ' || value >= 127)
+ _mkq_add_esc_(mkq, value);
+ else
+ switch(value) {
+ case '=':
+ case '&':
+ case '%':
+ _mkq_add_esc_(mkq, value);
+ break;
+ default:
+ _mkq_add_(mkq, value);
+ }
+}
+
+static void _mkq_append_(struct _mkq_ *mkq, const char *value)
+{
+ while(*value)
+ _mkq_add_char_(mkq, *value++);
+}
+
+static int _mkquery_(struct _mkq_ *mkq, enum MHD_ValueKind kind, const char *key, const char *value)
+{
+ _mkq_add_(mkq, mkq->count++ ? '&' : '?');
+ _mkq_append_(mkq, key);
+ if (value != NULL) {
+ _mkq_add_(mkq, '=');
+ _mkq_append_(mkq, value);
+ }
+ return 1;
+}
+
+static char *url_with_query(struct afb_hreq *hreq, const char *url)
+{
+ struct _mkq_ mkq;
+
+ mkq.count = 0;
+ mkq.length = strlen(url);
+ mkq.alloc = mkq.length + 1000;
+ mkq.text = malloc(mkq.alloc);
+ if (mkq.text != NULL) {
+ strcpy(mkq.text, url);
+ MHD_get_connection_values(hreq->connection, MHD_GET_ARGUMENT_KIND, (void*)_mkquery_, &mkq);
+ _mkq_add_(&mkq, 0);
+ }
+ return mkq.text;
+}
+
+int afb_hreq_redirect_to(struct afb_hreq *hreq, const char *url, int add_query_part)
{
- /* TODO: append the query part! */
+ const char *to;
+ char *wqp;
+
+ wqp = add_query_part ? url_with_query(hreq, url) : NULL;
+ to = wqp ? : url;
afb_hreq_reply_static(hreq, MHD_HTTP_MOVED_PERMANENTLY, 0, NULL,
- MHD_HTTP_HEADER_LOCATION, url, NULL);
+ MHD_HTTP_HEADER_LOCATION, to, NULL);
DEBUG("redirect from [%s] to [%s]", hreq->url, url);
+ free(wqp);
return 1;
}
diff --git a/src/afb-hreq.h b/src/afb-hreq.h
index 8e12b62d..836f4703 100644
--- a/src/afb-hreq.h
+++ b/src/afb-hreq.h
@@ -58,7 +58,7 @@ extern int afb_hreq_reply_file_if_exist(struct afb_hreq *request, int dirfd, con
extern int afb_hreq_reply_file(struct afb_hreq *request, int dirfd, const char *filename);
-extern int afb_hreq_redirect_to(struct afb_hreq *request, const char *url);
+extern int afb_hreq_redirect_to(struct afb_hreq *request, const char *url, int add_query_part);
extern const char *afb_hreq_get_cookie(struct afb_hreq *hreq, const char *name);
diff --git a/src/afb-hswitch.c b/src/afb-hswitch.c
index 417b773e..fea30c59 100644
--- a/src/afb-hswitch.c
+++ b/src/afb-hswitch.c
@@ -73,7 +73,7 @@ int afb_hswitch_one_page_api_redirect(struct afb_hreq *hreq, void *data)
url[plen++] = '#';
url[plen++] = '!';
memcpy(&url[plen], &hreq->tail[1], hreq->lentail);
- return afb_hreq_redirect_to(hreq, url);
+ return afb_hreq_redirect_to(hreq, url, 1);
}
int afb_hswitch_websocket_switch(struct afb_hreq *hreq, void *data)