mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 20:28:56 +00:00
cgi handler nearly finished
This commit is contained in:
parent
e404b423de
commit
5fe0874c5c
3 changed files with 233 additions and 1 deletions
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ LDFLAGS = -lpthread -lrt
|
||||||
|
|
||||||
BIN_NAME = cfloor
|
BIN_NAME = cfloor
|
||||||
|
|
||||||
OBJS = obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o obj/status.o obj/files.o obj/mime.o
|
OBJS = obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o obj/status.o obj/files.o obj/mime.o obj/cgi.o
|
||||||
DEPS = $(OBJS:%.o=%.d)
|
DEPS = $(OBJS:%.o=%.d)
|
||||||
|
|
||||||
all: $(BIN_NAME)
|
all: $(BIN_NAME)
|
||||||
|
|
220
src/cgi.c
220
src/cgi.c
|
@ -0,0 +1,220 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "cgi.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "files.h"
|
||||||
|
#include "status.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "headers.h"
|
||||||
|
#define EXIT_EXEC_FAILED (255)
|
||||||
|
|
||||||
|
static inline void setEnvStatic(const char* envname, const char* value) {
|
||||||
|
if (setenv(envname, value, true) < 0)
|
||||||
|
exit(EXIT_EXEC_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setEnvFromHeader(struct headers* headers, const char* envname, const char* headerKey) {
|
||||||
|
const char* tmp = headers_get(headers, headerKey);
|
||||||
|
setEnvStatic(envname, tmp == NULL ? "" : tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cgiHandler(struct request request, struct response response) {
|
||||||
|
struct cgiSettings* settings = (struct cgiSettings*) request.userData.ptr;
|
||||||
|
const char* documentRoot = settings->documentRoot;
|
||||||
|
|
||||||
|
char* path = normalizePath(request, response, documentRoot);
|
||||||
|
if (path == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (access(path, F_OK | X_OK) < 0) {
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
switch(errno) {
|
||||||
|
case EACCES:
|
||||||
|
warn("cgi: file is not executable");
|
||||||
|
status(request, response, 403);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
// this should not happen
|
||||||
|
error("cgi: Couldn't access file: %s", strerror(errno));
|
||||||
|
status(request, response, 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pipefd[2];
|
||||||
|
|
||||||
|
if (pipe(&(pipefd[0])) < 0) {
|
||||||
|
error("cgi: failed to create pipe: %s", strerror(errno));
|
||||||
|
status(request, response, 500);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
error("cgi: failed to fork: %s", strerror(errno));
|
||||||
|
status(request, response, 500);
|
||||||
|
} else if (pid > 0) {
|
||||||
|
// child
|
||||||
|
// logging is thread-only
|
||||||
|
// so no logging from here on out.
|
||||||
|
|
||||||
|
if (dup2(request.fd, 0) < 0) {
|
||||||
|
exit(EXIT_EXEC_FAILED);
|
||||||
|
}
|
||||||
|
if (dup2(pipefd[1], 1) < 0) {
|
||||||
|
exit(EXIT_EXEC_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headers* headers = request.headers;
|
||||||
|
|
||||||
|
setEnvStatic("GATEWAY_INTERFACE", "CGI/1.1");
|
||||||
|
setEnvStatic("DOCUMENT_ROOT", documentRoot);
|
||||||
|
setEnvStatic("HTTPS", request.bind.tls ? "on" : "off");
|
||||||
|
setEnvStatic("QUERY_STRING", request.metaData.queryString);
|
||||||
|
setEnvStatic("REQUEST_METHOD", methodString(request.metaData));
|
||||||
|
setEnvStatic("REQUEST_URI", request.metaData.uri);
|
||||||
|
setEnvStatic("REMOTE_ADDR", request.peer.addr);
|
||||||
|
setEnvStatic("REMOTE_HOST", request.peer.name);
|
||||||
|
setEnvStatic("REMOTE_PORT", request.peer.portStr);
|
||||||
|
setEnvStatic("SCRIPT_NAME", request.metaData.path);
|
||||||
|
setEnvStatic("SERVER_PROTOCOL", protocolString(request.metaData));
|
||||||
|
|
||||||
|
setEnvStatic("SERVER_NAME", ""); // TODO maybe bind addr?
|
||||||
|
setEnvStatic("SERVER_ADMIN", ""); // TODO
|
||||||
|
setEnvStatic("SERVER_ADDR", ""); // TODO
|
||||||
|
setEnvStatic("SERVER_PORT", ""); // TODO
|
||||||
|
setEnvStatic("SERVER_SIGNATURE", ""); // TODO
|
||||||
|
setEnvStatic("SERVER_SOFTWARE", ""); // TODO
|
||||||
|
|
||||||
|
setEnvStatic("REDIRECT_REMOTE_USER", ""); // TODO not implemented
|
||||||
|
setEnvStatic("REMOTE_USER", ""); // TODO not implemented
|
||||||
|
|
||||||
|
setEnvFromHeader(headers, "HTTP_ACCEPT_CHARSET", "Accept-Charset");
|
||||||
|
setEnvFromHeader(headers, "HTTP_ACCEPT_ENCODING", "Accept-Encoding");
|
||||||
|
setEnvFromHeader(headers, "HTTP_ACCEPT_LANGUAGE", "Accept-Language");
|
||||||
|
setEnvFromHeader(headers, "HTTP_CONNECTION", "Accept-Connection");
|
||||||
|
setEnvFromHeader(headers, "HTTP_ACCEPT", "Accept");
|
||||||
|
setEnvFromHeader(headers, "HTTP_HOST", "Host");
|
||||||
|
setEnvFromHeader(headers, "HTTP_USER_AGENT", "User-Agent");
|
||||||
|
setEnvFromHeader(headers, "HTTP_COOKIE", "Cookie");
|
||||||
|
setEnvFromHeader(headers, "CONTENT_TYPE", "Content-Type");
|
||||||
|
setEnvFromHeader(headers, "CONTENT_LENGTH", "Content-Length");
|
||||||
|
|
||||||
|
execl(path, path, NULL);
|
||||||
|
|
||||||
|
exit(EXIT_EXEC_FAILED);
|
||||||
|
} else {
|
||||||
|
// parent
|
||||||
|
info("cgi: child started successfully");
|
||||||
|
|
||||||
|
#define LOCAL_BUFFER_LENGTH (512)
|
||||||
|
|
||||||
|
char buffer[LOCAL_BUFFER_LENGTH];
|
||||||
|
int bufferIndex = 0;
|
||||||
|
|
||||||
|
int statusCode = 0;
|
||||||
|
bool wasLineEnd = false;
|
||||||
|
bool finished = false;
|
||||||
|
|
||||||
|
struct headers headers = headers_create();
|
||||||
|
|
||||||
|
char c;
|
||||||
|
while((read(pipefd[0], &c, 1)) > 0) {
|
||||||
|
bool malformed = false;
|
||||||
|
|
||||||
|
if (bufferIndex >= LOCAL_BUFFER_LENGTH - 1)
|
||||||
|
malformed = true;
|
||||||
|
else if (c == '\r')
|
||||||
|
continue;
|
||||||
|
else if (c == '\n') {
|
||||||
|
if (wasLineEnd) {
|
||||||
|
finished = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[bufferIndex] = '\0';
|
||||||
|
bufferIndex = 0;
|
||||||
|
|
||||||
|
if (statusCode == 0) {
|
||||||
|
char* endptr;
|
||||||
|
|
||||||
|
statusCode = strtol(&(buffer[0]), &endptr, 10);
|
||||||
|
|
||||||
|
if (endptr != '\0') {
|
||||||
|
malformed = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (headers_parse(&headers, &(buffer[0]), bufferIndex) < 0) {
|
||||||
|
malformed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasLineEnd = true;
|
||||||
|
} else {
|
||||||
|
wasLineEnd = false;
|
||||||
|
|
||||||
|
buffer[bufferIndex++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (malformed) {
|
||||||
|
error("cgi: response malformed");
|
||||||
|
|
||||||
|
finished = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!finished) {
|
||||||
|
error("cgi: error while reading header");
|
||||||
|
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
waitpid(pid, &statusCode, 0);
|
||||||
|
|
||||||
|
close(pipefd[0]);
|
||||||
|
close(pipefd[1]);
|
||||||
|
|
||||||
|
status(request, response, 500);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
headers_free(&headers);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pipefd[0]);
|
||||||
|
|
||||||
|
int fd = response.sendHeader(statusCode, &headers, &request);
|
||||||
|
|
||||||
|
headers_free(&headers);
|
||||||
|
|
||||||
|
// start copy thread
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
if (waitpid(pid, &statusCode, 0) < 1) {
|
||||||
|
error("cgi: error while waiting for child: %s", strerror(errno));
|
||||||
|
status(request, response, 500);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WIFEXISTED has to be true
|
||||||
|
statusCode = WEXITSTATUS(statusCode);
|
||||||
|
|
||||||
|
if (statusCode == EXIT_EXEC_FAILED) {
|
||||||
|
error("cgi: child exit code indicates that exec failed");
|
||||||
|
status(request, response, 500);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/cgi.h
12
src/cgi.h
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef CGI_H
|
||||||
|
#define CGI_H
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
struct cgiSettings {
|
||||||
|
const char* documentRoot;
|
||||||
|
};
|
||||||
|
|
||||||
|
void cgiHandler(struct request, struct response);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue