servedir: some line reading buffer optimizations - gopherproxy-c - Gopher HTTP proxy in C (CGI)
(HTM) git clone git://git.codemadness.org/gopherproxy-c
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 00c13341a4b18c68b1ea0b157c84b840c5f89245
(DIR) parent 407a5ede41c92b0b9b711bd376493a579995da36
(HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 4 Aug 2025 13:31:21 +0200
servedir: some line reading buffer optimizations
Diffstat:
M gopherproxy.c | 66 +++++++++++++++++++------------
1 file changed, 41 insertions(+), 25 deletions(-)
---
(DIR) diff --git a/gopherproxy.c b/gopherproxy.c
@@ -26,6 +26,9 @@ static struct tls *t;
static struct tls_config *tls_config;
#endif
+#define MAX_LINE_SIZ 2048 /* max size of a DirEntry in bytes */
+#define READ_BUF_SIZ 16384 /* read buffer size in bytes */
+
#define MAX_RESPONSETIMEOUT 10 /* timeout in seconds */
#define MAX_RESPONSESIZ 4000000 /* max download size in bytes */
@@ -53,6 +56,19 @@ struct visited {
char port[8];
};
+struct linebuf {
+ /* line buffer */
+ char *line;
+ char linebuf[MAX_LINE_SIZ];
+ size_t linelen;
+ size_t lineoff;
+ /* read buffer */
+ char buf[READ_BUF_SIZ];
+ char *bufoff, *bufend;
+ int err;
+ int eof;
+};
+
/* parsed URI */
static struct uri u;
/* socket fd */
@@ -338,21 +354,11 @@ plain_readbuf(char *buf, size_t bufsiz)
return len;
}
-struct linebuf {
- /* line buffer */
- char line[2048];
- size_t linelen;
- size_t lineoff;
- /* read buffer */
- char buf[4096];
- char *bufoff, *bufend;
- int err;
-};
-
void
linebuf_init(struct linebuf *b)
{
memset(b, 0, sizeof(struct linebuf));
+ b->line = b->linebuf;
}
ssize_t
@@ -362,7 +368,8 @@ linebuf_get(struct linebuf *b)
ssize_t n;
char *p;
- while (!(b->err)) {
+ b->line = b->linebuf;
+ while (!(b->err) && !(b->eof)) {
/* need to read more */
if (b->bufoff >= b->bufend) {
b->bufoff = b->buf;
@@ -372,8 +379,10 @@ linebuf_get(struct linebuf *b)
b->err = EIO;
/* use remaining data even if not terminated by a newline */
- if (n == 0 && b->linelen > 0)
- return b->linelen;
+ if (n == 0 && b->lineoff > 0) {
+ b->eof = 1;
+ return b->lineoff;
+ }
if (n > 0)
b->bufend = b->buf + n;
@@ -384,16 +393,22 @@ linebuf_get(struct linebuf *b)
/* search first newline */
if ((p = memchr(b->bufoff, '\n', b->bufend - b->bufoff))) {
len = (p - b->bufoff);
+ /* full line in buffer, no need to copy to line buffer */
+ if (b->lineoff == 0)
+ b->line = b->bufoff; /* just point to buffer, no copy */
} else {
- /* copy remaining data into line buffer and read more */
+ /* use remaining data into line buffer and read more */
len = (b->bufend - b->bufoff);
}
- if (b->lineoff + len + 1 >= sizeof(b->line)) {
- b->err = ENOMEM;
- return -1;
+ if (b->line == b->linebuf) {
+ if (b->lineoff + len + 1 >= sizeof(b->linebuf)) {
+ b->err = ENOMEM;
+ return -1;
+ }
+ memcpy(b->linebuf + b->lineoff, b->bufoff, len);
}
- memcpy(b->line + b->lineoff, b->bufoff, len);
+
b->lineoff += len;
b->linelen = b->lineoff;
b->line[b->linelen] = '\0';
@@ -453,7 +468,7 @@ typestr(int c)
void
servefile(const char *server, const char *port, const char *path, const char *query)
{
- char buf[1024];
+ char buf[READ_BUF_SIZ];
int r, w;
size_t totalsiz = 0;
@@ -484,7 +499,7 @@ servedir(const char *server, const char *port, const char *path, const char *que
struct visited v;
struct linebuf lb;
const char *prefix = "";
- char buf[1024], uri[2048];
+ char buf[1024], *uri;
char *line;
size_t totalsiz, linenr;
ssize_t n;
@@ -507,11 +522,11 @@ servedir(const char *server, const char *port, const char *path, const char *que
die(500, "servedir: writebuf failed\n");
linebuf_init(&lb);
- line = lb.line;
totalsiz = 0;
-
for (linenr = 1; (n = linebuf_get(&lb)) > 0; linenr++) {
+ line = lb.line;
+
/* too big total response */
if (n > 0)
totalsiz += n;
@@ -593,11 +608,12 @@ servedir(const char *server, const char *port, const char *path, const char *que
}
if (!strcmp(v.port, "70"))
- snprintf(uri, sizeof(uri), "%s%s/%c%s",
+ snprintf(buf, sizeof(buf), "%s%s/%c%s",
prefix, v.server, primarytype, v.path);
else
- snprintf(uri, sizeof(uri), "%s%s:%s/%c%s",
+ snprintf(buf, sizeof(buf), "%s%s:%s/%c%s",
prefix, v.server, v.port, primarytype, v.path);
+ uri = buf;
switch (primarytype) {
case 'i': /* info */