165 lines
4.6 KiB
C++
165 lines
4.6 KiB
C++
#include "ServerThread.h"
|
|
|
|
using namespace std;
|
|
|
|
// entry point for all threads
|
|
char echo_buffer[100 *1024];
|
|
|
|
void getExecDir(char*dir) {
|
|
char* filename = nullptr;
|
|
if (readlink("/proc/self/exe", dir, 1024) < 0) {
|
|
dir[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
filename = strrchr(dir, '/');
|
|
if (filename == nullptr) {
|
|
dir[0] = '\0';
|
|
return;
|
|
}
|
|
++filename;
|
|
*filename = '\0';
|
|
sprintf(dir + strlen(dir), "%s", "index.html");
|
|
return;
|
|
}
|
|
|
|
void* run(void* obj) {
|
|
((ServerThread*) obj)->Run();
|
|
// when Run() finishes, mark for termination
|
|
((ServerThread*) obj)->MarkFT();
|
|
}
|
|
|
|
bool getExt(const char* path, char* ext) {
|
|
int l = strlen(path), i = l;
|
|
while (i > 0 && path[--i] != '.' && path[i] != '/');
|
|
if (i == 0 || path[i] == '/') return false;
|
|
for (int j = 0; i < l; ext[j++] = path[++i]);
|
|
return true;
|
|
}
|
|
|
|
int getHeader(char *header, const char *buffer, int rd) {
|
|
int hl = 0;
|
|
int i = 0;
|
|
for (; hl < rd && strcmp(term, buffer + hl); hl++) {
|
|
for (i = 0; i < 4; i++)
|
|
if (term[i] != buffer[hl + i]) break;
|
|
if (i == 4) break;
|
|
header[hl] = buffer[hl];
|
|
}
|
|
header[hl] = '\0';
|
|
return hl;
|
|
}
|
|
///////////////////////////////////////////////////////////
|
|
|
|
ServerThread::ServerThread(int socket) {
|
|
this->socket = socket;
|
|
marked = serving = false;
|
|
}
|
|
|
|
ServerThread::~ServerThread() {
|
|
}
|
|
// start serving in a separate thread
|
|
|
|
void ServerThread::Serve() {
|
|
pthread_create(&tid, NULL, run, this);
|
|
start = time(NULL);
|
|
}
|
|
// terminate the thread and close the socket
|
|
|
|
bool ServerThread::Terminate(bool force) {
|
|
if (serving&&!force)return false;
|
|
pthread_cancel(tid);
|
|
close(socket);
|
|
return true;
|
|
}
|
|
// run in current thread
|
|
|
|
void ServerThread::Run() {
|
|
int rd, hl;
|
|
while (1) {
|
|
serving = false;
|
|
rd = read(socket, buffer, BUFFERLENGTH - 1);
|
|
if (rd <= 0) {
|
|
// client disconnected mysteriously
|
|
Terminate(true);
|
|
break; // precautionary
|
|
}
|
|
// parse the header
|
|
serving = true;
|
|
char method[8], path[261], version[8], ext[5];
|
|
strcpy(path, WORKDIR);
|
|
// getExecDir(path);
|
|
hl = getHeader(header, buffer, rd);
|
|
sscanf(header, "%s %s %s", method, path + WDLEN, version);
|
|
// handle default file name
|
|
// if (!getExt(path, ext))strcat(path, "/index.html");
|
|
getExecDir(path);
|
|
|
|
// handle the request
|
|
if (!strcmp("GET", method) || !strcmp("PUT", method)) {
|
|
|
|
if (strlen(echo_buffer) > 0) {
|
|
int size = strlen(echo_buffer);
|
|
sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
|
|
send(socket, buffer, strlen(buffer), 0);
|
|
send(socket, echo_buffer, size, 0);
|
|
} else {
|
|
// try to open the requested file
|
|
FILE * file = fopen(path, "r");
|
|
if (file) {
|
|
fseek(file, 0, SEEK_END);
|
|
int size = ftell(file);
|
|
fseek(file, 0, 0);
|
|
// send 200
|
|
sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
|
|
send(socket, buffer, strlen(buffer), 0);
|
|
cout << "200 " << path << endl;
|
|
do {
|
|
rd = fread(buffer, sizeof (char), BUFFERLENGTH, file);
|
|
send(socket, buffer, rd, 0);
|
|
} while (rd > 0);
|
|
fclose(file);
|
|
} else {
|
|
// send 404
|
|
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 404 Not Found");
|
|
send(socket, buffer, strlen(buffer), 0);
|
|
cout << "404 " << path << endl;
|
|
}
|
|
}
|
|
serving = false;
|
|
Terminate(true);
|
|
} else if (!strcmp("POST", method)) {
|
|
if (fopen(path, "r") > 0) {
|
|
int size = strlen(echo_buffer);
|
|
sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
|
|
send(socket, buffer, strlen(buffer), 0);
|
|
send(socket, echo_buffer, size, 0);
|
|
continue;
|
|
}
|
|
FILE *file = fopen(path, "w+");
|
|
if (file) {
|
|
// send 200
|
|
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 200 OK");
|
|
send(socket, buffer, strlen(buffer), 0);
|
|
cout << "200 " << path << endl;
|
|
// if client sent data after the header
|
|
if (rd - hl > 4)
|
|
fwrite(buffer + hl + 4, sizeof (char), rd - hl - 4, file);
|
|
rd = read(socket, buffer, BUFFERLENGTH - 1);
|
|
while (rd > 0) {
|
|
fwrite(buffer, sizeof (char), rd, file);
|
|
rd = read(socket, buffer, BUFFERLENGTH - 1);
|
|
// TODO: implement blocks or read content length
|
|
if (rd < BUFFERLENGTH - 1 || !strcmp(buffer - 4, term))
|
|
break;
|
|
}
|
|
fclose(file);
|
|
} else {
|
|
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 500 Internal Server Error");
|
|
send(socket, buffer, strlen(buffer), 0);
|
|
cout << "500 " << path << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|