123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- //
- // Created by xcbosa on 2023/1/28.
- //
- #include "ClientConnection.h"
- #include "../processor/processor.h"
- using namespace std;
- using namespace xc::processor;
- namespace xc {
- namespace httpserver {
- ClientConnection::ClientConnection(int sockFd, struct sockaddr_in address) {
- this->sockFd = sockFd;
- this->address = address;
- this->clRead = nullptr;
- this->clWrite = nullptr;
- this->requestBuff = nullptr;
- }
- void ClientConnection::workAndDestroy() {
- thread(&ClientConnection::workLoop, this).detach();
- }
- void ClientConnection::workLoop() {
- ::FILE *clRead = fdopen(this->sockFd, "r");
- ::FILE *clWrite = fdopen(dup(this->sockFd), "w");
- struct timeval timeout = { conf::clientSocketTimeoutSeconds, 0 };
- if (setsockopt(this->sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
- cleanUpAndDestroy();
- return;
- }
- this->clRead = clRead;
- this->clWrite = clWrite;
- char *requestBuff = (char *)::malloc(urlRequestBuffSize);
- this->requestBuff = requestBuff;
- ::fgets(requestBuff, urlRequestBuffSize, clRead);
- if (::strstr(requestBuff, "HTTP/") == NULL) {
- conf::errorPage400.writeTo(clWrite);
- cleanUpAndDestroy();
- return;
- }
- string method, url;
- char *ptr, *p;
- ptr = strtok_r(requestBuff, " ", &p);
- if (ptr != nullptr) {
- method = string(ptr);
- ptr = strtok_r(p, " ", &p);
- if (ptr != nullptr) {
- url = string(ptr);
- }
- }
- if (method == "GET" || method == "POST") {
- map<string, string> headers;
- ostringstream body;
- bool isHeader = true;
- bool lastLineIsEmpty = false;
- bool lastLineEmptyAndZero = false;
- while (bzero(requestBuff, urlRequestBuffSize), ::fgets(requestBuff, urlRequestBuffSize, clRead)) {
- if (method == "GET") {
- if (strcmp(requestBuff, "\r\n") == 0) {
- break;
- }
- }
- int len = ::strlen(requestBuff);
- char *lineBuff = (char *) ::malloc(len + 1), *pLineBuff = lineBuff;
- bool leftHasContext = false;
- for (int i = 0; i < len; i++) {
- if (requestBuff[i] == '\r' || requestBuff[i] == '\n') continue;
- if (requestBuff[i] == ' ' || requestBuff[i] == '\t') {
- if (leftHasContext) {
- *pLineBuff++ = requestBuff[i];
- }
- } else {
- leftHasContext = true;
- *pLineBuff++ = requestBuff[i];
- }
- }
- if (leftHasContext) {
- pLineBuff--;
- while (pLineBuff >= lineBuff && (*pLineBuff == ' ' || *pLineBuff == '\t')) {
- *pLineBuff = 0; // 从右往左,删掉右边的空白符
- pLineBuff--;
- }
- }
- if (::strlen(lineBuff) == 0) {
- // TODO: Fix Linux POST Method
- isHeader = false;
- lastLineIsEmpty = true;
- if (lastLineEmptyAndZero) {
- break;
- } else {
- lastLineEmptyAndZero = false;
- }
- if (method == "GET") {
- break;
- }
- continue;
- }
- if (lineBuff[0] == '0') {
- if (lastLineIsEmpty) {
- lastLineEmptyAndZero = true;
- lastLineIsEmpty = false;
- }
- }
- if (isHeader) {
- char *headerValue;
- char *headerName = strtok_r(lineBuff, ":", &headerValue);
- if (headerName != nullptr && headerValue != nullptr) {
- string name(headerName);
- string value(headerValue);
- headers[name] = value;
- }
- } else {
- body << lineBuff << endl;
- }
- }
- RequestData requestData(url, method, headers, body.str());
- cout << "[HTTPServer] Received " << method << " Request URL = " << url << endl;
- if (url.find("..") != string::npos) {
- conf::errorPage400.writeTo(clWrite);
- cleanUpAndDestroy();
- return;
- }
- RequestProcessTask *task = new RequestProcessTask(requestData);
- processor::enqueueTask(task);
- ::time_t start, now;
- ::time(&start);
- while (true) {
- usleep(1000 * 10);
- if (task->isFinish()) {
- ResponseData *taskResponse = task->getResponse();
- taskResponse->writeTo(clWrite);
- // taskResponse->writeTo(stdout);
- delete taskResponse;
- break;
- }
- ::time(&now);
- if (::difftime(now, start) > conf::taskProcessTimeoutSeconds) {
- cout << "[HTTPServer-Warn] Task failed because time out" << endl;
- conf::errorPageTimeout.writeTo(clWrite);
- processor::deleteTask(task);
- task->setHttpDiscarded(true);
- break;
- }
- }
- cleanUpAndDestroy();
- return;
- } else {
- conf::ErrorView view(400, "");
- view.setMessage("未知的协议 " + method);
- TemplateResponseData({ view }).writeTo(clWrite);
- cleanUpAndDestroy();
- return;
- }
- }
- void ClientConnection::cleanUpAndDestroy() {
- if (this->clRead) {
- ::fclose(this->clRead);
- this->clRead = nullptr;
- }
- if (this->clWrite) {
- ::fclose(this->clWrite);
- this->clWrite = nullptr;
- }
- if (this->requestBuff) {
- ::free(this->requestBuff);
- this->requestBuff = nullptr;
- }
- ::close(this->sockFd);
- delete this;
- }
- } // xc
- } // httpserver
|