1
0

HttpMessage.cpp 15 KB

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