ServerThread.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "ServerThread.h"
  2. using namespace std;
  3. // entry point for all threads
  4. char echo_buffer[100 *1024];
  5. void getExecDir(char*dir) {
  6. char* filename = nullptr;
  7. if (readlink("/proc/self/exe", dir, 1024) < 0) {
  8. dir[0] = '\0';
  9. return;
  10. }
  11. filename = strrchr(dir, '/');
  12. if (filename == nullptr) {
  13. dir[0] = '\0';
  14. return;
  15. }
  16. ++filename;
  17. *filename = '\0';
  18. sprintf(dir + strlen(dir), "%s", "index.html");
  19. return;
  20. }
  21. void* run(void* obj) {
  22. ((ServerThread*) obj)->Run();
  23. // when Run() finishes, mark for termination
  24. ((ServerThread*) obj)->MarkFT();
  25. }
  26. bool getExt(const char* path, char* ext) {
  27. int l = strlen(path), i = l;
  28. while (i > 0 && path[--i] != '.' && path[i] != '/');
  29. if (i == 0 || path[i] == '/') return false;
  30. for (int j = 0; i < l; ext[j++] = path[++i]);
  31. return true;
  32. }
  33. int getHeader(char *header, const char *buffer, int rd) {
  34. int hl = 0;
  35. int i = 0;
  36. for (; hl < rd && strcmp(term, buffer + hl); hl++) {
  37. for (i = 0; i < 4; i++)
  38. if (term[i] != buffer[hl + i]) break;
  39. if (i == 4) break;
  40. header[hl] = buffer[hl];
  41. }
  42. header[hl] = '\0';
  43. return hl;
  44. }
  45. ///////////////////////////////////////////////////////////
  46. ServerThread::ServerThread(int socket) {
  47. this->socket = socket;
  48. marked = serving = false;
  49. }
  50. ServerThread::~ServerThread() {
  51. }
  52. // start serving in a separate thread
  53. void ServerThread::Serve() {
  54. pthread_create(&tid, NULL, run, this);
  55. start = time(NULL);
  56. }
  57. // terminate the thread and close the socket
  58. bool ServerThread::Terminate(bool force) {
  59. if (serving&&!force)return false;
  60. pthread_cancel(tid);
  61. close(socket);
  62. return true;
  63. }
  64. // run in current thread
  65. void ServerThread::Run() {
  66. int rd, hl;
  67. while (1) {
  68. serving = false;
  69. rd = read(socket, buffer, BUFFERLENGTH - 1);
  70. if (rd <= 0) {
  71. // client disconnected mysteriously
  72. Terminate(true);
  73. break; // precautionary
  74. }
  75. // parse the header
  76. serving = true;
  77. char method[8], path[261], version[8], ext[5];
  78. strcpy(path, WORKDIR);
  79. // getExecDir(path);
  80. hl = getHeader(header, buffer, rd);
  81. sscanf(header, "%s %s %s", method, path + WDLEN, version);
  82. // handle default file name
  83. // if (!getExt(path, ext))strcat(path, "/index.html");
  84. getExecDir(path);
  85. // handle the request
  86. if (!strcmp("GET", method) || !strcmp("PUT", method)) {
  87. if (strlen(echo_buffer) > 0) {
  88. int size = strlen(echo_buffer);
  89. sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
  90. send(socket, buffer, strlen(buffer), 0);
  91. send(socket, echo_buffer, size, 0);
  92. } else {
  93. // try to open the requested file
  94. FILE * file = fopen(path, "r");
  95. if (file) {
  96. fseek(file, 0, SEEK_END);
  97. int size = ftell(file);
  98. fseek(file, 0, 0);
  99. // send 200
  100. sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
  101. send(socket, buffer, strlen(buffer), 0);
  102. cout << "200 " << path << endl;
  103. do {
  104. rd = fread(buffer, sizeof (char), BUFFERLENGTH, file);
  105. send(socket, buffer, rd, 0);
  106. } while (rd > 0);
  107. fclose(file);
  108. } else {
  109. // send 404
  110. sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 404 Not Found");
  111. send(socket, buffer, strlen(buffer), 0);
  112. cout << "404 " << path << endl;
  113. }
  114. }
  115. serving = false;
  116. Terminate(true);
  117. } else if (!strcmp("POST", method)) {
  118. if (fopen(path, "r") > 0) {
  119. int size = strlen(echo_buffer);
  120. sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
  121. send(socket, buffer, strlen(buffer), 0);
  122. send(socket, echo_buffer, size, 0);
  123. continue;
  124. }
  125. FILE *file = fopen(path, "w+");
  126. if (file) {
  127. // send 200
  128. sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 200 OK");
  129. send(socket, buffer, strlen(buffer), 0);
  130. cout << "200 " << path << endl;
  131. // if client sent data after the header
  132. if (rd - hl > 4)
  133. fwrite(buffer + hl + 4, sizeof (char), rd - hl - 4, file);
  134. rd = read(socket, buffer, BUFFERLENGTH - 1);
  135. while (rd > 0) {
  136. fwrite(buffer, sizeof (char), rd, file);
  137. rd = read(socket, buffer, BUFFERLENGTH - 1);
  138. // TODO: implement blocks or read content length
  139. if (rd < BUFFERLENGTH - 1 || !strcmp(buffer - 4, term))
  140. break;
  141. }
  142. fclose(file);
  143. } else {
  144. sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 500 Internal Server Error");
  145. send(socket, buffer, strlen(buffer), 0);
  146. cout << "500 " << path << endl;
  147. }
  148. }
  149. }
  150. }