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 |