diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-22 19:26:28 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-22 19:26:28 +0000 |
commit | a358604cd69a2b88be50b7055e377f97014b9ca2 (patch) | |
tree | 6f4da365353e1fdc89639b3ed600e8b258b77a82 | |
parent | c459c351504a1c124697b5a7e77d275c09047de0 (diff) | |
download | chromium_src-a358604cd69a2b88be50b7055e377f97014b9ca2.zip chromium_src-a358604cd69a2b88be50b7055e377f97014b9ca2.tar.gz chromium_src-a358604cd69a2b88be50b7055e377f97014b9ca2.tar.bz2 |
Handle proxy corruption including nesting of compressino algorithms
Vodaphone (UK) Mobile Broadband appears to be providing an extra level
of gzip compression, at the same time as it discards the content encoding
"sdch,gzip" and replaces it with "gzip."
The previous approach for handling a missing "sdch" content encoding
statement from a server that *probably* was trying to send encoded
content, was to replace the (probably) garbage content encoding with
tentative decodings for both gzip and sdch. That approach was not
sufficient for the resulting double-gzip encoding that Vodaphone
provided :-(.
This fix leaves the existing content encodings (such as Vodaphone's
solo "gzip"), and adds the tentative decodings (gzip plus sdch).
Hence we translate received content encodings (when we know we requested
an SDCH response by including an applicable dictionary) as follows:
"sdch,gzip" unchanged. This is perfect.
"" ==> "Tent_sdch, Tent_gzip"
"gzip" ==> "Tent_sdch, Test_gzip, gzip"
Note that the TENTATIVE_gzip is a sniffing gzip, that can turn into an
identity (no-op) filter if it can't find a gzip header.
By continuing to use a tentative SDCH, it is possible for the SDCH
filter to make error recovery decision, and to record stats
on this case.
In addition, I've changed the error recovery approach in the SDCH
filter to be ultra conservative. If there is ANY unrecoverable
error in a response to an SDCH request, then we will blacklist
the host of the URL. Recoverable errors are where the SDCH is fully
functional, and decodes its data using the dictionary.
The test cases added focus on the double gzip cases, as observed in
Vodaphone (UK) Mobile Broadband.
BUG=13606
r=huanr
Review URL: http://codereview.chromium.org/140037
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18936 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/base/filter.cc | 64 | ||||
-rw-r--r-- | net/base/gzip_filter_unittest.cc | 29 | ||||
-rw-r--r-- | net/base/sdch_filter.cc | 37 | ||||
-rw-r--r-- | net/base/sdch_filter_unittest.cc | 213 | ||||
-rw-r--r-- | net/base/sdch_manager.cc | 2 | ||||
-rw-r--r-- | net/base/sdch_manager.h | 2 |
6 files changed, 267 insertions, 80 deletions
diff --git a/net/base/filter.cc b/net/base/filter.cc index ceae763..275d398 100644 --- a/net/base/filter.cc +++ b/net/base/filter.cc @@ -117,7 +117,9 @@ void Filter::FixupEncodingTypes( } } + // If the request was for SDCH content, then we might need additional fixups. if (!filter_context.IsSdchResponse()) { + // It was not an SDCH request, so we'll just record stats. if (1 < encoding_types->size()) { // Multiple filters were intended to only be used for SDCH (thus far!) SdchManager::SdchErrorRecovery( @@ -131,7 +133,12 @@ void Filter::FixupEncodingTypes( return; } - // If content encoding included SDCH, then everything is fine. + // The request was tagged as an SDCH request, which means the server supplied + // a dictionary, and we advertised it in the request. Some proxies will do + // very strange things to the request, or the response, so we have to handle + // them gracefully. + + // If content encoding included SDCH, then everything is "relatively" fine. if (!encoding_types->empty() && (FILTER_TYPE_SDCH == encoding_types->front())) { // Some proxies (found currently in Argentina) strip the Content-Encoding @@ -147,21 +154,31 @@ void Filter::FixupEncodingTypes( return; } - // SDCH "search results" protective hack: To make sure we don't break the only - // currently deployed SDCH enabled server! Be VERY cautious about proxies that - // strip all content-encoding to not include sdch. IF we don't see content - // encodings that seem to match what we'd expect from a server that asked us - // to use a dictionary (and we advertised said dictionary in the GET), then - // we set the encoding to (try to) use SDCH to decode. Note that SDCH will - // degrade into a pass-through filter if it doesn't have a viable dictionary - // hash in its header. Also note that a solo "sdch" will implicitly create - // a "sdch,gzip" decoding filter, where the gzip portion will degrade to a - // pass through if a gzip header is not encountered. Hence we can replace - // "gzip" with "sdch" and "everything will work." - // The one failure mode comes when we advertise a dictionary, and the server - // tries to *send* a gzipped file (not gzip encode content), and then we could - // do a gzip decode :-(. Since current server support does not ever see such - // a transfer, we are safe (for now). + // There are now several cases to handle for an SDCH request. Foremost, if + // the outbound request was stripped so as not to advertise support for + // encodings, we might get back content with no encoding, or (for example) + // just gzip. We have to be sure that any changes we make allow for such + // minimal coding to work. That issue is why we use TENTATIVE filters if we + // add any, as those filters sniff the content, and act as pass-through + // filters if headers are not found. + + // If the outbound GET is not modified, then the server will generally try to + // send us SDCH encoded content. As that content returns, there are several + // corruptions of the header "content-encoding" that proxies may perform (and + // have been detected in the wild). We already dealt with the a honest + // content encoding of "sdch,gzip" being corrupted into "sdch" with on change + // of the actual content. Another common corruption is to either disscard + // the accurate content encoding, or to replace it with gzip only (again, with + // no change in actual content). The last observed corruption it to actually + // change the content, such as by re-gzipping it, and that may happen along + // with corruption of the stated content encoding (wow!). + + // The one unresolved failure mode comes when we advertise a dictionary, and + // the server tries to *send* a gzipped file (not gzip encode content), and + // then we could do a gzip decode :-(. Since SDCH is only (currently) + // supported server side on paths that only send HTML content, this mode has + // never surfaced in the wild (and is unlikely to). + // We will gather a lot of stats as we perform the fixups if (StartsWithASCII(mime_type, kTextHtml, false)) { // Suspicious case: Advertised dictionary, but server didn't use sdch, and // we're HTML tagged. @@ -193,9 +210,18 @@ void Filter::FixupEncodingTypes( } } - encoding_types->clear(); - encoding_types->push_back(FILTER_TYPE_SDCH_POSSIBLE); - encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH); + // Leave the existing encoding type to be processed first, and add our + // tentative decodings to be done afterwards. Vodaphone UK reportedyl will + // perform a second layer of gzip encoding atop the server's sdch,gzip + // encoding, and then claim that the content encoding is a mere gzip. As a + // result we'll need (in that case) to do the gunzip, plus our tentative + // gunzip and tentative SDCH decoding. + // This approach nicely handles the empty() list as well, and should work with + // other (as yet undiscovered) proxies the choose to re-compressed with some + // other encoding (such as bzip2, etc.). + encoding_types->insert(encoding_types->begin(), + FILTER_TYPE_GZIP_HELPING_SDCH); + encoding_types->insert(encoding_types->begin(), FILTER_TYPE_SDCH_POSSIBLE); return; } diff --git a/net/base/gzip_filter_unittest.cc b/net/base/gzip_filter_unittest.cc index 5d1b9c5..c933014 100644 --- a/net/base/gzip_filter_unittest.cc +++ b/net/base/gzip_filter_unittest.cc @@ -269,35 +269,6 @@ TEST_F(GZipUnitTest, DecodeGZip) { EXPECT_EQ(memcmp(source_buffer(), gzip_decode_buffer, source_len()), 0); } -// SDCH scenario: decoding gzip data when content type says sdch,gzip. -// This tests that sdch will degrade to pass through, and is what allows robust -// handling when the response *might* be sdch,gzip by simply adding in the -// tentative sdch decode. -// All test code is otherwise modeled after the "basic" scenario above. -TEST_F(GZipUnitTest, DecodeGZipWithMistakenSdch) { - // Decode the compressed data with filter - std::vector<Filter::FilterType> filter_types; - filter_types.push_back(Filter::FILTER_TYPE_SDCH); - filter_types.push_back(Filter::FILTER_TYPE_GZIP); - MockFilterContext filter_context(kDefaultBufferSize); - // We need a good response code to be sure that a proxy isn't injecting an - // error page (As is done by BlueCoat proxies and described in bug 8916). - filter_context.SetResponseCode(200); - scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context)); - ASSERT_TRUE(filter.get()); - memcpy(filter->stream_buffer()->data(), gzip_encode_buffer_, - gzip_encode_len_); - filter->FlushStreamBuffer(gzip_encode_len_); - - char gzip_decode_buffer[kDefaultBufferSize]; - int gzip_decode_size = kDefaultBufferSize; - filter->ReadData(gzip_decode_buffer, &gzip_decode_size); - - // Compare the decoding result with source data - EXPECT_TRUE(gzip_decode_size == source_len()); - EXPECT_EQ(memcmp(source_buffer(), gzip_decode_buffer, source_len()), 0); -} - // Tests we can call filter repeatedly to get all the data decoded. // To do that, we create a filter with a small buffer that can not hold all // the input data. diff --git a/net/base/sdch_filter.cc b/net/base/sdch_filter.cc index 9ddac28..8a21ed7 100644 --- a/net/base/sdch_filter.cc +++ b/net/base/sdch_filter.cc @@ -152,45 +152,50 @@ Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer, DCHECK_EQ(0u, dest_buffer_excess_index_); DCHECK(dest_buffer_excess_.empty()); // This is where we try very hard to do error recovery, and make this - // protocol robust in teh face of proxies that do many different things. + // protocol robust in the face of proxies that do many different things. // If we decide that things are looking very bad (too hard to recover), // we may even issue a "meta-refresh" to reload the page without an SDCH - // advertisement (so that we are sure we're not hurting anything). First - // we try for some light weight recovery, and teh final else clause below - // supports the last ditch meta-refresh approach. + // advertisement (so that we are sure we're not hurting anything). // // Watch out for an error page inserted by the proxy as part of a 40x // error response. When we see such content molestation, we certainly // need to fall into the meta-refresh case. bool successful_response = filter_context().GetResponseCode() == 200; - if (possible_pass_through_ && successful_response) { - // This is the most graceful response. There really was no error. We - // were just overly cautious. + if (filter_context().GetResponseCode() == 404) { + // We could be more generous, but for now, only a "NOT FOUND" code will + // cause a pass through. All other codes will fall into a meta-refresh + // attempt. + SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_404_CODE); + decoding_status_ = PASS_THROUGH; + } else if (possible_pass_through_ && successful_response) { + // This is the potentially most graceful response. There really was no + // error. We were just overly cautious when we added a TENTATIVE_SDCH. // We added the sdch coding tag, and it should not have been added. // This can happen in server experiments, where the server decides // not to use sdch, even though there is a dictionary. To be // conservative, we locally added the tentative sdch (fearing that a // proxy stripped it!) and we must now recant (pass through). SdchManager::SdchErrorRecovery(SdchManager::DISCARD_TENTATIVE_SDCH); - decoding_status_ = PASS_THROUGH; - dest_buffer_excess_ = dictionary_hash_; // Send what we scanned. + // However.... just to be sure we don't get burned by proxies that + // re-compress with gzip or other system, we can sniff to see if this + // is compressed data etc. For now, we do nothing, which gets us into + // the meta-refresh result. + // TODO(jar): Improve robustness by sniffing for valid text that we can + // actual use re: decoding_status_ = PASS_THROUGH; } else if (successful_response && !dictionary_hash_is_plausible_) { // One of the first 9 bytes precluded consideration as a hash. // This can't be an SDCH payload, even though the server said it was. // This is a major error, as the server or proxy tagged this SDCH even // though it is not! - // The good news is that error recovery is clear... SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH); + // Meta-refresh won't help... we didn't advertise an SDCH dictionary!! decoding_status_ = PASS_THROUGH; + } + + if (decoding_status_ == PASS_THROUGH) { dest_buffer_excess_ = dictionary_hash_; // Send what we scanned. } else { // This is where we try to do the expensive meta-refresh. - // Either this was an error response (probably an error page inserted - // by a proxy, as in bug 8916) or else we don't have the dictionary that - // was demanded. - // With very low probability, random garbage data looked like a - // dictionary specifier (8 ASCII characters followed by a null), but - // that is sufficiently unlikely that we ignore it. if (std::string::npos == mime_type_.find("text/html")) { // Since we can't do a meta-refresh (along with an exponential // backoff), we'll just make sure this NEVER happens again. diff --git a/net/base/sdch_filter_unittest.cc b/net/base/sdch_filter_unittest.cc index abab262..02dc215 100644 --- a/net/base/sdch_filter_unittest.cc +++ b/net/base/sdch_filter_unittest.cc @@ -37,7 +37,7 @@ static const char kTestData[] = "0000000000000000000000000000000000000000000000" "000000000000000000000000000000000000000\n"; // Note SDCH compressed data will include a reference to the SDCH dictionary. -static const char kCompressedTestData[] = +static const char kSdchCompressedTestData[] = "\326\303\304\0\0\001M\0\201S\202\004\0\201E\006\001" "00000000000000000000000000000000000000000000000000000000000000000000000000" "TestData 00000000000000000000000000000000000000000000000000000000000000000" @@ -50,8 +50,8 @@ class SdchFilterTest : public testing::Test { SdchFilterTest() : test_vcdiff_dictionary_(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1), - vcdiff_compressed_data_(kCompressedTestData, - sizeof(kCompressedTestData) - 1), + vcdiff_compressed_data_(kSdchCompressedTestData, + sizeof(kSdchCompressedTestData) - 1), expanded_(kTestData, sizeof(kTestData) - 1), sdch_manager_(new SdchManager) { sdch_manager_->EnableSdchSupport(""); @@ -171,7 +171,7 @@ TEST_F(SdchFilterTest, EmptyInputOk) { TEST_F(SdchFilterTest, PassThroughWhenTentative) { std::vector<Filter::FilterType> filter_types; // Selective a tentative filter (which can fall back to pass through). - filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE); + filter_types.push_back(Filter::FILTER_TYPE_GZIP_HELPING_SDCH); const int kInputBufferSize(30); char output_buffer[20]; MockFilterContext filter_context(kInputBufferSize); @@ -181,31 +181,30 @@ TEST_F(SdchFilterTest, PassThroughWhenTentative) { filter_context.SetURL(GURL(url_string)); scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context)); - // Supply enough data to force a pass-through mode, which means we have - // provided more than 9 characters that can't be a dictionary hash. - std::string non_sdch_content("This is not SDCH"); + // Supply enough data to force a pass-through mode.. + std::string non_gzip_content("not GZIPed data"); char* input_buffer = filter->stream_buffer()->data(); int input_buffer_size = filter->stream_buffer_size(); EXPECT_EQ(kInputBufferSize, input_buffer_size); - EXPECT_LT(static_cast<int>(non_sdch_content.size()), + EXPECT_LT(static_cast<int>(non_gzip_content.size()), input_buffer_size); - memcpy(input_buffer, non_sdch_content.data(), - non_sdch_content.size()); - filter->FlushStreamBuffer(non_sdch_content.size()); + memcpy(input_buffer, non_gzip_content.data(), + non_gzip_content.size()); + filter->FlushStreamBuffer(non_gzip_content.size()); // Try to read output. int output_bytes_or_buffer_size = sizeof(output_buffer); Filter::FilterStatus status = filter->ReadData(output_buffer, &output_bytes_or_buffer_size); - EXPECT_TRUE(non_sdch_content.size() == + EXPECT_EQ(non_gzip_content.size(), static_cast<size_t>(output_bytes_or_buffer_size)); - ASSERT_TRUE(sizeof(output_buffer) > + ASSERT_GT(sizeof(output_buffer), static_cast<size_t>(output_bytes_or_buffer_size)); output_buffer[output_bytes_or_buffer_size] = '\0'; - EXPECT_TRUE(non_sdch_content == output_buffer); + EXPECT_TRUE(non_gzip_content == output_buffer); EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status); } @@ -933,6 +932,70 @@ TEST_F(SdchFilterTest, DefaultGzipIfSdch) { filter_context.SetMimeType("anything/mime"); filter_context.SetSdchResponse(true); Filter::FixupEncodingTypes(filter_context, &filter_types); + ASSERT_EQ(filter_types.size(), 2u); + EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH); + EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); + + // First try with a large buffer (larger than test input, or compressed data). + filter_context.SetURL(url); + scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context)); + + + // Verify that chained filter is waiting for data. + char tiny_output_buffer[10]; + int tiny_output_size = sizeof(tiny_output_buffer); + EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, + filter->ReadData(tiny_output_buffer, &tiny_output_size)); + + size_t feed_block_size = 100; + size_t output_block_size = 100; + std::string output; + EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size, + output_block_size, filter.get(), &output)); + EXPECT_EQ(output, expanded_); + + // Next try with a tiny buffer to cover edge effects. + filter.reset(Filter::Factory(filter_types, filter_context)); + + feed_block_size = 1; + output_block_size = 1; + output.clear(); + EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size, + output_block_size, filter.get(), &output)); + EXPECT_EQ(output, expanded_); +} + +TEST_F(SdchFilterTest, AcceptGzipSdchIfGzip) { + // Construct a valid SDCH dictionary from a VCDIFF dictionary. + const std::string kSampleDomain = "sdchtest.com"; + std::string dictionary(NewSdchDictionary(kSampleDomain)); + + std::string url_string = "http://" + kSampleDomain; + + GURL url(url_string); + EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url)); + + std::string sdch_compressed(NewSdchCompressedData(dictionary)); + + // Use Gzip to compress the sdch sdch_compressed data. + std::string gzip_compressed_sdch = gzip_compress(sdch_compressed); + + // Some proxies strip the content encoding statement down to a mere gzip, but + // pass through the original content (with full sdch,gzip encoding). + // Only claim to have gzip content, but really use the gzipped sdch content. + // System should automatically add the missing (optional) sdch. + std::vector<Filter::FilterType> filter_types; + filter_types.push_back(Filter::FILTER_TYPE_GZIP); + + const int kInputBufferSize(100); + MockFilterContext filter_context(kInputBufferSize); + filter_context.SetMimeType("anything/mime"); + filter_context.SetSdchResponse(true); + Filter::FixupEncodingTypes(filter_context, &filter_types); + ASSERT_EQ(filter_types.size(), 3u); + EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE); + EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); + EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP); // First try with a large buffer (larger than test input, or compressed data). filter_context.SetURL(url); @@ -963,6 +1026,128 @@ TEST_F(SdchFilterTest, DefaultGzipIfSdch) { EXPECT_EQ(output, expanded_); } +TEST_F(SdchFilterTest, DefaultSdchGzipIfEmpty) { + // Construct a valid SDCH dictionary from a VCDIFF dictionary. + const std::string kSampleDomain = "sdchtest.com"; + std::string dictionary(NewSdchDictionary(kSampleDomain)); + + std::string url_string = "http://" + kSampleDomain; + + GURL url(url_string); + EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url)); + + std::string sdch_compressed(NewSdchCompressedData(dictionary)); + + // Use Gzip to compress the sdch sdch_compressed data. + std::string gzip_compressed_sdch = gzip_compress(sdch_compressed); + + // Only claim to have non-encoded content, but really use the gzipped sdch + // content. + // System should automatically add the missing (optional) sdch,gzip. + std::vector<Filter::FilterType> filter_types; + + const int kInputBufferSize(100); + MockFilterContext filter_context(kInputBufferSize); + filter_context.SetMimeType("anything/mime"); + filter_context.SetSdchResponse(true); + Filter::FixupEncodingTypes(filter_context, &filter_types); + ASSERT_EQ(filter_types.size(), 2u); + EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE); + EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); + + // First try with a large buffer (larger than test input, or compressed data). + filter_context.SetURL(url); + scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context)); + + + // Verify that chained filter is waiting for data. + char tiny_output_buffer[10]; + int tiny_output_size = sizeof(tiny_output_buffer); + EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, + filter->ReadData(tiny_output_buffer, &tiny_output_size)); + + size_t feed_block_size = 100; + size_t output_block_size = 100; + std::string output; + EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size, + output_block_size, filter.get(), &output)); + EXPECT_EQ(output, expanded_); + + // Next try with a tiny buffer to cover edge effects. + filter.reset(Filter::Factory(filter_types, filter_context)); + + feed_block_size = 1; + output_block_size = 1; + output.clear(); + EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size, + output_block_size, filter.get(), &output)); + EXPECT_EQ(output, expanded_); +} + +TEST_F(SdchFilterTest, AcceptGzipGzipSdchIfGzip) { + // Construct a valid SDCH dictionary from a VCDIFF dictionary. + const std::string kSampleDomain = "sdchtest.com"; + std::string dictionary(NewSdchDictionary(kSampleDomain)); + + std::string url_string = "http://" + kSampleDomain; + + GURL url(url_string); + EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url)); + + std::string sdch_compressed(NewSdchCompressedData(dictionary)); + + // Vodaphone (UK) Mobile Broadband provides double gzipped sdch with a content + // encoding of merely gzip (apparently, only listing the extra level of + // wrapper compression they added, but discarding the actual content encoding. + // Use Gzip to double compress the sdch sdch_compressed data. + std::string double_gzip_compressed_sdch = gzip_compress(gzip_compress( + sdch_compressed)); + + // Only claim to have gzip content, but really use the double gzipped sdch + // content. + // System should automatically add the missing (optional) sdch, gzip decoders. + std::vector<Filter::FilterType> filter_types; + filter_types.push_back(Filter::FILTER_TYPE_GZIP); + + const int kInputBufferSize(100); + MockFilterContext filter_context(kInputBufferSize); + filter_context.SetMimeType("anything/mime"); + filter_context.SetSdchResponse(true); + Filter::FixupEncodingTypes(filter_context, &filter_types); + ASSERT_EQ(filter_types.size(), 3u); + EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE); + EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); + EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP); + + // First try with a large buffer (larger than test input, or compressed data). + filter_context.SetURL(url); + scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context)); + + + // Verify that chained filter is waiting for data. + char tiny_output_buffer[10]; + int tiny_output_size = sizeof(tiny_output_buffer); + EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, + filter->ReadData(tiny_output_buffer, &tiny_output_size)); + + size_t feed_block_size = 100; + size_t output_block_size = 100; + std::string output; + EXPECT_TRUE(FilterTestData(double_gzip_compressed_sdch, feed_block_size, + output_block_size, filter.get(), &output)); + EXPECT_EQ(output, expanded_); + + // Next try with a tiny buffer to cover edge effects. + filter.reset(Filter::Factory(filter_types, filter_context)); + + feed_block_size = 1; + output_block_size = 1; + output.clear(); + EXPECT_TRUE(FilterTestData(double_gzip_compressed_sdch, feed_block_size, + output_block_size, filter.get(), &output)); + EXPECT_EQ(output, expanded_); +} + TEST_F(SdchFilterTest, DomainSupported) { GURL test_url("http://www.test.com"); GURL google_url("http://www.google.com"); diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc index 7de9f0b..4dbde70 100644 --- a/net/base/sdch_manager.cc +++ b/net/base/sdch_manager.cc @@ -32,7 +32,7 @@ SdchManager* SdchManager::Global() { // static void SdchManager::SdchErrorRecovery(ProblemCodes problem) { - static LinearHistogram histogram("Sdch3.ProblemCodes_3", MIN_PROBLEM_CODE, + static LinearHistogram histogram("Sdch3.ProblemCodes_4", MIN_PROBLEM_CODE, MAX_PROBLEM_CODE - 1, MAX_PROBLEM_CODE); histogram.SetFlags(kUmaTargetedHistogramFlag); histogram.Add(problem); diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h index a6c7a3b..c95b890 100644 --- a/net/base/sdch_manager.h +++ b/net/base/sdch_manager.h @@ -122,7 +122,7 @@ class SdchManager { CACHED_META_REFRESH_UNSUPPORTED = 75, // As above, but pulled from cache. PASSING_THROUGH_NON_SDCH = 76, // Non-html tagged as sdch but malformed. INCOMPLETE_SDCH_CONTENT = 77, // Last window was not completely decoded. - + PASS_THROUGH_404_CODE = 78, // URL not found message passing through. // Common decoded recovery methods. META_REFRESH_CACHED_RECOVERY = 80, // Probably startup tab loading. |