HttpMessage.cpp 18 KB

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