HttpMessage.cpp 14 KB

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