HttpMessage.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  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. HttpMessage::HttpMessage() {
  123. type = HTTP_BOTH;
  124. Init();
  125. }
  126. HttpMessage::~HttpMessage() {
  127. }
  128. void HttpMessage::Init() {
  129. http_major = 1;
  130. http_minor = 1;
  131. content = NULL;
  132. content_length = 0;
  133. content_type = CONTENT_TYPE_NONE;
  134. }
  135. void HttpMessage::Reset() {
  136. Init();
  137. headers.clear();
  138. cookies.clear();
  139. body.clear();
  140. #ifndef WITHOUT_HTTP_CONTENT
  141. json.clear();
  142. form.clear();
  143. kv.clear();
  144. #endif
  145. }
  146. #ifndef WITHOUT_HTTP_CONTENT
  147. // NOTE: json ignore number/string, 123/"123"
  148. std::string HttpMessage::GetString(const char* key, const std::string& defvalue) {
  149. switch (ContentType()) {
  150. case APPLICATION_JSON:
  151. {
  152. if (json.empty()) {
  153. ParseBody();
  154. }
  155. if (!json.is_object()) {
  156. return defvalue;
  157. }
  158. const auto& value = json[key];
  159. if (value.is_string()) {
  160. return value;
  161. }
  162. else if (value.is_number()) {
  163. return hv::to_string(value);
  164. }
  165. else if (value.is_null()) {
  166. return "null";
  167. }
  168. else if (value.is_boolean()) {
  169. bool b = value;
  170. return b ? "true" : "false";
  171. }
  172. else {
  173. return defvalue;
  174. }
  175. }
  176. break;
  177. case MULTIPART_FORM_DATA:
  178. {
  179. if (form.empty()) {
  180. ParseBody();
  181. }
  182. auto iter = form.find(key);
  183. if (iter != form.end()) {
  184. return iter->second.content;
  185. }
  186. }
  187. break;
  188. case APPLICATION_URLENCODED:
  189. {
  190. if (kv.empty()) {
  191. ParseBody();
  192. }
  193. auto iter = kv.find(key);
  194. if (iter != kv.end()) {
  195. return iter->second;
  196. }
  197. }
  198. break;
  199. default:
  200. break;
  201. }
  202. return defvalue;
  203. }
  204. template<>
  205. HV_EXPORT int64_t HttpMessage::Get(const char* key, int64_t defvalue) {
  206. if (ContentType() == APPLICATION_JSON) {
  207. if (json.empty()) {
  208. ParseBody();
  209. }
  210. if (!json.is_object()) {
  211. return defvalue;
  212. }
  213. const auto& value = json[key];
  214. if (value.is_number()) {
  215. return value;
  216. }
  217. else if (value.is_string()) {
  218. std::string str = value;
  219. return atoll(str.c_str());
  220. }
  221. else if (value.is_null()) {
  222. return 0;
  223. }
  224. else if (value.is_boolean()) {
  225. bool b = value;
  226. return b ? 1 : 0;
  227. }
  228. else {
  229. return defvalue;
  230. }
  231. }
  232. else {
  233. std::string str = GetString(key);
  234. return str.empty() ? defvalue : atoll(str.c_str());
  235. }
  236. }
  237. template<>
  238. HV_EXPORT int HttpMessage::Get(const char* key, int defvalue) {
  239. return (int)Get<int64_t>(key, defvalue);
  240. }
  241. template<>
  242. HV_EXPORT double HttpMessage::Get(const char* key, double defvalue) {
  243. if (ContentType() == APPLICATION_JSON) {
  244. if (json.empty()) {
  245. ParseBody();
  246. }
  247. if (!json.is_object()) {
  248. return defvalue;
  249. }
  250. const auto& value = json[key];
  251. if (value.is_number()) {
  252. return value;
  253. }
  254. else if (value.is_string()) {
  255. std::string str = value;
  256. return atof(str.c_str());
  257. }
  258. else if (value.is_null()) {
  259. return 0.0f;
  260. }
  261. else {
  262. return defvalue;
  263. }
  264. }
  265. else {
  266. std::string str = GetString(key);
  267. return str.empty() ? defvalue : atof(str.c_str());
  268. }
  269. }
  270. template<>
  271. HV_EXPORT float HttpMessage::Get(const char* key, float defvalue) {
  272. return (float)Get<double>(key, defvalue);
  273. }
  274. template<>
  275. HV_EXPORT bool HttpMessage::Get(const char* key, bool defvalue) {
  276. if (ContentType() == APPLICATION_JSON) {
  277. if (json.empty()) {
  278. ParseBody();
  279. }
  280. if (!json.is_object()) {
  281. return defvalue;
  282. }
  283. const auto& value = json[key];
  284. if (value.is_boolean()) {
  285. return value;
  286. }
  287. else if (value.is_string()) {
  288. std::string str = value;
  289. return hv_getboolean(str.c_str());
  290. }
  291. else if (value.is_null()) {
  292. return false;
  293. }
  294. else if (value.is_number()) {
  295. return value != 0;
  296. }
  297. else {
  298. return defvalue;
  299. }
  300. }
  301. else {
  302. std::string str = GetString(key);
  303. return str.empty() ? defvalue : hv_getboolean(str.c_str());
  304. }
  305. }
  306. bool HttpMessage::GetBool(const char* key, bool defvalue) {
  307. return Get<bool>(key, defvalue);
  308. }
  309. int64_t HttpMessage::GetInt(const char* key, int64_t defvalue) {
  310. return Get<int64_t>(key, defvalue);
  311. }
  312. double HttpMessage::GetFloat(const char* key, double defvalue) {
  313. return Get<double>(key, defvalue);
  314. }
  315. #endif
  316. void HttpMessage::FillContentType() {
  317. auto iter = headers.find("Content-Type");
  318. if (iter != headers.end()) {
  319. content_type = http_content_type_enum(iter->second.c_str());
  320. goto append;
  321. }
  322. #ifndef WITHOUT_HTTP_CONTENT
  323. if (content_type == CONTENT_TYPE_NONE) {
  324. if (json.size() != 0) {
  325. content_type = APPLICATION_JSON;
  326. }
  327. else if (form.size() != 0) {
  328. content_type = MULTIPART_FORM_DATA;
  329. }
  330. else if (kv.size() != 0) {
  331. content_type = X_WWW_FORM_URLENCODED;
  332. }
  333. else if (body.size() != 0) {
  334. content_type = TEXT_PLAIN;
  335. }
  336. }
  337. #endif
  338. if (content_type != CONTENT_TYPE_NONE) {
  339. headers["Content-Type"] = http_content_type_str(content_type);
  340. }
  341. append:
  342. #ifndef WITHOUT_HTTP_CONTENT
  343. if (content_type == MULTIPART_FORM_DATA) {
  344. auto iter = headers.find("Content-Type");
  345. if (iter != headers.end()) {
  346. const char* boundary = strstr(iter->second.c_str(), "boundary=");
  347. if (boundary == NULL) {
  348. boundary = DEFAULT_MULTIPART_BOUNDARY;
  349. iter->second += "; boundary=";
  350. iter->second += boundary;
  351. }
  352. }
  353. }
  354. #endif
  355. return;
  356. }
  357. void HttpMessage::FillContentLength() {
  358. auto iter = headers.find("Content-Length");
  359. if (iter != headers.end()) {
  360. content_length = atoll(iter->second.c_str());
  361. }
  362. if (content_length == 0) {
  363. DumpBody();
  364. content_length = body.size();
  365. }
  366. if (iter == headers.end() && !IsChunked() && content_type != TEXT_EVENT_STREAM) {
  367. if (content_length != 0 || type == HTTP_RESPONSE) {
  368. headers["Content-Length"] = hv::to_string(content_length);
  369. }
  370. }
  371. }
  372. bool HttpMessage::IsChunked() {
  373. auto iter = headers.find("Transfer-Encoding");
  374. return iter != headers.end() && stricmp(iter->second.c_str(), "chunked") == 0;
  375. }
  376. bool HttpMessage::IsKeepAlive() {
  377. bool keepalive = true;
  378. auto iter = headers.find("connection");
  379. if (iter != headers.end()) {
  380. const char* keepalive_value = iter->second.c_str();
  381. if (stricmp(keepalive_value, "keep-alive") == 0) {
  382. keepalive = true;
  383. }
  384. else if (stricmp(keepalive_value, "close") == 0) {
  385. keepalive = false;
  386. }
  387. else if (stricmp(keepalive_value, "upgrade") == 0) {
  388. keepalive = true;
  389. }
  390. }
  391. else if (http_major == 1 && http_minor == 0) {
  392. keepalive = false;
  393. }
  394. return keepalive;
  395. }
  396. // headers
  397. void HttpMessage::SetHeader(const char* key, const std::string& value) {
  398. headers[key] = value;
  399. }
  400. std::string HttpMessage::GetHeader(const char* key, const std::string& defvalue) {
  401. auto iter = headers.find(key);
  402. return iter == headers.end() ? defvalue : iter->second;
  403. }
  404. // cookies
  405. void HttpMessage::AddCookie(const HttpCookie& cookie) {
  406. cookies.push_back(cookie);
  407. }
  408. const HttpCookie& HttpMessage::GetCookie(const std::string& name) {
  409. for (auto iter = cookies.begin(); iter != cookies.end(); ++iter) {
  410. if (iter->name == name) {
  411. return *iter;
  412. }
  413. }
  414. return NoCookie;
  415. }
  416. // body
  417. void HttpMessage::SetBody(const std::string& body) {
  418. this->body = body;
  419. }
  420. const std::string& HttpMessage::Body() {
  421. return this->body;
  422. }
  423. void HttpMessage::DumpHeaders(std::string& str) {
  424. FillContentType();
  425. FillContentLength();
  426. // headers
  427. for (auto& header: headers) {
  428. // http2 :method :path :scheme :authority :status
  429. if (*str.c_str() != ':') {
  430. // %s: %s\r\n
  431. str += header.first;
  432. str += ": ";
  433. str += header.second;
  434. str += "\r\n";
  435. }
  436. }
  437. // cookies
  438. const char* cookie_field = "Cookie";
  439. if (type == HTTP_RESPONSE) {
  440. cookie_field = "Set-Cookie";
  441. }
  442. for (auto& cookie : cookies) {
  443. str += cookie_field;
  444. str += ": ";
  445. str += cookie.dump();
  446. str += "\r\n";
  447. }
  448. }
  449. void HttpMessage::DumpBody() {
  450. if (body.size() != 0) {
  451. return;
  452. }
  453. FillContentType();
  454. #ifndef WITHOUT_HTTP_CONTENT
  455. switch(content_type) {
  456. case APPLICATION_JSON:
  457. body = dump_json(json, 2);
  458. break;
  459. case MULTIPART_FORM_DATA:
  460. {
  461. auto iter = headers.find("Content-Type");
  462. if (iter == headers.end()) {
  463. return;
  464. }
  465. const char* boundary = strstr(iter->second.c_str(), "boundary=");
  466. if (boundary == NULL) {
  467. return;
  468. }
  469. boundary += strlen("boundary=");
  470. body = dump_multipart(form, boundary);
  471. }
  472. break;
  473. case X_WWW_FORM_URLENCODED:
  474. body = dump_query_params(kv);
  475. break;
  476. default:
  477. // nothing to do
  478. break;
  479. }
  480. #endif
  481. }
  482. void HttpMessage::DumpBody(std::string& str) {
  483. DumpBody();
  484. const char* content = (const char*)Content();
  485. size_t content_length = ContentLength();
  486. if (content && content_length) {
  487. str.append(content, content_length);
  488. }
  489. }
  490. int HttpMessage::ParseBody() {
  491. if (body.size() == 0) {
  492. return -1;
  493. }
  494. FillContentType();
  495. #ifndef WITHOUT_HTTP_CONTENT
  496. switch(content_type) {
  497. case APPLICATION_JSON:
  498. {
  499. std::string errmsg;
  500. int ret = parse_json(body.c_str(), json, errmsg);
  501. if (ret != 0 && errmsg.size() != 0) {
  502. hloge("%s", errmsg.c_str());
  503. }
  504. return ret;
  505. }
  506. case MULTIPART_FORM_DATA:
  507. {
  508. auto iter = headers.find("Content-Type");
  509. if (iter == headers.end()) {
  510. return -1;
  511. }
  512. const char* boundary = strstr(iter->second.c_str(), "boundary=");
  513. if (boundary == NULL) {
  514. return -1;
  515. }
  516. boundary += strlen("boundary=");
  517. std::string strBoundary(boundary);
  518. strBoundary = trim_pairs(strBoundary, "\"\"\'\'");
  519. return parse_multipart(body, form, strBoundary.c_str());
  520. }
  521. case X_WWW_FORM_URLENCODED:
  522. return parse_query_params(body.c_str(), kv);
  523. default:
  524. // nothing to do
  525. return 0;
  526. }
  527. #endif
  528. return 0;
  529. }
  530. std::string HttpMessage::Dump(bool is_dump_headers, bool is_dump_body) {
  531. std::string str;
  532. if (is_dump_headers) {
  533. DumpHeaders(str);
  534. }
  535. str += "\r\n";
  536. if (is_dump_body) {
  537. DumpBody(str);
  538. }
  539. return str;
  540. }
  541. HttpRequest::HttpRequest() : HttpMessage() {
  542. type = HTTP_REQUEST;
  543. Init();
  544. }
  545. void HttpRequest::Init() {
  546. headers["User-Agent"] = DEFAULT_HTTP_USER_AGENT;
  547. headers["Accept"] = "*/*";
  548. method = HTTP_GET;
  549. scheme = "http";
  550. host = "127.0.0.1";
  551. port = DEFAULT_HTTP_PORT;
  552. path = "/";
  553. timeout = DEFAULT_HTTP_TIMEOUT;
  554. connect_timeout = DEFAULT_HTTP_CONNECT_TIMEOUT;
  555. retry_count = DEFAULT_HTTP_FAIL_RETRY_COUNT;
  556. retry_delay = DEFAULT_HTTP_FAIL_RETRY_DELAY;
  557. redirect = 1;
  558. proxy = 0;
  559. }
  560. void HttpRequest::Reset() {
  561. HttpMessage::Reset();
  562. Init();
  563. url.clear();
  564. query_params.clear();
  565. }
  566. void HttpRequest::DumpUrl() {
  567. std::string str;
  568. if (url.size() != 0 &&
  569. *url.c_str() != '/' &&
  570. strstr(url.c_str(), "://") != NULL) {
  571. // have been complete url
  572. goto query;
  573. }
  574. // scheme://
  575. str = scheme;
  576. str += "://";
  577. // host:port
  578. if (url.size() != 0 && *url.c_str() != '/') {
  579. // url begin with host
  580. str += url;
  581. }
  582. else {
  583. if (port == 0 ||
  584. port == DEFAULT_HTTP_PORT ||
  585. port == DEFAULT_HTTPS_PORT) {
  586. str += Host();
  587. }
  588. else {
  589. str += hv::asprintf("%s:%d", host.c_str(), port);
  590. }
  591. }
  592. // /path
  593. if (url.size() != 0 && *url.c_str() == '/') {
  594. // url begin with path
  595. str += url;
  596. }
  597. else if (path.size() > 1 && *path.c_str() == '/') {
  598. str += path;
  599. }
  600. else if (url.size() == 0) {
  601. str += '/';
  602. }
  603. url = str;
  604. query:
  605. // ?query
  606. if (strchr(url.c_str(), '?') == NULL &&
  607. query_params.size() != 0) {
  608. url += '?';
  609. url += dump_query_params(query_params);
  610. }
  611. }
  612. void HttpRequest::ParseUrl() {
  613. DumpUrl();
  614. hurl_t parser;
  615. hv_parse_url(&parser, url.c_str());
  616. // scheme
  617. std::string scheme_ = url.substr(parser.fields[HV_URL_SCHEME].off, parser.fields[HV_URL_SCHEME].len);
  618. // host
  619. std::string host_(host);
  620. if (parser.fields[HV_URL_HOST].len > 0) {
  621. host_ = url.substr(parser.fields[HV_URL_HOST].off, parser.fields[HV_URL_HOST].len);
  622. }
  623. // port
  624. int port_ = parser.port ? parser.port : strcmp(scheme_.c_str(), "https") ? DEFAULT_HTTP_PORT : DEFAULT_HTTPS_PORT;
  625. if (!proxy) {
  626. scheme = scheme_;
  627. host = host_;
  628. port = port_;
  629. }
  630. FillHost(host_.c_str(), port_);
  631. // path
  632. if (parser.fields[HV_URL_PATH].len > 0) {
  633. path = url.substr(parser.fields[HV_URL_PATH].off);
  634. }
  635. // query
  636. if (parser.fields[HV_URL_QUERY].len > 0) {
  637. parse_query_params(url.c_str()+parser.fields[HV_URL_QUERY].off, query_params);
  638. }
  639. }
  640. std::string HttpRequest::Path() {
  641. const char* s = path.c_str();
  642. const char* e = s;
  643. while (*e && *e != '?' && *e != '#') ++e;
  644. return HUrl::unescape(std::string(s, e));
  645. }
  646. void HttpRequest::FillHost(const char* host, int port) {
  647. if (headers.find("Host") == headers.end()) {
  648. if (port == 0 ||
  649. port == DEFAULT_HTTP_PORT ||
  650. port == DEFAULT_HTTPS_PORT) {
  651. headers["Host"] = host;
  652. } else {
  653. headers["Host"] = asprintf("%s:%d", host, port);
  654. }
  655. }
  656. }
  657. void HttpRequest::SetHost(const char* host, int port) {
  658. this->host = host;
  659. this->port = port;
  660. FillHost(host, port);
  661. }
  662. void HttpRequest::SetProxy(const char* host, int port) {
  663. this->scheme = "http";
  664. this->host = host;
  665. this->port = port;
  666. proxy = 1;
  667. }
  668. std::string HttpRequest::Dump(bool is_dump_headers, bool is_dump_body) {
  669. ParseUrl();
  670. std::string str;
  671. str.reserve(MAX(512, path.size() + 128));
  672. // GET / HTTP/1.1\r\n
  673. str = asprintf("%s %s HTTP/%d.%d\r\n",
  674. http_method_str(method),
  675. proxy ? url.c_str() : path.c_str(),
  676. (int)http_major, (int)http_minor);
  677. if (is_dump_headers) {
  678. DumpHeaders(str);
  679. }
  680. str += "\r\n";
  681. if (is_dump_body) {
  682. DumpBody(str);
  683. }
  684. return str;
  685. }
  686. void HttpRequest::SetRange(long from, long to) {
  687. SetHeader("Range", hv::asprintf("bytes=%ld-%ld", from, to));
  688. }
  689. bool HttpRequest::GetRange(long& from, long& to) {
  690. auto iter = headers.find("Range");
  691. if (iter != headers.end()) {
  692. sscanf(iter->second.c_str(), "bytes=%ld-%ld", &from, &to);
  693. return true;
  694. }
  695. from = to = 0;
  696. return false;
  697. }
  698. HttpResponse::HttpResponse() : HttpMessage() {
  699. type = HTTP_RESPONSE;
  700. Init();
  701. }
  702. void HttpResponse::Init() {
  703. status_code = HTTP_STATUS_OK;
  704. }
  705. void HttpResponse::Reset() {
  706. HttpMessage::Reset();
  707. Init();
  708. }
  709. std::string HttpResponse::Dump(bool is_dump_headers, bool is_dump_body) {
  710. char c_str[256] = {0};
  711. std::string str;
  712. str.reserve(512);
  713. // HTTP/1.1 200 OK\r\n
  714. snprintf(c_str, sizeof(c_str), "HTTP/%d.%d %d %s\r\n",
  715. (int)http_major, (int)http_minor,
  716. (int)status_code, http_status_str(status_code));
  717. str = c_str;
  718. if (is_dump_headers) {
  719. if (*s_date) {
  720. headers["Date"] = s_date;
  721. } else {
  722. headers["Date"] = gmtime_fmt(time(NULL), c_str);
  723. }
  724. DumpHeaders(str);
  725. }
  726. str += "\r\n";
  727. if (is_dump_body) {
  728. DumpBody(str);
  729. }
  730. return str;
  731. }
  732. void HttpResponse::SetRange(long from, long to, long total) {
  733. SetHeader("Content-Range", hv::asprintf("bytes %ld-%ld/%ld", from, to, total));
  734. }
  735. bool HttpResponse::GetRange(long& from, long& to, long& total) {
  736. auto iter = headers.find("Content-Range");
  737. if (iter != headers.end()) {
  738. sscanf(iter->second.c_str(), "bytes %ld-%ld/%ld", &from, &to, &total);
  739. return true;
  740. }
  741. from = to = total = 0;
  742. return false;
  743. }