| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <map> | 5 #include <map> |
| 6 #include <string> | 6 #include <string> |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
| 11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
| 12 #include "content/public/test/test_browser_thread_bundle.h" | 12 #include "content/public/test/test_browser_thread_bundle.h" |
| 13 #include "content/public/test/test_utils.h" | 13 #include "content/public/test/test_utils.h" |
| 14 #include "extensions/browser/api/extensions_api_client.h" | 14 #include "extensions/browser/api/extensions_api_client.h" |
| 15 #include "extensions/browser/extensions_browser_client.h" | 15 #include "extensions/browser/extensions_browser_client.h" |
| 16 #include "extensions/browser/updater/update_service.h" | 16 #include "extensions/browser/updater/update_service.h" |
| 17 #include "extensions/common/extension_urls.h" | 17 #include "extensions/common/extension_urls.h" |
| 18 #include "extensions/shell/test/shell_test.h" | 18 #include "extensions/shell/test/shell_test.h" |
| 19 #include "net/base/escape.h" | 19 #include "net/base/escape.h" |
| 20 #include "net/http/http_status_code.h" | 20 #include "net/http/http_status_code.h" |
| 21 #include "net/url_request/test_url_fetcher_factory.h" | 21 #include "net/url_request/test_url_fetcher_factory.h" |
| 22 | 22 |
| 23 namespace extensions { | 23 namespace extensions { |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 using FakeResponse = std::pair<std::string, net::HttpStatusCode>; | 27 using FakeResponse = std::pair<std::string, net::HttpStatusCode>; |
| 28 | 28 |
| 29 // TODO(rockot): In general there's enough mock-Omaha-noise that this might be | 29 // TODO(rockot): In general there's enough mock-Omaha-noise that this might be |
| 30 // better placed into some test library code in //components/omaha_client. | 30 // better placed into some test library code in //components/update_client. |
| 31 FakeResponse CreateFakeOmahaResponse(const std::string& id, size_t crx_length) { | 31 FakeResponse CreateFakeUpdateResponse(const std::string& id, |
| 32 size_t crx_length) { |
| 32 std::string response_text = base::StringPrintf( | 33 std::string response_text = base::StringPrintf( |
| 33 "<gupdate xmlns=\"http://www.google.com/update2/response\" " | 34 "<gupdate xmlns=\"http://www.google.com/update2/response\" " |
| 34 " protocol=\"2.0\" server=\"prod\">\n" | 35 " protocol=\"2.0\" server=\"prod\">\n" |
| 35 " <daystart elapsed_days=\"2860\" elapsed_seconds=\"42042\"/>\n" | 36 " <daystart elapsed_days=\"2860\" elapsed_seconds=\"42042\"/>\n" |
| 36 " <app appid=\"%s\" status=\"ok\">\n" | 37 " <app appid=\"%s\" status=\"ok\">\n" |
| 37 " <updatecheck codebase=\"%s\" fp=\"0\" hash=\"\" hash_sha256=\"\" " | 38 " <updatecheck codebase=\"%s\" fp=\"0\" hash=\"\" hash_sha256=\"\" " |
| 38 " size=\"%d\" status=\"ok\" version=\"1\"/>\n" | 39 " size=\"%d\" status=\"ok\" version=\"1\"/>\n" |
| 39 " </app>\n" | 40 " </app>\n" |
| 40 "</gupdate>\n", | 41 "</gupdate>\n", |
| 41 id.c_str(), | 42 id.c_str(), |
| 42 base::StringPrintf("https://fake-omaha-hostname/%s.crx", | 43 base::StringPrintf("https://fake-omaha-hostname/%s.crx", |
| 43 id.c_str()).c_str(), | 44 id.c_str()).c_str(), |
| 44 static_cast<int>(crx_length)); | 45 static_cast<int>(crx_length)); |
| 45 return std::make_pair(response_text, net::HTTP_OK); | 46 return std::make_pair(response_text, net::HTTP_OK); |
| 46 } | 47 } |
| 47 | 48 |
| 48 FakeResponse CreateFakeOmahaNotFoundResponse() { | 49 FakeResponse CreateFakeUpdateNotFoundResponse() { |
| 49 return std::make_pair( | 50 return std::make_pair( |
| 50 std::string( | 51 std::string( |
| 51 "<gupdate xmlns=\"http://www.google.com/update2/response\" " | 52 "<gupdate xmlns=\"http://www.google.com/update2/response\" " |
| 52 " protocol=\"2.0\" server=\"prod\">\n" | 53 " protocol=\"2.0\" server=\"prod\">\n" |
| 53 " <daystart elapsed_days=\"4242\" elapsed_seconds=\"42042\"/>\n" | 54 " <daystart elapsed_days=\"4242\" elapsed_seconds=\"42042\"/>\n" |
| 54 " <app appid=\"\" status=\"error-invalidAppId\">\n" | 55 " <app appid=\"\" status=\"error-invalidAppId\">\n" |
| 55 "</gupdate>"), | 56 "</gupdate>"), |
| 56 net::HTTP_OK); | 57 net::HTTP_OK); |
| 57 } | 58 } |
| 58 | 59 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 69 } | 70 } |
| 70 } | 71 } |
| 71 return false; | 72 return false; |
| 72 } | 73 } |
| 73 | 74 |
| 74 // This extracts an extension ID from an Omaha update query. Queries have the | 75 // This extracts an extension ID from an Omaha update query. Queries have the |
| 75 // form https://foo/bar/update?x=id%3Dabcdefghijklmnopqrstuvwxyzaaaaaa%26... | 76 // form https://foo/bar/update?x=id%3Dabcdefghijklmnopqrstuvwxyzaaaaaa%26... |
| 76 // This function extracts the 'x' query parameter (e.g. "id%3Dabcdef...."), | 77 // This function extracts the 'x' query parameter (e.g. "id%3Dabcdef...."), |
| 77 // unescapes its value (to become e.g., "id=abcdef...", and then extracts the | 78 // unescapes its value (to become e.g., "id=abcdef...", and then extracts the |
| 78 // 'id' value from the result (e.g. "abcdef..."). | 79 // 'id' value from the result (e.g. "abcdef..."). |
| 79 bool ExtractIdFromOmahaQuery(const std::string& query_str, std::string* id) { | 80 bool ExtractIdFromUpdateQuery(const std::string& query_str, std::string* id) { |
| 80 std::string data_string; | 81 std::string data_string; |
| 81 if (!ExtractKeyValueFromComponent(query_str, "x", &data_string)) | 82 if (!ExtractKeyValueFromComponent(query_str, "x", &data_string)) |
| 82 return false; | 83 return false; |
| 83 data_string = net::UnescapeURLComponent(data_string, | 84 data_string = net::UnescapeURLComponent(data_string, |
| 84 net::UnescapeRule::URL_SPECIAL_CHARS); | 85 net::UnescapeRule::URL_SPECIAL_CHARS); |
| 85 if (!ExtractKeyValueFromComponent(data_string, "id", id)) | 86 if (!ExtractKeyValueFromComponent(data_string, "id", id)) |
| 86 return false; | 87 return false; |
| 87 EXPECT_EQ(32u, id->size()); | 88 EXPECT_EQ(32u, id->size()); |
| 88 return true; | 89 return true; |
| 89 } | 90 } |
| 90 | 91 |
| 91 void ExpectDownloadSuccess(const base::Closure& continuation, bool success) { | 92 void ExpectDownloadSuccess(const base::Closure& continuation, bool success) { |
| 92 EXPECT_TRUE(success) << "Download failed."; | 93 EXPECT_TRUE(success) << "Download failed."; |
| 93 continuation.Run(); | 94 continuation.Run(); |
| 94 } | 95 } |
| 95 | 96 |
| 96 class FakeUpdateURLFetcherFactory : public net::URLFetcherFactory { | 97 class FakeUpdateURLFetcherFactory : public net::URLFetcherFactory { |
| 97 public: | 98 public: |
| 98 ~FakeUpdateURLFetcherFactory() override {} | 99 ~FakeUpdateURLFetcherFactory() override {} |
| 99 | 100 |
| 100 void RegisterFakeExtension(const std::string& id, | 101 void RegisterFakeExtension(const std::string& id, |
| 101 const std::string& contents) { | 102 const std::string& contents) { |
| 102 CHECK(id.size() == 32); | 103 CHECK_EQ(32u, id.size()); |
| 103 fake_extensions_.insert(std::make_pair(id, contents)); | 104 fake_extensions_.insert(std::make_pair(id, contents)); |
| 104 } | 105 } |
| 105 | 106 |
| 106 // net::URLFetcherFactory: | 107 // net::URLFetcherFactory: |
| 107 net::URLFetcher* CreateURLFetcher( | 108 net::URLFetcher* CreateURLFetcher( |
| 108 int id, | 109 int id, |
| 109 const GURL& url, | 110 const GURL& url, |
| 110 net::URLFetcher::RequestType request_type, | 111 net::URLFetcher::RequestType request_type, |
| 111 net::URLFetcherDelegate* delegate) override { | 112 net::URLFetcherDelegate* delegate) override { |
| 112 if (url.spec().find(extension_urls::GetWebstoreUpdateUrl().spec()) == 0) { | 113 if (url.spec().find(extension_urls::GetWebstoreUpdateUrl().spec()) == 0) { |
| 113 // Handle fake Omaha requests. | 114 // Handle fake Omaha requests. |
| 114 return CreateUpdateManifestFetcher(url, delegate); | 115 return CreateUpdateManifestFetcher(url, delegate); |
| 115 } else if (url.spec().find("https://fake-omaha-hostname") == 0) { | 116 } else if (url.spec().find("https://fake-omaha-hostname") == 0) { |
| 116 // Handle a fake CRX request. | 117 // Handle a fake CRX request. |
| 117 return CreateCrxFetcher(url, delegate); | 118 return CreateCrxFetcher(url, delegate); |
| 118 } | 119 } |
| 119 NOTREACHED(); | 120 NOTREACHED(); |
| 120 return nullptr; | 121 return nullptr; |
| 121 } | 122 } |
| 122 | 123 |
| 123 private: | 124 private: |
| 124 net::URLFetcher* CreateUpdateManifestFetcher( | 125 net::URLFetcher* CreateUpdateManifestFetcher( |
| 125 const GURL& url, | 126 const GURL& url, |
| 126 net::URLFetcherDelegate* delegate) { | 127 net::URLFetcherDelegate* delegate) { |
| 127 // If we have a fake CRX for the ID, return a fake update blob for it. | 128 // If we have a fake CRX for the ID, return a fake update blob for it. |
| 128 // Otherwise return an invalid-ID response. | 129 // Otherwise return an invalid-ID response. |
| 129 FakeResponse response; | 130 FakeResponse response; |
| 130 std::string extension_id; | 131 std::string extension_id; |
| 131 if (!ExtractIdFromOmahaQuery(url.query(), &extension_id)) { | 132 if (!ExtractIdFromUpdateQuery(url.query(), &extension_id)) { |
| 132 response = CreateFakeOmahaNotFoundResponse(); | 133 response = CreateFakeUpdateNotFoundResponse(); |
| 133 } else { | 134 } else { |
| 134 const auto& iter = fake_extensions_.find(extension_id); | 135 const auto& iter = fake_extensions_.find(extension_id); |
| 135 if (iter == fake_extensions_.end()) | 136 if (iter == fake_extensions_.end()) |
| 136 response = CreateFakeOmahaNotFoundResponse(); | 137 response = CreateFakeUpdateNotFoundResponse(); |
| 137 else | 138 else |
| 138 response = CreateFakeOmahaResponse(extension_id, iter->second.size()); | 139 response = CreateFakeUpdateResponse(extension_id, iter->second.size()); |
| 139 } | 140 } |
| 140 return new net::FakeURLFetcher(url, delegate, response.first, | 141 return new net::FakeURLFetcher(url, delegate, response.first, |
| 141 response.second, | 142 response.second, |
| 142 net::URLRequestStatus::SUCCESS); | 143 net::URLRequestStatus::SUCCESS); |
| 143 } | 144 } |
| 144 | 145 |
| 145 net::URLFetcher* CreateCrxFetcher(const GURL& url, | 146 net::URLFetcher* CreateCrxFetcher(const GURL& url, |
| 146 net::URLFetcherDelegate* delegate) { | 147 net::URLFetcherDelegate* delegate) { |
| 147 FakeResponse response; | 148 FakeResponse response; |
| 148 std::string extension_id = url.path().substr(1, 32); | 149 std::string extension_id = url.path().substr(1, 32); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 const char kCrxContents[] = "Hello, world!"; | 199 const char kCrxContents[] = "Hello, world!"; |
| 199 RegisterFakeExtension(kCrxId, kCrxContents); | 200 RegisterFakeExtension(kCrxId, kCrxContents); |
| 200 | 201 |
| 201 base::RunLoop run_loop; | 202 base::RunLoop run_loop; |
| 202 update_service()->DownloadAndInstall( | 203 update_service()->DownloadAndInstall( |
| 203 kCrxId, base::Bind(ExpectDownloadSuccess, run_loop.QuitClosure())); | 204 kCrxId, base::Bind(ExpectDownloadSuccess, run_loop.QuitClosure())); |
| 204 run_loop.Run(); | 205 run_loop.Run(); |
| 205 } | 206 } |
| 206 | 207 |
| 207 } // namespace extensions | 208 } // namespace extensions |
| OLD | NEW |