httplib.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. //
  2. // httplib.h
  3. //
  4. // Copyright (c) 2012 Yuji Hirose. All rights reserved.
  5. // The Boost Software License 1.0
  6. //
  7. #ifndef HTTPSVRKIT_H
  8. #define HTTPSVRKIT_H
  9. #ifdef _WIN32
  10. #define _CRT_SECURE_NO_WARNINGS
  11. #define _CRT_NONSTDC_NO_DEPRECATE
  12. #ifndef SO_SYNCHRONOUS_NONALERT
  13. #define SO_SYNCHRONOUS_NONALERT 0x20;
  14. #endif
  15. #ifndef SO_OPENTYPE
  16. #define SO_OPENTYPE 0x7008
  17. #endif
  18. #include <fcntl.h>
  19. #include <io.h>
  20. #include <winsock2.h>
  21. typedef SOCKET socket_t;
  22. #else
  23. #include <pthread.h>
  24. #include <unistd.h>
  25. #include <netdb.h>
  26. #include <netinet/in.h>
  27. #include <arpa/inet.h>
  28. #include <sys/socket.h>
  29. typedef int socket_t;
  30. #endif
  31. #include <functional>
  32. #include <map>
  33. #include <regex>
  34. #include <string>
  35. #include <assert.h>
  36. namespace httplib
  37. {
  38. typedef std::map<std::string, std::string> Map;
  39. typedef std::multimap<std::string, std::string> MultiMap;
  40. typedef std::smatch Match;
  41. struct Request {
  42. std::string method;
  43. std::string url;
  44. MultiMap headers;
  45. std::string body;
  46. Map query;
  47. Match match;
  48. bool has_header(const char* key) const;
  49. std::string get_header_value(const char* key) const;
  50. };
  51. struct Response {
  52. int status;
  53. MultiMap headers;
  54. std::string body;
  55. bool has_header(const char* key) const;
  56. std::string get_header_value(const char* key) const;
  57. void set_header(const char* key, const char* val);
  58. void set_redirect(const char* url);
  59. void set_content(const std::string& s, const char* content_type);
  60. };
  61. struct Connection {
  62. Request request;
  63. Response response;
  64. };
  65. class Server {
  66. public:
  67. typedef std::function<void (Connection& c)> Handler;
  68. Server(const char* host, int port);
  69. ~Server();
  70. void get(const char* pattern, Handler handler);
  71. void post(const char* pattern, Handler handler);
  72. void set_error_handler(Handler handler);
  73. void set_logger(std::function<void (const Connection&)> logger);
  74. bool run();
  75. void stop();
  76. private:
  77. void process_request(FILE* fp_read, FILE* fp_write);
  78. bool read_request_line(FILE* fp, Request& req);
  79. void write_response(FILE* fp, const Response& res);
  80. const std::string host_;
  81. const int port_;
  82. socket_t sock_;
  83. std::vector<std::pair<std::regex, Handler>> get_handlers_;
  84. std::vector<std::pair<std::string, Handler>> post_handlers_;
  85. Handler error_handler_;
  86. std::function<void (const Connection&)> logger_;
  87. };
  88. class Client {
  89. public:
  90. Client(const char* host, int port);
  91. ~Client();
  92. bool get(const char* url, Response& res);
  93. private:
  94. bool read_response_line(FILE* fp, Response& res);
  95. const std::string host_;
  96. const int port_;
  97. };
  98. // Implementation
  99. template <class Fn>
  100. void split(const char* b, const char* e, char d, Fn fn)
  101. {
  102. int i = 0;
  103. int beg = 0;
  104. while (e ? (b + i != e) : (b[i] != '\0')) {
  105. if (b[i] == d) {
  106. fn(&b[beg], &b[i]);
  107. beg = i + 1;
  108. }
  109. i++;
  110. }
  111. if (i) {
  112. fn(&b[beg], &b[i]);
  113. }
  114. }
  115. inline void get_flie_pointers(int fd, FILE*& fp_read, FILE*& fp_write)
  116. {
  117. #ifdef _WIN32
  118. int osfhandle = _open_osfhandle(fd, _O_RDONLY);
  119. fp_read = fdopen(osfhandle, "rb");
  120. fp_write = fdopen(osfhandle, "wb");
  121. #else
  122. fp_read = fdopen(fd, "rb");
  123. fp_write = fdopen(fd, "wb");
  124. #endif
  125. }
  126. template <typename Fn>
  127. socket_t create_socket(const char* host, int port, Fn fn)
  128. {
  129. #ifdef _WIN32
  130. int opt = SO_SYNCHRONOUS_NONALERT;
  131. setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char*)&opt, sizeof(opt));
  132. #endif
  133. // Create a server socket
  134. socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
  135. if (sock == -1) {
  136. return -1;
  137. }
  138. // Make 'reuse address' option available
  139. int yes = 1;
  140. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
  141. // Get a host entry info
  142. struct hostent* hp;
  143. if (!(hp = gethostbyname(host))) {
  144. return -1;
  145. }
  146. // Bind the socket to the given address
  147. struct sockaddr_in addr;
  148. memset(&addr, 0, sizeof(addr));
  149. memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
  150. addr.sin_family = AF_INET;
  151. addr.sin_port = htons(port);
  152. return fn(sock, addr);
  153. }
  154. inline socket_t create_server_socket(const char* host, int port)
  155. {
  156. return create_socket(host, port, [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
  157. if (::bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
  158. return -1;
  159. }
  160. // Listen through 5 channels
  161. if (listen(sock, 5)) {
  162. return -1;
  163. }
  164. return sock;
  165. });
  166. }
  167. inline int close_server_socket(socket_t sock)
  168. {
  169. #ifdef _WIN32
  170. shutdown(sock, SD_BOTH);
  171. return closesocket(sock);
  172. #else
  173. shutdown(sock, SHUT_RDWR);
  174. return close(sock);
  175. #endif
  176. }
  177. inline socket_t create_client_socket(const char* host, int port)
  178. {
  179. return create_socket(host, port,
  180. [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
  181. if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) {
  182. return -1;
  183. }
  184. return sock;
  185. });
  186. }
  187. inline int close_client_socket(socket_t sock)
  188. {
  189. #ifdef _WIN32
  190. return closesocket(sock);
  191. #else
  192. return close(sock);
  193. #endif
  194. }
  195. inline const char* status_message(int status)
  196. {
  197. const char* s = NULL;
  198. switch (status) {
  199. case 400:
  200. s = "Bad Request";
  201. break;
  202. case 404:
  203. s = "Not Found";
  204. break;
  205. default:
  206. status = 500;
  207. s = "Internal Server Error";
  208. break;
  209. }
  210. return s;
  211. }
  212. inline const char* get_header_value_text(const MultiMap& map, const char* key, const char* def)
  213. {
  214. auto it = map.find(key);
  215. if (it != map.end()) {
  216. return it->second.c_str();
  217. }
  218. return def;
  219. }
  220. inline int get_header_value_int(const MultiMap& map, const char* key, int def)
  221. {
  222. auto it = map.find(key);
  223. if (it != map.end()) {
  224. return std::atoi(it->second.c_str());
  225. }
  226. return def;
  227. }
  228. inline void read_headers(FILE* fp, MultiMap& headers)
  229. {
  230. static std::regex re("(.+?): (.+?)\r\n");
  231. const size_t BUFSIZ_HEADER = 2048;
  232. char buf[BUFSIZ_HEADER];
  233. while (fgets(buf, BUFSIZ_HEADER, fp) && strcmp(buf, "\r\n")) {
  234. std::cmatch m;
  235. if (std::regex_match(buf, m, re)) {
  236. auto key = std::string(m[1]);
  237. auto val = std::string(m[2]);
  238. headers.insert(std::make_pair(key, val));
  239. }
  240. }
  241. }
  242. // HTTP server implementation
  243. inline bool Request::has_header(const char* key) const
  244. {
  245. return headers.find(key) != headers.end();
  246. }
  247. inline std::string Request::get_header_value(const char* key) const
  248. {
  249. return get_header_value_text(headers, key, "");
  250. }
  251. inline bool Response::has_header(const char* key) const
  252. {
  253. return headers.find(key) != headers.end();
  254. }
  255. inline std::string Response::get_header_value(const char* key) const
  256. {
  257. return get_header_value_text(headers, key, "");
  258. }
  259. inline void Response::set_header(const char* key, const char* val)
  260. {
  261. headers.insert(std::make_pair(key, val));
  262. }
  263. inline void Response::set_redirect(const char* url)
  264. {
  265. set_header("Location", url);
  266. status = 302;
  267. }
  268. inline void Response::set_content(const std::string& s, const char* content_type)
  269. {
  270. body = s;
  271. set_header("Content-Type", content_type);
  272. status = 200;
  273. }
  274. inline Server::Server(const char* host, int port)
  275. : host_(host)
  276. , port_(port)
  277. , sock_(-1)
  278. {
  279. #ifdef _WIN32
  280. WSADATA wsaData;
  281. WSAStartup(0x0002, &wsaData);
  282. #endif
  283. }
  284. inline Server::~Server()
  285. {
  286. #ifdef _WIN32
  287. WSACleanup();
  288. #endif
  289. }
  290. inline void Server::get(const char* pattern, Handler handler)
  291. {
  292. get_handlers_.push_back(std::make_pair(pattern, handler));
  293. }
  294. inline void Server::post(const char* pattern, Handler handler)
  295. {
  296. post_handlers_.push_back(std::make_pair(pattern, handler));
  297. }
  298. inline void Server::set_error_handler(Handler handler)
  299. {
  300. error_handler_ = handler;
  301. }
  302. inline void Server::set_logger(std::function<void (const Connection&)> logger)
  303. {
  304. logger_ = logger;
  305. }
  306. inline bool Server::run()
  307. {
  308. sock_ = create_server_socket(host_.c_str(), port_);
  309. if (sock_ == -1) {
  310. return false;
  311. }
  312. for (;;) {
  313. socket_t fd = accept(sock_, NULL, NULL);
  314. if (fd == -1) {
  315. // The server socket was closed by user.
  316. if (sock_ == -1) {
  317. return true;
  318. }
  319. close_server_socket(sock_);
  320. return false;
  321. }
  322. FILE* fp_read;
  323. FILE* fp_write;
  324. get_flie_pointers(fd, fp_read, fp_write);
  325. process_request(fp_read, fp_write);
  326. fflush(fp_write);
  327. close_server_socket(fd);
  328. }
  329. // NOTREACHED
  330. }
  331. inline void Server::stop()
  332. {
  333. close_server_socket(sock_);
  334. sock_ = -1;
  335. }
  336. inline bool Server::read_request_line(FILE* fp, Request& req)
  337. {
  338. const size_t BUFSIZ_REQUESTLINE = 2048;
  339. char buf[BUFSIZ_REQUESTLINE];
  340. if (!fgets(buf, BUFSIZ_REQUESTLINE, fp)) {
  341. return false;
  342. }
  343. static std::regex re("(GET|POST) ([^?]+)(?:\\?(.+?))? HTTP/1\\.[01]\r\n");
  344. std::cmatch m;
  345. if (std::regex_match(buf, m, re)) {
  346. req.method = std::string(m[1]);
  347. req.url = std::string(m[2]);
  348. // Parse query text
  349. auto len = std::distance(m[3].first, m[3].second);
  350. if (len > 0) {
  351. const auto& pos = m[3];
  352. split(pos.first, pos.second, '&', [&](const char* b, const char* e) {
  353. std::string key;
  354. std::string val;
  355. split(b, e, '=', [&](const char* b, const char* e) {
  356. if (key.empty()) {
  357. key.assign(b, e);
  358. } else {
  359. val.assign(b, e);
  360. }
  361. });
  362. req.query[key] = val;
  363. });
  364. }
  365. return true;
  366. }
  367. return false;
  368. }
  369. inline void Server::write_response(FILE* fp, const Response& res)
  370. {
  371. fprintf(fp, "HTTP/1.0 %d %s\r\n", res.status, status_message(res.status));
  372. fprintf(fp, "Connection: close\r\n");
  373. for (auto it = res.headers.begin(); it != res.headers.end(); ++it) {
  374. if (it->first != "Content-Type" && it->second != "Content-Length") {
  375. fprintf(fp, "%s: %s\r\n", it->first.c_str(), it->second.c_str());
  376. }
  377. }
  378. if (!res.body.empty()) {
  379. auto content_type = get_header_value_text(res.headers, "Content-Type", "text/plain");
  380. fprintf(fp, "Content-Type: %s\r\n", content_type);
  381. fprintf(fp, "Content-Length: %ld\r\n", res.body.size());
  382. }
  383. fprintf(fp, "\r\n");
  384. if (!res.body.empty()) {
  385. fprintf(fp, "%s", res.body.c_str());
  386. }
  387. }
  388. inline void Server::process_request(FILE* fp_read, FILE* fp_write)
  389. {
  390. Connection c;
  391. if (!read_request_line(fp_read, c.request)) {
  392. return;
  393. }
  394. read_headers(fp_read, c.request.headers);
  395. // Routing
  396. c.response.status = 0;
  397. if (c.request.method == "GET") {
  398. for (auto it = get_handlers_.begin(); it != get_handlers_.end(); ++it) {
  399. const auto& pattern = it->first;
  400. const auto& handler = it->second;
  401. if (std::regex_match(c.request.url, c.request.match, pattern)) {
  402. handler(c);
  403. break;
  404. }
  405. }
  406. } else if (c.request.method == "POST") {
  407. // TODO: parse body
  408. }
  409. if (!c.response.status) {
  410. c.response.status = 404;
  411. }
  412. if (400 <= c.response.status) {
  413. if (error_handler_) {
  414. error_handler_(c);
  415. }
  416. }
  417. if (logger_) {
  418. logger_(c);
  419. }
  420. write_response(fp_write, c.response);
  421. }
  422. // HTTP client implementation
  423. inline Client::Client(const char* host, int port)
  424. : host_(host)
  425. , port_(port)
  426. {
  427. #ifdef _WIN32
  428. WSADATA wsaData;
  429. WSAStartup(0x0002, &wsaData);
  430. #endif
  431. }
  432. inline Client::~Client()
  433. {
  434. #ifdef _WIN32
  435. WSACleanup();
  436. #endif
  437. }
  438. inline bool Client::read_response_line(FILE* fp, Response& res)
  439. {
  440. const size_t BUFSIZ_RESPONSELINE = 2048;
  441. char buf[BUFSIZ_RESPONSELINE];
  442. if (!fgets(buf, BUFSIZ_RESPONSELINE, fp)) {
  443. return false;
  444. }
  445. static std::regex re("HTTP/1\\.[01] (\\d+?) .+\r\n");
  446. std::cmatch m;
  447. if (std::regex_match(buf, m, re)) {
  448. res.status = std::atoi(std::string(m[1]).c_str());
  449. }
  450. return true;
  451. }
  452. inline bool Client::get(const char* url, Response& res)
  453. {
  454. socket_t sock = create_client_socket(host_.c_str(), port_);
  455. if (sock == -1) {
  456. return false;
  457. }
  458. FILE* fp_read;
  459. FILE* fp_write;
  460. get_flie_pointers(sock, fp_read, fp_write);
  461. // Send request
  462. fprintf(fp_write, "GET %s HTTP/1.0\r\n\r\n", url);
  463. fflush(fp_write);
  464. if (!read_response_line(fp_read, res)) {
  465. return false;
  466. }
  467. read_headers(fp_read, res.headers);
  468. // Read content body
  469. auto len = get_header_value_int(res.headers, "Content-Length", 0);
  470. if (len) {
  471. res.body.assign(len, 0);
  472. if (!fgets(&res.body[0], res.body.size() + 1, fp_read)) {
  473. return false;
  474. }
  475. }
  476. close_client_socket(sock);
  477. return true;
  478. }
  479. } // namespace httplib
  480. #endif
  481. // vim: et ts=4 sw=4 cin cino={1s ff=unix