1
0

HttpMessage.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. #include "HttpMessage.h"
  2. #include <string.h>
  3. #include "htime.h"
  4. #include "hlog.h"
  5. #include "hurl.h"
  6. #include "http_parser.h" // for http_parser_url
  7. char HttpMessage::s_date[32] = {0};
  8. bool HttpCookie::parse(const std::string& str) {
  9. std::stringstream ss;
  10. ss << str;
  11. std::string kv;
  12. std::string::size_type pos;
  13. std::string key;
  14. std::string val;
  15. while (std::getline(ss, kv, ';')) {
  16. pos = kv.find_first_of('=');
  17. if (pos != std::string::npos) {
  18. key = trim(kv.substr(0, pos));
  19. val = trim(kv.substr(pos+1));
  20. } else {
  21. key = trim(kv);
  22. }
  23. const char* pkey = key.c_str();
  24. if (stricmp(pkey, "domain") == 0) {
  25. domain = val;
  26. }
  27. else if (stricmp(pkey, "path") == 0) {
  28. path = val;
  29. }
  30. else if (stricmp(pkey, "max-age") == 0) {
  31. max_age = atoi(val.c_str());
  32. }
  33. else if (stricmp(pkey, "secure") == 0) {
  34. secure = true;
  35. }
  36. else if (stricmp(pkey, "httponly") == 0) {
  37. httponly = true;
  38. }
  39. else if (val.size() > 0) {
  40. name = key;
  41. value = val;
  42. }
  43. else {
  44. hlogw("Unrecognized key '%s'", key.c_str());
  45. }
  46. }
  47. return !name.empty() && !value.empty();
  48. }
  49. std::string HttpCookie::dump() const {
  50. assert(!name.empty() && !value.empty());
  51. std::string res;
  52. res = name;
  53. res += "=";
  54. res += value;
  55. if (!domain.empty()) {
  56. res += "; domain=";
  57. res += domain;
  58. }
  59. if (!path.empty()) {
  60. res += "; path=";
  61. res += path;
  62. }
  63. if (max_age > 0) {
  64. res += "; max-age=";
  65. res += hv::to_string(max_age);
  66. }
  67. if (secure) {
  68. res += "; secure";
  69. }
  70. if (httponly) {
  71. res += "; httponly";
  72. }
  73. return res;
  74. }
  75. #ifndef WITHOUT_HTTP_CONTENT
  76. // NOTE: json ignore number/string, 123/"123"
  77. std::string HttpMessage::GetString(const char* key, const std::string& defvalue) {
  78. switch (content_type) {
  79. case APPLICATION_JSON:
  80. {
  81. if (!json.is_object()) {
  82. return defvalue;
  83. }
  84. const auto& value = json[key];
  85. if (value.is_string()) {
  86. return value;
  87. }
  88. else if (value.is_number()) {
  89. return hv::to_string(value);
  90. }
  91. else if (value.is_null()) {
  92. return "null";
  93. }
  94. else if (value.is_boolean()) {
  95. bool b = value;
  96. return b ? "true" : "false";
  97. }
  98. else {
  99. return defvalue;
  100. }
  101. }
  102. break;
  103. case MULTIPART_FORM_DATA:
  104. {
  105. auto iter = form.find(key);
  106. if (iter != form.end()) {
  107. return iter->second.content;
  108. }
  109. }
  110. break;
  111. case APPLICATION_URLENCODED:
  112. {
  113. auto iter = kv.find(key);
  114. if (iter != kv.end()) {
  115. return iter->second;
  116. }
  117. }
  118. break;
  119. default:
  120. break;
  121. }
  122. return defvalue;
  123. }
  124. template<>
  125. HV_EXPORT int64_t HttpMessage::Get(const char* key, int64_t defvalue) {
  126. if (content_type == APPLICATION_JSON) {
  127. if (!json.is_object()) {
  128. return defvalue;
  129. }
  130. const auto& value = json[key];
  131. if (value.is_number()) {
  132. return value;
  133. }
  134. else if (value.is_string()) {
  135. std::string str = value;
  136. return atoll(str.c_str());
  137. }
  138. else if (value.is_null()) {
  139. return 0;
  140. }
  141. else if (value.is_boolean()) {
  142. bool b = value;
  143. return b ? 1 : 0;
  144. }
  145. else {
  146. return defvalue;
  147. }
  148. }
  149. else {
  150. std::string str = GetString(key);
  151. return str.empty() ? defvalue : atoll(str.c_str());
  152. }
  153. }
  154. template<>
  155. HV_EXPORT int HttpMessage::Get(const char* key, int defvalue) {
  156. return (int)Get<int64_t>(key, defvalue);
  157. }
  158. template<>
  159. HV_EXPORT double HttpMessage::Get(const char* key, double defvalue) {
  160. if (content_type == APPLICATION_JSON) {
  161. if (!json.is_object()) {
  162. return defvalue;
  163. }
  164. const auto& value = json[key];
  165. if (value.is_number()) {
  166. return value;
  167. }
  168. else if (value.is_string()) {
  169. std::string str = value;
  170. return atof(str.c_str());
  171. }
  172. else if (value.is_null()) {
  173. return 0.0f;
  174. }
  175. else {
  176. return defvalue;
  177. }
  178. }
  179. else {
  180. std::string str = GetString(key);
  181. return str.empty() ? defvalue : atof(str.c_str());
  182. }
  183. }
  184. template<>
  185. HV_EXPORT float HttpMessage::Get(const char* key, float defvalue) {
  186. return (float)Get<double>(key, defvalue);
  187. }
  188. template<>
  189. HV_EXPORT bool HttpMessage::Get(const char* key, bool defvalue) {
  190. if (content_type == APPLICATION_JSON) {
  191. if (!json.is_object()) {
  192. return defvalue;
  193. }
  194. const auto& value = json[key];
  195. if (value.is_boolean()) {
  196. return value;
  197. }
  198. else if (value.is_string()) {
  199. std::string str = value;
  200. return getboolean(str.c_str());
  201. }
  202. else if (value.is_null()) {
  203. return false;
  204. }
  205. else if (value.is_number()) {
  206. return value != 0;
  207. }
  208. else {
  209. return defvalue;
  210. }
  211. }
  212. else {
  213. std::string str = GetString(key);
  214. return str.empty() ? defvalue : getboolean(str.c_str());
  215. }
  216. }
  217. bool HttpMessage::GetBool(const char* key, bool defvalue) {
  218. return Get<bool>(key, defvalue);
  219. }
  220. int64_t HttpMessage::GetInt(const char* key, int64_t defvalue) {
  221. return Get<int64_t>(key, defvalue);
  222. }
  223. double HttpMessage::GetFloat(const char* key, double defvalue) {
  224. return Get<double>(key, defvalue);
  225. }
  226. #endif
  227. void HttpMessage::FillContentType() {
  228. auto iter = headers.find("Content-Type");
  229. if (iter != headers.end()) {
  230. content_type = http_content_type_enum(iter->second.c_str());
  231. goto append;
  232. }
  233. #ifndef WITHOUT_HTTP_CONTENT
  234. if (content_type == CONTENT_TYPE_NONE) {
  235. if (json.size() != 0) {
  236. content_type = APPLICATION_JSON;
  237. }
  238. else if (form.size() != 0) {
  239. content_type = MULTIPART_FORM_DATA;
  240. }
  241. else if (kv.size() != 0) {
  242. content_type = X_WWW_FORM_URLENCODED;
  243. }
  244. else if (body.size() != 0) {
  245. content_type = TEXT_PLAIN;
  246. }
  247. }
  248. #endif
  249. if (content_type != CONTENT_TYPE_NONE) {
  250. headers["Content-Type"] = http_content_type_str(content_type);
  251. }
  252. append:
  253. #ifndef WITHOUT_HTTP_CONTENT
  254. if (content_type == MULTIPART_FORM_DATA) {
  255. auto iter = headers.find("Content-Type");
  256. if (iter != headers.end()) {
  257. const char* boundary = strstr(iter->second.c_str(), "boundary=");
  258. if (boundary == NULL) {
  259. boundary = DEFAULT_MULTIPART_BOUNDARY;
  260. iter->second += "; boundary=";
  261. iter->second += boundary;
  262. }
  263. }
  264. }
  265. #endif
  266. return;
  267. }
  268. void HttpMessage::FillContentLength() {
  269. auto iter = headers.find("Content-Length");
  270. if (iter != headers.end()) {
  271. content_length = atoi(iter->second.c_str());
  272. }
  273. if (content_length == 0) {
  274. DumpBody();
  275. content_length = body.size();
  276. }
  277. if (iter == headers.end() && content_length != 0 && !IsChunked()) {
  278. headers["Content-Length"] = hv::to_string(content_length);
  279. }
  280. }
  281. bool HttpMessage::IsChunked() {
  282. auto iter = headers.find("Transfer-Encoding");
  283. return iter == headers.end() ? false : stricmp(iter->second.c_str(), "chunked") == 0;
  284. }
  285. bool HttpMessage::IsKeepAlive() {
  286. bool keepalive = true;
  287. auto iter = headers.find("connection");
  288. if (iter != headers.end()) {
  289. const char* keepalive_value = iter->second.c_str();
  290. if (stricmp(keepalive_value, "keep-alive") == 0) {
  291. keepalive = true;
  292. }
  293. else if (stricmp(keepalive_value, "close") == 0) {
  294. keepalive = false;
  295. }
  296. else if (stricmp(keepalive_value, "upgrade") == 0) {
  297. keepalive = true;
  298. }
  299. }
  300. else if (http_major == 1 && http_minor == 0) {
  301. keepalive = false;
  302. }
  303. return keepalive;
  304. }
  305. void HttpMessage::DumpHeaders(std::string& str) {
  306. FillContentType();
  307. FillContentLength();
  308. // headers
  309. for (auto& header: headers) {
  310. // http2 :method :path :scheme :authority :status
  311. if (*str.c_str() != ':') {
  312. // %s: %s\r\n
  313. str += header.first;
  314. str += ": ";
  315. str += header.second;
  316. str += "\r\n";
  317. }
  318. }
  319. // cookies
  320. const char* cookie_field = "Cookie";
  321. if (type == HTTP_RESPONSE) {
  322. cookie_field = "Set-Cookie";
  323. }
  324. for (auto& cookie : cookies) {
  325. str += cookie_field;
  326. str += ": ";
  327. str += cookie.dump();
  328. str += "\r\n";
  329. }
  330. }
  331. void HttpMessage::DumpBody() {
  332. if (body.size() != 0) {
  333. return;
  334. }
  335. FillContentType();
  336. #ifndef WITHOUT_HTTP_CONTENT
  337. switch(content_type) {
  338. case APPLICATION_JSON:
  339. body = dump_json(json, 2);
  340. break;
  341. case MULTIPART_FORM_DATA:
  342. {
  343. auto iter = headers.find("Content-Type");
  344. if (iter == headers.end()) {
  345. return;
  346. }
  347. const char* boundary = strstr(iter->second.c_str(), "boundary=");
  348. if (boundary == NULL) {
  349. return;
  350. }
  351. boundary += strlen("boundary=");
  352. body = dump_multipart(form, boundary);
  353. }
  354. break;
  355. case X_WWW_FORM_URLENCODED:
  356. body = dump_query_params(kv);
  357. break;
  358. default:
  359. // nothing to do
  360. break;
  361. }
  362. #endif
  363. }
  364. void HttpMessage::DumpBody(std::string& str) {
  365. DumpBody();
  366. const char* content = (const char*)Content();
  367. int content_length = ContentLength();
  368. if (content && content_length) {
  369. str.append(content, content_length);
  370. }
  371. }
  372. int HttpMessage::ParseBody() {
  373. if (body.size() == 0) {
  374. return -1;
  375. }
  376. FillContentType();
  377. #ifndef WITHOUT_HTTP_CONTENT
  378. switch(content_type) {
  379. case APPLICATION_JSON:
  380. {
  381. std::string errmsg;
  382. int ret = parse_json(body.c_str(), json, errmsg);
  383. if (ret != 0 && errmsg.size() != 0) {
  384. hloge("%s", errmsg.c_str());
  385. }
  386. return ret;
  387. }
  388. case MULTIPART_FORM_DATA:
  389. {
  390. auto iter = headers.find("Content-Type");
  391. if (iter == headers.end()) {
  392. return false;
  393. }
  394. const char* boundary = strstr(iter->second.c_str(), "boundary=");
  395. if (boundary == NULL) {
  396. return false;
  397. }
  398. boundary += strlen("boundary=");
  399. string strBoundary(boundary);
  400. strBoundary = trim_pairs(strBoundary, "\"\"\'\'");
  401. return parse_multipart(body, form, strBoundary.c_str());
  402. }
  403. case X_WWW_FORM_URLENCODED:
  404. return parse_query_params(body.c_str(), kv);
  405. default:
  406. // nothing to do
  407. return 0;
  408. }
  409. #endif
  410. return 0;
  411. }
  412. std::string HttpMessage::Dump(bool is_dump_headers, bool is_dump_body) {
  413. std::string str;
  414. if (is_dump_headers) {
  415. DumpHeaders(str);
  416. }
  417. str += "\r\n";
  418. if (is_dump_body) {
  419. DumpBody(str);
  420. }
  421. return str;
  422. }
  423. void HttpRequest::DumpUrl() {
  424. if (url.size() != 0 && strstr(url.c_str(), "://") != NULL) {
  425. // have been complete url
  426. return;
  427. }
  428. std::string str;
  429. // scheme://
  430. str = scheme;
  431. str += "://";
  432. // host:port
  433. char c_str[256] = {0};
  434. if (url.size() != 0 && *url.c_str() != '/') {
  435. // url begin with host
  436. str += url;
  437. }
  438. else {
  439. if (port == 0 ||
  440. port == DEFAULT_HTTP_PORT ||
  441. port == DEFAULT_HTTPS_PORT) {
  442. str += Host();
  443. }
  444. else {
  445. snprintf(c_str, sizeof(c_str), "%s:%d", host.c_str(), port);
  446. str += c_str;
  447. }
  448. }
  449. // /path
  450. if (url.size() != 0 && *url.c_str() == '/') {
  451. // url begin with path
  452. str += url;
  453. }
  454. else if (path.size() > 1 && *path.c_str() == '/') {
  455. str += path;
  456. }
  457. else if (url.size() == 0) {
  458. str += '/';
  459. }
  460. // ?query
  461. if (strchr(str.c_str(), '?') == NULL &&
  462. query_params.size() != 0) {
  463. str += '?';
  464. str += dump_query_params(query_params);
  465. }
  466. url = str;
  467. }
  468. void HttpRequest::ParseUrl() {
  469. DumpUrl();
  470. http_parser_url parser;
  471. http_parser_url_init(&parser);
  472. http_parser_parse_url(url.c_str(), url.size(), 0, &parser);
  473. // scheme
  474. scheme = url.substr(parser.field_data[UF_SCHEMA].off, parser.field_data[UF_SCHEMA].len);
  475. // host
  476. if (parser.field_set & (1<<UF_HOST)) {
  477. host = url.substr(parser.field_data[UF_HOST].off, parser.field_data[UF_HOST].len);
  478. }
  479. // port
  480. port = parser.port ? parser.port : strcmp(scheme.c_str(), "https") ? DEFAULT_HTTP_PORT : DEFAULT_HTTPS_PORT;
  481. // path
  482. if (parser.field_set & (1<<UF_PATH)) {
  483. const char* sp = url.c_str() + parser.field_data[UF_PATH].off;
  484. char* ep = (char*)(sp + parser.field_data[UF_PATH].len);
  485. char ev = *ep;
  486. *ep = '\0';
  487. path = url_unescape(sp);
  488. if (ev != '\0') {
  489. *ep = ev;
  490. path += ep;
  491. }
  492. }
  493. // query
  494. if (parser.field_set & (1<<UF_QUERY)) {
  495. parse_query_params(url.c_str()+parser.field_data[UF_QUERY].off, query_params);
  496. }
  497. }
  498. std::string HttpRequest::Dump(bool is_dump_headers, bool is_dump_body) {
  499. ParseUrl();
  500. std::string str;
  501. str.reserve(MAX(512, path.size() + 128));
  502. // GET / HTTP/1.1\r\n
  503. str = asprintf("%s %s HTTP/%d.%d\r\n",
  504. http_method_str(method), path.c_str(),
  505. (int)http_major, (int)http_minor);
  506. if (is_dump_headers) {
  507. // Host:
  508. if (headers.find("Host") == headers.end()) {
  509. if (port == 0 ||
  510. port == DEFAULT_HTTP_PORT ||
  511. port == DEFAULT_HTTPS_PORT) {
  512. headers["Host"] = host;
  513. }
  514. else {
  515. headers["Host"] = asprintf("%s:%d", host.c_str(), port);
  516. }
  517. }
  518. DumpHeaders(str);
  519. }
  520. str += "\r\n";
  521. if (is_dump_body) {
  522. DumpBody(str);
  523. }
  524. return str;
  525. }
  526. std::string HttpResponse::Dump(bool is_dump_headers, bool is_dump_body) {
  527. char c_str[256] = {0};
  528. std::string str;
  529. str.reserve(512);
  530. // HTTP/1.1 200 OK\r\n
  531. snprintf(c_str, sizeof(c_str), "HTTP/%d.%d %d %s\r\n",
  532. (int)http_major, (int)http_minor,
  533. (int)status_code, http_status_str(status_code));
  534. str = c_str;
  535. if (is_dump_headers) {
  536. if (*s_date) {
  537. headers["Date"] = s_date;
  538. } else {
  539. headers["Date"] = gmtime_fmt(time(NULL), c_str);
  540. }
  541. DumpHeaders(str);
  542. }
  543. str += "\r\n";
  544. if (is_dump_body) {
  545. DumpBody(str);
  546. }
  547. return str;
  548. }