Files
aliyun-openapi-cpp-sdk/test/httpserver/ServerThread.cpp

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;
}
}
}
}