1
0

HttpMessage.cpp 17 KB

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