moved functions around
This commit is contained in:
@@ -16,6 +16,7 @@ COPY entrypoint.sh /
|
|||||||
COPY content/ /var/www/html
|
COPY content/ /var/www/html
|
||||||
|
|
||||||
RUN mkdir -p /var/log/seaweb
|
RUN mkdir -p /var/log/seaweb
|
||||||
|
RUN touch /var/log/seaweb/log
|
||||||
|
|
||||||
WORKDIR /src/
|
WORKDIR /src/
|
||||||
|
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -42,5 +42,8 @@ dockerBuild: output_dir
|
|||||||
dockerTestDeploy: dockerBuild
|
dockerTestDeploy: dockerBuild
|
||||||
docker run -p8080:8080 --rm -d seaweb:latest
|
docker run -p8080:8080 --rm -d seaweb:latest
|
||||||
|
|
||||||
|
dockerReleaseDeploy: dockerBuild
|
||||||
|
docker run -p8080:8080 --rm -d seaweb:latest --cert /src/certs/cert.pem --privkey /src/certs/key.pem
|
||||||
|
|
||||||
killTestDocker:
|
killTestDocker:
|
||||||
docker stop -t 0 `docker ps | grep "seaweb:latest" | tail -n 1 | tr -s " " | cut -d " " -f 1`
|
docker stop -t 0 `docker ps | grep "seaweb:latest" | tail -n 1 | tr -s " " | cut -d " " -f 1`
|
||||||
|
|||||||
30
README.md
Normal file
30
README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# SeaWeb
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
It is recommended to run this application using Docker.
|
||||||
|
For a deployment running the application without HTTPS run `make dockerTestDeploy`, this will open a socket on port 8080.
|
||||||
|
For a deployment running the application with HTTPS run `make dockerReleaseDeploy`, this will also open a socket on port 8080.
|
||||||
|
Running `make killTestDocker` will kill the running instance of seaweb:latest running in Docker.
|
||||||
|
To view logs within the running container run `docker exec -it $(docker ps | grep "seaweb:latest" | grep -o '[^ ]*$') tail -f /var/log/seaweb/log`, or manually view the `/var/log/seaweb/log` file.
|
||||||
|
|
||||||
|
If you run this application without Docker please ensure the OpenSSL development headers are installed onto your system, this will be important if running with HTTPS.
|
||||||
|
|
||||||
|
To build this application outside of Docker run `make`, and the binary will be build into `./bin`.
|
||||||
|
Running `./bin/seaweb --help` or `./bin/seaweb -h` will show you the help message for the application showing all possible options.
|
||||||
|
|
||||||
|
By default the application is compiled to utilize `/var/www/html` as the WEB root, and will output logs to `/var/log/seaweb/log`; if running the application outside of Docker please ensure this is setup with correct permissions to run.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- All new connections will spawn a child process which is used to deal with the request
|
||||||
|
- If the process takes longer than 5 seconds to resolve the request, the child process will be killed
|
||||||
|
- php-cgi seems to randomly return empty data from scripts without throwing an error message (these are caught and a HTTP 500 response is return)
|
||||||
|
- If the request is made again it will eventually return correct data (this seems to be an issue with php-cgi and not this application)
|
||||||
|
- Running `make genCerts` will generate a root authority and generate certificates to utilize for the web server
|
||||||
|
- Certificate authority related files start with `ca` while the certificates which should be utilized for the web server omit the `ca`
|
||||||
|
- Making a request to the web server which does not match the current protocol (e.g. making a https request when it is server http) will result in the server ignoring the request
|
||||||
|
- Returning an error here is not possible since if we have a none SSL socket created we cannot respond to a SSL request
|
||||||
|
- This will cause a fork of the process to spawn which will be killed in 5 seconds after the timeout is met
|
||||||
|
- If a request to the root directory is made, `/`, it is assumed that the user was trying to navigate to `/index.html` and the request will be treated as such
|
||||||
|
|
||||||
257
cmd/server.c
257
cmd/server.c
@@ -15,6 +15,7 @@
|
|||||||
#include "returnRequest.h"
|
#include "returnRequest.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "requestHandlers.h"
|
||||||
|
|
||||||
#define WEB_ROOT "/var/www/html/"
|
#define WEB_ROOT "/var/www/html/"
|
||||||
//#define WEB_ROOT "content/"
|
//#define WEB_ROOT "content/"
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
|
|
||||||
static int verbose_flag = 0;
|
static int verbose_flag = 0;
|
||||||
bool enableHTTPS = 0;
|
bool enableHTTPS = 0;
|
||||||
|
char *WEB_ROOT_DIR = NULL;
|
||||||
|
|
||||||
static int timeout = 0;
|
static int timeout = 0;
|
||||||
|
|
||||||
@@ -32,91 +34,6 @@ int printDebug(char message[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *php_cgi(char *sPath, struct HTTPRequest *r) {
|
|
||||||
int phpPipe[2];
|
|
||||||
char *buf = NULL;
|
|
||||||
size_t bufLen = 1024;
|
|
||||||
|
|
||||||
buf = malloc(bufLen);
|
|
||||||
pipe(phpPipe);
|
|
||||||
|
|
||||||
pid_t pid;
|
|
||||||
int status = 0;
|
|
||||||
pid = fork();
|
|
||||||
|
|
||||||
if (pid == 0) { // Child fork
|
|
||||||
char script[500];
|
|
||||||
char *queryString = NULL;
|
|
||||||
close(phpPipe[0]);
|
|
||||||
dup2(phpPipe[1], STDOUT_FILENO);
|
|
||||||
strcpy(script, "SCRIPT_FILENAME=");
|
|
||||||
strcat(script, WEB_ROOT);
|
|
||||||
strcat(script, sPath);
|
|
||||||
putenv("GATEWAY_INTERFACE=CGI/1.1");
|
|
||||||
putenv(script);
|
|
||||||
putenv("REDIRECT_STATUS=true");
|
|
||||||
putenv("SERVER_PROTOCOL=HTTP/1.1");
|
|
||||||
putenv("REMOTE_HOST=127.0.0.1");
|
|
||||||
if (!strcmp(r->requestType, "POST")) {
|
|
||||||
putenv("REQUEST_METHOD=POST");
|
|
||||||
char conLenString[256];
|
|
||||||
sprintf(conLenString, "CONTENT_LENGTH=%zu", r->requestBodyLen);
|
|
||||||
putenv(conLenString);
|
|
||||||
putenv("CONTENT_TYPE=application/x-www-form-urlencoded");
|
|
||||||
queryString = malloc(r->requestBodyLen + 24);
|
|
||||||
sprintf(queryString, "QUERY_STRING=%s", r->requestBody);
|
|
||||||
putenv(queryString);
|
|
||||||
|
|
||||||
// Starting fork to pipe stdin into php-cgi
|
|
||||||
int phpPipe2[2];
|
|
||||||
pipe(phpPipe2);
|
|
||||||
pid_t pid2;
|
|
||||||
pid2 = fork();
|
|
||||||
|
|
||||||
if (pid2 == 0) { // Child fork
|
|
||||||
close(phpPipe2[0]);
|
|
||||||
dup2(phpPipe2[1], STDOUT_FILENO);
|
|
||||||
printf("%s", r->requestBody);
|
|
||||||
close(phpPipe2[1]);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
} else if (pid < 0) { // Error forking
|
|
||||||
printDebug("Error in stdin php frok");
|
|
||||||
} else { // Parent fork
|
|
||||||
close(phpPipe[1]);
|
|
||||||
dup2(phpPipe2[0], STDIN_FILENO);
|
|
||||||
execlp("/usr/bin/php-cgi", "php-cgi", NULL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
queryString = malloc(strlen(r->requestVars) + 24);
|
|
||||||
sprintf(queryString, "QUERY_STRING=%s", r->requestVars);
|
|
||||||
putenv(queryString);
|
|
||||||
putenv("REQUEST_METHOD=GET");
|
|
||||||
execl("/usr/bin/php-cgi", "php-cgi", NULL);
|
|
||||||
}
|
|
||||||
} else if (pid < 0) { // Error forking
|
|
||||||
printDebug("Error forking php exec");
|
|
||||||
} else { // Parent fork
|
|
||||||
size_t buffCount;
|
|
||||||
close(phpPipe[1]);
|
|
||||||
do {
|
|
||||||
buffCount = read(phpPipe[0], buf, BUFF_READ);
|
|
||||||
if (strlen(buf) == bufLen) {
|
|
||||||
bufLen *= 2;
|
|
||||||
buf = realloc(buf, bufLen);
|
|
||||||
}
|
|
||||||
} while (buffCount == 0);
|
|
||||||
do {
|
|
||||||
waitpid(pid, &status, WUNTRACED);
|
|
||||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
close(phpPipe[0]);
|
|
||||||
if (status != 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
||||||
char temp[1]; // Used to check newlines
|
char temp[1]; // Used to check newlines
|
||||||
char *token = calloc(8, sizeof(char));
|
char *token = calloc(8, sizeof(char));
|
||||||
@@ -219,171 +136,6 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
||||||
char errResponse[256];
|
|
||||||
char ch;
|
|
||||||
size_t size = 8;
|
|
||||||
int i = 0;
|
|
||||||
unsigned char *fileContent = calloc(size, sizeof(unsigned char));
|
|
||||||
FILE *fp;
|
|
||||||
char *workingReqDir;
|
|
||||||
|
|
||||||
char *phpReturn = NULL;
|
|
||||||
char phpEnd[5] = ".php";
|
|
||||||
bool endsWithPhp = false;
|
|
||||||
if (strlen(phpEnd) <= strlen(r->requestDir)) {
|
|
||||||
for (int i = 0; i < strlen(phpEnd); i++) {
|
|
||||||
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
|
|
||||||
endsWithPhp = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
endsWithPhp = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endsWithPhp) {
|
|
||||||
phpReturn = php_cgi(r->requestDir, r);
|
|
||||||
if (phpReturn != NULL) {
|
|
||||||
return returnPHPRequest(socket, phpReturn, ssl);
|
|
||||||
} else {
|
|
||||||
return return500Request(socket, ssl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If requesting root directory change to index.html
|
|
||||||
if (!strcmp(r->requestDir, "/")) {
|
|
||||||
workingReqDir = "index.html";
|
|
||||||
} else {
|
|
||||||
workingReqDir = r->requestDir;
|
|
||||||
}
|
|
||||||
char *reqDir = calloc((strlen(WEB_ROOT) + strlen(workingReqDir) + 1), sizeof(char));
|
|
||||||
|
|
||||||
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
|
|
||||||
|
|
||||||
fp = fopen(reqDir, "r");
|
|
||||||
|
|
||||||
if (fp == NULL) {
|
|
||||||
sprintf(errResponse, "Error opening file: %s", workingReqDir);
|
|
||||||
printDebug(errResponse);
|
|
||||||
return404Request(socket, ssl);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((ch = fgetc(fp)) != EOF) {
|
|
||||||
if (i == size) {
|
|
||||||
size *= 2;
|
|
||||||
fileContent = realloc(fileContent, size);
|
|
||||||
}
|
|
||||||
fileContent[i] = ch;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return200Request(socket, fileContent, ssl);
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
free(reqDir);
|
|
||||||
free(fileContent);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
||||||
FILE *fp;
|
|
||||||
char *reqDir;
|
|
||||||
char * workingReqDir;
|
|
||||||
char errResponse[256];
|
|
||||||
|
|
||||||
if (!strcmp(r->requestDir, "/")) {
|
|
||||||
workingReqDir = "index.html";
|
|
||||||
} else {
|
|
||||||
workingReqDir = r->requestDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
reqDir = calloc(strlen(WEB_ROOT) + strlen(workingReqDir), sizeof(char));
|
|
||||||
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
|
|
||||||
|
|
||||||
fp = fopen(reqDir, "w");
|
|
||||||
if (fp == NULL) {
|
|
||||||
sprintf(errResponse, "Error opening file: %s", workingReqDir);
|
|
||||||
printDebug(errResponse);
|
|
||||||
return return404Request(socket, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "%s", r->requestBody);
|
|
||||||
|
|
||||||
free(reqDir);
|
|
||||||
fclose(fp);
|
|
||||||
return return201Request(socket, r->requestBody, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
||||||
char *reqDir;
|
|
||||||
char * workingReqDir;
|
|
||||||
char logLine[256];
|
|
||||||
|
|
||||||
if (!strcmp(r->requestDir, "/")) {
|
|
||||||
workingReqDir = "index.html";
|
|
||||||
} else {
|
|
||||||
workingReqDir = r->requestDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
reqDir = calloc(strlen(WEB_ROOT) + strlen(workingReqDir), sizeof(char));
|
|
||||||
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
|
|
||||||
|
|
||||||
if (remove(reqDir) == 0) {
|
|
||||||
sprintf(logLine, "Deleted file");
|
|
||||||
free(reqDir);
|
|
||||||
return return200Request(socket, NULL, ssl);
|
|
||||||
} else {
|
|
||||||
printDebug("Failed to delete file");
|
|
||||||
free(reqDir);
|
|
||||||
if (errno == 1) { // Permission denided
|
|
||||||
return return403Request(socket, ssl);
|
|
||||||
} else { // Catch all (likely file != exist)
|
|
||||||
return return404Request(socket, ssl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
||||||
char *phpReturn = NULL;
|
|
||||||
// Supported data types application/x-www-form-urlencoded application/json
|
|
||||||
if (r->requestConLen == NULL) { // Return 411 if length var not specified
|
|
||||||
printDebug("Content Length was not sent in POST request");
|
|
||||||
return return411Request(socket, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->requestConType != NULL) {
|
|
||||||
if (!strcmp(r->requestConType, "application/x-www-form-utlencoded") == 0) {
|
|
||||||
printDebug("Application From Selected");
|
|
||||||
} else {
|
|
||||||
printDebug("Content will likely get parsed wrong");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char phpEnd[5] = ".php";
|
|
||||||
bool endsWithPhp = false;
|
|
||||||
if (strlen(phpEnd) <= strlen(r->requestDir)) {
|
|
||||||
for (int i = 0; i < strlen(phpEnd); i++) {
|
|
||||||
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
|
|
||||||
endsWithPhp = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
endsWithPhp = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endsWithPhp) {
|
|
||||||
phpReturn = php_cgi(r->requestDir, r);
|
|
||||||
if (phpReturn != NULL) {
|
|
||||||
return returnPHPRequest(socket, phpReturn, ssl);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return return200Request(socket, NULL, ssl);
|
|
||||||
}
|
|
||||||
return return500Request(socket, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int handleRequest(unsigned char buffer[], int socket, SSL *ssl) {
|
int handleRequest(unsigned char buffer[], int socket, SSL *ssl) {
|
||||||
struct HTTPRequest r; // Holds relevant HTTP request information
|
struct HTTPRequest r; // Holds relevant HTTP request information
|
||||||
r.requestConLen = malloc(sizeof(char));
|
r.requestConLen = malloc(sizeof(char));
|
||||||
@@ -453,6 +205,10 @@ int main(int argc, char **argv) {
|
|||||||
size_t bufSize = BUFF_READ;
|
size_t bufSize = BUFF_READ;
|
||||||
unsigned char *buffer = calloc(bufSize, sizeof(unsigned char));
|
unsigned char *buffer = calloc(bufSize, sizeof(unsigned char));
|
||||||
|
|
||||||
|
// Copy WEB_ROOT into extern value
|
||||||
|
WEB_ROOT_DIR = malloc(strlen(WEB_ROOT));
|
||||||
|
strcpy(WEB_ROOT_DIR, WEB_ROOT);
|
||||||
|
|
||||||
// Setting up options
|
// Setting up options
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
@@ -625,6 +381,7 @@ int main(int argc, char **argv) {
|
|||||||
free(certFile);
|
free(certFile);
|
||||||
free(listenAddr);
|
free(listenAddr);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
free(WEB_ROOT_DIR);
|
||||||
close(server_fd);
|
close(server_fd);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,4 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "$@"
|
exec seaweb "$@"
|
||||||
|
|
||||||
exec seaweb $@
|
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ struct HTTPRequest {
|
|||||||
unsigned char *requestBody;
|
unsigned char *requestBody;
|
||||||
size_t requestBodyLen;
|
size_t requestBodyLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
6
include/requestHandlers.h
Normal file
6
include/requestHandlers.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl);
|
||||||
|
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl);
|
||||||
|
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl);
|
||||||
|
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl);
|
||||||
|
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
extern bool enableHTTPS;
|
int printDebug(char message[]);
|
||||||
|
|
||||||
|
extern bool enableHTTPS;
|
||||||
|
extern char *WEB_ROOT_DIR;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
int PrintLog(unsigned char *message);
|
int PrintLog(unsigned char *message);
|
||||||
int checkHTTPVersion(char *version);
|
int checkHTTPVersion(char *version);
|
||||||
|
char *php_cgi(char *sPath, struct HTTPRequest *r);
|
||||||
|
|
||||||
|
|||||||
177
src/requestHandlers.c
Normal file
177
src/requestHandlers.c
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
//#include <unistd.h>
|
||||||
|
//#include <stdio.h>
|
||||||
|
//#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "httpStruct.h"
|
||||||
|
#include "returnRequest.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
||||||
|
char errResponse[256];
|
||||||
|
char ch;
|
||||||
|
size_t size = 8;
|
||||||
|
int i = 0;
|
||||||
|
unsigned char *fileContent = calloc(size, sizeof(unsigned char));
|
||||||
|
FILE *fp;
|
||||||
|
char *workingReqDir;
|
||||||
|
|
||||||
|
char *phpReturn = NULL;
|
||||||
|
char phpEnd[5] = ".php";
|
||||||
|
bool endsWithPhp = false;
|
||||||
|
if (strlen(phpEnd) <= strlen(r->requestDir)) {
|
||||||
|
for (int i = 0; i < strlen(phpEnd); i++) {
|
||||||
|
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
|
||||||
|
endsWithPhp = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
endsWithPhp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endsWithPhp) {
|
||||||
|
phpReturn = php_cgi(r->requestDir, r);
|
||||||
|
if (phpReturn != NULL) {
|
||||||
|
return returnPHPRequest(socket, phpReturn, ssl);
|
||||||
|
} else {
|
||||||
|
return return500Request(socket, ssl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If requesting root directory change to index.html
|
||||||
|
if (!strcmp(r->requestDir, "/")) {
|
||||||
|
workingReqDir = "index.html";
|
||||||
|
} else {
|
||||||
|
workingReqDir = r->requestDir;
|
||||||
|
}
|
||||||
|
char *reqDir = calloc((strlen(WEB_ROOT_DIR) + strlen(workingReqDir) + 1), sizeof(char));
|
||||||
|
|
||||||
|
sprintf(reqDir, "%s%s", WEB_ROOT_DIR, workingReqDir);
|
||||||
|
|
||||||
|
fp = fopen(reqDir, "r");
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
|
sprintf(errResponse, "Error opening file: %s", workingReqDir);
|
||||||
|
printDebug(errResponse);
|
||||||
|
return404Request(socket, ssl);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((ch = fgetc(fp)) != EOF) {
|
||||||
|
if (i == size) {
|
||||||
|
size *= 2;
|
||||||
|
fileContent = realloc(fileContent, size);
|
||||||
|
}
|
||||||
|
fileContent[i] = ch;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return200Request(socket, fileContent, ssl);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
free(reqDir);
|
||||||
|
free(fileContent);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
||||||
|
FILE *fp;
|
||||||
|
char *reqDir;
|
||||||
|
char * workingReqDir;
|
||||||
|
char errResponse[256];
|
||||||
|
|
||||||
|
if (!strcmp(r->requestDir, "/")) {
|
||||||
|
workingReqDir = "index.html";
|
||||||
|
} else {
|
||||||
|
workingReqDir = r->requestDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
reqDir = calloc(strlen(WEB_ROOT_DIR) + strlen(workingReqDir), sizeof(char));
|
||||||
|
sprintf(reqDir, "%s%s", WEB_ROOT_DIR, workingReqDir);
|
||||||
|
|
||||||
|
fp = fopen(reqDir, "w");
|
||||||
|
if (fp == NULL) {
|
||||||
|
sprintf(errResponse, "Error opening file: %s", workingReqDir);
|
||||||
|
printDebug(errResponse);
|
||||||
|
return return404Request(socket, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "%s", r->requestBody);
|
||||||
|
|
||||||
|
free(reqDir);
|
||||||
|
fclose(fp);
|
||||||
|
return return201Request(socket, r->requestBody, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
||||||
|
char *reqDir;
|
||||||
|
char * workingReqDir;
|
||||||
|
char logLine[256];
|
||||||
|
|
||||||
|
if (!strcmp(r->requestDir, "/")) {
|
||||||
|
workingReqDir = "index.html";
|
||||||
|
} else {
|
||||||
|
workingReqDir = r->requestDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
reqDir = calloc(strlen(WEB_ROOT_DIR) + strlen(workingReqDir), sizeof(char));
|
||||||
|
sprintf(reqDir, "%s%s", WEB_ROOT_DIR, workingReqDir);
|
||||||
|
|
||||||
|
if (remove(reqDir) == 0) {
|
||||||
|
sprintf(logLine, "Deleted file");
|
||||||
|
free(reqDir);
|
||||||
|
return return200Request(socket, NULL, ssl);
|
||||||
|
} else {
|
||||||
|
printDebug("Failed to delete file");
|
||||||
|
free(reqDir);
|
||||||
|
if (errno == 1) { // Permission denided
|
||||||
|
return return403Request(socket, ssl);
|
||||||
|
} else { // Catch all (likely file != exist)
|
||||||
|
return return404Request(socket, ssl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
||||||
|
char *phpReturn = NULL;
|
||||||
|
// Supported data types application/x-www-form-urlencoded application/json
|
||||||
|
if (r->requestConLen == NULL) { // Return 411 if length var not specified
|
||||||
|
printDebug("Content Length was not sent in POST request");
|
||||||
|
return return411Request(socket, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->requestConType != NULL) {
|
||||||
|
if (!strcmp(r->requestConType, "application/x-www-form-utlencoded") == 0) {
|
||||||
|
printDebug("Application From Selected");
|
||||||
|
} else {
|
||||||
|
printDebug("Content will likely get parsed wrong");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char phpEnd[5] = ".php";
|
||||||
|
bool endsWithPhp = false;
|
||||||
|
if (strlen(phpEnd) <= strlen(r->requestDir)) {
|
||||||
|
for (int i = 0; i < strlen(phpEnd); i++) {
|
||||||
|
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
|
||||||
|
endsWithPhp = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
endsWithPhp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endsWithPhp) {
|
||||||
|
phpReturn = php_cgi(r->requestDir, r);
|
||||||
|
if (phpReturn != NULL) {
|
||||||
|
return returnPHPRequest(socket, phpReturn, ssl);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return return200Request(socket, NULL, ssl);
|
||||||
|
}
|
||||||
|
return return500Request(socket, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -39,6 +39,12 @@ int return201Request(int socket, char *content, SSL *ssl) {
|
|||||||
return returnRequest(socket, message, 201, ssl);
|
return returnRequest(socket, message, 201, ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int return400Request(int socket, SSL *ssl) {
|
||||||
|
char *message = calloc(128, sizeof(char));
|
||||||
|
sprintf(message, "HTTP/1.1 400 HTTP Request Not Valid\nContent-Length: 0\nConnection: close\n\n");
|
||||||
|
return returnRequest(socket, message, 400, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
int return403Request(int socket, SSL *ssl) {
|
int return403Request(int socket, SSL *ssl) {
|
||||||
char *message = calloc(128, sizeof(char));
|
char *message = calloc(128, sizeof(char));
|
||||||
sprintf(message, "HTTP/1.1 403 Forbidden\nContent-Length: 0\nConnection: close\n\n");
|
sprintf(message, "HTTP/1.1 403 Forbidden\nContent-Length: 0\nConnection: close\n\n");
|
||||||
@@ -47,16 +53,10 @@ int return403Request(int socket, SSL *ssl) {
|
|||||||
|
|
||||||
int return404Request(int socket, SSL *ssl) {
|
int return404Request(int socket, SSL *ssl) {
|
||||||
char *message = calloc(128, sizeof(char));
|
char *message = calloc(128, sizeof(char));
|
||||||
sprintf(message, "HTTP/1.1 404 Not Found\nContent-Length: 12\nConnection: close\n\n404 Request\n\n");
|
sprintf(message, "HTTP/1.1 404 Not Found\nContent-Length: 13\nConnection: close\n\n404 Request\n\n");
|
||||||
return returnRequest(socket, message, 404, ssl);
|
return returnRequest(socket, message, 404, ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int return400Request(int socket, SSL *ssl) {
|
|
||||||
char *message = calloc(128, sizeof(char));
|
|
||||||
sprintf(message, "HTTP/1.1 400 HTTP Request Not Valid\nContent-Length: 0\nConnection: close\n\n");
|
|
||||||
return returnRequest(socket, message, 400, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int return411Request(int socket, SSL *ssl) {
|
int return411Request(int socket, SSL *ssl) {
|
||||||
char *message = calloc(128, sizeof(char));
|
char *message = calloc(128, sizeof(char));
|
||||||
sprintf(message, "HTTP/1.1 411 Length Required\nContent-Length: 0\nConnection: close\n\n");
|
sprintf(message, "HTTP/1.1 411 Length Required\nContent-Length: 0\nConnection: close\n\n");
|
||||||
|
|||||||
103
src/utils.c
103
src/utils.c
@@ -1,6 +1,14 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wait.h>
|
||||||
|
|
||||||
|
#include "server.h"
|
||||||
|
#include "httpStruct.h"
|
||||||
|
|
||||||
|
#define BUFF_READ 1024
|
||||||
|
|
||||||
#define NUM_SUPPORTED_VERSIONS 2
|
#define NUM_SUPPORTED_VERSIONS 2
|
||||||
static char supportedHTTPVersions[NUM_SUPPORTED_VERSIONS][16] = {
|
static char supportedHTTPVersions[NUM_SUPPORTED_VERSIONS][16] = {
|
||||||
@@ -14,8 +22,17 @@ int PrintLog(unsigned char *message) {
|
|||||||
time(&UTCTime);
|
time(&UTCTime);
|
||||||
struct tm *now = localtime(&UTCTime);
|
struct tm *now = localtime(&UTCTime);
|
||||||
|
|
||||||
|
if (!strcmp(WEB_ROOT_DIR, "/var/www/html/")) {
|
||||||
|
FILE *fp;
|
||||||
|
fp = fopen("/var/log/seaweb/log", "w");
|
||||||
|
fprintf(fp, "[Log] %02d/%02d/%d %02d:%02d:%02d - %s\n", (now->tm_mon + 1), now->tm_mday,
|
||||||
|
(now->tm_year + 1900), now->tm_hour, now->tm_min, now->tm_sec, message);
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
printf("[Log] %02d/%02d/%d %02d:%02d:%02d - %s\n", (now->tm_mon + 1), now->tm_mday,
|
printf("[Log] %02d/%02d/%d %02d:%02d:%02d - %s\n", (now->tm_mon + 1), now->tm_mday,
|
||||||
(now->tm_year + 1900), now->tm_hour, now->tm_min, now->tm_sec, message);
|
(now->tm_year + 1900), now->tm_hour, now->tm_min, now->tm_sec, message);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,3 +47,89 @@ int checkHTTPVersion(char *version) {
|
|||||||
}
|
}
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *php_cgi(char *sPath, struct HTTPRequest *r) {
|
||||||
|
int phpPipe[2];
|
||||||
|
char *buf = NULL;
|
||||||
|
size_t bufLen = 1024;
|
||||||
|
|
||||||
|
buf = malloc(bufLen);
|
||||||
|
pipe(phpPipe);
|
||||||
|
|
||||||
|
pid_t pid;
|
||||||
|
int status = 0;
|
||||||
|
pid = fork();
|
||||||
|
|
||||||
|
if (pid == 0) { // Child fork
|
||||||
|
char script[500];
|
||||||
|
char *queryString = NULL;
|
||||||
|
close(phpPipe[0]);
|
||||||
|
dup2(phpPipe[1], STDOUT_FILENO);
|
||||||
|
strcpy(script, "SCRIPT_FILENAME=");
|
||||||
|
strcat(script, WEB_ROOT_DIR);
|
||||||
|
strcat(script, sPath);
|
||||||
|
putenv("GATEWAY_INTERFACE=CGI/1.1");
|
||||||
|
putenv(script);
|
||||||
|
putenv("REDIRECT_STATUS=true");
|
||||||
|
putenv("SERVER_PROTOCOL=HTTP/1.1");
|
||||||
|
putenv("REMOTE_HOST=127.0.0.1");
|
||||||
|
if (!strcmp(r->requestType, "POST")) {
|
||||||
|
putenv("REQUEST_METHOD=POST");
|
||||||
|
char conLenString[256];
|
||||||
|
sprintf(conLenString, "CONTENT_LENGTH=%zu", r->requestBodyLen);
|
||||||
|
putenv(conLenString);
|
||||||
|
putenv("CONTENT_TYPE=application/x-www-form-urlencoded");
|
||||||
|
queryString = malloc(r->requestBodyLen + 24);
|
||||||
|
sprintf(queryString, "QUERY_STRING=%s", r->requestBody);
|
||||||
|
putenv(queryString);
|
||||||
|
|
||||||
|
// Starting fork to pipe stdin into php-cgi
|
||||||
|
int phpPipe2[2];
|
||||||
|
pipe(phpPipe2);
|
||||||
|
pid_t pid2;
|
||||||
|
pid2 = fork();
|
||||||
|
|
||||||
|
if (pid2 == 0) { // Child fork
|
||||||
|
close(phpPipe2[0]);
|
||||||
|
dup2(phpPipe2[1], STDOUT_FILENO);
|
||||||
|
printf("%s", r->requestBody);
|
||||||
|
close(phpPipe2[1]);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
} else if (pid < 0) { // Error forking
|
||||||
|
printDebug("Error in stdin php frok");
|
||||||
|
} else { // Parent fork
|
||||||
|
close(phpPipe[1]);
|
||||||
|
dup2(phpPipe2[0], STDIN_FILENO);
|
||||||
|
execlp("/usr/bin/php-cgi", "php-cgi", NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queryString = malloc(strlen(r->requestVars) + 24);
|
||||||
|
sprintf(queryString, "QUERY_STRING=%s", r->requestVars);
|
||||||
|
putenv(queryString);
|
||||||
|
putenv("REQUEST_METHOD=GET");
|
||||||
|
execl("/usr/bin/php-cgi", "php-cgi", NULL);
|
||||||
|
}
|
||||||
|
} else if (pid < 0) { // Error forking
|
||||||
|
printDebug("Error forking php exec");
|
||||||
|
} else { // Parent fork
|
||||||
|
size_t buffCount;
|
||||||
|
close(phpPipe[1]);
|
||||||
|
do {
|
||||||
|
buffCount = read(phpPipe[0], buf, BUFF_READ);
|
||||||
|
if (strlen(buf) == bufLen) {
|
||||||
|
bufLen *= 2;
|
||||||
|
buf = realloc(buf, bufLen);
|
||||||
|
}
|
||||||
|
} while (buffCount == 0);
|
||||||
|
do {
|
||||||
|
waitpid(pid, &status, WUNTRACED);
|
||||||
|
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
close(phpPipe[0]);
|
||||||
|
if (status != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user