httplib.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. //
  2. // httplib.h
  3. //
  4. // Copyright (c) 2012 Yuji Hirose. All rights reserved.
  5. // The Boost Software License 1.0
  6. //
  7. #ifndef _CPPHTTPLIB_HTTPSLIB_H_
  8. #define _CPPHTTPLIB_HTTPSLIB_H_
  9. #ifdef _MSC_VER
  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. #ifndef snprintf
  19. #define snprintf _snprintf_s
  20. #endif
  21. #ifndef getcwd
  22. #define getcwd _getcwd
  23. #endif
  24. #define S_ISREG(m) (((m)&S_IFREG)==S_IFREG)
  25. #include <fcntl.h>
  26. #include <io.h>
  27. #include <winsock2.h>
  28. typedef SOCKET socket_t;
  29. #else
  30. #include <pthread.h>
  31. #include <unistd.h>
  32. #include <netdb.h>
  33. #include <cstring>
  34. #include <netinet/in.h>
  35. #include <arpa/inet.h>
  36. #include <sys/socket.h>
  37. #include <sys/stat.h>
  38. typedef int socket_t;
  39. #endif
  40. #include <fstream>
  41. #include <functional>
  42. #include <map>
  43. #include <memory>
  44. #include <regex>
  45. #include <string>
  46. #include <assert.h>
  47. namespace httplib
  48. {
  49. typedef std::map<std::string, std::string> Map;
  50. typedef std::multimap<std::string, std::string> MultiMap;
  51. typedef std::smatch Match;
  52. struct Request {
  53. std::string method;
  54. std::string url;
  55. MultiMap headers;
  56. std::string body;
  57. Map params;
  58. Match matches;
  59. bool has_header(const char* key) const;
  60. std::string get_header_value(const char* key) const;
  61. void set_header(const char* key, const char* val);
  62. bool has_param(const char* key) const;
  63. };
  64. struct Response {
  65. int status;
  66. MultiMap headers;
  67. std::string body;
  68. bool has_header(const char* key) const;
  69. std::string get_header_value(const char* key) const;
  70. void set_header(const char* key, const char* val);
  71. void set_redirect(const char* url);
  72. void set_content(const std::string& s, const char* content_type);
  73. Response() : status(-1) {}
  74. };
  75. class Server {
  76. public:
  77. typedef std::function<void (const Request&, Response&)> Handler;
  78. typedef std::function<void (const Request&, const Response&)> Logger;
  79. Server();
  80. void get(const char* pattern, Handler handler);
  81. void post(const char* pattern, Handler handler);
  82. void set_base_dir(const char* path);
  83. void set_error_handler(Handler handler);
  84. void set_logger(Logger logger);
  85. bool listen(const char* host, int port);
  86. void stop();
  87. private:
  88. typedef std::vector<std::pair<std::regex, Handler>> Handlers;
  89. void process_request(socket_t sock);
  90. bool read_request_line(FILE* fp, Request& req);
  91. bool routing(Request& req, Response& res);
  92. bool handle_file_request(Request& req, Response& res);
  93. bool dispatch_request(Request& req, Response& res, Handlers& handlers);
  94. socket_t svr_sock_;
  95. std::string base_dir_;
  96. Handlers get_handlers_;
  97. Handlers post_handlers_;
  98. Handler error_handler_;
  99. Logger logger_;
  100. };
  101. class Client {
  102. public:
  103. Client(const char* host, int port);
  104. std::shared_ptr<Response> get(const char* url);
  105. std::shared_ptr<Response> head(const char* url);
  106. std::shared_ptr<Response> post(const char* url, const std::string& body, const char* content_type);
  107. std::shared_ptr<Response> post(const char* url, const Map& params);
  108. bool send(const Request& req, Response& res);
  109. private:
  110. bool read_response_line(FILE* fp, Response& res);
  111. const std::string host_;
  112. const int port_;
  113. };
  114. // Implementation
  115. namespace detail {
  116. template <class Fn>
  117. void split(const char* b, const char* e, char d, Fn fn)
  118. {
  119. int i = 0;
  120. int beg = 0;
  121. while (e ? (b + i != e) : (b[i] != '\0')) {
  122. if (b[i] == d) {
  123. fn(&b[beg], &b[i]);
  124. beg = i + 1;
  125. }
  126. i++;
  127. }
  128. if (i) {
  129. fn(&b[beg], &b[i]);
  130. }
  131. }
  132. inline void get_flie_pointers(int fd, FILE*& fp_read, FILE*& fp_write)
  133. {
  134. #ifdef _MSC_VER
  135. int osfhandle = _open_osfhandle(fd, _O_RDONLY);
  136. fp_read = _fdopen(osfhandle, "rb");
  137. fp_write = _fdopen(osfhandle, "wb");
  138. #else
  139. fp_read = fdopen(fd, "rb");
  140. fp_write = fdopen(fd, "wb");
  141. #endif
  142. }
  143. template <typename Fn>
  144. socket_t create_socket(const char* host, int port, Fn fn)
  145. {
  146. #ifdef _MSC_VER
  147. int opt = SO_SYNCHRONOUS_NONALERT;
  148. setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char*)&opt, sizeof(opt));
  149. #endif
  150. // Create a socket
  151. auto sock = socket(AF_INET, SOCK_STREAM, 0);
  152. if (sock == -1) {
  153. return -1;
  154. }
  155. // Make 'reuse address' option available
  156. int yes = 1;
  157. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
  158. // Get a host entry info
  159. struct hostent* hp;
  160. if (!(hp = gethostbyname(host))) {
  161. return -1;
  162. }
  163. // Bind the socket to the given address
  164. struct sockaddr_in addr;
  165. memset(&addr, 0, sizeof(addr));
  166. memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
  167. addr.sin_family = AF_INET;
  168. addr.sin_port = htons(port);
  169. return fn(sock, addr);
  170. }
  171. inline socket_t create_server_socket(const char* host, int port)
  172. {
  173. return create_socket(host, port, [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
  174. if (::bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
  175. return -1;
  176. }
  177. if (listen(sock, 5)) { // Listen through 5 channels
  178. return -1;
  179. }
  180. return sock;
  181. });
  182. }
  183. inline int shutdown_socket(socket_t sock)
  184. {
  185. #ifdef _MSC_VER
  186. return shutdown(sock, SD_BOTH);
  187. #else
  188. return shutdown(sock, SHUT_RDWR);
  189. #endif
  190. }
  191. inline int close_socket(socket_t sock)
  192. {
  193. #ifdef _MSC_VER
  194. return closesocket(sock);
  195. #else
  196. return close(sock);
  197. #endif
  198. }
  199. inline socket_t create_client_socket(const char* host, int port)
  200. {
  201. return create_socket(host, port, [](socket_t sock, struct sockaddr_in& addr) -> socket_t {
  202. if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))) {
  203. return -1;
  204. }
  205. return sock;
  206. });
  207. }
  208. inline bool is_file(const std::string& s)
  209. {
  210. struct stat st;
  211. if (stat(s.c_str(), &st) < 0) {
  212. return false;
  213. }
  214. return S_ISREG(st.st_mode);
  215. }
  216. inline void read_file(const std::string& path, std::string& out)
  217. {
  218. auto fs = std::ifstream(path, std::ios_base::binary);
  219. fs.seekg(0, std::ios_base::end);
  220. auto size = fs.tellg();
  221. fs.seekg(0);
  222. out.assign(size, 0);
  223. fs.read(&out[0], size);
  224. }
  225. inline std::string get_file_extention(const std::string& path)
  226. {
  227. std::smatch m;
  228. auto pat = std::regex("\\.([a-zA-Z0-9]+)$");
  229. auto ret = std::regex_search(path, m, pat);
  230. std::string content_type;
  231. if (ret) {
  232. return m[1].str();
  233. }
  234. return std::string();
  235. }
  236. inline const char* get_content_type_from_file_extention(const std::string& ext)
  237. {
  238. if (ext == "html") {
  239. return "text/html";
  240. }
  241. return "text/plain";
  242. }
  243. inline const char* status_message(int status)
  244. {
  245. switch (status) {
  246. case 200: return "OK";
  247. case 400: return "Bad Request";
  248. case 404: return "Not Found";
  249. default:
  250. case 500: return "Internal Server Error";
  251. }
  252. }
  253. inline const char* get_header_value(const MultiMap& map, const char* key, const char* def)
  254. {
  255. auto it = map.find(key);
  256. if (it != map.end()) {
  257. return it->second.c_str();
  258. }
  259. return def;
  260. }
  261. inline int get_header_value_int(const MultiMap& map, const char* key, int def)
  262. {
  263. auto it = map.find(key);
  264. if (it != map.end()) {
  265. return std::stoi(it->second);
  266. }
  267. return def;
  268. }
  269. inline bool read_headers(FILE* fp, MultiMap& headers)
  270. {
  271. static std::regex re("(.+?): (.+?)\r\n");
  272. const auto BUFSIZ_HEADER = 2048;
  273. char buf[BUFSIZ_HEADER];
  274. for (;;) {
  275. if (!fgets(buf, BUFSIZ_HEADER, fp)) {
  276. return false;
  277. }
  278. if (!strcmp(buf, "\r\n")) {
  279. break;
  280. }
  281. std::cmatch m;
  282. if (std::regex_match(buf, m, re)) {
  283. auto key = std::string(m[1]);
  284. auto val = std::string(m[2]);
  285. headers.insert(std::make_pair(key, val));
  286. }
  287. }
  288. return true;
  289. }
  290. template <typename T>
  291. bool read_content(T& x, FILE* fp)
  292. {
  293. auto len = get_header_value_int(x.headers, "Content-Length", 0);
  294. if (len) {
  295. x.body.assign(len, 0);
  296. if (!fgets(&x.body[0], x.body.size() + 1, fp)) {
  297. return false;
  298. }
  299. }
  300. return true;
  301. }
  302. template <typename T>
  303. inline void write_headers(FILE* fp, const T& res)
  304. {
  305. fprintf(fp, "Connection: close\r\n");
  306. for (const auto& x: res.headers) {
  307. if (x.first != "Content-Type" && x.first != "Content-Length") {
  308. fprintf(fp, "%s: %s\r\n", x.first.c_str(), x.second.c_str());
  309. }
  310. }
  311. if (!res.body.empty()) {
  312. auto t = get_header_value(res.headers, "Content-Type", "text/plain");
  313. fprintf(fp, "Content-Type: %s\r\n", t);
  314. fprintf(fp, "Content-Length: %ld\r\n", res.body.size());
  315. }
  316. fprintf(fp, "\r\n");
  317. }
  318. inline void write_response(FILE* fp, const Request& req, const Response& res)
  319. {
  320. fprintf(fp, "HTTP/1.0 %d %s\r\n", res.status, status_message(res.status));
  321. write_headers(fp, res);
  322. if (!res.body.empty() && req.method != "HEAD") {
  323. fprintf(fp, "%s", res.body.c_str());
  324. }
  325. }
  326. inline std::string encode_url(const std::string& s)
  327. {
  328. std::string result;
  329. for (auto i = 0; s[i]; i++) {
  330. switch (s[i]) {
  331. case ' ': result += "+"; break;
  332. case '\'': result += "%27"; break;
  333. case ',': result += "%2C"; break;
  334. case ':': result += "%3A"; break;
  335. case ';': result += "%3B"; break;
  336. default:
  337. if (s[i] < 0) {
  338. result += '%';
  339. char hex[4];
  340. size_t len = snprintf(hex, sizeof(hex), "%02X", (unsigned char)s[i]);
  341. assert(len == 2);
  342. result.append(hex, len);
  343. } else {
  344. result += s[i];
  345. }
  346. break;
  347. }
  348. }
  349. return result;
  350. }
  351. inline bool is_hex(char c, int& v)
  352. {
  353. if (0x20 <= c && isdigit(c)) {
  354. v = c - '0';
  355. return true;
  356. } else if ('A' <= c && c <= 'F') {
  357. v = c - 'A' + 10;
  358. return true;
  359. } else if ('a' <= c && c <= 'f') {
  360. v = c - 'a' + 10;
  361. return true;
  362. }
  363. return false;
  364. }
  365. inline int from_hex_to_i(const std::string& s, int i, int cnt, int& val)
  366. {
  367. val = 0;
  368. for (; s[i] && cnt; i++, cnt--) {
  369. int v = 0;
  370. if (is_hex(s[i], v)) {
  371. val = val * 16 + v;
  372. } else {
  373. break;
  374. }
  375. }
  376. return --i;
  377. }
  378. size_t to_utf8(int code, char* buff)
  379. {
  380. if (code < 0x0080) {
  381. buff[0] = (code & 0x7F);
  382. return 1;
  383. } else if (code < 0x0800) {
  384. buff[0] = (0xC0 | ((code >> 6) & 0x1F));
  385. buff[1] = (0x80 | (code & 0x3F));
  386. return 2;
  387. } else if (code < 0xD800) {
  388. buff[0] = (0xE0 | ((code >> 12) & 0xF));
  389. buff[1] = (0x80 | ((code >> 6) & 0x3F));
  390. buff[2] = (0x80 | (code & 0x3F));
  391. return 3;
  392. } else if (code < 0xE000) { // D800 - DFFF is invalid...
  393. return 0;
  394. } else if (code < 0x10000) {
  395. buff[0] = (0xE0 | ((code >> 12) & 0xF));
  396. buff[1] = (0x80 | ((code >> 6) & 0x3F));
  397. buff[2] = (0x80 | (code & 0x3F));
  398. return 3;
  399. } else if (code < 0x110000) {
  400. buff[0] = (0xF0 | ((code >> 18) & 0x7));
  401. buff[1] = (0x80 | ((code >> 12) & 0x3F));
  402. buff[2] = (0x80 | ((code >> 6) & 0x3F));
  403. buff[3] = (0x80 | (code & 0x3F));
  404. return 4;
  405. }
  406. // NOTREACHED
  407. return 0;
  408. }
  409. inline std::string decode_url(const std::string& s)
  410. {
  411. std::string result;
  412. for (int i = 0; s[i]; i++) {
  413. if (s[i] == '%') {
  414. i++;
  415. assert(s[i]);
  416. if (s[i] == '%') {
  417. result += s[i];
  418. } else if (s[i] == 'u') {
  419. // Unicode
  420. i++;
  421. assert(s[i]);
  422. int val = 0;
  423. i = from_hex_to_i(s, i, 4, val);
  424. char buff[4];
  425. size_t len = to_utf8(val, buff);
  426. if (len > 0) {
  427. result.append(buff, len);
  428. }
  429. } else {
  430. // HEX
  431. int val = 0;
  432. i = from_hex_to_i(s, i, 2, val);
  433. result += val;
  434. }
  435. } else if (s[i] == '+') {
  436. result += ' ';
  437. } else {
  438. result += s[i];
  439. }
  440. }
  441. return result;
  442. }
  443. inline void write_request(FILE* fp, const Request& req)
  444. {
  445. auto url = encode_url(req.url);
  446. fprintf(fp, "%s %s HTTP/1.0\r\n", req.method.c_str(), url.c_str());
  447. write_headers(fp, req);
  448. if (!req.body.empty()) {
  449. if (req.has_header("application/x-www-form-urlencoded")) {
  450. fprintf(fp, "%s", encode_url(req.body).c_str());
  451. } else {
  452. fprintf(fp, "%s", req.body.c_str());
  453. }
  454. }
  455. }
  456. inline void parse_query_text(const std::string& s, Map& params)
  457. {
  458. split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
  459. std::string key;
  460. std::string val;
  461. split(b, e, '=', [&](const char* b, const char* e) {
  462. if (key.empty()) {
  463. key.assign(b, e);
  464. } else {
  465. val.assign(b, e);
  466. }
  467. });
  468. params[key] = val;
  469. });
  470. }
  471. #ifdef _MSC_VER
  472. class WSInit {
  473. public:
  474. WSInit::WSInit() {
  475. WSADATA wsaData;
  476. WSAStartup(0x0002, &wsaData);
  477. }
  478. WSInit::~WSInit() {
  479. WSACleanup();
  480. }
  481. };
  482. static WSInit wsinit_;
  483. #endif
  484. } // namespace detail
  485. // Request implementation
  486. inline bool Request::has_header(const char* key) const
  487. {
  488. return headers.find(key) != headers.end();
  489. }
  490. inline std::string Request::get_header_value(const char* key) const
  491. {
  492. return detail::get_header_value(headers, key, "");
  493. }
  494. inline void Request::set_header(const char* key, const char* val)
  495. {
  496. headers.insert(std::make_pair(key, val));
  497. }
  498. inline bool Request::has_param(const char* key) const
  499. {
  500. return params.find(key) != params.end();
  501. }
  502. // Response implementation
  503. inline bool Response::has_header(const char* key) const
  504. {
  505. return headers.find(key) != headers.end();
  506. }
  507. inline std::string Response::get_header_value(const char* key) const
  508. {
  509. return detail::get_header_value(headers, key, "");
  510. }
  511. inline void Response::set_header(const char* key, const char* val)
  512. {
  513. headers.insert(std::make_pair(key, val));
  514. }
  515. inline void Response::set_redirect(const char* url)
  516. {
  517. set_header("Location", url);
  518. status = 302;
  519. }
  520. inline void Response::set_content(const std::string& s, const char* content_type)
  521. {
  522. body = s;
  523. set_header("Content-Type", content_type);
  524. }
  525. // HTTP server implementation
  526. inline Server::Server()
  527. : svr_sock_(-1)
  528. {
  529. char curr_dir[FILENAME_MAX];
  530. if (getcwd(curr_dir, sizeof(curr_dir))) {
  531. curr_dir[sizeof(curr_dir) - 1] = '\0';
  532. base_dir_ = curr_dir;
  533. }
  534. }
  535. inline void Server::get(const char* pattern, Handler handler)
  536. {
  537. get_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
  538. }
  539. inline void Server::post(const char* pattern, Handler handler)
  540. {
  541. post_handlers_.push_back(std::make_pair(std::regex(pattern), handler));
  542. }
  543. inline void Server::set_base_dir(const char* path)
  544. {
  545. base_dir_ = path;
  546. }
  547. inline void Server::set_error_handler(Handler handler)
  548. {
  549. error_handler_ = handler;
  550. }
  551. inline void Server::set_logger(Logger logger)
  552. {
  553. logger_ = logger;
  554. }
  555. inline bool Server::listen(const char* host, int port)
  556. {
  557. svr_sock_ = detail::create_server_socket(host, port);
  558. if (svr_sock_ == -1) {
  559. return false;
  560. }
  561. auto ret = true;
  562. for (;;) {
  563. socket_t sock = accept(svr_sock_, NULL, NULL);
  564. if (sock == -1) {
  565. if (svr_sock_ != -1) {
  566. detail::close_socket(svr_sock_);
  567. ret = false;
  568. } else {
  569. ; // The server socket was closed by user.
  570. }
  571. break;
  572. }
  573. // TODO: should be async
  574. process_request(sock);
  575. detail::shutdown_socket(sock);
  576. detail::close_socket(sock);
  577. }
  578. return ret;
  579. }
  580. inline void Server::stop()
  581. {
  582. detail::shutdown_socket(svr_sock_);
  583. detail::close_socket(svr_sock_);
  584. svr_sock_ = -1;
  585. }
  586. inline bool Server::read_request_line(FILE* fp, Request& req)
  587. {
  588. const auto BUFSIZ_REQUESTLINE = 2048;
  589. char buf[BUFSIZ_REQUESTLINE];
  590. if (!fgets(buf, BUFSIZ_REQUESTLINE, fp)) {
  591. return false;
  592. }
  593. static std::regex re("(GET|HEAD|POST) ([^?]+)(?:\\?(.+?))? HTTP/1\\.[01]\r\n");
  594. std::cmatch m;
  595. if (std::regex_match(buf, m, re)) {
  596. req.method = std::string(m[1]);
  597. req.url = detail::decode_url(m[2]);
  598. // Parse query text
  599. auto len = std::distance(m[3].first, m[3].second);
  600. if (len > 0) {
  601. detail::parse_query_text(detail::decode_url(m[3]), req.params);
  602. }
  603. return true;
  604. }
  605. return false;
  606. }
  607. inline bool Server::handle_file_request(Request& req, Response& res)
  608. {
  609. std::string path = base_dir_ + req.url;
  610. if (!path.empty() && path.back() == '/') {
  611. path += "index.html";
  612. }
  613. if (detail::is_file(path)) {
  614. detail::read_file(path, res.body);
  615. auto type = detail::get_content_type_from_file_extention(detail::get_file_extention(path));
  616. res.set_header("Content-Type", type);
  617. res.status = 200;
  618. return true;
  619. }
  620. return false;
  621. }
  622. inline bool Server::routing(Request& req, Response& res)
  623. {
  624. if (req.method == "GET" && handle_file_request(req, res)) {
  625. return true;
  626. }
  627. if (req.method == "GET" || req.method == "HEAD") {
  628. return dispatch_request(req, res, get_handlers_);
  629. } else if (req.method == "POST") {
  630. return dispatch_request(req, res, post_handlers_);
  631. }
  632. return false;
  633. }
  634. inline bool Server::dispatch_request(Request& req, Response& res, Handlers& handlers)
  635. {
  636. for (const auto& x: handlers) {
  637. const auto& pattern = x.first;
  638. const auto& handler = x.second;
  639. if (std::regex_match(req.url, req.matches, pattern)) {
  640. handler(req, res);
  641. return true;
  642. }
  643. }
  644. return false;
  645. }
  646. inline void Server::process_request(socket_t sock)
  647. {
  648. FILE* fp_read;
  649. FILE* fp_write;
  650. detail::get_flie_pointers(sock, fp_read, fp_write);
  651. Request req;
  652. Response res;
  653. if (!read_request_line(fp_read, req) ||
  654. !detail::read_headers(fp_read, req.headers)) {
  655. return;
  656. }
  657. if (req.method == "POST") {
  658. if (!detail::read_content(req, fp_read)) {
  659. return;
  660. }
  661. if (req.get_header_value("Content-Type") == "application/x-www-form-urlencoded") {
  662. detail::parse_query_text(detail::decode_url(req.body), req.params);
  663. }
  664. }
  665. if (routing(req, res)) {
  666. if (res.status == -1) {
  667. res.status = 200;
  668. }
  669. } else {
  670. res.status = 404;
  671. }
  672. assert(res.status != -1);
  673. if (400 <= res.status && error_handler_) {
  674. error_handler_(req, res);
  675. }
  676. detail::write_response(fp_write, req, res);
  677. fflush(fp_write);
  678. // NOTE: The following code causes problem on Windows...
  679. //fclose(fp_read);
  680. //fclose(fp_write);
  681. if (logger_) {
  682. logger_(req, res);
  683. }
  684. }
  685. // HTTP client implementation
  686. inline Client::Client(const char* host, int port)
  687. : host_(host)
  688. , port_(port)
  689. {
  690. }
  691. inline bool Client::read_response_line(FILE* fp, Response& res)
  692. {
  693. const auto BUFSIZ_RESPONSELINE = 2048;
  694. char buf[BUFSIZ_RESPONSELINE];
  695. if (!fgets(buf, BUFSIZ_RESPONSELINE, fp)) {
  696. return false;
  697. }
  698. const static std::regex re("HTTP/1\\.[01] (\\d+?) .+\r\n");
  699. std::cmatch m;
  700. if (std::regex_match(buf, m, re)) {
  701. res.status = std::stoi(std::string(m[1]));
  702. }
  703. return true;
  704. }
  705. inline bool Client::send(const Request& req, Response& res)
  706. {
  707. auto sock = detail::create_client_socket(host_.c_str(), port_);
  708. if (sock == -1) {
  709. return false;
  710. }
  711. FILE* fp_read;
  712. FILE* fp_write;
  713. detail::get_flie_pointers(sock, fp_read, fp_write);
  714. // Send request
  715. detail::write_request(fp_write, req);
  716. fflush(fp_write);
  717. // Receive response
  718. if (!read_response_line(fp_read, res) ||
  719. !detail::read_headers(fp_read, res.headers)) {
  720. return false;
  721. }
  722. if (req.method != "HEAD") {
  723. if (!detail::read_content(res, fp_read)) {
  724. return false;
  725. }
  726. }
  727. // NOTE: The following code causes problem on Windows...
  728. //fclose(fp_read);
  729. //fclose(fp_write);
  730. detail::shutdown_socket(sock);
  731. detail::close_socket(sock);
  732. return true;
  733. }
  734. inline std::shared_ptr<Response> Client::get(const char* url)
  735. {
  736. Request req;
  737. req.method = "GET";
  738. req.url = url;
  739. auto res = std::make_shared<Response>();
  740. return send(req, *res) ? res : nullptr;
  741. }
  742. inline std::shared_ptr<Response> Client::head(const char* url)
  743. {
  744. Request req;
  745. req.method = "HEAD";
  746. req.url = url;
  747. auto res = std::make_shared<Response>();
  748. return send(req, *res) ? res : nullptr;
  749. }
  750. inline std::shared_ptr<Response> Client::post(
  751. const char* url, const std::string& body, const char* content_type)
  752. {
  753. Request req;
  754. req.method = "POST";
  755. req.url = url;
  756. req.set_header("Content-Type", content_type);
  757. req.body = body;
  758. auto res = std::make_shared<Response>();
  759. return send(req, *res) ? res : nullptr;
  760. }
  761. inline std::shared_ptr<Response> Client::post(
  762. const char* url, const Map& params)
  763. {
  764. std::string query;
  765. for (auto it = params.begin(); it != params.end(); ++it) {
  766. if (it != params.begin()) {
  767. query += "&";
  768. }
  769. query += it->first;
  770. query += "=";
  771. query += it->second;
  772. }
  773. return post(url, query, "application/x-www-form-urlencoded");
  774. }
  775. } // namespace httplib
  776. #endif
  777. // vim: et ts=4 sw=4 cin cino={1s ff=unix