1
0
mirror of https://git.sr.ht/~sircmpwn/gmnisrv synced 2024-06-01 17:21:10 +00:00

Serve files from root

This commit is contained in:
Drew DeVault 2020-09-26 14:36:52 -04:00
parent 0d6eca2c79
commit dfab99ace5
4 changed files with 119 additions and 11 deletions

1
configure vendored
View File

@ -9,6 +9,7 @@ gmnisrv() {
src/ini.c \
src/log.c \
src/main.c \
src/mime.c \
src/server.c \
src/tls.c \
src/url.c \

6
include/mime.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef GMNISRV_MIME
#define GMNISRV_MIME
const char *gmnisrv_mimetype_for_path(const char *path);
#endif

30
src/mime.c Normal file
View File

@ -0,0 +1,30 @@
#include <stdbool.h>
#include <string.h>
#include "mime.h"
static bool
has_suffix(const char *str, const char *suff)
{
size_t a = strlen(str), b = strlen(suff);
if (a < b) {
return false;
}
return strncmp(&str[a - b], suff, b) == 0;
}
const char *
gmnisrv_mimetype_for_path(const char *path)
{
// TODO: Read /etc/mime.types
// TODO: Consider adding content-disposition fields like filename
if (has_suffix(path, ".gmi") || has_suffix(path, ".gemini")) {
return "text/gemini";
}
if (has_suffix(path, ".txt")) {
return "text/plain";
}
if (has_suffix(path, ".png")) {
return "image/png";
}
return "application/octet-stream";
}

View File

@ -13,6 +13,7 @@
#include "config.h"
#include "gemini.h"
#include "log.h"
#include "mime.h"
#include "server.h"
#include "tls.h"
#include "url.h"
@ -307,6 +308,45 @@ exit:
return true;
}
static void
serve_request(struct gmnisrv_client *client)
{
struct gmnisrv_host *host = client->host;
assert(host);
assert(host->root); // TODO: reverse proxy support
char path[PATH_MAX + 1];
int n = snprintf(path, sizeof(path), "%s%s", host->root, client->path);
if ((size_t)n >= sizeof(path)) {
client_submit_response(client, GEMINI_STATUS_PERMANENT_FAILURE,
"Request path exceeds PATH_MAX", -1);
return;
}
if (path[strlen(path) - 1] == '/') {
// TODO: Let user configure index file name?
strncat(path, "index.gmi", sizeof(path) - 1);
}
int fd = open(path, O_RDONLY);
if (fd == -1) {
if (errno == ENOENT) {
client_submit_response(client, GEMINI_STATUS_NOT_FOUND,
"Not found", -1);
return;
} else {
client_error(&client->addr, "error opening %s: %s",
path, strerror(errno));
client_submit_response(client, GEMINI_STATUS_PERMANENT_FAILURE,
"Internal server error", -1);
return;
}
}
const char *meta = gmnisrv_mimetype_for_path(path);
client_submit_response(client, GEMINI_STATUS_SUCCESS, meta, fd);
}
static void
client_readable(struct gmnisrv_server *server, struct gmnisrv_client *client)
{
@ -347,10 +387,7 @@ client_readable(struct gmnisrv_server *server, struct gmnisrv_client *client)
return;
}
// TODO: prep response
const char *error = "TODO: Finish implementation";
client_submit_response(client,
GEMINI_STATUS_TEMPORARY_FAILURE, error, -1);
serve_request(client);
}
static void
@ -376,24 +413,58 @@ client_writable(struct gmnisrv_server *server, struct gmnisrv_client *client)
return;
}
client->status = GEMINI_STATUS_NONE;
client_error(&client->addr, "SSL read error %s, disconnecting",
ERR_error_string(r, NULL));
client_error(&client->addr,
"header write error %s, disconnecting",
ERR_error_string(r, NULL));
disconnect_client(server, client);
return;
}
client->bufix += r;
if (client->bufix >= client->bufln) {
// TODO: Start sending response body as well
disconnect_client(server, client);
if (client->bodyfd == -1) {
disconnect_client(server, client);
} else {
client->state = RESPOND_BODY;
client->bufix = client->bufln = 0;
}
return;
}
break;
case RESPOND_BODY:
assert(0);
if (client->bufix >= client->bufln) {
n = read(client->bodyfd,
client->buf, sizeof(client->buf));
if (n == -1) {
client_error(&client->addr,
"Error reading response body: %s",
strerror(errno));
disconnect_client(server, client);
return;
}
if (n == 0) {
// EOF
disconnect_client(server, client);
return;
}
client->bufln = n;
client->bufix = 0;
}
r = BIO_write(client->sbio, &client->buf[client->bufix],
client->bufln - client->bufix);
if (r <= 0) {
r = SSL_get_error(client->ssl, r);
if (r == SSL_ERROR_WANT_WRITE) {
return;
}
client->status = GEMINI_STATUS_NONE;
client_error(&client->addr, "body write error %s, disconnecting",
ERR_error_string(r, NULL));
disconnect_client(server, client);
return;
}
client->bufix += r;
break;
}
(void)server;
}
static long