diff --git a/src/include/responses.h b/src/include/responses.h index cb8e250..1b1219b 100644 --- a/src/include/responses.h +++ b/src/include/responses.h @@ -21,6 +21,4 @@ #include int sendResponse(Connection *conn, Sitefile *site); -//This function assumes that every field in conn has been initialized, and -//resets conn for the next request #endif diff --git a/src/include/responseutil.h b/src/include/responseutil.h new file mode 100644 index 0000000..292484d --- /dev/null +++ b/src/include/responseutil.h @@ -0,0 +1,30 @@ +/* + swebs - a simple web server + Copyright (C) 2022 Nate Choe + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _HAVE_RESPONSE_UTIL +#define _HAVE_RESPONSE_UTIL +#include + +#define ERROR_403 "403 Forbidden" +#define ERROR_404 "404 Not Found" +#define ERROR_500 "500 Internal Server Error" + +int sendStringResponse(Connection *conn, char *status, char *str); +int sendBinaryResponse(Connection *conn, char *status, void *data, size_t len); +int sendErrorResponse(Connection *conn, char *error); +//sendErrorResponse(conn, "404 Not found"); +#endif diff --git a/src/responses.c b/src/responses.c index 81392cf..3b4f2f9 100644 --- a/src/responses.c +++ b/src/responses.c @@ -15,59 +15,49 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #include #include -#include #include + +#include #include #include #include #include - -static int sendConnection(Connection *conn, char *format, ...) { - va_list ap; - va_start(ap, format); - int len = vsnprintf(NULL, 0, format, ap); - char *data = malloc(len + 1); - if (data == NULL) - return 1; - - va_end(ap); - va_start(ap, format); - - vsnprintf(data, len + 1, format, ap); - if (write(conn->fd, data, len) < len) { - free(data); - return 1; - } - free(data); - return 0; -} +#include static void readResponse(Connection *conn, char *path) { FILE *file; struct stat statbuf; - if (stat(path, &statbuf)) + if (stat(path, &statbuf)) { + sendErrorResponse(conn, ERROR_404); return; + } if (S_ISDIR(statbuf.st_mode)) { long reqPathLen = strlen(conn->path); long pathLen = strlen(path); char *assembledPath = malloc(reqPathLen + pathLen + 1); if (assembledPath == NULL) - return; + goto error; memcpy(assembledPath, path, pathLen); memcpy(assembledPath + pathLen, conn->path, reqPathLen + 1); char requestPath[PATH_MAX]; if (realpath(assembledPath, requestPath) == NULL) { + if (errno == ENOENT) { + free(assembledPath); + sendErrorResponse(conn, ERROR_404); + return; + } free(assembledPath); - return; + goto error; } char responsePath[PATH_MAX]; if (realpath(path, responsePath) == NULL) { free(assembledPath); - return; + goto error; } size_t responsePathLen = strlen(responsePath); if (memcmp(requestPath, responsePath, responsePathLen)) { @@ -76,45 +66,34 @@ static void readResponse(Connection *conn, char *path) { } file = fopen(requestPath, "r"); + puts(requestPath); free(assembledPath); } else file = fopen(path, "r"); - if (file == NULL) { + if (file == NULL) goto forbidden; - } fseek(file, 0, SEEK_END); long len = ftell(file); char *data = malloc(len); if (data == NULL) return; fseek(file, 0, SEEK_SET); - if (fread(data, 1, len, file) < len) + if (fread(data, 1, len, file) < len) { + fclose(file); goto error; + } fclose(file); - sendConnection(conn, - "HTTP/1.1 200 OK\r\n" - "Server: swebs/0.1\r\n" - "Content-Length: %ld\r\n" - "\r\n", len - ); - if (write(conn->fd, data, len) < len) + if (sendBinaryResponse(conn, "200 OK", data, len) < len) goto error; free(data); fsync(conn->fd); return; error: - fclose(file); + sendErrorResponse(conn, ERROR_500); return; forbidden: - sendConnection(conn, - "HTTP/1.1 403 Forbidden\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Server: swebs/0.1\r\n" - "Content-Length: 21\r\n" - "\r\n" - "

Invalid page

\n" - ); + sendErrorResponse(conn, ERROR_403); return; } @@ -133,14 +112,7 @@ int sendResponse(Connection *conn, Sitefile *site) { } } } - sendConnection(conn, - "HTTP/1.1 404 Not Found\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Server: swebs/0.1\r\n" - "Content-Length: 24\r\n" - "\r\n" - "

File not found

\n" - ); + sendErrorResponse(conn, ERROR_404); end: resetConnection(conn); return 0; diff --git a/src/responseutil.c b/src/responseutil.c new file mode 100644 index 0000000..d3f7c6e --- /dev/null +++ b/src/responseutil.c @@ -0,0 +1,87 @@ +/* + swebs - a simple web server + Copyright (C) 2022 Nate Choe + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CONST_FIELDS "Server: swebs/0.1\r\n" + +static int sendConnection(Connection *conn, char *format, ...) { + va_list ap; + va_start(ap, format); + int len = vsnprintf(NULL, 0, format, ap); + char *data = malloc(len + 1); + if (data == NULL) + return 1; + + va_end(ap); + va_start(ap, format); + + vsprintf(data, format, ap); + if (write(conn->fd, data, len) < len) { + free(data); + return 1; + } + free(data); + return 0; +} + +int sendStringResponse(Connection *conn, char *status, char *str) { + return sendConnection(conn, + "HTTP/1.1 %s\r\n" + CONST_FIELDS + "Content-Length: %lu\r\n" + "\r\n" + "%s" + , status, strlen(str), str + ); +} + +int sendErrorResponse(Connection *conn, char *error) { + const char *template = + "" + "

" + "%s" + "

"; + int len = snprintf(NULL, 0, template, error); + char *response = malloc(len + 1); + sprintf(response, template, error); + int ret = sendStringResponse(conn, error, response); + free(response); + return ret; +} + +int sendBinaryResponse(Connection *conn, char *status, + void *data, size_t len) { + if (sendConnection(conn, + "HTTP/1.1 %s\r\n" + CONST_FIELDS + "Content-Length: %lu\r\n" + "\r\n" + , status, len) + ) + return 1; + return write(conn->fd, data, len) < len; +}