aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2016-08-25 23:51:00 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2016-08-25 23:54:21 +0200
commit9c4961a0e68458061171aef5f3b30a9b1fa8e333 (patch)
treeac0428ddf608aff18e0534e66c6ae64cf6333f00
parent677813c6a26eca5629ef8201fd0616511400a99e (diff)
enforce locale processing for files
Change-Id: I7de05d2acd02d088a3a2034ad8bccf524b5b6c12 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/afb-hreq.c107
-rw-r--r--src/afb-hreq.h5
-rw-r--r--src/afb-hsrv.c33
4 files changed, 125 insertions, 21 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b16c3121..60f83269 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -50,6 +50,7 @@ ADD_LIBRARY(afb-lib STATIC
afb-ws-json1.c
afb-ws.c
afb-wsj1.c
+ locale-root.c
session.c
verbose.c
websock.c
diff --git a/src/afb-hreq.c b/src/afb-hreq.c
index a4ccf676..885a4561 100644
--- a/src/afb-hreq.c
+++ b/src/afb-hreq.c
@@ -40,6 +40,7 @@
#include "afb-subcall.h"
#include "session.h"
#include "verbose.h"
+#include "locale-root.h"
#define SIZE_RESPONSE_BUFFER 8192
@@ -487,6 +488,112 @@ int afb_hreq_reply_file(struct afb_hreq *hreq, int dirfd, const char *filename)
return 1;
}
+int afb_hreq_reply_locale_file_if_exist(struct afb_hreq *hreq, struct locale_search *search, const char *filename)
+{
+ int rc;
+ int fd;
+ unsigned int status;
+ struct stat st;
+ char etag[1 + 2 * 8];
+ const char *inm;
+ struct MHD_Response *response;
+ const char *mimetype;
+
+ /* Opens the file or directory */
+ fd = locale_search_open(search, filename[0] ? filename : ".", O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+ afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN);
+ return 1;
+ }
+
+ /* Retrieves file's status */
+ if (fstat(fd, &st) != 0) {
+ close(fd);
+ afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
+ return 1;
+ }
+
+ /* serve directory */
+ if (S_ISDIR(st.st_mode)) {
+ rc = afb_hreq_redirect_to_ending_slash_if_needed(hreq);
+ if (rc == 0) {
+ static const char *indexes[] = { "index.html", NULL };
+ int i = 0;
+ size_t length = strlen(filename);
+ char *extname = alloca(length + 30); /* 30 is enough to old data of indexes */
+ memcpy(extname, filename, length);
+ if (length && extname[length - 1] != '/')
+ extname[length++] = '/';
+ while (rc == 0 && indexes[i] != NULL) {
+ strcpy(extname + length, indexes[i++]);
+ rc = afb_hreq_reply_locale_file_if_exist(hreq, search, extname);
+ }
+ }
+ close(fd);
+ return rc;
+ }
+
+ /* Don't serve special files */
+ if (!S_ISREG(st.st_mode)) {
+ close(fd);
+ afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN);
+ return 1;
+ }
+
+ /* Check the method */
+ if ((hreq->method & (afb_method_get | afb_method_head)) == 0) {
+ close(fd);
+ afb_hreq_reply_error(hreq, MHD_HTTP_METHOD_NOT_ALLOWED);
+ return 1;
+ }
+
+ /* computes the etag */
+ sprintf(etag, "%08X%08X", ((int)(st.st_mtim.tv_sec) ^ (int)(st.st_mtim.tv_nsec)), (int)(st.st_size));
+
+ /* checks the etag */
+ inm = MHD_lookup_connection_value(hreq->connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_NONE_MATCH);
+ if (inm && 0 == strcmp(inm, etag)) {
+ /* etag ok, return NOT MODIFIED */
+ close(fd);
+ DEBUG("Not Modified: [%s]", filename);
+ response = MHD_create_response_from_buffer(0, empty_string, MHD_RESPMEM_PERSISTENT);
+ status = MHD_HTTP_NOT_MODIFIED;
+ } else {
+ /* check the size */
+ if (st.st_size != (off_t) (size_t) st.st_size) {
+ close(fd);
+ afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
+ return 1;
+ }
+
+ /* create the response */
+ response = MHD_create_response_from_fd((size_t) st.st_size, fd);
+ status = MHD_HTTP_OK;
+
+ /* set the type */
+ mimetype = mimetype_fd_name(fd, filename);
+ if (mimetype != NULL)
+ MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype);
+ }
+
+ /* fills the value and send */
+ afb_hreq_reply(hreq, status, response,
+ MHD_HTTP_HEADER_CACHE_CONTROL, hreq->cacheTimeout,
+ MHD_HTTP_HEADER_ETAG, etag,
+ NULL);
+ return 1;
+}
+
+int afb_hreq_reply_locale_file(struct afb_hreq *hreq, struct locale_search *search, const char *filename)
+{
+ int rc = afb_hreq_reply_locale_file_if_exist(hreq, search, filename);
+ if (rc == 0)
+ afb_hreq_reply_error(hreq, MHD_HTTP_NOT_FOUND);
+ return 1;
+}
+
struct _mkq_ {
int count;
size_t length;
diff --git a/src/afb-hreq.h b/src/afb-hreq.h
index 3d7954a9..9ccf6c9b 100644
--- a/src/afb-hreq.h
+++ b/src/afb-hreq.h
@@ -22,6 +22,7 @@ struct json_object;
struct hreq_data;
struct afb_hsrv;
struct afb_req_itf;
+struct locale_search;
extern const struct afb_req_itf afb_hreq_req_itf;
@@ -62,6 +63,10 @@ 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_reply_locale_file_if_exist(struct afb_hreq *hreq, struct locale_search *search, const char *filename);
+
+extern int afb_hreq_reply_locale_file(struct afb_hreq *hreq, struct locale_search *search, const char *filename);
+
extern void afb_hreq_redirect_to(struct afb_hreq *request, const char *url, int add_query_part);
extern int afb_hreq_redirect_to_ending_slash_if_needed(struct afb_hreq *hreq);
diff --git a/src/afb-hsrv.c b/src/afb-hsrv.c
index 9d838381..15b2a5f2 100644
--- a/src/afb-hsrv.c
+++ b/src/afb-hsrv.c
@@ -35,6 +35,7 @@
#include "afb-hsrv.h"
#include <afb/afb-req-itf.h>
#include "verbose.h"
+#include "locale-root.h"
#include "afb-common.h"
@@ -54,10 +55,7 @@ struct hsrv_handler {
};
struct hsrv_alias {
- const char *alias;
- const char *directory;
- size_t lendir;
- int dirfd;
+ struct locale_root *root;
int relax;
};
@@ -142,7 +140,7 @@ static int access_handler(
hreq->connection = connection;
hreq->method = method;
hreq->version = version;
- hreq->lang = afb_hreq_get_header(hreq, MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
+ hreq->lang = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
hreq->tail = hreq->url = url;
hreq->lentail = hreq->lenurl = strlen(url);
*recordreq = hreq;
@@ -308,6 +306,7 @@ static int handle_alias(struct afb_hreq *hreq, void *data)
{
int rc;
struct hsrv_alias *da = data;
+ struct locale_search *search;
if (hreq->method != afb_method_get) {
if (da->relax)
@@ -316,14 +315,9 @@ static int handle_alias(struct afb_hreq *hreq, void *data)
return 1;
}
- if (!afb_hreq_valid_tail(hreq)) {
- if (da->relax)
- return 0;
- afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN);
- return 1;
- }
-
- rc = afb_hreq_reply_file_if_exist(hreq, da->dirfd, &hreq->tail[1]);
+ search = locale_root_search(da->root, hreq->lang, 0);
+ rc = afb_hreq_reply_locale_file_if_exist(hreq, search, &hreq->tail[1]);
+ locale_search_unref(search);
if (rc == 0) {
if (da->relax)
return 0;
@@ -350,26 +344,23 @@ int afb_hsrv_add_handler(
int afb_hsrv_add_alias(struct afb_hsrv *hsrv, const char *prefix, const char *alias, int priority, int relax)
{
+ struct locale_root *root;
struct hsrv_alias *da;
- int dirfd;
- dirfd = open(alias, O_PATH|O_DIRECTORY);
- if (dirfd < 0) {
+ root = locale_root_create(AT_FDCWD, alias);
+ if (root == NULL) {
/* TODO message */
return 0;
}
da = malloc(sizeof *da);
if (da != NULL) {
- da->alias = prefix;
- da->directory = alias;
- da->lendir = strlen(da->directory);
- da->dirfd = dirfd;
+ da->root = root;
da->relax = relax;
if (afb_hsrv_add_handler(hsrv, prefix, handle_alias, da, priority))
return 1;
free(da);
}
- close(dirfd);
+ locale_root_unref(root);
return 0;
}