HttpMessage.cpp 15 KB

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