OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "net/http/http_cache.h" | 5 #include "net/http/http_cache.h" |
6 | 6 |
7 #include <stdint.h> | |
8 | |
7 #include <algorithm> | 9 #include <algorithm> |
8 | 10 |
9 #include "base/bind.h" | 11 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
11 #include "base/memory/scoped_vector.h" | 13 #include "base/memory/scoped_vector.h" |
12 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
13 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
14 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
15 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
16 #include "base/test/simple_test_clock.h" | 18 #include "base/test/simple_test_clock.h" |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 std::string expected(trans_info.data); | 131 std::string expected(trans_info.data); |
130 EXPECT_EQ(expected, content); | 132 EXPECT_EQ(expected, content); |
131 } | 133 } |
132 | 134 |
133 void RunTransactionTestBase(HttpCache* cache, | 135 void RunTransactionTestBase(HttpCache* cache, |
134 const MockTransaction& trans_info, | 136 const MockTransaction& trans_info, |
135 const MockHttpRequest& request, | 137 const MockHttpRequest& request, |
136 HttpResponseInfo* response_info, | 138 HttpResponseInfo* response_info, |
137 const BoundNetLog& net_log, | 139 const BoundNetLog& net_log, |
138 LoadTimingInfo* load_timing_info, | 140 LoadTimingInfo* load_timing_info, |
139 int64* received_bytes) { | 141 int64_t* sent_bytes, |
142 int64_t* received_bytes) { | |
140 TestCompletionCallback callback; | 143 TestCompletionCallback callback; |
141 | 144 |
142 // write to the cache | 145 // write to the cache |
143 | 146 |
144 scoped_ptr<HttpTransaction> trans; | 147 scoped_ptr<HttpTransaction> trans; |
145 int rv = cache->CreateTransaction(DEFAULT_PRIORITY, &trans); | 148 int rv = cache->CreateTransaction(DEFAULT_PRIORITY, &trans); |
146 EXPECT_EQ(OK, rv); | 149 EXPECT_EQ(OK, rv); |
147 ASSERT_TRUE(trans.get()); | 150 ASSERT_TRUE(trans.get()); |
148 | 151 |
149 rv = trans->Start(&request, callback.callback(), net_log); | 152 rv = trans->Start(&request, callback.callback(), net_log); |
(...skipping 13 matching lines...) Expand all Loading... | |
163 if (load_timing_info) { | 166 if (load_timing_info) { |
164 // If a fake network connection is used, need a NetLog to get a fake socket | 167 // If a fake network connection is used, need a NetLog to get a fake socket |
165 // ID. | 168 // ID. |
166 EXPECT_TRUE(net_log.net_log()); | 169 EXPECT_TRUE(net_log.net_log()); |
167 *load_timing_info = LoadTimingInfo(); | 170 *load_timing_info = LoadTimingInfo(); |
168 trans->GetLoadTimingInfo(load_timing_info); | 171 trans->GetLoadTimingInfo(load_timing_info); |
169 } | 172 } |
170 | 173 |
171 ReadAndVerifyTransaction(trans.get(), trans_info); | 174 ReadAndVerifyTransaction(trans.get(), trans_info); |
172 | 175 |
176 if (sent_bytes) | |
177 *sent_bytes = trans->GetTotalSentBytes(); | |
173 if (received_bytes) | 178 if (received_bytes) |
174 *received_bytes = trans->GetTotalReceivedBytes(); | 179 *received_bytes = trans->GetTotalReceivedBytes(); |
175 } | 180 } |
176 | 181 |
177 void RunTransactionTestWithRequest(HttpCache* cache, | 182 void RunTransactionTestWithRequest(HttpCache* cache, |
178 const MockTransaction& trans_info, | 183 const MockTransaction& trans_info, |
179 const MockHttpRequest& request, | 184 const MockHttpRequest& request, |
180 HttpResponseInfo* response_info) { | 185 HttpResponseInfo* response_info) { |
181 RunTransactionTestBase(cache, trans_info, request, response_info, | 186 RunTransactionTestBase(cache, trans_info, request, response_info, |
182 BoundNetLog(), NULL, NULL); | 187 BoundNetLog(), NULL, NULL, NULL); |
mmenke
2015/09/04 15:21:48
While you're here, mind switching these to be null
sclittle
2015/09/04 22:03:10
Done.
| |
183 } | 188 } |
184 | 189 |
185 void RunTransactionTestAndGetTiming(HttpCache* cache, | 190 void RunTransactionTestAndGetTiming(HttpCache* cache, |
186 const MockTransaction& trans_info, | 191 const MockTransaction& trans_info, |
187 const BoundNetLog& log, | 192 const BoundNetLog& log, |
188 LoadTimingInfo* load_timing_info) { | 193 LoadTimingInfo* load_timing_info) { |
189 RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info), | 194 RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info), NULL, |
190 NULL, log, load_timing_info, NULL); | 195 log, load_timing_info, NULL, NULL); |
191 } | 196 } |
192 | 197 |
193 void RunTransactionTest(HttpCache* cache, const MockTransaction& trans_info) { | 198 void RunTransactionTest(HttpCache* cache, const MockTransaction& trans_info) { |
194 RunTransactionTestAndGetTiming(cache, trans_info, BoundNetLog(), NULL); | 199 RunTransactionTestAndGetTiming(cache, trans_info, BoundNetLog(), NULL); |
195 } | 200 } |
196 | 201 |
197 void RunTransactionTestWithLog(HttpCache* cache, | 202 void RunTransactionTestWithLog(HttpCache* cache, |
198 const MockTransaction& trans_info, | 203 const MockTransaction& trans_info, |
199 const BoundNetLog& log) { | 204 const BoundNetLog& log) { |
200 RunTransactionTestAndGetTiming(cache, trans_info, log, NULL); | 205 RunTransactionTestAndGetTiming(cache, trans_info, log, NULL); |
201 } | 206 } |
202 | 207 |
203 void RunTransactionTestWithResponseInfo(HttpCache* cache, | 208 void RunTransactionTestWithResponseInfo(HttpCache* cache, |
204 const MockTransaction& trans_info, | 209 const MockTransaction& trans_info, |
205 HttpResponseInfo* response) { | 210 HttpResponseInfo* response) { |
206 RunTransactionTestWithRequest(cache, trans_info, MockHttpRequest(trans_info), | 211 RunTransactionTestWithRequest(cache, trans_info, MockHttpRequest(trans_info), |
207 response); | 212 response); |
208 } | 213 } |
209 | 214 |
210 void RunTransactionTestWithResponseInfoAndGetTiming( | 215 void RunTransactionTestWithResponseInfoAndGetTiming( |
211 HttpCache* cache, | 216 HttpCache* cache, |
212 const MockTransaction& trans_info, | 217 const MockTransaction& trans_info, |
213 HttpResponseInfo* response, | 218 HttpResponseInfo* response, |
214 const BoundNetLog& log, | 219 const BoundNetLog& log, |
215 LoadTimingInfo* load_timing_info) { | 220 LoadTimingInfo* load_timing_info) { |
216 RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info), | 221 RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info), |
217 response, log, load_timing_info, NULL); | 222 response, log, load_timing_info, NULL, NULL); |
218 } | 223 } |
219 | 224 |
220 void RunTransactionTestWithResponse(HttpCache* cache, | 225 void RunTransactionTestWithResponse(HttpCache* cache, |
221 const MockTransaction& trans_info, | 226 const MockTransaction& trans_info, |
222 std::string* response_headers) { | 227 std::string* response_headers) { |
223 HttpResponseInfo response; | 228 HttpResponseInfo response; |
224 RunTransactionTestWithResponseInfo(cache, trans_info, &response); | 229 RunTransactionTestWithResponseInfo(cache, trans_info, &response); |
225 response.headers->GetNormalizedHeaders(response_headers); | 230 response.headers->GetNormalizedHeaders(response_headers); |
226 } | 231 } |
227 | 232 |
228 void RunTransactionTestWithResponseAndGetTiming( | 233 void RunTransactionTestWithResponseAndGetTiming( |
229 HttpCache* cache, | 234 HttpCache* cache, |
230 const MockTransaction& trans_info, | 235 const MockTransaction& trans_info, |
231 std::string* response_headers, | 236 std::string* response_headers, |
232 const BoundNetLog& log, | 237 const BoundNetLog& log, |
233 LoadTimingInfo* load_timing_info) { | 238 LoadTimingInfo* load_timing_info) { |
234 HttpResponseInfo response; | 239 HttpResponseInfo response; |
235 RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info), | 240 RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info), |
236 &response, log, load_timing_info, NULL); | 241 &response, log, load_timing_info, NULL, NULL); |
237 response.headers->GetNormalizedHeaders(response_headers); | 242 response.headers->GetNormalizedHeaders(response_headers); |
238 } | 243 } |
239 | 244 |
240 // This class provides a handler for kFastNoStoreGET_Transaction so that the | 245 // This class provides a handler for kFastNoStoreGET_Transaction so that the |
241 // no-store header can be included on demand. | 246 // no-store header can be included on demand. |
242 class FastTransactionServer { | 247 class FastTransactionServer { |
243 public: | 248 public: |
244 FastTransactionServer() { | 249 FastTransactionServer() { |
245 no_store = false; | 250 no_store = false; |
246 } | 251 } |
(...skipping 6854 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7101 trans->SetPriority(HIGHEST); | 7106 trans->SetPriority(HIGHEST); |
7102 // Should trigger a new network transaction and pick up the new | 7107 // Should trigger a new network transaction and pick up the new |
7103 // priority. | 7108 // priority. |
7104 ReadAndVerifyTransaction(trans.get(), transaction); | 7109 ReadAndVerifyTransaction(trans.get(), transaction); |
7105 | 7110 |
7106 EXPECT_EQ(HIGHEST, cache.network_layer()->last_create_transaction_priority()); | 7111 EXPECT_EQ(HIGHEST, cache.network_layer()->last_create_transaction_priority()); |
7107 | 7112 |
7108 RemoveMockTransaction(&kRangeGET_TransactionOK); | 7113 RemoveMockTransaction(&kRangeGET_TransactionOK); |
7109 } | 7114 } |
7110 | 7115 |
7111 int64 RunTransactionAndGetReceivedBytes( | 7116 namespace { |
7112 MockHttpCache& cache, | 7117 |
7113 const MockTransaction& trans_info) { | 7118 void RunTransactionAndGetNetworkBytes(MockHttpCache& cache, |
7114 int64 received_bytes = -1; | 7119 const MockTransaction& trans_info, |
7120 int64_t* sent_bytes, | |
7121 int64_t* received_bytes) { | |
7115 RunTransactionTestBase(cache.http_cache(), trans_info, | 7122 RunTransactionTestBase(cache.http_cache(), trans_info, |
7116 MockHttpRequest(trans_info), NULL, BoundNetLog(), NULL, | 7123 MockHttpRequest(trans_info), NULL, BoundNetLog(), NULL, |
7117 &received_bytes); | 7124 sent_bytes, received_bytes); |
7118 return received_bytes; | |
7119 } | 7125 } |
7120 | 7126 |
7121 int64 TransactionSize(const MockTransaction& transaction) { | 7127 // Helper function to get the typical request size in bytes of |transaction|. |
mmenke
2015/09/04 15:21:48
Should note for both these functions that they ass
sclittle
2015/09/04 22:03:10
Done.
| |
7128 int64_t RequestSize(const MockTransaction& transaction) { | |
mmenke
2015/09/04 15:21:48
TransactionSize and RequestSize are not good names
sclittle
2015/09/04 22:03:10
Done.
| |
7129 // Request line, e.g. "GET /index.html HTTP/1.1\r\n". | |
7130 int64_t sent_bytes = strlen(transaction.method) + | |
7131 GURL(transaction.url).PathForRequest().size() + 12; | |
7132 | |
7133 if (transaction.request_headers) | |
7134 sent_bytes += strlen(transaction.request_headers); | |
7135 | |
7136 return sent_bytes; | |
7137 } | |
7138 | |
7139 int64_t TransactionSize(const MockTransaction& transaction) { | |
7122 return strlen(transaction.status) + strlen(transaction.response_headers) + | 7140 return strlen(transaction.status) + strlen(transaction.response_headers) + |
7123 strlen(transaction.data); | 7141 strlen(transaction.data); |
7124 } | 7142 } |
7125 | 7143 |
7126 TEST(HttpCache, ReceivedBytesCacheMissAndThenHit) { | 7144 } // namespace |
7145 | |
7146 TEST(HttpCache, NetworkBytesCacheMissAndThenHit) { | |
7127 MockHttpCache cache; | 7147 MockHttpCache cache; |
7128 | 7148 |
7129 MockTransaction transaction(kSimpleGET_Transaction); | 7149 MockTransaction transaction(kSimpleGET_Transaction); |
7130 int64 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7150 int64_t sent, received; |
7131 EXPECT_EQ(TransactionSize(transaction), received_bytes); | 7151 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7152 EXPECT_EQ(RequestSize(transaction), sent); | |
7153 EXPECT_EQ(TransactionSize(transaction), received); | |
7132 | 7154 |
7133 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7155 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7134 EXPECT_EQ(0, received_bytes); | 7156 EXPECT_EQ(0, sent); |
7157 EXPECT_EQ(0, received); | |
7135 } | 7158 } |
7136 | 7159 |
7137 TEST(HttpCache, ReceivedBytesConditionalRequest304) { | 7160 TEST(HttpCache, NetworkBytesConditionalRequest304) { |
7138 MockHttpCache cache; | 7161 MockHttpCache cache; |
7139 | 7162 |
7140 ScopedMockTransaction transaction(kETagGET_Transaction); | 7163 ScopedMockTransaction transaction(kETagGET_Transaction); |
7141 int64 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7164 int64_t sent, received; |
7142 EXPECT_EQ(TransactionSize(transaction), received_bytes); | 7165 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7166 EXPECT_EQ(RequestSize(transaction), sent); | |
7167 EXPECT_EQ(TransactionSize(transaction), received); | |
7143 | 7168 |
7144 transaction.load_flags = LOAD_VALIDATE_CACHE; | 7169 transaction.load_flags = LOAD_VALIDATE_CACHE; |
7145 transaction.handler = ETagGet_ConditionalRequest_Handler; | 7170 transaction.handler = ETagGet_ConditionalRequest_Handler; |
7146 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7171 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7147 EXPECT_EQ(TransactionSize(transaction), received_bytes); | 7172 EXPECT_EQ(RequestSize(transaction), sent); |
7173 EXPECT_EQ(TransactionSize(transaction), received); | |
7148 } | 7174 } |
7149 | 7175 |
7150 TEST(HttpCache, ReceivedBytesConditionalRequest200) { | 7176 TEST(HttpCache, NetworkBytesConditionalRequest200) { |
7151 MockHttpCache cache; | 7177 MockHttpCache cache; |
7152 | 7178 |
7153 MockTransaction transaction(kTypicalGET_Transaction); | 7179 MockTransaction transaction(kTypicalGET_Transaction); |
7154 transaction.request_headers = "Foo: bar\r\n"; | 7180 transaction.request_headers = "Foo: bar\r\n"; |
7155 transaction.response_headers = | 7181 transaction.response_headers = |
7156 "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" | 7182 "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" |
7157 "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n" | 7183 "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n" |
7158 "Etag: \"foopy\"\n" | 7184 "Etag: \"foopy\"\n" |
7159 "Cache-Control: max-age=0\n" | 7185 "Cache-Control: max-age=0\n" |
7160 "Vary: Foo\n"; | 7186 "Vary: Foo\n"; |
7161 AddMockTransaction(&transaction); | 7187 AddMockTransaction(&transaction); |
7162 int64 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7188 int64_t sent, received; |
7163 EXPECT_EQ(TransactionSize(transaction), received_bytes); | 7189 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7190 EXPECT_EQ(RequestSize(transaction), sent); | |
7191 EXPECT_EQ(TransactionSize(transaction), received); | |
7164 | 7192 |
7165 RevalidationServer server; | 7193 RevalidationServer server; |
7166 transaction.handler = server.Handler; | 7194 transaction.handler = server.Handler; |
7167 transaction.request_headers = "Foo: none\r\n"; | 7195 transaction.request_headers = "Foo: none\r\n"; |
7168 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7196 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7169 EXPECT_EQ(TransactionSize(transaction), received_bytes); | 7197 EXPECT_EQ(RequestSize(transaction), sent); |
7198 EXPECT_EQ(TransactionSize(transaction), received); | |
7170 | 7199 |
7171 RemoveMockTransaction(&transaction); | 7200 RemoveMockTransaction(&transaction); |
7172 } | 7201 } |
7173 | 7202 |
7174 TEST(HttpCache, ReceivedBytesRange) { | 7203 TEST(HttpCache, NetworkBytesRange) { |
7175 MockHttpCache cache; | 7204 MockHttpCache cache; |
7176 AddMockTransaction(&kRangeGET_TransactionOK); | 7205 AddMockTransaction(&kRangeGET_TransactionOK); |
7177 MockTransaction transaction(kRangeGET_TransactionOK); | 7206 MockTransaction transaction(kRangeGET_TransactionOK); |
7178 | 7207 |
7179 // Read bytes 40-49 from the network. | 7208 // Read bytes 40-49 from the network. |
7180 int64 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7209 int64_t sent, received; |
7181 int64 range_response_size = TransactionSize(transaction); | 7210 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7182 EXPECT_EQ(range_response_size, received_bytes); | 7211 int64_t range_response_size = TransactionSize(transaction); |
7212 EXPECT_EQ(RequestSize(transaction), sent); | |
7213 EXPECT_EQ(range_response_size, received); | |
7183 | 7214 |
7184 // Read bytes 40-49 from the cache. | 7215 // Read bytes 40-49 from the cache. |
7185 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7216 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7186 EXPECT_EQ(0, received_bytes); | 7217 EXPECT_EQ(0, sent); |
7218 EXPECT_EQ(0, received); | |
7187 base::MessageLoop::current()->RunUntilIdle(); | 7219 base::MessageLoop::current()->RunUntilIdle(); |
7188 | 7220 |
7189 // Read bytes 30-39 from the network. | 7221 // Read bytes 30-39 from the network. |
7190 transaction.request_headers = "Range: bytes = 30-39\r\n" EXTRA_HEADER; | 7222 transaction.request_headers = "Range: bytes = 30-39\r\n" EXTRA_HEADER; |
7191 transaction.data = "rg: 30-39 "; | 7223 transaction.data = "rg: 30-39 "; |
7192 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7224 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7193 EXPECT_EQ(range_response_size, received_bytes); | 7225 EXPECT_EQ(RequestSize(transaction), sent); |
7226 EXPECT_EQ(range_response_size, received); | |
7194 base::MessageLoop::current()->RunUntilIdle(); | 7227 base::MessageLoop::current()->RunUntilIdle(); |
7195 | 7228 |
7196 // Read bytes 20-29 and 50-59 from the network, bytes 30-49 from the cache. | 7229 // Read bytes 20-29 and 50-59 from the network, bytes 30-49 from the cache. |
7197 transaction.request_headers = "Range: bytes = 20-59\r\n" EXTRA_HEADER; | 7230 transaction.request_headers = "Range: bytes = 20-59\r\n" EXTRA_HEADER; |
7198 transaction.data = "rg: 20-29 rg: 30-39 rg: 40-49 rg: 50-59 "; | 7231 transaction.data = "rg: 20-29 rg: 30-39 rg: 40-49 rg: 50-59 "; |
7199 received_bytes = RunTransactionAndGetReceivedBytes(cache, transaction); | 7232 RunTransactionAndGetNetworkBytes(cache, transaction, &sent, &received); |
7200 EXPECT_EQ(range_response_size * 2, received_bytes); | 7233 EXPECT_EQ(RequestSize(transaction) * 2, sent); |
7234 EXPECT_EQ(range_response_size * 2, received); | |
7201 | 7235 |
7202 RemoveMockTransaction(&kRangeGET_TransactionOK); | 7236 RemoveMockTransaction(&kRangeGET_TransactionOK); |
7203 } | 7237 } |
7204 | 7238 |
7205 class HttpCachePrefetchValidationTest : public ::testing::Test { | 7239 class HttpCachePrefetchValidationTest : public ::testing::Test { |
7206 protected: | 7240 protected: |
7207 static const int kMaxAgeSecs = 100; | 7241 static const int kMaxAgeSecs = 100; |
7208 static const int kRequireValidationSecs = kMaxAgeSecs + 1; | 7242 static const int kRequireValidationSecs = kMaxAgeSecs + 1; |
7209 | 7243 |
7210 HttpCachePrefetchValidationTest() : transaction_(kSimpleGET_Transaction) { | 7244 HttpCachePrefetchValidationTest() : transaction_(kSimpleGET_Transaction) { |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7631 EXPECT_EQ(1, cache.disk_cache()->open_count()); | 7665 EXPECT_EQ(1, cache.disk_cache()->open_count()); |
7632 EXPECT_EQ(1, cache.disk_cache()->create_count()); | 7666 EXPECT_EQ(1, cache.disk_cache()->create_count()); |
7633 EXPECT_TRUE(response_info.was_cached); | 7667 EXPECT_TRUE(response_info.was_cached); |
7634 | 7668 |
7635 // The new SSL state is reported. | 7669 // The new SSL state is reported. |
7636 EXPECT_EQ(status2, response_info.ssl_info.connection_status); | 7670 EXPECT_EQ(status2, response_info.ssl_info.connection_status); |
7637 EXPECT_TRUE(cert2->Equals(response_info.ssl_info.cert.get())); | 7671 EXPECT_TRUE(cert2->Equals(response_info.ssl_info.cert.get())); |
7638 } | 7672 } |
7639 | 7673 |
7640 } // namespace net | 7674 } // namespace net |
OLD | NEW |