webserver.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #include <iostream>
  2. #include <fstream>
  3. #include <map>
  4. #include <atomic>
  5. #include <thread>
  6. #include <pthread.h>
  7. #include "misc.h"
  8. #include "socket.h"
  9. #include "webserver.h"
  10. typedef std::vector<std::string> string_array;
  11. int def_timeout = 5;
  12. struct responseRoute
  13. {
  14. std::string method;
  15. std::string path;
  16. std::string content_type;
  17. response_callback rc;
  18. };
  19. std::vector<responseRoute> responses;
  20. //for use of multi-thread
  21. int max_send_failure = 10;
  22. std::atomic_bool SERVER_EXIT_FLAG(false);
  23. std::atomic_int working_thread(0)
  24. int sendall(SOCKET sock, std::string data)
  25. {
  26. unsigned int total = 0, bytesleft = data.size();
  27. int sent = 0;
  28. const char* datastr = data.data();
  29. while(total < bytesleft)
  30. {
  31. sent = send(sock, datastr + total, bytesleft, 0);
  32. if(sent < 0)
  33. {
  34. std::cerr<<strerror(errno)<<std::endl;
  35. if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
  36. {
  37. continue;
  38. }
  39. else
  40. {
  41. break;
  42. }
  43. }
  44. total += sent;
  45. bytesleft -= sent;
  46. }
  47. return sent == -1 ? -1 : 0;
  48. }
  49. void wrong_req(SOCKET sock)
  50. {
  51. std::string response = "HTTP/1.1 501 Not Implemented\r\n"
  52. "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\n"
  53. "Content-Type: text/plain\r\n\r\n"
  54. "The command is not yet completed\r\n";
  55. if (sendall(sock, response) == -1)
  56. {
  57. std::cerr << "Sending failed!" << std::endl;
  58. }
  59. }
  60. void file_not_found(std::string arguments, int sock)
  61. {
  62. std::string prompt_info = "Not found: " + arguments;
  63. std::string response = "HTTP/1.1 404 Not Found\r\n"
  64. "Content-Type: text/plain\r\nConnection: close\r\n"
  65. "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\n"
  66. "Content-Length: " + std::__cxx11::to_string(prompt_info.size()) + "\r\n\r\n" + prompt_info + "\r\n";
  67. if (sendall(sock, response) == -1)
  68. {
  69. printf("Sending error!");
  70. return;
  71. }
  72. }
  73. void send_header(SOCKET send_to, std::string content_type)
  74. {
  75. std::string header = "HTTP/1.1 200 OK\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\n";
  76. if(content_type.size())
  77. header += "Content-Type: " + content_type + "\r\n";
  78. if(sendall(send_to, header) == -1)
  79. {
  80. printf("Sending error!");
  81. }
  82. }
  83. void send_options_header(SOCKET send_to)
  84. {
  85. std::string header = "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\n";
  86. if(sendall(send_to, header) == -1)
  87. {
  88. printf("Sending error!");
  89. }
  90. }
  91. char* file_type(const char* arg)
  92. {
  93. char * temp;
  94. if ((temp=strrchr(arg,'.')) != NULL)
  95. {
  96. return temp+1;
  97. }
  98. return nullptr;
  99. }
  100. void serve_options(SOCKET sock)
  101. {
  102. send_options_header(sock);
  103. std::string extra_header = "Content-Length: 0\r\n\r\n";
  104. sendall(sock, extra_header);
  105. sendall(sock, "\r\n\r\n");
  106. }
  107. void serve_content(SOCKET sock, std::string type, std::string content)
  108. {
  109. send_header(sock, type.data());
  110. std::string extra_header = "Content-Length: " + std::__cxx11::to_string(content.size()) + "\r\n";
  111. sendall(sock, extra_header);
  112. send(sock, "\r\n", 2, 0);
  113. if (sendall(sock, content) == -1)
  114. {
  115. printf("Sending error!");
  116. }
  117. sendall(sock, "\r\n\r\n");
  118. }
  119. void send_file(std::string arguments, int sock)
  120. {
  121. char* extension = file_type(arguments.data());
  122. std::string content_type = "text/plain", data;
  123. char sizestr[16] = {};
  124. int len;
  125. if (strcmp(extension, "html") == 0)
  126. {
  127. content_type = "text/html";
  128. }
  129. if (strcmp(extension, "gif") == 0)
  130. {
  131. content_type = "image/gif";
  132. }
  133. if (strcmp(extension, "jpg") == 0)
  134. {
  135. content_type = "image/jpg";
  136. }
  137. send_header(sock, content_type);
  138. sendall(sock, "Transfer-Encoding: chunked\r\n\r\n");
  139. data = fileGet(arguments);
  140. len = data.size();
  141. sprintf(sizestr, "%x\r\n", len);
  142. if (sendall(sock, sizestr) == -1)
  143. {
  144. printf("Sending error!");
  145. }
  146. if (sendall(sock, data) == -1)
  147. {
  148. printf("Sending error!");
  149. }
  150. len = 2;
  151. sendall(sock, "\r\n");
  152. len = 7;
  153. sendall(sock, "0\r\n\r\n");
  154. }
  155. int setTimeout(SOCKET s, int timeout)
  156. {
  157. int ret = -1;
  158. #ifdef _WIN32
  159. ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(int));
  160. ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(int));
  161. #else
  162. struct timeval timeo = {timeout / 1000, (timeout % 1000) * 1000};
  163. ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeo, sizeof(timeo));
  164. ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeo, sizeof(timeo));
  165. #endif
  166. def_timeout = timeout;
  167. return ret;
  168. }
  169. void handle_req(std::string request, int client_sock)
  170. {
  171. working_thread++;
  172. std::cerr<<"worker startup"<<std::endl;
  173. string_array vArray;
  174. char command[16] = {};
  175. char arguments[BUFSIZ] = {};
  176. std::string uri, args, target, postdata;
  177. if (sscanf(request.data(), "%s%s", command, arguments) != 2)
  178. {
  179. goto end;
  180. }
  181. std::cerr<<"handle_cmd: "<<command<<"\n"<<"handle_path: "<<arguments<<"\n";
  182. vArray = split(arguments, "?");
  183. if(vArray.size() > 2)
  184. {
  185. wrong_req(client_sock);
  186. goto end;
  187. }
  188. else if(vArray.size() > 1)
  189. {
  190. uri = vArray[0];
  191. args = vArray[1];
  192. }
  193. else
  194. uri = arguments;
  195. if(strcmp(command, "POST") == 0)
  196. {
  197. if(request.find("\r\n\r\n") != request.npos)
  198. postdata = request.substr(request.find("\r\n\r\n") + 4);
  199. }
  200. else if(strcmp(command, "OPTIONS") == 0)
  201. {
  202. serve_options(client_sock);
  203. goto end;
  204. }
  205. for(std::vector<responseRoute>::iterator iter = responses.begin(); iter != responses.end(); ++iter)
  206. {
  207. if(iter->method.compare(command) == 0 && iter->path == uri)
  208. {
  209. response_callback &rc = iter->rc;
  210. serve_content(client_sock, iter->content_type, rc(args, postdata));
  211. goto end;
  212. }
  213. }
  214. file_not_found(uri, client_sock);
  215. end:
  216. std::cerr<<"worker stop"<<std::endl;
  217. sleep(1);
  218. closesocket(client_sock);
  219. working_thread--;
  220. }
  221. void append_response(std::string type, std::string request, std::string content_type, response_callback response)
  222. {
  223. responseRoute rr;
  224. rr.method = type;
  225. rr.path = request;
  226. rr.content_type = content_type;
  227. rr.rc = response;
  228. responses.push_back(rr);
  229. }
  230. void stop_web_server()
  231. {
  232. SERVER_EXIT_FLAG = true;
  233. }
  234. int start_web_server(void *argv)
  235. {
  236. struct listener_args *args = (listener_args*)argv;
  237. args->max_workers = 1;
  238. return start_web_server_multi(args);
  239. }
  240. int start_web_server_multi(void *argv)
  241. {
  242. //log startup
  243. struct listener_args *args = (listener_args*)argv;
  244. std::string listen_address = args->listen_address, request;
  245. int port = args->port, max_conn = args->max_conn, max_workers = args->max_workers, numbytes, worker_index = 0;
  246. socklen_t sock_size = sizeof(struct sockaddr_in);
  247. char buf[BUFSIZ];
  248. struct sockaddr_in user_socket, server_addr;
  249. SOCKET acc_socket;
  250. int server_socket, fail_counter = 0;
  251. server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  252. std::thread workers[max_workers];
  253. if (server_socket == -1)
  254. {
  255. //log socket error
  256. std::cerr<<"socket build error!"<<std::endl;
  257. return 0;
  258. }
  259. ZeroMemory(&server_addr, sizeof(server_addr));
  260. server_addr.sin_family = AF_INET;
  261. server_addr.sin_port = htons((short)port);
  262. server_addr.sin_addr.s_addr = inet_addr(listen_address.data());
  263. if (::bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
  264. {
  265. //log bind error
  266. std::cerr<<"socket bind error!"<<std::endl;
  267. closesocket(server_socket);
  268. return 0;
  269. }
  270. if (listen(server_socket, max_conn) == -1 )
  271. {
  272. //log listen error
  273. std::cerr<<"socket listen error!"<<std::endl;
  274. closesocket(server_socket);
  275. return 0;
  276. }
  277. setTimeout(server_socket, 500);
  278. while(true)
  279. {
  280. acc_socket = accept(server_socket, (struct sockaddr *)&user_socket, &sock_size); //wait for connection
  281. if(acc_socket < 0)
  282. {
  283. if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
  284. {
  285. fail_counter++;
  286. if(fail_counter > max_send_failure)
  287. break;
  288. continue;
  289. }
  290. else
  291. {
  292. break;
  293. }
  294. }
  295. request = "";
  296. while(true) //receive the complete request
  297. {
  298. numbytes = recv(acc_socket, buf, BUFSIZ - 1, 0);
  299. if(numbytes > 0) //received
  300. request.append(buf);
  301. if(numbytes < 0)
  302. {
  303. if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
  304. {
  305. continue;
  306. }
  307. else
  308. {
  309. break;
  310. }
  311. }
  312. if(numbytes == 0)
  313. break;
  314. }
  315. //handle_req(buf, acc_socket);
  316. while(working_thread >= max_workers)
  317. {
  318. sleep(10);
  319. if(SERVER_EXIT_FLAG)
  320. break;
  321. }
  322. while(workers[worker_index].get_id() != std::thread::id())
  323. {
  324. worker_index++;
  325. }
  326. workers[worker_index] = std::thread(handle_req, request, acc_socket);
  327. workers[worker_index].detach();
  328. worker_index++;
  329. if(worker_index > max_workers)
  330. worker_index = 0;
  331. }
  332. return 0;
  333. }