summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/filter.cc64
-rw-r--r--net/base/gzip_filter_unittest.cc29
-rw-r--r--net/base/sdch_filter.cc37
-rw-r--r--net/base/sdch_filter_unittest.cc213
-rw-r--r--net/base/sdch_manager.cc2
-rw-r--r--net/base/sdch_manager.h2
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.