[hackers] [quark] Add http_send_body() and data_send_error() and refactor || Laslo Hunhold
commit a36b901d404f4d4268384a379fd040898f78b1b3
Author: Laslo Hunhold <dev_AT_frign.de>
AuthorDate: Sat Aug 29 00:42:54 2020 +0200
Commit: Laslo Hunhold <dev_AT_frign.de>
CommitDate: Sat Aug 29 00:49:16 2020 +0200
Add http_send_body() and data_send_error() and refactor
This turns the data-functions into the only functions "allowed"
to send body-data (called with http_send_body()). The previous (hacky)
approach of doing this in http_send_header() is not only out of place,
it's an easy source of bugs given, for instance, the sending of body
data is not expected with HEAD-requests.
Given html_escape() is now only used in data.c, we move it there from
util.c and make it a static method again.
Signed-off-by: Laslo Hunhold <dev_AT_frign.de>
diff --git a/data.c b/data.c
index 46486aa..3b6b2e5 100644
--- a/data.c
+++ b/data.c
_AT_@ -38,10 +38,55 @@ suffix(int t)
return "";
}
+static void
+html_escape(const char *src, char *dst, size_t dst_siz)
+{
+ const struct {
+ char c;
+ char *s;
+ } escape[] = {
+ { '&', "&" },
+ { '<', "<" },
+ { '>', ">" },
+ { '"', """ },
+ { '\'', "'" },
+ };
+ size_t i, j, k, esclen;
+
+ for (i = 0, j = 0; src[i] != '\0'; i++) {
+ for (k = 0; k < LEN(escape); k++) {
+ if (src[i] == escape[k].c) {
+ break;
+ }
+ }
+ if (k == LEN(escape)) {
+ /* no escape char at src[i] */
+ if (j == dst_siz - 1) {
+ /* silent truncation */
+ break;
+ } else {
+ dst[j++] = src[i];
+ }
+ } else {
+ /* escape char at src[i] */
+ esclen = strlen(escape[k].s);
+
+ if (j >= dst_siz - esclen) {
+ /* silent truncation */
+ break;
+ } else {
+ memcpy(&dst[j], escape[k].s, esclen);
+ j += esclen;
+ }
+ }
+ }
+ dst[j] = '\0';
+}
+
enum status
data_send_dirlisting(int fd, const struct response *res)
{
- enum status ret;
+ enum status ret = 0;
struct dirent **e;
size_t i;
int dirlen;
_AT_@ -52,6 +97,17 @@ data_send_dirlisting(int fd, const struct response *res)
return S_FORBIDDEN;
}
+ /* listing header (we use esc because sizeof(esc) >= PATH_MAX) */
+ html_escape(res->uri, esc, MIN(PATH_MAX, sizeof(esc)));
+ if (dprintf(fd,
+ "<!DOCTYPE html>\n<html>\n\t<head>"
+ "<title>Index of %s</title></head>\n"
+ "\t<body>\n\t\t<a href=\"..\">..</a>",
+ esc) < 0) {
+ ret = S_REQUEST_TIMEOUT;
+ goto cleanup;
+ }
+
/* listing */
for (i = 0; i < (size_t)dirlen; i++) {
/* skip hidden files, "." and ".." */
_AT_@ -86,6 +142,21 @@ cleanup:
return ret;
}
+enum status
+data_send_error(int fd, const struct response *res)
+{
+ if (dprintf(fd,
+ "<!DOCTYPE html>\n<html>\n\t<head>\n"
+ "\t\t<title>%d %s</title>\n\t</head>\n\t<body>\n"
+ "\t\t<h1>%d %s</h1>\n\t</body>\n</html>\n",
+ res->status, status_str[res->status],
+ res->status, status_str[res->status]) < 0) {
+ return S_REQUEST_TIMEOUT;
+ }
+
+ return 0;
+}
+
enum status
data_send_file(int fd, const struct response *res)
{
diff --git a/data.h b/data.h
index 12aacc8..91aedf5 100644
--- a/data.h
+++ b/data.h
_AT_@ -5,6 +5,7 @@
#include "http.h"
enum status data_send_dirlisting(int, const struct response *);
+enum status data_send_error(int, const struct response *);
enum status data_send_file(int, const struct response *);
#endif /* DATA_H */
diff --git a/http.c b/http.c
index 6e32fba..96e673a 100644
--- a/http.c
+++ b/http.c
_AT_@ -17,6 +17,7 @@
#include <unistd.h>
#include "config.h"
+#include "data.h"
#include "http.h"
#include "util.h"
_AT_@ -57,10 +58,16 @@ const char *res_field_str[] = {
[RES_CONTENT_TYPE] = "Content-Type",
};
+enum status (* const body_fct[])(int, const struct response *) = {
+ [RESTYPE_ERROR] = data_send_error,
+ [RESTYPE_FILE] = data_send_file,
+ [RESTYPE_DIRLISTING] = data_send_dirlisting,
+};
+
enum status
http_send_header(int fd, const struct response *res)
{
- char t[FIELD_MAX], esc[PATH_MAX];
+ char t[FIELD_MAX];
size_t i;
if (timestamp(t, sizeof(t), time(NULL))) {
_AT_@ -88,27 +95,6 @@ http_send_header(int fd, const struct response *res)
return S_REQUEST_TIMEOUT;
}
- /* listing header */
- if (res->type == RESTYPE_DIRLISTING) {
- html_escape(res->uri, esc, sizeof(esc));
- if (dprintf(fd,
- "<!DOCTYPE html>\n<html>\n\t<head>"
- "<title>Index of %s</title></head>\n"
- "\t<body>\n\t\t<a href=\"..\">..</a>",
- esc) < 0) {
- return S_REQUEST_TIMEOUT;
- }
- } else if (res->type == RESTYPE_ERROR) {
- if (dprintf(fd,
- "<!DOCTYPE html>\n<html>\n\t<head>\n"
- "\t\t<title>%d %s</title>\n\t</head>\n\t<body>\n"
- "\t\t<h1>%d %s</h1>\n\t</body>\n</html>\n",
- res->status, status_str[res->status],
- res->status, status_str[res->status]) < 0) {
- return S_REQUEST_TIMEOUT;
- }
- }
-
return 0;
}
_AT_@ -854,3 +840,16 @@ http_prepare_error_response(const struct request *req,
}
}
}
+
+enum status
+http_send_body(int fd, const struct response *res,
+ const struct request *req)
+{
+ enum status s;
+
+ if (req->method == M_GET && (s = body_fct[res->type](fd, res))) {
+ return s;
+ }
+
+ return 0;
+}
diff --git a/http.h b/http.h
index d75d8d0..3d6d4d2 100644
--- a/http.h
+++ b/http.h
_AT_@ -82,11 +82,13 @@ struct response {
} file;
};
+extern enum status (* const body_fct[])(int, const struct response *);
+
enum conn_state {
C_VACANT,
C_RECV_HEADER,
C_SEND_HEADER,
- C_SEND_DATA,
+ C_SEND_BODY,
NUM_CONN_STATES,
};
_AT_@ -107,5 +109,7 @@ void http_prepare_response(const struct request *, struct response *,
const struct server *);
void http_prepare_error_response(const struct request *,
struct response *, enum status);
+enum status http_send_body(int, const struct response *,
+ const struct request *);
#endif /* HTTP_H */
diff --git a/main.c b/main.c
index 2946a0b..739e2fa 100644
--- a/main.c
+++ b/main.c
_AT_@ -45,15 +45,9 @@ serve(int infd, const struct sockaddr_storage *in_sa, const struct server *srv)
http_prepare_response(&c.req, &c.res, srv);
}
- if ((s = http_send_header(c.fd, &c.res))) {
+ if ((s = http_send_header(c.fd, &c.res)) ||
+ (s = http_send_body(c.fd, &c.res, &c.req))) {
c.res.status = s;
- } else {
- /* send data */
- if (c.res.type == RESTYPE_FILE) {
- data_send_file(c.fd, &c.res);
- } else if (c.res.type == RESTYPE_DIRLISTING) {
- data_send_dirlisting(c.fd, &c.res);
- }
}
/* write output to log */
diff --git a/util.c b/util.c
index 2b54df1..b281613 100644
--- a/util.c
+++ b/util.c
_AT_@ -123,51 +123,6 @@ prepend(char *str, size_t size, const char *prefix)
return 0;
}
-void
-html_escape(const char *src, char *dst, size_t dst_siz)
-{
- const struct {
- char c;
- char *s;
- } escape[] = {
- { '&', "&" },
- { '<', "<" },
- { '>', ">" },
- { '"', """ },
- { '\'', "'" },
- };
- size_t i, j, k, esclen;
-
- for (i = 0, j = 0; src[i] != '\0'; i++) {
- for (k = 0; k < LEN(escape); k++) {
- if (src[i] == escape[k].c) {
- break;
- }
- }
- if (k == LEN(escape)) {
- /* no escape char at src[i] */
- if (j == dst_siz - 1) {
- /* silent truncation */
- break;
- } else {
- dst[j++] = src[i];
- }
- } else {
- /* escape char at src[i] */
- esclen = strlen(escape[k].s);
-
- if (j >= dst_siz - esclen) {
- /* silent truncation */
- break;
- } else {
- memcpy(&dst[j], escape[k].s, esclen);
- j += esclen;
- }
- }
- }
- dst[j] = '\0';
-}
-
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
diff --git a/util.h b/util.h
index 6b6d17d..bc7f8ec 100644
--- a/util.h
+++ b/util.h
_AT_@ -52,7 +52,6 @@ void eunveil(const char *, const char *);
int timestamp(char *, size_t, time_t);
int esnprintf(char *, size_t, const char *, ...);
int prepend(char *, size_t, const char *);
-void html_escape(const char *, char *, size_t);
void *reallocarray(void *, size_t, size_t);
long long strtonum(const char *, long long, long long, const char **);
Received on Sat Aug 29 2020 - 00:49:59 CEST
This archive was generated by hypermail 2.3.0
: Sat Aug 29 2020 - 01:00:35 CEST