HttpMessage.cpp 16 KB

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