ClientConnection.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. //
  2. // Created by xcbosa on 2023/1/28.
  3. //
  4. #include "ClientConnection.h"
  5. #include "../processor/processor.h"
  6. using namespace std;
  7. using namespace xc::processor;
  8. namespace xc {
  9. namespace httpserver {
  10. ClientConnection::ClientConnection(int sockFd, struct sockaddr_in address) {
  11. this->sockFd = sockFd;
  12. this->address = address;
  13. this->clRead = nullptr;
  14. this->clWrite = nullptr;
  15. this->requestBuff = nullptr;
  16. }
  17. void ClientConnection::workAndDestroy() {
  18. thread(&ClientConnection::workLoop, this).detach();
  19. }
  20. void ClientConnection::workLoop() {
  21. ::FILE *clRead = fdopen(this->sockFd, "r");
  22. ::FILE *clWrite = fdopen(dup(this->sockFd), "w");
  23. struct timeval timeout = { conf::clientSocketTimeoutSeconds, 0 };
  24. if (setsockopt(this->sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
  25. cleanUpAndDestroy();
  26. return;
  27. }
  28. this->clRead = clRead;
  29. this->clWrite = clWrite;
  30. char *requestBuff = (char *)::malloc(urlRequestBuffSize);
  31. this->requestBuff = requestBuff;
  32. ::fgets(requestBuff, urlRequestBuffSize, clRead);
  33. if (::strstr(requestBuff, "HTTP/") == NULL) {
  34. conf::errorPage400.writeTo(clWrite);
  35. cleanUpAndDestroy();
  36. return;
  37. }
  38. string method, url;
  39. char *ptr, *p;
  40. ptr = strtok_r(requestBuff, " ", &p);
  41. if (ptr != nullptr) {
  42. method = string(ptr);
  43. ptr = strtok_r(p, " ", &p);
  44. if (ptr != nullptr) {
  45. url = string(ptr);
  46. }
  47. }
  48. if (method == "GET" || method == "POST") {
  49. map<string, string> headers;
  50. ostringstream body;
  51. bool isHeader = true;
  52. bool lastLineIsEmpty = false;
  53. bool lastLineEmptyAndZero = false;
  54. while (bzero(requestBuff, urlRequestBuffSize), ::fgets(requestBuff, urlRequestBuffSize, clRead)) {
  55. if (method == "GET") {
  56. if (strcmp(requestBuff, "\r\n") == 0) {
  57. break;
  58. }
  59. }
  60. int len = ::strlen(requestBuff);
  61. char *lineBuff = (char *) ::malloc(len + 1), *pLineBuff = lineBuff;
  62. bool leftHasContext = false;
  63. for (int i = 0; i < len; i++) {
  64. if (requestBuff[i] == '\r' || requestBuff[i] == '\n') continue;
  65. if (requestBuff[i] == ' ' || requestBuff[i] == '\t') {
  66. if (leftHasContext) {
  67. *pLineBuff++ = requestBuff[i];
  68. }
  69. } else {
  70. leftHasContext = true;
  71. *pLineBuff++ = requestBuff[i];
  72. }
  73. }
  74. if (leftHasContext) {
  75. pLineBuff--;
  76. while (pLineBuff >= lineBuff && (*pLineBuff == ' ' || *pLineBuff == '\t')) {
  77. *pLineBuff = 0; // 从右往左,删掉右边的空白符
  78. pLineBuff--;
  79. }
  80. }
  81. if (::strlen(lineBuff) == 0) {
  82. // TODO: Fix Linux POST Method
  83. isHeader = false;
  84. lastLineIsEmpty = true;
  85. if (lastLineEmptyAndZero) {
  86. break;
  87. } else {
  88. lastLineEmptyAndZero = false;
  89. }
  90. if (method == "GET") {
  91. break;
  92. }
  93. continue;
  94. }
  95. if (lineBuff[0] == '0') {
  96. if (lastLineIsEmpty) {
  97. lastLineEmptyAndZero = true;
  98. lastLineIsEmpty = false;
  99. }
  100. }
  101. if (isHeader) {
  102. char *headerValue;
  103. char *headerName = strtok_r(lineBuff, ":", &headerValue);
  104. if (headerName != nullptr && headerValue != nullptr) {
  105. string name(headerName);
  106. string value(headerValue);
  107. headers[name] = value;
  108. }
  109. } else {
  110. body << lineBuff << endl;
  111. }
  112. }
  113. RequestData requestData(url, method, headers, body.str());
  114. cout << "[HTTPServer] Received " << method << " Request URL = " << url << endl;
  115. if (url.find("..") != string::npos) {
  116. conf::errorPage400.writeTo(clWrite);
  117. cleanUpAndDestroy();
  118. return;
  119. }
  120. RequestProcessTask *task = new RequestProcessTask(requestData);
  121. processor::enqueueTask(task);
  122. ::time_t start, now;
  123. ::time(&start);
  124. while (true) {
  125. usleep(1000 * 10);
  126. if (task->isFinish()) {
  127. ResponseData *taskResponse = task->getResponse();
  128. taskResponse->writeTo(clWrite);
  129. // taskResponse->writeTo(stdout);
  130. delete taskResponse;
  131. break;
  132. }
  133. ::time(&now);
  134. if (::difftime(now, start) > conf::taskProcessTimeoutSeconds) {
  135. cout << "[HTTPServer-Warn] Task failed because time out" << endl;
  136. conf::errorPageTimeout.writeTo(clWrite);
  137. processor::deleteTask(task);
  138. task->setHttpDiscarded(true);
  139. break;
  140. }
  141. }
  142. cleanUpAndDestroy();
  143. return;
  144. } else {
  145. conf::ErrorView view(400, "");
  146. view.setMessage("未知的协议 " + method);
  147. TemplateResponseData({ view }).writeTo(clWrite);
  148. cleanUpAndDestroy();
  149. return;
  150. }
  151. }
  152. void ClientConnection::cleanUpAndDestroy() {
  153. if (this->clRead) {
  154. ::fclose(this->clRead);
  155. this->clRead = nullptr;
  156. }
  157. if (this->clWrite) {
  158. ::fclose(this->clWrite);
  159. this->clWrite = nullptr;
  160. }
  161. if (this->requestBuff) {
  162. ::free(this->requestBuff);
  163. this->requestBuff = nullptr;
  164. }
  165. ::close(this->sockFd);
  166. delete this;
  167. }
  168. } // xc
  169. } // httpserver