HttpMessage.cpp 16 KB

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