Introduction
Introduction Statistics Contact Development Disclaimer Help
Add http_send_body() and data_send_error() and refactor - quark - quark web ser…
git clone git://git.suckless.org/quark
Log
Files
Refs
LICENSE
---
commit a36b901d404f4d4268384a379fd040898f78b1b3
parent db127723c67534d5693fc033f19c855a403d1447
Author: Laslo Hunhold <[email protected]>
Date: Sat, 29 Aug 2020 00:42:54 +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 <[email protected]>
Diffstat:
M data.c | 73 +++++++++++++++++++++++++++++…
M data.h | 1 +
M http.c | 43 +++++++++++++++--------------…
M http.h | 6 +++++-
M main.c | 10 ++--------
M util.c | 45 -----------------------------…
M util.h | 1 -
7 files changed, 101 insertions(+), 78 deletions(-)
---
diff --git a/data.c b/data.c
@@ -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[] = {
+ { '&', "&amp;" },
+ { '<', "&lt;" },
+ { '>', "&gt;" },
+ { '"', "&quot;" },
+ { '\'', "&#x27;" },
+ };
+ 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;
@@ -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 ".." */
@@ -87,6 +143,21 @@ cleanup:
}
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)
{
FILE *fp;
diff --git a/data.h b/data.h
@@ -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
@@ -17,6 +17,7 @@
#include <unistd.h>
#include "config.h"
+#include "data.h"
#include "http.h"
#include "util.h"
@@ -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))) {
@@ -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;
}
@@ -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
@@ -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,
};
@@ -107,5 +109,7 @@ void http_prepare_response(const struct request *, struct r…
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
@@ -45,15 +45,9 @@ serve(int infd, const struct sockaddr_storage *in_sa, const …
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
@@ -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[] = {
- { '&', "&amp;" },
- { '<', "&lt;" },
- { '>', "&gt;" },
- { '"', "&quot;" },
- { '\'', "&#x27;" },
- };
- 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
@@ -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 **);
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.