http_response_headers_unittest.cc 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/http/http_response_headers.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <iostream>
  8. #include <limits>
  9. #include <memory>
  10. #include <unordered_set>
  11. #include "base/pickle.h"
  12. #include "base/time/time.h"
  13. #include "base/trace_event/trace_event.h"
  14. #include "base/values.h"
  15. #include "net/http/http_byte_range.h"
  16. #include "net/http/http_util.h"
  17. #include "net/log/net_log_capture_mode.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #include "third_party/perfetto/include/perfetto/test/traced_value_test_support.h"
  20. namespace net {
  21. namespace {
  22. struct TestData {
  23. const char* raw_headers;
  24. const char* expected_headers;
  25. HttpVersion expected_version;
  26. int expected_response_code;
  27. const char* expected_status_text;
  28. };
  29. class HttpResponseHeadersTest : public testing::Test {
  30. };
  31. // Transform "normal"-looking headers (\n-separated) to the appropriate
  32. // input format for ParseRawHeaders (\0-separated).
  33. void HeadersToRaw(std::string* headers) {
  34. std::replace(headers->begin(), headers->end(), '\n', '\0');
  35. if (!headers->empty())
  36. *headers += '\0';
  37. }
  38. class HttpResponseHeadersCacheControlTest : public HttpResponseHeadersTest {
  39. protected:
  40. // Make tests less verbose.
  41. typedef base::TimeDelta TimeDelta;
  42. // Initilise the headers() value with a Cache-Control header set to
  43. // |cache_control|. |cache_control| is copied and so can safely be a
  44. // temporary.
  45. void InitializeHeadersWithCacheControl(const char* cache_control) {
  46. std::string raw_headers("HTTP/1.1 200 OK\n");
  47. raw_headers += "Cache-Control: ";
  48. raw_headers += cache_control;
  49. raw_headers += "\n";
  50. HeadersToRaw(&raw_headers);
  51. headers_ = base::MakeRefCounted<HttpResponseHeaders>(raw_headers);
  52. }
  53. const scoped_refptr<HttpResponseHeaders>& headers() { return headers_; }
  54. // Return a pointer to a TimeDelta object. For use when the value doesn't
  55. // matter.
  56. TimeDelta* TimeDeltaPointer() { return &delta_; }
  57. // Get the max-age value. This should only be used in tests where a valid
  58. // max-age parameter is expected to be present.
  59. TimeDelta GetMaxAgeValue() {
  60. DCHECK(headers_.get()) << "Call InitializeHeadersWithCacheControl() first";
  61. TimeDelta max_age_value;
  62. EXPECT_TRUE(headers()->GetMaxAgeValue(&max_age_value));
  63. return max_age_value;
  64. }
  65. // Get the stale-while-revalidate value. This should only be used in tests
  66. // where a valid max-age parameter is expected to be present.
  67. TimeDelta GetStaleWhileRevalidateValue() {
  68. DCHECK(headers_.get()) << "Call InitializeHeadersWithCacheControl() first";
  69. TimeDelta stale_while_revalidate_value;
  70. EXPECT_TRUE(
  71. headers()->GetStaleWhileRevalidateValue(&stale_while_revalidate_value));
  72. return stale_while_revalidate_value;
  73. }
  74. private:
  75. scoped_refptr<HttpResponseHeaders> headers_;
  76. TimeDelta delta_;
  77. };
  78. class CommonHttpResponseHeadersTest
  79. : public HttpResponseHeadersTest,
  80. public ::testing::WithParamInterface<TestData> {
  81. };
  82. // Returns a simple text serialization of the given
  83. // |HttpResponseHeaders|. This is used by tests to verify that an
  84. // |HttpResponseHeaders| matches an expectation string.
  85. //
  86. // * One line per header, written as:
  87. // HEADER_NAME: HEADER_VALUE\n
  88. // * The original case of header names is preserved.
  89. // * Whitespace around head names/values is stripped.
  90. // * Repeated headers are not aggregated.
  91. // * Headers are listed in their original order.
  92. std::string ToSimpleString(const scoped_refptr<HttpResponseHeaders>& parsed) {
  93. std::string result = parsed->GetStatusLine() + "\n";
  94. size_t iter = 0;
  95. std::string name;
  96. std::string value;
  97. while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
  98. std::string new_line = name + ": " + value + "\n";
  99. // Verify that |name| and |value| do not contain ':' or '\n' (if they did
  100. // it would make this serialized format ambiguous).
  101. if (std::count(new_line.begin(), new_line.end(), '\n') != 1 ||
  102. std::count(new_line.begin(), new_line.end(), ':') != 1) {
  103. ADD_FAILURE() << "Unexpected characters in the header name or value: "
  104. << new_line;
  105. return result;
  106. }
  107. result += new_line;
  108. }
  109. return result;
  110. }
  111. TEST_P(CommonHttpResponseHeadersTest, TestCommon) {
  112. const TestData test = GetParam();
  113. std::string raw_headers(test.raw_headers);
  114. HeadersToRaw(&raw_headers);
  115. std::string expected_headers(test.expected_headers);
  116. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(raw_headers);
  117. std::string headers = ToSimpleString(parsed);
  118. // Transform to readable output format (so it's easier to see diffs).
  119. std::replace(headers.begin(), headers.end(), ' ', '_');
  120. std::replace(headers.begin(), headers.end(), '\n', '\\');
  121. std::replace(expected_headers.begin(), expected_headers.end(), ' ', '_');
  122. std::replace(expected_headers.begin(), expected_headers.end(), '\n', '\\');
  123. EXPECT_EQ(expected_headers, headers);
  124. EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
  125. EXPECT_EQ(test.expected_response_code, parsed->response_code());
  126. EXPECT_EQ(test.expected_status_text, parsed->GetStatusText());
  127. }
  128. TestData response_headers_tests[] = {
  129. {// Normalize whitespace.
  130. "HTTP/1.1 202 Accepted \n"
  131. "Content-TYPE : text/html; charset=utf-8 \n"
  132. "Set-Cookie: a \n"
  133. "Set-Cookie: b \n",
  134. "HTTP/1.1 202 Accepted\n"
  135. "Content-TYPE: text/html; charset=utf-8\n"
  136. "Set-Cookie: a\n"
  137. "Set-Cookie: b\n",
  138. HttpVersion(1, 1), 202, "Accepted"},
  139. {// Normalize leading whitespace.
  140. "HTTP/1.1 202 Accepted \n"
  141. // Starts with space -- will be skipped as invalid.
  142. " Content-TYPE : text/html; charset=utf-8 \n"
  143. "Set-Cookie: a \n"
  144. "Set-Cookie: b \n",
  145. "HTTP/1.1 202 Accepted\n"
  146. "Set-Cookie: a\n"
  147. "Set-Cookie: b\n",
  148. HttpVersion(1, 1), 202, "Accepted"},
  149. {// Keep whitespace within status text.
  150. "HTTP/1.0 404 Not found \n",
  151. "HTTP/1.0 404 Not found\n",
  152. HttpVersion(1, 0), 404, "Not found"},
  153. {// Normalize blank headers.
  154. "HTTP/1.1 200 OK\n"
  155. "Header1 : \n"
  156. "Header2: \n"
  157. "Header3:\n"
  158. "Header4\n"
  159. "Header5 :\n",
  160. "HTTP/1.1 200 OK\n"
  161. "Header1: \n"
  162. "Header2: \n"
  163. "Header3: \n"
  164. "Header5: \n",
  165. HttpVersion(1, 1), 200, "OK"},
  166. {// Don't believe the http/0.9 version if there are headers!
  167. "hTtP/0.9 201\n"
  168. "Content-TYPE: text/html; charset=utf-8\n",
  169. "HTTP/1.0 201\n"
  170. "Content-TYPE: text/html; charset=utf-8\n",
  171. HttpVersion(1, 0), 201, ""},
  172. {// Accept the HTTP/0.9 version number if there are no headers.
  173. // This is how HTTP/0.9 responses get constructed from
  174. // HttpNetworkTransaction.
  175. "hTtP/0.9 200 OK\n",
  176. "HTTP/0.9 200 OK\n",
  177. HttpVersion(0, 9), 200, "OK"},
  178. {// Do not add missing status text.
  179. "HTTP/1.1 201\n"
  180. "Content-TYPE: text/html; charset=utf-8\n",
  181. "HTTP/1.1 201\n"
  182. "Content-TYPE: text/html; charset=utf-8\n",
  183. HttpVersion(1, 1), 201, ""},
  184. {// Normalize bad status line.
  185. "SCREWED_UP_STATUS_LINE\n"
  186. "Content-TYPE: text/html; charset=utf-8\n",
  187. "HTTP/1.0 200 OK\n"
  188. "Content-TYPE: text/html; charset=utf-8\n",
  189. HttpVersion(1, 0), 200, "OK"},
  190. {// Normalize bad status line.
  191. "Foo bar.",
  192. "HTTP/1.0 200\n",
  193. HttpVersion(1, 0), 200, ""},
  194. {// Normalize invalid status code.
  195. "HTTP/1.1 -1 Unknown\n",
  196. "HTTP/1.1 200\n",
  197. HttpVersion(1, 1), 200, ""},
  198. {// Normalize empty header.
  199. "",
  200. "HTTP/1.0 200 OK\n",
  201. HttpVersion(1, 0), 200, "OK"},
  202. {// Normalize headers that start with a colon.
  203. "HTTP/1.1 202 Accepted \n"
  204. "foo: bar\n"
  205. ": a \n"
  206. " : b\n"
  207. "baz: blat \n",
  208. "HTTP/1.1 202 Accepted\n"
  209. "foo: bar\n"
  210. "baz: blat\n",
  211. HttpVersion(1, 1), 202, "Accepted"},
  212. {// Normalize headers that end with a colon.
  213. "HTTP/1.1 202 Accepted \n"
  214. "foo: \n"
  215. "bar:\n"
  216. "baz: blat \n"
  217. "zip:\n",
  218. "HTTP/1.1 202 Accepted\n"
  219. "foo: \n"
  220. "bar: \n"
  221. "baz: blat\n"
  222. "zip: \n",
  223. HttpVersion(1, 1), 202, "Accepted"},
  224. {// Normalize whitespace headers.
  225. "\n \n",
  226. "HTTP/1.0 200 OK\n",
  227. HttpVersion(1, 0), 200, "OK"},
  228. {// Has multiple Set-Cookie headers.
  229. "HTTP/1.1 200 OK\n"
  230. "Set-Cookie: x=1\n"
  231. "Set-Cookie: y=2\n",
  232. "HTTP/1.1 200 OK\n"
  233. "Set-Cookie: x=1\n"
  234. "Set-Cookie: y=2\n",
  235. HttpVersion(1, 1), 200, "OK"},
  236. {// Has multiple cache-control headers.
  237. "HTTP/1.1 200 OK\n"
  238. "Cache-control: private\n"
  239. "cache-Control: no-store\n",
  240. "HTTP/1.1 200 OK\n"
  241. "Cache-control: private\n"
  242. "cache-Control: no-store\n",
  243. HttpVersion(1, 1), 200, "OK"},
  244. };
  245. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  246. CommonHttpResponseHeadersTest,
  247. testing::ValuesIn(response_headers_tests));
  248. struct PersistData {
  249. HttpResponseHeaders::PersistOptions options;
  250. const char* raw_headers;
  251. const char* expected_headers;
  252. };
  253. class PersistenceTest
  254. : public HttpResponseHeadersTest,
  255. public ::testing::WithParamInterface<PersistData> {
  256. };
  257. TEST_P(PersistenceTest, Persist) {
  258. const PersistData test = GetParam();
  259. std::string headers = test.raw_headers;
  260. HeadersToRaw(&headers);
  261. auto parsed1 = base::MakeRefCounted<HttpResponseHeaders>(headers);
  262. base::Pickle pickle;
  263. parsed1->Persist(&pickle, test.options);
  264. base::PickleIterator iter(pickle);
  265. auto parsed2 = base::MakeRefCounted<HttpResponseHeaders>(&iter);
  266. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed2));
  267. }
  268. const struct PersistData persistence_tests[] = {
  269. {HttpResponseHeaders::PERSIST_ALL,
  270. "HTTP/1.1 200 OK\n"
  271. "Cache-control:private\n"
  272. "cache-Control:no-store\n",
  273. "HTTP/1.1 200 OK\n"
  274. "Cache-control: private\n"
  275. "cache-Control: no-store\n"},
  276. {HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
  277. "HTTP/1.1 200 OK\n"
  278. "connection: keep-alive\n"
  279. "server: blah\n",
  280. "HTTP/1.1 200 OK\n"
  281. "server: blah\n"},
  282. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
  283. HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
  284. "HTTP/1.1 200 OK\n"
  285. "fOo: 1\n"
  286. "Foo: 2\n"
  287. "Transfer-Encoding: chunked\n"
  288. "CoNnection: keep-alive\n"
  289. "cache-control: private, no-cache=\"foo\"\n",
  290. "HTTP/1.1 200 OK\n"
  291. "cache-control: private, no-cache=\"foo\"\n"},
  292. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  293. "HTTP/1.1 200 OK\n"
  294. "Foo: 2\n"
  295. "Cache-Control: private,no-cache=\"foo, bar\"\n"
  296. "bar",
  297. "HTTP/1.1 200 OK\n"
  298. "Cache-Control: private,no-cache=\"foo, bar\"\n"},
  299. // Ignore bogus no-cache value.
  300. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  301. "HTTP/1.1 200 OK\n"
  302. "Foo: 2\n"
  303. "Cache-Control: private,no-cache=foo\n",
  304. "HTTP/1.1 200 OK\n"
  305. "Foo: 2\n"
  306. "Cache-Control: private,no-cache=foo\n"},
  307. // Ignore bogus no-cache value.
  308. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  309. "HTTP/1.1 200 OK\n"
  310. "Foo: 2\n"
  311. "Cache-Control: private, no-cache=\n",
  312. "HTTP/1.1 200 OK\n"
  313. "Foo: 2\n"
  314. "Cache-Control: private, no-cache=\n"},
  315. // Ignore empty no-cache value.
  316. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  317. "HTTP/1.1 200 OK\n"
  318. "Foo: 2\n"
  319. "Cache-Control: private, no-cache=\"\"\n",
  320. "HTTP/1.1 200 OK\n"
  321. "Foo: 2\n"
  322. "Cache-Control: private, no-cache=\"\"\n"},
  323. // Ignore wrong quotes no-cache value.
  324. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  325. "HTTP/1.1 200 OK\n"
  326. "Foo: 2\n"
  327. "Cache-Control: private, no-cache=\'foo\'\n",
  328. "HTTP/1.1 200 OK\n"
  329. "Foo: 2\n"
  330. "Cache-Control: private, no-cache=\'foo\'\n"},
  331. // Ignore unterminated quotes no-cache value.
  332. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  333. "HTTP/1.1 200 OK\n"
  334. "Foo: 2\n"
  335. "Cache-Control: private, no-cache=\"foo\n",
  336. "HTTP/1.1 200 OK\n"
  337. "Foo: 2\n"
  338. "Cache-Control: private, no-cache=\"foo\n"},
  339. // Accept sloppy LWS.
  340. {HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
  341. "HTTP/1.1 200 OK\n"
  342. "Foo: 2\n"
  343. "Cache-Control: private, no-cache=\" foo\t, bar\"\n",
  344. "HTTP/1.1 200 OK\n"
  345. "Cache-Control: private, no-cache=\" foo\t, bar\"\n"},
  346. // Header name appears twice, separated by another header.
  347. {HttpResponseHeaders::PERSIST_ALL,
  348. "HTTP/1.1 200 OK\n"
  349. "Foo: 1\n"
  350. "Bar: 2\n"
  351. "Foo: 3\n",
  352. "HTTP/1.1 200 OK\n"
  353. "Foo: 1\n"
  354. "Bar: 2\n"
  355. "Foo: 3\n"},
  356. // Header name appears twice, separated by another header (type 2).
  357. {HttpResponseHeaders::PERSIST_ALL,
  358. "HTTP/1.1 200 OK\n"
  359. "Foo: 1, 3\n"
  360. "Bar: 2\n"
  361. "Foo: 4\n",
  362. "HTTP/1.1 200 OK\n"
  363. "Foo: 1, 3\n"
  364. "Bar: 2\n"
  365. "Foo: 4\n"},
  366. // Test filtering of cookie headers.
  367. {HttpResponseHeaders::PERSIST_SANS_COOKIES,
  368. "HTTP/1.1 200 OK\n"
  369. "Set-Cookie: foo=bar; httponly\n"
  370. "Set-Cookie: bar=foo\n"
  371. "Bar: 1\n"
  372. "Set-Cookie2: bar2=foo2\n",
  373. "HTTP/1.1 200 OK\n"
  374. "Bar: 1\n"},
  375. {HttpResponseHeaders::PERSIST_SANS_COOKIES,
  376. "HTTP/1.1 200 OK\n"
  377. "Set-Cookie: foo=bar\n"
  378. "Foo: 2\n"
  379. "Clear-Site-Data: { \"types\" : [ \"cookies\" ] }\n"
  380. "Bar: 3\n",
  381. "HTTP/1.1 200 OK\n"
  382. "Foo: 2\n"
  383. "Bar: 3\n"},
  384. // Test LWS at the end of a header.
  385. {HttpResponseHeaders::PERSIST_ALL,
  386. "HTTP/1.1 200 OK\n"
  387. "Content-Length: 450 \n"
  388. "Content-Encoding: gzip\n",
  389. "HTTP/1.1 200 OK\n"
  390. "Content-Length: 450\n"
  391. "Content-Encoding: gzip\n"},
  392. // Test LWS at the end of a header.
  393. {HttpResponseHeaders::PERSIST_RAW,
  394. "HTTP/1.1 200 OK\n"
  395. "Content-Length: 450 \n"
  396. "Content-Encoding: gzip\n",
  397. "HTTP/1.1 200 OK\n"
  398. "Content-Length: 450\n"
  399. "Content-Encoding: gzip\n"},
  400. // Test filtering of transport security state headers.
  401. {HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE,
  402. "HTTP/1.1 200 OK\n"
  403. "Strict-Transport-Security: max-age=1576800\n"
  404. "Bar: 1\n",
  405. "HTTP/1.1 200 OK\n"
  406. "Bar: 1\n"},
  407. };
  408. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  409. PersistenceTest,
  410. testing::ValuesIn(persistence_tests));
  411. TEST(HttpResponseHeadersTest, EnumerateHeader_Coalesced) {
  412. // Ensure that commas in quoted strings are not regarded as value separators.
  413. // Ensure that whitespace following a value is trimmed properly.
  414. std::string headers =
  415. "HTTP/1.1 200 OK\n"
  416. "Cache-control:,,private , no-cache=\"set-cookie,server\",\n"
  417. "cache-Control: no-store\n"
  418. "cache-Control:\n";
  419. HeadersToRaw(&headers);
  420. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  421. size_t iter = 0;
  422. std::string value;
  423. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  424. EXPECT_EQ("", value);
  425. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  426. EXPECT_EQ("", value);
  427. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  428. EXPECT_EQ("private", value);
  429. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  430. EXPECT_EQ("no-cache=\"set-cookie,server\"", value);
  431. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  432. EXPECT_EQ("", value);
  433. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  434. EXPECT_EQ("no-store", value);
  435. ASSERT_TRUE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  436. EXPECT_EQ("", value);
  437. EXPECT_FALSE(parsed->EnumerateHeader(&iter, "cache-control", &value));
  438. }
  439. TEST(HttpResponseHeadersTest, EnumerateHeader_Challenge) {
  440. // Even though WWW-Authenticate has commas, it should not be treated as
  441. // coalesced values.
  442. std::string headers =
  443. "HTTP/1.1 401 OK\n"
  444. "WWW-Authenticate:Digest realm=foobar, nonce=x, domain=y\n"
  445. "WWW-Authenticate:Basic realm=quatar\n";
  446. HeadersToRaw(&headers);
  447. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  448. size_t iter = 0;
  449. std::string value;
  450. EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
  451. EXPECT_EQ("Digest realm=foobar, nonce=x, domain=y", value);
  452. EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
  453. EXPECT_EQ("Basic realm=quatar", value);
  454. EXPECT_FALSE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
  455. }
  456. TEST(HttpResponseHeadersTest, EnumerateHeader_DateValued) {
  457. // The comma in a date valued header should not be treated as a
  458. // field-value separator.
  459. std::string headers =
  460. "HTTP/1.1 200 OK\n"
  461. "Date: Tue, 07 Aug 2007 23:10:55 GMT\n"
  462. "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n";
  463. HeadersToRaw(&headers);
  464. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  465. std::string value;
  466. EXPECT_TRUE(parsed->EnumerateHeader(nullptr, "date", &value));
  467. EXPECT_EQ("Tue, 07 Aug 2007 23:10:55 GMT", value);
  468. EXPECT_TRUE(parsed->EnumerateHeader(nullptr, "last-modified", &value));
  469. EXPECT_EQ("Wed, 01 Aug 2007 23:23:45 GMT", value);
  470. }
  471. TEST(HttpResponseHeadersTest, DefaultDateToGMT) {
  472. // Verify we make the best interpretation when parsing dates that incorrectly
  473. // do not end in "GMT" as RFC2616 requires.
  474. std::string headers =
  475. "HTTP/1.1 200 OK\n"
  476. "Date: Tue, 07 Aug 2007 23:10:55\n"
  477. "Last-Modified: Tue, 07 Aug 2007 19:10:55 EDT\n"
  478. "Expires: Tue, 07 Aug 2007 23:10:55 UTC\n";
  479. HeadersToRaw(&headers);
  480. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  481. base::Time expected_value;
  482. ASSERT_TRUE(base::Time::FromString("Tue, 07 Aug 2007 23:10:55 GMT",
  483. &expected_value));
  484. base::Time value;
  485. // When the timezone is missing, GMT is a good guess as its what RFC2616
  486. // requires.
  487. EXPECT_TRUE(parsed->GetDateValue(&value));
  488. EXPECT_EQ(expected_value, value);
  489. // If GMT is missing but an RFC822-conforming one is present, use that.
  490. EXPECT_TRUE(parsed->GetLastModifiedValue(&value));
  491. EXPECT_EQ(expected_value, value);
  492. // If an unknown timezone is present, treat like a missing timezone and
  493. // default to GMT. The only example of a web server not specifying "GMT"
  494. // used "UTC" which is equivalent to GMT.
  495. if (parsed->GetExpiresValue(&value))
  496. EXPECT_EQ(expected_value, value);
  497. }
  498. TEST(HttpResponseHeadersTest, GetAgeValue10) {
  499. std::string headers =
  500. "HTTP/1.1 200 OK\n"
  501. "Age: 10\n";
  502. HeadersToRaw(&headers);
  503. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  504. base::TimeDelta age;
  505. ASSERT_TRUE(parsed->GetAgeValue(&age));
  506. EXPECT_EQ(10, age.InSeconds());
  507. }
  508. TEST(HttpResponseHeadersTest, GetAgeValue0) {
  509. std::string headers =
  510. "HTTP/1.1 200 OK\n"
  511. "Age: 0\n";
  512. HeadersToRaw(&headers);
  513. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  514. base::TimeDelta age;
  515. ASSERT_TRUE(parsed->GetAgeValue(&age));
  516. EXPECT_EQ(0, age.InSeconds());
  517. }
  518. TEST(HttpResponseHeadersTest, GetAgeValueBogus) {
  519. std::string headers =
  520. "HTTP/1.1 200 OK\n"
  521. "Age: donkey\n";
  522. HeadersToRaw(&headers);
  523. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  524. base::TimeDelta age;
  525. ASSERT_FALSE(parsed->GetAgeValue(&age));
  526. }
  527. TEST(HttpResponseHeadersTest, GetAgeValueNegative) {
  528. std::string headers =
  529. "HTTP/1.1 200 OK\n"
  530. "Age: -10\n";
  531. HeadersToRaw(&headers);
  532. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  533. base::TimeDelta age;
  534. ASSERT_FALSE(parsed->GetAgeValue(&age));
  535. }
  536. TEST(HttpResponseHeadersTest, GetAgeValueLeadingPlus) {
  537. std::string headers =
  538. "HTTP/1.1 200 OK\n"
  539. "Age: +10\n";
  540. HeadersToRaw(&headers);
  541. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  542. base::TimeDelta age;
  543. ASSERT_FALSE(parsed->GetAgeValue(&age));
  544. }
  545. TEST(HttpResponseHeadersTest, GetAgeValueOverflow) {
  546. std::string headers =
  547. "HTTP/1.1 200 OK\n"
  548. "Age: 999999999999999999999999999999999999999999\n";
  549. HeadersToRaw(&headers);
  550. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  551. base::TimeDelta age;
  552. ASSERT_TRUE(parsed->GetAgeValue(&age));
  553. // Should have saturated to 2^32 - 1.
  554. EXPECT_EQ(static_cast<int64_t>(0xFFFFFFFFL), age.InSeconds());
  555. }
  556. struct ContentTypeTestData {
  557. const std::string raw_headers;
  558. const std::string mime_type;
  559. const bool has_mimetype;
  560. const std::string charset;
  561. const bool has_charset;
  562. const std::string all_content_type;
  563. };
  564. class ContentTypeTest
  565. : public HttpResponseHeadersTest,
  566. public ::testing::WithParamInterface<ContentTypeTestData> {
  567. };
  568. TEST_P(ContentTypeTest, GetMimeType) {
  569. const ContentTypeTestData test = GetParam();
  570. std::string headers(test.raw_headers);
  571. HeadersToRaw(&headers);
  572. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  573. std::string value;
  574. EXPECT_EQ(test.has_mimetype, parsed->GetMimeType(&value));
  575. EXPECT_EQ(test.mime_type, value);
  576. value.clear();
  577. EXPECT_EQ(test.has_charset, parsed->GetCharset(&value));
  578. EXPECT_EQ(test.charset, value);
  579. EXPECT_TRUE(parsed->GetNormalizedHeader("content-type", &value));
  580. EXPECT_EQ(test.all_content_type, value);
  581. }
  582. // clang-format off
  583. const ContentTypeTestData mimetype_tests[] = {
  584. { "HTTP/1.1 200 OK\n"
  585. "Content-type: text/html\n",
  586. "text/html", true,
  587. "", false,
  588. "text/html" },
  589. // Multiple content-type headers should give us the last one.
  590. { "HTTP/1.1 200 OK\n"
  591. "Content-type: text/html\n"
  592. "Content-type: text/html\n",
  593. "text/html", true,
  594. "", false,
  595. "text/html, text/html" },
  596. { "HTTP/1.1 200 OK\n"
  597. "Content-type: text/plain\n"
  598. "Content-type: text/html\n"
  599. "Content-type: text/plain\n"
  600. "Content-type: text/html\n",
  601. "text/html", true,
  602. "", false,
  603. "text/plain, text/html, text/plain, text/html" },
  604. // Test charset parsing.
  605. { "HTTP/1.1 200 OK\n"
  606. "Content-type: text/html\n"
  607. "Content-type: text/html; charset=ISO-8859-1\n",
  608. "text/html", true,
  609. "iso-8859-1", true,
  610. "text/html, text/html; charset=ISO-8859-1" },
  611. // Test charset in double quotes.
  612. { "HTTP/1.1 200 OK\n"
  613. "Content-type: text/html\n"
  614. "Content-type: text/html; charset=\"ISO-8859-1\"\n",
  615. "text/html", true,
  616. "iso-8859-1", true,
  617. "text/html, text/html; charset=\"ISO-8859-1\"" },
  618. // If there are multiple matching content-type headers, we carry
  619. // over the charset value.
  620. { "HTTP/1.1 200 OK\n"
  621. "Content-type: text/html;charset=utf-8\n"
  622. "Content-type: text/html\n",
  623. "text/html", true,
  624. "utf-8", true,
  625. "text/html;charset=utf-8, text/html" },
  626. // Regression test for https://crbug.com/772350:
  627. // Single quotes are not delimiters but must be treated as part of charset.
  628. { "HTTP/1.1 200 OK\n"
  629. "Content-type: text/html;charset='utf-8'\n"
  630. "Content-type: text/html\n",
  631. "text/html", true,
  632. "'utf-8'", true,
  633. "text/html;charset='utf-8', text/html" },
  634. // First charset wins if matching content-type.
  635. { "HTTP/1.1 200 OK\n"
  636. "Content-type: text/html;charset=utf-8\n"
  637. "Content-type: text/html;charset=iso-8859-1\n",
  638. "text/html", true,
  639. "iso-8859-1", true,
  640. "text/html;charset=utf-8, text/html;charset=iso-8859-1" },
  641. // Charset is ignored if the content types change.
  642. { "HTTP/1.1 200 OK\n"
  643. "Content-type: text/plain;charset=utf-8\n"
  644. "Content-type: text/html\n",
  645. "text/html", true,
  646. "", false,
  647. "text/plain;charset=utf-8, text/html" },
  648. // Empty content-type.
  649. { "HTTP/1.1 200 OK\n"
  650. "Content-type: \n",
  651. "", false,
  652. "", false,
  653. "" },
  654. // Emtpy charset.
  655. { "HTTP/1.1 200 OK\n"
  656. "Content-type: text/html;charset=\n",
  657. "text/html", true,
  658. "", false,
  659. "text/html;charset=" },
  660. // Multiple charsets, first one wins.
  661. { "HTTP/1.1 200 OK\n"
  662. "Content-type: text/html;charset=utf-8; charset=iso-8859-1\n",
  663. "text/html", true,
  664. "utf-8", true,
  665. "text/html;charset=utf-8; charset=iso-8859-1" },
  666. // Multiple params.
  667. { "HTTP/1.1 200 OK\n"
  668. "Content-type: text/html; foo=utf-8; charset=iso-8859-1\n",
  669. "text/html", true,
  670. "iso-8859-1", true,
  671. "text/html; foo=utf-8; charset=iso-8859-1" },
  672. { "HTTP/1.1 200 OK\n"
  673. "Content-type: text/html ; charset=utf-8 ; bar=iso-8859-1\n",
  674. "text/html", true,
  675. "utf-8", true,
  676. "text/html ; charset=utf-8 ; bar=iso-8859-1" },
  677. // Comma embeded in quotes.
  678. { "HTTP/1.1 200 OK\n"
  679. "Content-type: text/html ; charset=\"utf-8,text/plain\" ;\n",
  680. "text/html", true,
  681. "utf-8,text/plain", true,
  682. "text/html ; charset=\"utf-8,text/plain\" ;" },
  683. // Charset with leading spaces.
  684. { "HTTP/1.1 200 OK\n"
  685. "Content-type: text/html ; charset= \"utf-8\" ;\n",
  686. "text/html", true,
  687. "utf-8", true,
  688. "text/html ; charset= \"utf-8\" ;" },
  689. // Media type comments in mime-type.
  690. { "HTTP/1.1 200 OK\n"
  691. "Content-type: text/html (html)\n",
  692. "text/html", true,
  693. "", false,
  694. "text/html (html)" },
  695. // Incomplete charset= param.
  696. { "HTTP/1.1 200 OK\n"
  697. "Content-type: text/html; char=\n",
  698. "text/html", true,
  699. "", false,
  700. "text/html; char=" },
  701. // Invalid media type: no slash.
  702. { "HTTP/1.1 200 OK\n"
  703. "Content-type: texthtml\n",
  704. "", false,
  705. "", false,
  706. "texthtml" },
  707. // Invalid media type: "*/*".
  708. { "HTTP/1.1 200 OK\n"
  709. "Content-type: */*\n",
  710. "", false,
  711. "", false,
  712. "*/*" },
  713. };
  714. // clang-format on
  715. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  716. ContentTypeTest,
  717. testing::ValuesIn(mimetype_tests));
  718. struct RequiresValidationTestData {
  719. const char* headers;
  720. ValidationType validation_type;
  721. };
  722. class RequiresValidationTest
  723. : public HttpResponseHeadersTest,
  724. public ::testing::WithParamInterface<RequiresValidationTestData> {
  725. };
  726. TEST_P(RequiresValidationTest, RequiresValidation) {
  727. const RequiresValidationTestData test = GetParam();
  728. base::Time request_time, response_time, current_time;
  729. ASSERT_TRUE(
  730. base::Time::FromString("Wed, 28 Nov 2007 00:40:09 GMT", &request_time));
  731. ASSERT_TRUE(
  732. base::Time::FromString("Wed, 28 Nov 2007 00:40:12 GMT", &response_time));
  733. ASSERT_TRUE(
  734. base::Time::FromString("Wed, 28 Nov 2007 00:45:20 GMT", &current_time));
  735. std::string headers(test.headers);
  736. HeadersToRaw(&headers);
  737. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  738. ValidationType validation_type =
  739. parsed->RequiresValidation(request_time, response_time, current_time);
  740. EXPECT_EQ(test.validation_type, validation_type);
  741. }
  742. const struct RequiresValidationTestData requires_validation_tests[] = {
  743. // No expiry info: expires immediately.
  744. {"HTTP/1.1 200 OK\n"
  745. "\n",
  746. VALIDATION_SYNCHRONOUS},
  747. // No expiry info: expires immediately.
  748. {"HTTP/1.1 200 OK\n"
  749. "\n",
  750. VALIDATION_SYNCHRONOUS},
  751. // Valid for a little while.
  752. {"HTTP/1.1 200 OK\n"
  753. "cache-control: max-age=10000\n"
  754. "\n",
  755. VALIDATION_NONE},
  756. // Expires in the future.
  757. {"HTTP/1.1 200 OK\n"
  758. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  759. "expires: Wed, 28 Nov 2007 01:00:00 GMT\n"
  760. "\n",
  761. VALIDATION_NONE},
  762. // Already expired.
  763. {"HTTP/1.1 200 OK\n"
  764. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  765. "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
  766. "\n",
  767. VALIDATION_SYNCHRONOUS},
  768. // Max-age trumps expires.
  769. {"HTTP/1.1 200 OK\n"
  770. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  771. "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
  772. "cache-control: max-age=10000\n"
  773. "\n",
  774. VALIDATION_NONE},
  775. // Last-modified heuristic: modified a while ago.
  776. {"HTTP/1.1 200 OK\n"
  777. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  778. "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
  779. "\n",
  780. VALIDATION_NONE},
  781. {"HTTP/1.1 203 Non-Authoritative Information\n"
  782. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  783. "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
  784. "\n",
  785. VALIDATION_NONE},
  786. {"HTTP/1.1 206 Partial Content\n"
  787. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  788. "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
  789. "\n",
  790. VALIDATION_NONE},
  791. // Last-modified heuristic: modified recently.
  792. {"HTTP/1.1 200 OK\n"
  793. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  794. "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
  795. "\n",
  796. VALIDATION_SYNCHRONOUS},
  797. {"HTTP/1.1 203 Non-Authoritative Information\n"
  798. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  799. "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
  800. "\n",
  801. VALIDATION_SYNCHRONOUS},
  802. {"HTTP/1.1 206 Partial Content\n"
  803. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  804. "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
  805. "\n",
  806. VALIDATION_SYNCHRONOUS},
  807. // Cached permanent redirect.
  808. {"HTTP/1.1 301 Moved Permanently\n"
  809. "\n",
  810. VALIDATION_NONE},
  811. // Another cached permanent redirect.
  812. {"HTTP/1.1 308 Permanent Redirect\n"
  813. "\n",
  814. VALIDATION_NONE},
  815. // Cached redirect: not reusable even though by default it would be.
  816. {"HTTP/1.1 300 Multiple Choices\n"
  817. "Cache-Control: no-cache\n"
  818. "\n",
  819. VALIDATION_SYNCHRONOUS},
  820. // Cached forever by default.
  821. {"HTTP/1.1 410 Gone\n"
  822. "\n",
  823. VALIDATION_NONE},
  824. // Cached temporary redirect: not reusable.
  825. {"HTTP/1.1 302 Found\n"
  826. "\n",
  827. VALIDATION_SYNCHRONOUS},
  828. // Cached temporary redirect: reusable.
  829. {"HTTP/1.1 302 Found\n"
  830. "cache-control: max-age=10000\n"
  831. "\n",
  832. VALIDATION_NONE},
  833. // Cache-control: max-age=N overrides expires: date in the past.
  834. {"HTTP/1.1 200 OK\n"
  835. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  836. "expires: Wed, 28 Nov 2007 00:20:11 GMT\n"
  837. "cache-control: max-age=10000\n"
  838. "\n",
  839. VALIDATION_NONE},
  840. // Cache-control: no-store overrides expires: in the future.
  841. {"HTTP/1.1 200 OK\n"
  842. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  843. "expires: Wed, 29 Nov 2007 00:40:11 GMT\n"
  844. "cache-control: no-store,private,no-cache=\"foo\"\n"
  845. "\n",
  846. VALIDATION_SYNCHRONOUS},
  847. // Pragma: no-cache overrides last-modified heuristic.
  848. {"HTTP/1.1 200 OK\n"
  849. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  850. "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
  851. "pragma: no-cache\n"
  852. "\n",
  853. VALIDATION_SYNCHRONOUS},
  854. // max-age has expired, needs synchronous revalidation
  855. {"HTTP/1.1 200 OK\n"
  856. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  857. "cache-control: max-age=300\n"
  858. "\n",
  859. VALIDATION_SYNCHRONOUS},
  860. // max-age has expired, stale-while-revalidate has not, eligible for
  861. // asynchronous revalidation
  862. {"HTTP/1.1 200 OK\n"
  863. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  864. "cache-control: max-age=300, stale-while-revalidate=3600\n"
  865. "\n",
  866. VALIDATION_ASYNCHRONOUS},
  867. // max-age and stale-while-revalidate have expired, needs synchronous
  868. // revalidation
  869. {"HTTP/1.1 200 OK\n"
  870. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  871. "cache-control: max-age=300, stale-while-revalidate=5\n"
  872. "\n",
  873. VALIDATION_SYNCHRONOUS},
  874. // max-age is 0, stale-while-revalidate is large enough to permit
  875. // asynchronous revalidation
  876. {"HTTP/1.1 200 OK\n"
  877. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  878. "cache-control: max-age=0, stale-while-revalidate=360\n"
  879. "\n",
  880. VALIDATION_ASYNCHRONOUS},
  881. // stale-while-revalidate must not override no-cache or similar directives.
  882. {"HTTP/1.1 200 OK\n"
  883. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  884. "cache-control: no-cache, stale-while-revalidate=360\n"
  885. "\n",
  886. VALIDATION_SYNCHRONOUS},
  887. // max-age has not expired, so no revalidation is needed.
  888. {"HTTP/1.1 200 OK\n"
  889. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  890. "cache-control: max-age=3600, stale-while-revalidate=3600\n"
  891. "\n",
  892. VALIDATION_NONE},
  893. // must-revalidate overrides stale-while-revalidate, so synchronous
  894. // validation
  895. // is needed.
  896. {"HTTP/1.1 200 OK\n"
  897. "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
  898. "cache-control: must-revalidate, max-age=300, "
  899. "stale-while-revalidate=3600\n"
  900. "\n",
  901. VALIDATION_SYNCHRONOUS},
  902. // TODO(darin): Add many many more tests here.
  903. };
  904. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  905. RequiresValidationTest,
  906. testing::ValuesIn(requires_validation_tests));
  907. struct UpdateTestData {
  908. const char* orig_headers;
  909. const char* new_headers;
  910. const char* expected_headers;
  911. };
  912. class UpdateTest
  913. : public HttpResponseHeadersTest,
  914. public ::testing::WithParamInterface<UpdateTestData> {
  915. };
  916. TEST_P(UpdateTest, Update) {
  917. const UpdateTestData test = GetParam();
  918. std::string orig_headers(test.orig_headers);
  919. HeadersToRaw(&orig_headers);
  920. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(orig_headers);
  921. std::string new_headers(test.new_headers);
  922. HeadersToRaw(&new_headers);
  923. auto new_parsed = base::MakeRefCounted<HttpResponseHeaders>(new_headers);
  924. parsed->Update(*new_parsed.get());
  925. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
  926. }
  927. const UpdateTestData update_tests[] = {
  928. {"HTTP/1.1 200 OK\n",
  929. "HTTP/1/1 304 Not Modified\n"
  930. "connection: keep-alive\n"
  931. "Cache-control: max-age=10000\n",
  932. "HTTP/1.1 200 OK\n"
  933. "Cache-control: max-age=10000\n"},
  934. {"HTTP/1.1 200 OK\n"
  935. "Foo: 1\n"
  936. "Cache-control: private\n",
  937. "HTTP/1/1 304 Not Modified\n"
  938. "connection: keep-alive\n"
  939. "Cache-control: max-age=10000\n",
  940. "HTTP/1.1 200 OK\n"
  941. "Cache-control: max-age=10000\n"
  942. "Foo: 1\n"},
  943. {"HTTP/1.1 200 OK\n"
  944. "Foo: 1\n"
  945. "Cache-control: private\n",
  946. "HTTP/1/1 304 Not Modified\n"
  947. "connection: keep-alive\n"
  948. "Cache-CONTROL: max-age=10000\n",
  949. "HTTP/1.1 200 OK\n"
  950. "Cache-CONTROL: max-age=10000\n"
  951. "Foo: 1\n"},
  952. {"HTTP/1.1 200 OK\n"
  953. "Content-Length: 450\n",
  954. "HTTP/1/1 304 Not Modified\n"
  955. "connection: keep-alive\n"
  956. "Cache-control: max-age=10001 \n",
  957. "HTTP/1.1 200 OK\n"
  958. "Cache-control: max-age=10001\n"
  959. "Content-Length: 450\n"},
  960. {
  961. "HTTP/1.1 200 OK\n"
  962. "X-Frame-Options: DENY\n",
  963. "HTTP/1/1 304 Not Modified\n"
  964. "X-Frame-Options: ALLOW\n",
  965. "HTTP/1.1 200 OK\n"
  966. "X-Frame-Options: DENY\n",
  967. },
  968. {
  969. "HTTP/1.1 200 OK\n"
  970. "X-WebKit-CSP: default-src 'none'\n",
  971. "HTTP/1/1 304 Not Modified\n"
  972. "X-WebKit-CSP: default-src *\n",
  973. "HTTP/1.1 200 OK\n"
  974. "X-WebKit-CSP: default-src 'none'\n",
  975. },
  976. {
  977. "HTTP/1.1 200 OK\n"
  978. "X-XSS-Protection: 1\n",
  979. "HTTP/1/1 304 Not Modified\n"
  980. "X-XSS-Protection: 0\n",
  981. "HTTP/1.1 200 OK\n"
  982. "X-XSS-Protection: 1\n",
  983. },
  984. {"HTTP/1.1 200 OK\n",
  985. "HTTP/1/1 304 Not Modified\n"
  986. "X-Content-Type-Options: nosniff\n",
  987. "HTTP/1.1 200 OK\n"},
  988. {"HTTP/1.1 200 OK\n"
  989. "Content-Encoding: identity\n"
  990. "Content-Length: 100\n"
  991. "Content-Type: text/html\n"
  992. "Content-Security-Policy: default-src 'none'\n",
  993. "HTTP/1/1 304 Not Modified\n"
  994. "Content-Encoding: gzip\n"
  995. "Content-Length: 200\n"
  996. "Content-Type: text/xml\n"
  997. "Content-Security-Policy: default-src 'self'\n",
  998. "HTTP/1.1 200 OK\n"
  999. "Content-Security-Policy: default-src 'self'\n"
  1000. "Content-Encoding: identity\n"
  1001. "Content-Length: 100\n"
  1002. "Content-Type: text/html\n"},
  1003. {"HTTP/1.1 200 OK\n"
  1004. "Content-Location: /example_page.html\n",
  1005. "HTTP/1/1 304 Not Modified\n"
  1006. "Content-Location: /not_example_page.html\n",
  1007. "HTTP/1.1 200 OK\n"
  1008. "Content-Location: /example_page.html\n"},
  1009. };
  1010. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1011. UpdateTest,
  1012. testing::ValuesIn(update_tests));
  1013. struct EnumerateHeaderTestData {
  1014. const char* headers;
  1015. const char* expected_lines;
  1016. };
  1017. class EnumerateHeaderLinesTest
  1018. : public HttpResponseHeadersTest,
  1019. public ::testing::WithParamInterface<EnumerateHeaderTestData> {
  1020. };
  1021. TEST_P(EnumerateHeaderLinesTest, EnumerateHeaderLines) {
  1022. const EnumerateHeaderTestData test = GetParam();
  1023. std::string headers(test.headers);
  1024. HeadersToRaw(&headers);
  1025. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1026. std::string name, value, lines;
  1027. size_t iter = 0;
  1028. while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
  1029. lines.append(name);
  1030. lines.append(": ");
  1031. lines.append(value);
  1032. lines.append("\n");
  1033. }
  1034. EXPECT_EQ(std::string(test.expected_lines), lines);
  1035. }
  1036. const EnumerateHeaderTestData enumerate_header_tests[] = {
  1037. {"HTTP/1.1 200 OK\n",
  1038. ""},
  1039. {"HTTP/1.1 200 OK\n"
  1040. "Foo: 1\n",
  1041. "Foo: 1\n"},
  1042. {"HTTP/1.1 200 OK\n"
  1043. "Foo: 1\n"
  1044. "Bar: 2\n"
  1045. "Foo: 3\n",
  1046. "Foo: 1\nBar: 2\nFoo: 3\n"},
  1047. {"HTTP/1.1 200 OK\n"
  1048. "Foo: 1, 2, 3\n",
  1049. "Foo: 1, 2, 3\n"},
  1050. {"HTTP/1.1 200 OK\n"
  1051. "Foo: ,, 1,, 2, 3,, \n",
  1052. "Foo: ,, 1,, 2, 3,,\n"},
  1053. };
  1054. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1055. EnumerateHeaderLinesTest,
  1056. testing::ValuesIn(enumerate_header_tests));
  1057. struct IsRedirectTestData {
  1058. const char* headers;
  1059. const char* location;
  1060. bool is_redirect;
  1061. };
  1062. class IsRedirectTest
  1063. : public HttpResponseHeadersTest,
  1064. public ::testing::WithParamInterface<IsRedirectTestData> {
  1065. };
  1066. TEST_P(IsRedirectTest, IsRedirect) {
  1067. const IsRedirectTestData test = GetParam();
  1068. std::string headers(test.headers);
  1069. HeadersToRaw(&headers);
  1070. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1071. std::string location;
  1072. EXPECT_EQ(parsed->IsRedirect(&location), test.is_redirect);
  1073. EXPECT_EQ(location, test.location);
  1074. }
  1075. const IsRedirectTestData is_redirect_tests[] = {
  1076. { "HTTP/1.1 200 OK\n",
  1077. "",
  1078. false
  1079. },
  1080. { "HTTP/1.1 301 Moved\n"
  1081. "Location: http://foopy/\n",
  1082. "http://foopy/",
  1083. true
  1084. },
  1085. { "HTTP/1.1 301 Moved\n"
  1086. "Location: \t \n",
  1087. "",
  1088. false
  1089. },
  1090. // We use the first location header as the target of the redirect.
  1091. { "HTTP/1.1 301 Moved\n"
  1092. "Location: http://foo/\n"
  1093. "Location: http://bar/\n",
  1094. "http://foo/",
  1095. true
  1096. },
  1097. // We use the first _valid_ location header as the target of the redirect.
  1098. { "HTTP/1.1 301 Moved\n"
  1099. "Location: \n"
  1100. "Location: http://bar/\n",
  1101. "http://bar/",
  1102. true
  1103. },
  1104. // Bug 1050541 (location header with an unescaped comma).
  1105. { "HTTP/1.1 301 Moved\n"
  1106. "Location: http://foo/bar,baz.html\n",
  1107. "http://foo/bar,baz.html",
  1108. true
  1109. },
  1110. // Bug 1224617 (location header with non-ASCII bytes).
  1111. { "HTTP/1.1 301 Moved\n"
  1112. "Location: http://foo/bar?key=\xE4\xF6\xFC\n",
  1113. "http://foo/bar?key=%E4%F6%FC",
  1114. true
  1115. },
  1116. // Shift_JIS, Big5, and GBK contain multibyte characters with the trailing
  1117. // byte falling in the ASCII range.
  1118. { "HTTP/1.1 301 Moved\n"
  1119. "Location: http://foo/bar?key=\x81\x5E\xD8\xBF\n",
  1120. "http://foo/bar?key=%81^%D8%BF",
  1121. true
  1122. },
  1123. { "HTTP/1.1 301 Moved\n"
  1124. "Location: http://foo/bar?key=\x82\x40\xBD\xC4\n",
  1125. "http://foo/bar?key=%82@%BD%C4",
  1126. true
  1127. },
  1128. { "HTTP/1.1 301 Moved\n"
  1129. "Location: http://foo/bar?key=\x83\x5C\x82\x5D\xCB\xD7\n",
  1130. "http://foo/bar?key=%83\\%82]%CB%D7",
  1131. true
  1132. },
  1133. };
  1134. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1135. IsRedirectTest,
  1136. testing::ValuesIn(is_redirect_tests));
  1137. struct ContentLengthTestData {
  1138. const char* headers;
  1139. int64_t expected_len;
  1140. };
  1141. class GetContentLengthTest
  1142. : public HttpResponseHeadersTest,
  1143. public ::testing::WithParamInterface<ContentLengthTestData> {
  1144. };
  1145. TEST_P(GetContentLengthTest, GetContentLength) {
  1146. const ContentLengthTestData test = GetParam();
  1147. std::string headers(test.headers);
  1148. HeadersToRaw(&headers);
  1149. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1150. EXPECT_EQ(test.expected_len, parsed->GetContentLength());
  1151. }
  1152. const ContentLengthTestData content_length_tests[] = {
  1153. {"HTTP/1.1 200 OK\n", -1},
  1154. {"HTTP/1.1 200 OK\n"
  1155. "Content-Length: 10\n",
  1156. 10},
  1157. {"HTTP/1.1 200 OK\n"
  1158. "Content-Length: \n",
  1159. -1},
  1160. {"HTTP/1.1 200 OK\n"
  1161. "Content-Length: abc\n",
  1162. -1},
  1163. {"HTTP/1.1 200 OK\n"
  1164. "Content-Length: -10\n",
  1165. -1},
  1166. {"HTTP/1.1 200 OK\n"
  1167. "Content-Length: +10\n",
  1168. -1},
  1169. {"HTTP/1.1 200 OK\n"
  1170. "Content-Length: 23xb5\n",
  1171. -1},
  1172. {"HTTP/1.1 200 OK\n"
  1173. "Content-Length: 0xA\n",
  1174. -1},
  1175. {"HTTP/1.1 200 OK\n"
  1176. "Content-Length: 010\n",
  1177. 10},
  1178. // Content-Length too big, will overflow an int64_t.
  1179. {"HTTP/1.1 200 OK\n"
  1180. "Content-Length: 40000000000000000000\n",
  1181. -1},
  1182. {"HTTP/1.1 200 OK\n"
  1183. "Content-Length: 10\n",
  1184. 10},
  1185. {"HTTP/1.1 200 OK\n"
  1186. "Content-Length: 10 \n",
  1187. 10},
  1188. {"HTTP/1.1 200 OK\n"
  1189. "Content-Length: \t10\n",
  1190. 10},
  1191. {"HTTP/1.1 200 OK\n"
  1192. "Content-Length: \v10\n",
  1193. -1},
  1194. {"HTTP/1.1 200 OK\n"
  1195. "Content-Length: \f10\n",
  1196. -1},
  1197. {"HTTP/1.1 200 OK\n"
  1198. "cOnTeNt-LENgth: 33\n",
  1199. 33},
  1200. {"HTTP/1.1 200 OK\n"
  1201. "Content-Length: 34\r\n",
  1202. -1},
  1203. };
  1204. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1205. GetContentLengthTest,
  1206. testing::ValuesIn(content_length_tests));
  1207. struct ContentRangeTestData {
  1208. const char* headers;
  1209. bool expected_return_value;
  1210. int64_t expected_first_byte_position;
  1211. int64_t expected_last_byte_position;
  1212. int64_t expected_instance_size;
  1213. };
  1214. class ContentRangeTest
  1215. : public HttpResponseHeadersTest,
  1216. public ::testing::WithParamInterface<ContentRangeTestData> {
  1217. };
  1218. TEST_P(ContentRangeTest, GetContentRangeFor206) {
  1219. const ContentRangeTestData test = GetParam();
  1220. std::string headers(test.headers);
  1221. HeadersToRaw(&headers);
  1222. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1223. int64_t first_byte_position;
  1224. int64_t last_byte_position;
  1225. int64_t instance_size;
  1226. bool return_value = parsed->GetContentRangeFor206(
  1227. &first_byte_position, &last_byte_position, &instance_size);
  1228. EXPECT_EQ(test.expected_return_value, return_value);
  1229. EXPECT_EQ(test.expected_first_byte_position, first_byte_position);
  1230. EXPECT_EQ(test.expected_last_byte_position, last_byte_position);
  1231. EXPECT_EQ(test.expected_instance_size, instance_size);
  1232. }
  1233. const ContentRangeTestData content_range_tests[] = {
  1234. {"HTTP/1.1 206 Partial Content", false, -1, -1, -1},
  1235. {"HTTP/1.1 206 Partial Content\n"
  1236. "Content-Range:",
  1237. false, -1, -1, -1},
  1238. {"HTTP/1.1 206 Partial Content\n"
  1239. "Content-Range: bytes 0-50/51",
  1240. true, 0, 50, 51},
  1241. {"HTTP/1.1 206 Partial Content\n"
  1242. "Content-Range: bytes 50-0/51",
  1243. false, -1, -1, -1},
  1244. {"HTTP/1.1 416 Requested range not satisfiable\n"
  1245. "Content-Range: bytes */*",
  1246. false, -1, -1, -1},
  1247. {"HTTP/1.1 206 Partial Content\n"
  1248. "Content-Range: bytes 0-50/*",
  1249. false, -1, -1, -1},
  1250. };
  1251. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1252. ContentRangeTest,
  1253. testing::ValuesIn(content_range_tests));
  1254. struct KeepAliveTestData {
  1255. const char* headers;
  1256. bool expected_keep_alive;
  1257. };
  1258. // Enable GTest to print KeepAliveTestData in an intelligible way if the test
  1259. // fails.
  1260. void PrintTo(const KeepAliveTestData& keep_alive_test_data,
  1261. std::ostream* os) {
  1262. *os << "{\"" << keep_alive_test_data.headers << "\", " << std::boolalpha
  1263. << keep_alive_test_data.expected_keep_alive << "}";
  1264. }
  1265. class IsKeepAliveTest
  1266. : public HttpResponseHeadersTest,
  1267. public ::testing::WithParamInterface<KeepAliveTestData> {
  1268. };
  1269. TEST_P(IsKeepAliveTest, IsKeepAlive) {
  1270. const KeepAliveTestData test = GetParam();
  1271. std::string headers(test.headers);
  1272. HeadersToRaw(&headers);
  1273. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1274. EXPECT_EQ(test.expected_keep_alive, parsed->IsKeepAlive());
  1275. }
  1276. const KeepAliveTestData keepalive_tests[] = {
  1277. // The status line fabricated by HttpNetworkTransaction for a 0.9 response.
  1278. // Treated as 0.9.
  1279. { "HTTP/0.9 200 OK",
  1280. false
  1281. },
  1282. // This could come from a broken server. Treated as 1.0 because it has a
  1283. // header.
  1284. { "HTTP/0.9 200 OK\n"
  1285. "connection: keep-alive\n",
  1286. true
  1287. },
  1288. { "HTTP/1.1 200 OK\n",
  1289. true
  1290. },
  1291. { "HTTP/1.0 200 OK\n",
  1292. false
  1293. },
  1294. { "HTTP/1.0 200 OK\n"
  1295. "connection: close\n",
  1296. false
  1297. },
  1298. { "HTTP/1.0 200 OK\n"
  1299. "connection: keep-alive\n",
  1300. true
  1301. },
  1302. { "HTTP/1.0 200 OK\n"
  1303. "connection: kEeP-AliVe\n",
  1304. true
  1305. },
  1306. { "HTTP/1.0 200 OK\n"
  1307. "connection: keep-aliveX\n",
  1308. false
  1309. },
  1310. { "HTTP/1.1 200 OK\n"
  1311. "connection: close\n",
  1312. false
  1313. },
  1314. { "HTTP/1.1 200 OK\n"
  1315. "connection: keep-alive\n",
  1316. true
  1317. },
  1318. { "HTTP/1.0 200 OK\n"
  1319. "proxy-connection: close\n",
  1320. false
  1321. },
  1322. { "HTTP/1.0 200 OK\n"
  1323. "proxy-connection: keep-alive\n",
  1324. true
  1325. },
  1326. { "HTTP/1.1 200 OK\n"
  1327. "proxy-connection: close\n",
  1328. false
  1329. },
  1330. { "HTTP/1.1 200 OK\n"
  1331. "proxy-connection: keep-alive\n",
  1332. true
  1333. },
  1334. { "HTTP/1.1 200 OK\n"
  1335. "Connection: Upgrade, close\n",
  1336. false
  1337. },
  1338. { "HTTP/1.1 200 OK\n"
  1339. "Connection: Upgrade, keep-alive\n",
  1340. true
  1341. },
  1342. { "HTTP/1.1 200 OK\n"
  1343. "Connection: Upgrade\n"
  1344. "Connection: close\n",
  1345. false
  1346. },
  1347. { "HTTP/1.1 200 OK\n"
  1348. "Connection: Upgrade\n"
  1349. "Connection: keep-alive\n",
  1350. true
  1351. },
  1352. { "HTTP/1.1 200 OK\n"
  1353. "Connection: close, Upgrade\n",
  1354. false
  1355. },
  1356. { "HTTP/1.1 200 OK\n"
  1357. "Connection: keep-alive, Upgrade\n",
  1358. true
  1359. },
  1360. { "HTTP/1.1 200 OK\n"
  1361. "Connection: Upgrade\n"
  1362. "Proxy-Connection: close\n",
  1363. false
  1364. },
  1365. { "HTTP/1.1 200 OK\n"
  1366. "Connection: Upgrade\n"
  1367. "Proxy-Connection: keep-alive\n",
  1368. true
  1369. },
  1370. // In situations where the response headers conflict with themselves, use the
  1371. // first one for backwards-compatibility.
  1372. { "HTTP/1.1 200 OK\n"
  1373. "Connection: close\n"
  1374. "Connection: keep-alive\n",
  1375. false
  1376. },
  1377. { "HTTP/1.1 200 OK\n"
  1378. "Connection: keep-alive\n"
  1379. "Connection: close\n",
  1380. true
  1381. },
  1382. { "HTTP/1.0 200 OK\n"
  1383. "Connection: close\n"
  1384. "Connection: keep-alive\n",
  1385. false
  1386. },
  1387. { "HTTP/1.0 200 OK\n"
  1388. "Connection: keep-alive\n"
  1389. "Connection: close\n",
  1390. true
  1391. },
  1392. // Ignore the Proxy-Connection header if at all possible.
  1393. { "HTTP/1.0 200 OK\n"
  1394. "Proxy-Connection: keep-alive\n"
  1395. "Connection: close\n",
  1396. false
  1397. },
  1398. { "HTTP/1.1 200 OK\n"
  1399. "Proxy-Connection: close\n"
  1400. "Connection: keep-alive\n",
  1401. true
  1402. },
  1403. // Older versions of Chrome would have ignored Proxy-Connection in this case,
  1404. // but it doesn't seem safe.
  1405. { "HTTP/1.1 200 OK\n"
  1406. "Proxy-Connection: close\n"
  1407. "Connection: Transfer-Encoding\n",
  1408. false
  1409. },
  1410. };
  1411. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1412. IsKeepAliveTest,
  1413. testing::ValuesIn(keepalive_tests));
  1414. struct HasStrongValidatorsTestData {
  1415. const char* headers;
  1416. bool expected_result;
  1417. };
  1418. class HasStrongValidatorsTest
  1419. : public HttpResponseHeadersTest,
  1420. public ::testing::WithParamInterface<HasStrongValidatorsTestData> {
  1421. };
  1422. TEST_P(HasStrongValidatorsTest, HasStrongValidators) {
  1423. const HasStrongValidatorsTestData test = GetParam();
  1424. std::string headers(test.headers);
  1425. HeadersToRaw(&headers);
  1426. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1427. EXPECT_EQ(test.expected_result, parsed->HasStrongValidators());
  1428. }
  1429. const HasStrongValidatorsTestData strong_validators_tests[] = {
  1430. { "HTTP/0.9 200 OK",
  1431. false
  1432. },
  1433. { "HTTP/1.0 200 OK\n"
  1434. "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
  1435. "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
  1436. "ETag: \"foo\"\n",
  1437. false
  1438. },
  1439. { "HTTP/1.1 200 OK\n"
  1440. "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
  1441. "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
  1442. "ETag: \"foo\"\n",
  1443. true
  1444. },
  1445. { "HTTP/1.1 200 OK\n"
  1446. "Date: Wed, 28 Nov 2007 00:41:10 GMT\n"
  1447. "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
  1448. true
  1449. },
  1450. { "HTTP/1.1 200 OK\n"
  1451. "Date: Wed, 28 Nov 2007 00:41:09 GMT\n"
  1452. "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
  1453. false
  1454. },
  1455. { "HTTP/1.1 200 OK\n"
  1456. "ETag: \"foo\"\n",
  1457. true
  1458. },
  1459. // This is not really a weak etag:
  1460. { "HTTP/1.1 200 OK\n"
  1461. "etag: \"w/foo\"\n",
  1462. true
  1463. },
  1464. // This is a weak etag:
  1465. { "HTTP/1.1 200 OK\n"
  1466. "etag: w/\"foo\"\n",
  1467. false
  1468. },
  1469. { "HTTP/1.1 200 OK\n"
  1470. "etag: W / \"foo\"\n",
  1471. false
  1472. }
  1473. };
  1474. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1475. HasStrongValidatorsTest,
  1476. testing::ValuesIn(strong_validators_tests));
  1477. TEST(HttpResponseHeadersTest, HasValidatorsNone) {
  1478. std::string headers("HTTP/1.1 200 OK");
  1479. HeadersToRaw(&headers);
  1480. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1481. EXPECT_FALSE(parsed->HasValidators());
  1482. }
  1483. TEST(HttpResponseHeadersTest, HasValidatorsEtag) {
  1484. std::string headers(
  1485. "HTTP/1.1 200 OK\n"
  1486. "etag: \"anything\"");
  1487. HeadersToRaw(&headers);
  1488. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1489. EXPECT_TRUE(parsed->HasValidators());
  1490. }
  1491. TEST(HttpResponseHeadersTest, HasValidatorsLastModified) {
  1492. std::string headers(
  1493. "HTTP/1.1 200 OK\n"
  1494. "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT");
  1495. HeadersToRaw(&headers);
  1496. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1497. EXPECT_TRUE(parsed->HasValidators());
  1498. }
  1499. TEST(HttpResponseHeadersTest, HasValidatorsWeakEtag) {
  1500. std::string headers(
  1501. "HTTP/1.1 200 OK\n"
  1502. "etag: W/\"anything\"");
  1503. HeadersToRaw(&headers);
  1504. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1505. EXPECT_TRUE(parsed->HasValidators());
  1506. }
  1507. TEST(HttpResponseHeadersTest, GetNormalizedHeaderWithEmptyValues) {
  1508. std::string headers(
  1509. "HTTP/1.1 200 OK\n"
  1510. "a:\n"
  1511. "b: \n"
  1512. "c:*\n"
  1513. "d: *\n"
  1514. "e: \n"
  1515. "a: \n"
  1516. "b:*\n"
  1517. "c:\n"
  1518. "d:*\n"
  1519. "a:\n");
  1520. HeadersToRaw(&headers);
  1521. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1522. std::string value;
  1523. EXPECT_TRUE(parsed->GetNormalizedHeader("a", &value));
  1524. EXPECT_EQ(value, ", , ");
  1525. EXPECT_TRUE(parsed->GetNormalizedHeader("b", &value));
  1526. EXPECT_EQ(value, ", *");
  1527. EXPECT_TRUE(parsed->GetNormalizedHeader("c", &value));
  1528. EXPECT_EQ(value, "*, ");
  1529. EXPECT_TRUE(parsed->GetNormalizedHeader("d", &value));
  1530. EXPECT_EQ(value, "*, *");
  1531. EXPECT_TRUE(parsed->GetNormalizedHeader("e", &value));
  1532. EXPECT_EQ(value, "");
  1533. EXPECT_FALSE(parsed->GetNormalizedHeader("f", &value));
  1534. }
  1535. TEST(HttpResponseHeadersTest, GetNormalizedHeaderWithCommas) {
  1536. std::string headers(
  1537. "HTTP/1.1 200 OK\n"
  1538. "a: foo, bar\n"
  1539. "b: , foo, bar,\n"
  1540. "c: ,,,\n"
  1541. "d: , , , \n"
  1542. "e:\t,\t,\t,\t\n"
  1543. "a: ,");
  1544. HeadersToRaw(&headers);
  1545. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  1546. std::string value;
  1547. // TODO(mmenke): "Normalized" headers probably should preserve the
  1548. // leading/trailing whitespace from the original headers.
  1549. ASSERT_TRUE(parsed->GetNormalizedHeader("a", &value));
  1550. EXPECT_EQ("foo, bar, ,", value);
  1551. ASSERT_TRUE(parsed->GetNormalizedHeader("b", &value));
  1552. EXPECT_EQ(", foo, bar,", value);
  1553. ASSERT_TRUE(parsed->GetNormalizedHeader("c", &value));
  1554. EXPECT_EQ(",,,", value);
  1555. ASSERT_TRUE(parsed->GetNormalizedHeader("d", &value));
  1556. EXPECT_EQ(", , ,", value);
  1557. ASSERT_TRUE(parsed->GetNormalizedHeader("e", &value));
  1558. EXPECT_EQ(",\t,\t,", value);
  1559. EXPECT_FALSE(parsed->GetNormalizedHeader("f", &value));
  1560. }
  1561. TEST(HttpResponseHeadersTest, AddHeader) {
  1562. scoped_refptr<HttpResponseHeaders> headers = HttpResponseHeaders::TryToCreate(
  1563. "HTTP/1.1 200 OK\n"
  1564. "connection: keep-alive\n"
  1565. "Cache-control: max-age=10000\n");
  1566. ASSERT_TRUE(headers);
  1567. headers->AddHeader("Content-Length", "450");
  1568. EXPECT_EQ(
  1569. "HTTP/1.1 200 OK\n"
  1570. "connection: keep-alive\n"
  1571. "Cache-control: max-age=10000\n"
  1572. "Content-Length: 450\n",
  1573. ToSimpleString(headers));
  1574. // Add a second Content-Length header with extra spaces in the value. It
  1575. // should be added to the end, and the extra spaces removed.
  1576. headers->AddHeader("Content-Length", " 42 ");
  1577. EXPECT_EQ(
  1578. "HTTP/1.1 200 OK\n"
  1579. "connection: keep-alive\n"
  1580. "Cache-control: max-age=10000\n"
  1581. "Content-Length: 450\n"
  1582. "Content-Length: 42\n",
  1583. ToSimpleString(headers));
  1584. }
  1585. TEST(HttpResponseHeadersTest, SetHeader) {
  1586. scoped_refptr<HttpResponseHeaders> headers = HttpResponseHeaders::TryToCreate(
  1587. "HTTP/1.1 200 OK\n"
  1588. "connection: keep-alive\n"
  1589. "Cache-control: max-age=10000\n");
  1590. ASSERT_TRUE(headers);
  1591. headers->SetHeader("Content-Length", "450");
  1592. EXPECT_EQ(
  1593. "HTTP/1.1 200 OK\n"
  1594. "connection: keep-alive\n"
  1595. "Cache-control: max-age=10000\n"
  1596. "Content-Length: 450\n",
  1597. ToSimpleString(headers));
  1598. headers->SetHeader("Content-Length", " 42 ");
  1599. EXPECT_EQ(
  1600. "HTTP/1.1 200 OK\n"
  1601. "connection: keep-alive\n"
  1602. "Cache-control: max-age=10000\n"
  1603. "Content-Length: 42\n",
  1604. ToSimpleString(headers));
  1605. headers->SetHeader("connection", "close");
  1606. EXPECT_EQ(
  1607. "HTTP/1.1 200 OK\n"
  1608. "Cache-control: max-age=10000\n"
  1609. "Content-Length: 42\n"
  1610. "connection: close\n",
  1611. ToSimpleString(headers));
  1612. }
  1613. TEST(HttpResponseHeadersTest, TracingSupport) {
  1614. scoped_refptr<HttpResponseHeaders> headers = HttpResponseHeaders::TryToCreate(
  1615. "HTTP/1.1 200 OK\n"
  1616. "connection: keep-alive\n");
  1617. ASSERT_TRUE(headers);
  1618. EXPECT_EQ(perfetto::TracedValueToString(headers),
  1619. "{response_code:200,headers:[{name:connection,value:keep-alive}]}");
  1620. }
  1621. struct RemoveHeaderTestData {
  1622. const char* orig_headers;
  1623. const char* to_remove;
  1624. const char* expected_headers;
  1625. };
  1626. class RemoveHeaderTest
  1627. : public HttpResponseHeadersTest,
  1628. public ::testing::WithParamInterface<RemoveHeaderTestData> {
  1629. };
  1630. TEST_P(RemoveHeaderTest, RemoveHeader) {
  1631. const RemoveHeaderTestData test = GetParam();
  1632. std::string orig_headers(test.orig_headers);
  1633. HeadersToRaw(&orig_headers);
  1634. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(orig_headers);
  1635. std::string name(test.to_remove);
  1636. parsed->RemoveHeader(name);
  1637. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
  1638. }
  1639. const RemoveHeaderTestData remove_header_tests[] = {
  1640. { "HTTP/1.1 200 OK\n"
  1641. "connection: keep-alive\n"
  1642. "Cache-control: max-age=10000\n"
  1643. "Content-Length: 450\n",
  1644. "Content-Length",
  1645. "HTTP/1.1 200 OK\n"
  1646. "connection: keep-alive\n"
  1647. "Cache-control: max-age=10000\n"
  1648. },
  1649. { "HTTP/1.1 200 OK\n"
  1650. "connection: keep-alive \n"
  1651. "Content-Length : 450 \n"
  1652. "Cache-control: max-age=10000\n",
  1653. "Content-Length",
  1654. "HTTP/1.1 200 OK\n"
  1655. "connection: keep-alive\n"
  1656. "Cache-control: max-age=10000\n"
  1657. },
  1658. };
  1659. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1660. RemoveHeaderTest,
  1661. testing::ValuesIn(remove_header_tests));
  1662. struct RemoveHeadersTestData {
  1663. const char* orig_headers;
  1664. const char* to_remove[2];
  1665. const char* expected_headers;
  1666. };
  1667. class RemoveHeadersTest
  1668. : public HttpResponseHeadersTest,
  1669. public ::testing::WithParamInterface<RemoveHeadersTestData> {};
  1670. TEST_P(RemoveHeadersTest, RemoveHeaders) {
  1671. const RemoveHeadersTestData test = GetParam();
  1672. std::string orig_headers(test.orig_headers);
  1673. HeadersToRaw(&orig_headers);
  1674. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(orig_headers);
  1675. std::unordered_set<std::string> to_remove;
  1676. for (auto* header : test.to_remove) {
  1677. if (header)
  1678. to_remove.insert(header);
  1679. }
  1680. parsed->RemoveHeaders(to_remove);
  1681. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
  1682. }
  1683. const RemoveHeadersTestData remove_headers_tests[] = {
  1684. {"HTTP/1.1 200 OK\n"
  1685. "connection: keep-alive\n"
  1686. "Cache-control: max-age=10000\n"
  1687. "Content-Length: 450\n",
  1688. {"Content-Length", "CACHE-control"},
  1689. "HTTP/1.1 200 OK\n"
  1690. "connection: keep-alive\n"},
  1691. {"HTTP/1.1 200 OK\n"
  1692. "connection: keep-alive\n"
  1693. "Content-Length: 450\n",
  1694. {"foo", "bar"},
  1695. "HTTP/1.1 200 OK\n"
  1696. "connection: keep-alive\n"
  1697. "Content-Length: 450\n"},
  1698. {"HTTP/1.1 404 Kinda not OK\n"
  1699. "connection: keep-alive \n",
  1700. {},
  1701. "HTTP/1.1 404 Kinda not OK\n"
  1702. "connection: keep-alive\n"},
  1703. };
  1704. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1705. RemoveHeadersTest,
  1706. testing::ValuesIn(remove_headers_tests));
  1707. struct RemoveIndividualHeaderTestData {
  1708. const char* orig_headers;
  1709. const char* to_remove_name;
  1710. const char* to_remove_value;
  1711. const char* expected_headers;
  1712. };
  1713. class RemoveIndividualHeaderTest
  1714. : public HttpResponseHeadersTest,
  1715. public ::testing::WithParamInterface<RemoveIndividualHeaderTestData> {
  1716. };
  1717. TEST_P(RemoveIndividualHeaderTest, RemoveIndividualHeader) {
  1718. const RemoveIndividualHeaderTestData test = GetParam();
  1719. std::string orig_headers(test.orig_headers);
  1720. HeadersToRaw(&orig_headers);
  1721. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(orig_headers);
  1722. std::string name(test.to_remove_name);
  1723. std::string value(test.to_remove_value);
  1724. parsed->RemoveHeaderLine(name, value);
  1725. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
  1726. }
  1727. const RemoveIndividualHeaderTestData remove_individual_header_tests[] = {
  1728. { "HTTP/1.1 200 OK\n"
  1729. "connection: keep-alive\n"
  1730. "Cache-control: max-age=10000\n"
  1731. "Content-Length: 450\n",
  1732. "Content-Length",
  1733. "450",
  1734. "HTTP/1.1 200 OK\n"
  1735. "connection: keep-alive\n"
  1736. "Cache-control: max-age=10000\n"
  1737. },
  1738. { "HTTP/1.1 200 OK\n"
  1739. "connection: keep-alive \n"
  1740. "Content-Length : 450 \n"
  1741. "Cache-control: max-age=10000\n",
  1742. "Content-Length",
  1743. "450",
  1744. "HTTP/1.1 200 OK\n"
  1745. "connection: keep-alive\n"
  1746. "Cache-control: max-age=10000\n"
  1747. },
  1748. { "HTTP/1.1 200 OK\n"
  1749. "connection: keep-alive \n"
  1750. "Content-Length: 450\n"
  1751. "Cache-control: max-age=10000\n",
  1752. "Content-Length", // Matching name.
  1753. "999", // Mismatching value.
  1754. "HTTP/1.1 200 OK\n"
  1755. "connection: keep-alive\n"
  1756. "Content-Length: 450\n"
  1757. "Cache-control: max-age=10000\n"
  1758. },
  1759. { "HTTP/1.1 200 OK\n"
  1760. "connection: keep-alive \n"
  1761. "Foo: bar, baz\n"
  1762. "Foo: bar\n"
  1763. "Cache-control: max-age=10000\n",
  1764. "Foo",
  1765. "bar, baz", // Space in value.
  1766. "HTTP/1.1 200 OK\n"
  1767. "connection: keep-alive\n"
  1768. "Foo: bar\n"
  1769. "Cache-control: max-age=10000\n"
  1770. },
  1771. { "HTTP/1.1 200 OK\n"
  1772. "connection: keep-alive \n"
  1773. "Foo: bar, baz\n"
  1774. "Cache-control: max-age=10000\n",
  1775. "Foo",
  1776. "baz", // Only partial match -> ignored.
  1777. "HTTP/1.1 200 OK\n"
  1778. "connection: keep-alive\n"
  1779. "Foo: bar, baz\n"
  1780. "Cache-control: max-age=10000\n"
  1781. },
  1782. };
  1783. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1784. RemoveIndividualHeaderTest,
  1785. testing::ValuesIn(remove_individual_header_tests));
  1786. struct ReplaceStatusTestData {
  1787. const char* orig_headers;
  1788. const char* new_status;
  1789. const char* expected_headers;
  1790. };
  1791. class ReplaceStatusTest
  1792. : public HttpResponseHeadersTest,
  1793. public ::testing::WithParamInterface<ReplaceStatusTestData> {
  1794. };
  1795. TEST_P(ReplaceStatusTest, ReplaceStatus) {
  1796. const ReplaceStatusTestData test = GetParam();
  1797. std::string orig_headers(test.orig_headers);
  1798. HeadersToRaw(&orig_headers);
  1799. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(orig_headers);
  1800. std::string name(test.new_status);
  1801. parsed->ReplaceStatusLine(name);
  1802. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
  1803. }
  1804. const ReplaceStatusTestData replace_status_tests[] = {
  1805. { "HTTP/1.1 206 Partial Content\n"
  1806. "connection: keep-alive\n"
  1807. "Cache-control: max-age=10000\n"
  1808. "Content-Length: 450\n",
  1809. "HTTP/1.1 200 OK",
  1810. "HTTP/1.1 200 OK\n"
  1811. "connection: keep-alive\n"
  1812. "Cache-control: max-age=10000\n"
  1813. "Content-Length: 450\n"
  1814. },
  1815. { "HTTP/1.1 200 OK\n"
  1816. "connection: keep-alive\n",
  1817. "HTTP/1.1 304 Not Modified",
  1818. "HTTP/1.1 304 Not Modified\n"
  1819. "connection: keep-alive\n"
  1820. },
  1821. { "HTTP/1.1 200 OK\n"
  1822. "connection: keep-alive \n"
  1823. "Content-Length : 450 \n"
  1824. "Cache-control: max-age=10000\n",
  1825. "HTTP/1//1 304 Not Modified",
  1826. "HTTP/1.0 304 Not Modified\n"
  1827. "connection: keep-alive\n"
  1828. "Content-Length: 450\n"
  1829. "Cache-control: max-age=10000\n"
  1830. },
  1831. };
  1832. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1833. ReplaceStatusTest,
  1834. testing::ValuesIn(replace_status_tests));
  1835. struct UpdateWithNewRangeTestData {
  1836. const char* orig_headers;
  1837. const char* expected_headers;
  1838. const char* expected_headers_with_replaced_status;
  1839. };
  1840. class UpdateWithNewRangeTest
  1841. : public HttpResponseHeadersTest,
  1842. public ::testing::WithParamInterface<UpdateWithNewRangeTestData> {
  1843. };
  1844. TEST_P(UpdateWithNewRangeTest, UpdateWithNewRange) {
  1845. const UpdateWithNewRangeTestData test = GetParam();
  1846. const HttpByteRange range = HttpByteRange::Bounded(3, 5);
  1847. std::string orig_headers(test.orig_headers);
  1848. std::replace(orig_headers.begin(), orig_headers.end(), '\n', '\0');
  1849. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(orig_headers + '\0');
  1850. int64_t content_size = parsed->GetContentLength();
  1851. // Update headers without replacing status line.
  1852. parsed->UpdateWithNewRange(range, content_size, false);
  1853. EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
  1854. // Replace status line too.
  1855. parsed->UpdateWithNewRange(range, content_size, true);
  1856. EXPECT_EQ(std::string(test.expected_headers_with_replaced_status),
  1857. ToSimpleString(parsed));
  1858. }
  1859. const UpdateWithNewRangeTestData update_range_tests[] = {
  1860. { "HTTP/1.1 200 OK\n"
  1861. "Content-Length: 450\n",
  1862. "HTTP/1.1 200 OK\n"
  1863. "Content-Range: bytes 3-5/450\n"
  1864. "Content-Length: 3\n",
  1865. "HTTP/1.1 206 Partial Content\n"
  1866. "Content-Range: bytes 3-5/450\n"
  1867. "Content-Length: 3\n",
  1868. },
  1869. { "HTTP/1.1 200 OK\n"
  1870. "Content-Length: 5\n",
  1871. "HTTP/1.1 200 OK\n"
  1872. "Content-Range: bytes 3-5/5\n"
  1873. "Content-Length: 3\n",
  1874. "HTTP/1.1 206 Partial Content\n"
  1875. "Content-Range: bytes 3-5/5\n"
  1876. "Content-Length: 3\n",
  1877. },
  1878. };
  1879. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  1880. UpdateWithNewRangeTest,
  1881. testing::ValuesIn(update_range_tests));
  1882. TEST_F(HttpResponseHeadersCacheControlTest, AbsentMaxAgeReturnsFalse) {
  1883. InitializeHeadersWithCacheControl("nocache");
  1884. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1885. }
  1886. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithNoParameterRejected) {
  1887. InitializeHeadersWithCacheControl("max-age=,private");
  1888. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1889. }
  1890. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithSpaceParameterRejected) {
  1891. InitializeHeadersWithCacheControl("max-age= ,private");
  1892. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1893. }
  1894. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithInterimSpaceIsRejected) {
  1895. InitializeHeadersWithCacheControl("max-age=1 2");
  1896. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1897. }
  1898. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeWithMinusSignIsRejected) {
  1899. InitializeHeadersWithCacheControl("max-age=-7");
  1900. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1901. }
  1902. TEST_F(HttpResponseHeadersCacheControlTest,
  1903. MaxAgeWithSpaceBeforeEqualsIsRejected) {
  1904. InitializeHeadersWithCacheControl("max-age = 7");
  1905. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1906. }
  1907. TEST_F(HttpResponseHeadersCacheControlTest,
  1908. MaxAgeWithLeadingandTrailingSpaces) {
  1909. InitializeHeadersWithCacheControl("max-age= 7 ");
  1910. EXPECT_EQ(base::Seconds(7), GetMaxAgeValue());
  1911. }
  1912. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeFirstMatchUsed) {
  1913. InitializeHeadersWithCacheControl("max-age=10, max-age=20");
  1914. EXPECT_EQ(base::Seconds(10), GetMaxAgeValue());
  1915. }
  1916. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeBogusFirstMatchUsed) {
  1917. // "max-age10" isn't parsed as "max-age"; "max-age=now" is bogus and
  1918. // ignored and so "max-age=20" is used.
  1919. InitializeHeadersWithCacheControl(
  1920. "max-age10, max-age=now, max-age=20, max-age=30");
  1921. EXPECT_EQ(base::Seconds(20), GetMaxAgeValue());
  1922. }
  1923. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeCaseInsensitive) {
  1924. InitializeHeadersWithCacheControl("Max-aGe=15");
  1925. EXPECT_EQ(base::Seconds(15), GetMaxAgeValue());
  1926. }
  1927. TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeOverflow) {
  1928. InitializeHeadersWithCacheControl("max-age=99999999999999999999");
  1929. EXPECT_EQ(base::TimeDelta::FiniteMax().InSeconds(),
  1930. GetMaxAgeValue().InSeconds());
  1931. }
  1932. struct MaxAgeTestData {
  1933. const char* max_age_string;
  1934. const absl::optional<int64_t> expected_seconds;
  1935. };
  1936. class MaxAgeEdgeCasesTest
  1937. : public HttpResponseHeadersCacheControlTest,
  1938. public ::testing::WithParamInterface<MaxAgeTestData> {
  1939. };
  1940. TEST_P(MaxAgeEdgeCasesTest, MaxAgeEdgeCases) {
  1941. const MaxAgeTestData test = GetParam();
  1942. std::string max_age = "max-age=";
  1943. InitializeHeadersWithCacheControl(
  1944. (max_age + test.max_age_string).c_str());
  1945. if (test.expected_seconds.has_value()) {
  1946. EXPECT_EQ(test.expected_seconds.value(), GetMaxAgeValue().InSeconds())
  1947. << " for max-age=" << test.max_age_string;
  1948. } else {
  1949. EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
  1950. }
  1951. }
  1952. const MaxAgeTestData max_age_tests[] = {
  1953. {" 1 ", 1}, // Spaces are ignored.
  1954. {"-1", absl::nullopt},
  1955. {"--1", absl::nullopt},
  1956. {"2s", absl::nullopt},
  1957. {"3 days", absl::nullopt},
  1958. {"'4'", absl::nullopt},
  1959. {"\"5\"", absl::nullopt},
  1960. {"0x6", absl::nullopt}, // Hex not parsed as hex.
  1961. {"7F", absl::nullopt}, // Hex without 0x still not parsed as hex.
  1962. {"010", 10}, // Octal not parsed as octal.
  1963. {"9223372036853", 9223372036853},
  1964. {"9223372036854", 9223372036854},
  1965. {"9223372036855", 9223372036854},
  1966. {"9223372036854775806", 9223372036854},
  1967. {"9223372036854775807", 9223372036854},
  1968. {"20000000000000000000", 9223372036854}, // Overflow int64_t.
  1969. };
  1970. INSTANTIATE_TEST_SUITE_P(HttpResponseHeadersCacheControl,
  1971. MaxAgeEdgeCasesTest,
  1972. testing::ValuesIn(max_age_tests));
  1973. TEST_F(HttpResponseHeadersCacheControlTest,
  1974. AbsentStaleWhileRevalidateReturnsFalse) {
  1975. InitializeHeadersWithCacheControl("max-age=3600");
  1976. EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
  1977. }
  1978. TEST_F(HttpResponseHeadersCacheControlTest,
  1979. StaleWhileRevalidateWithoutValueRejected) {
  1980. InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=");
  1981. EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
  1982. }
  1983. TEST_F(HttpResponseHeadersCacheControlTest,
  1984. StaleWhileRevalidateWithInvalidValueIgnored) {
  1985. InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=true");
  1986. EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
  1987. }
  1988. TEST_F(HttpResponseHeadersCacheControlTest, StaleWhileRevalidateValueReturned) {
  1989. InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=7200");
  1990. EXPECT_EQ(base::Seconds(7200), GetStaleWhileRevalidateValue());
  1991. }
  1992. TEST_F(HttpResponseHeadersCacheControlTest,
  1993. FirstStaleWhileRevalidateValueUsed) {
  1994. InitializeHeadersWithCacheControl(
  1995. "stale-while-revalidate=1,stale-while-revalidate=7200");
  1996. EXPECT_EQ(base::Seconds(1), GetStaleWhileRevalidateValue());
  1997. }
  1998. struct GetCurrentAgeTestData {
  1999. const char* headers;
  2000. const char* request_time;
  2001. const char* response_time;
  2002. const char* current_time;
  2003. const int expected_age;
  2004. };
  2005. class GetCurrentAgeTest
  2006. : public HttpResponseHeadersTest,
  2007. public ::testing::WithParamInterface<GetCurrentAgeTestData> {
  2008. };
  2009. TEST_P(GetCurrentAgeTest, GetCurrentAge) {
  2010. const GetCurrentAgeTestData test = GetParam();
  2011. base::Time request_time, response_time, current_time;
  2012. ASSERT_TRUE(base::Time::FromString(test.request_time, &request_time));
  2013. ASSERT_TRUE(base::Time::FromString(test.response_time, &response_time));
  2014. ASSERT_TRUE(base::Time::FromString(test.current_time, &current_time));
  2015. std::string headers(test.headers);
  2016. HeadersToRaw(&headers);
  2017. auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
  2018. base::TimeDelta age =
  2019. parsed->GetCurrentAge(request_time, response_time, current_time);
  2020. EXPECT_EQ(test.expected_age, age.InSeconds());
  2021. }
  2022. const struct GetCurrentAgeTestData get_current_age_tests[] = {
  2023. // Without Date header.
  2024. {"HTTP/1.1 200 OK\n"
  2025. "Age: 2",
  2026. "Fri, 20 Jan 2011 10:40:08 GMT", "Fri, 20 Jan 2011 10:40:12 GMT",
  2027. "Fri, 20 Jan 2011 10:40:14 GMT", 8},
  2028. // Without Age header.
  2029. {"HTTP/1.1 200 OK\n"
  2030. "Date: Fri, 20 Jan 2011 10:40:10 GMT\n",
  2031. "Fri, 20 Jan 2011 10:40:08 GMT", "Fri, 20 Jan 2011 10:40:12 GMT",
  2032. "Fri, 20 Jan 2011 10:40:14 GMT", 6},
  2033. // date_value > response_time with Age header.
  2034. {"HTTP/1.1 200 OK\n"
  2035. "Date: Fri, 20 Jan 2011 10:40:14 GMT\n"
  2036. "Age: 2\n",
  2037. "Fri, 20 Jan 2011 10:40:08 GMT", "Fri, 20 Jan 2011 10:40:12 GMT",
  2038. "Fri, 20 Jan 2011 10:40:14 GMT", 8},
  2039. // date_value > response_time without Age header.
  2040. {"HTTP/1.1 200 OK\n"
  2041. "Date: Fri, 20 Jan 2011 10:40:14 GMT\n",
  2042. "Fri, 20 Jan 2011 10:40:08 GMT", "Fri, 20 Jan 2011 10:40:12 GMT",
  2043. "Fri, 20 Jan 2011 10:40:14 GMT", 6},
  2044. // apparent_age > corrected_age_value
  2045. {"HTTP/1.1 200 OK\n"
  2046. "Date: Fri, 20 Jan 2011 10:40:07 GMT\n"
  2047. "Age: 0\n",
  2048. "Fri, 20 Jan 2011 10:40:08 GMT", "Fri, 20 Jan 2011 10:40:12 GMT",
  2049. "Fri, 20 Jan 2011 10:40:14 GMT", 7}};
  2050. INSTANTIATE_TEST_SUITE_P(HttpResponseHeaders,
  2051. GetCurrentAgeTest,
  2052. testing::ValuesIn(get_current_age_tests));
  2053. } // namespace
  2054. } // namespace net