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 "build/build_config.h" | 5 #include "build/build_config.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <windows.h> | 8 #include <windows.h> |
9 #include <shlobj.h> | 9 #include <shlobj.h> |
10 #endif | 10 #endif |
11 | 11 |
12 #include <stdint.h> | 12 #include <stdint.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 | 15 |
16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
17 #include "base/bind.h" | 17 #include "base/bind.h" |
18 #include "base/compiler_specific.h" | 18 #include "base/compiler_specific.h" |
19 #include "base/files/file_path.h" | 19 #include "base/files/file_path.h" |
20 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
21 #include "base/files/scoped_temp_dir.h" | 21 #include "base/files/scoped_temp_dir.h" |
22 #include "base/format_macros.h" | 22 #include "base/format_macros.h" |
23 #include "base/json/json_reader.h" | |
23 #include "base/location.h" | 24 #include "base/location.h" |
24 #include "base/memory/scoped_ptr.h" | 25 #include "base/memory/scoped_ptr.h" |
25 #include "base/memory/weak_ptr.h" | 26 #include "base/memory/weak_ptr.h" |
26 #include "base/message_loop/message_loop.h" | 27 #include "base/message_loop/message_loop.h" |
27 #include "base/path_service.h" | 28 #include "base/path_service.h" |
28 #include "base/run_loop.h" | 29 #include "base/run_loop.h" |
29 #include "base/single_thread_task_runner.h" | 30 #include "base/single_thread_task_runner.h" |
30 #include "base/strings/string_number_conversions.h" | 31 #include "base/strings/string_number_conversions.h" |
31 #include "base/strings/string_piece.h" | 32 #include "base/strings/string_piece.h" |
32 #include "base/strings/string_split.h" | 33 #include "base/strings/string_split.h" |
33 #include "base/strings/string_util.h" | 34 #include "base/strings/string_util.h" |
34 #include "base/strings/stringprintf.h" | 35 #include "base/strings/stringprintf.h" |
35 #include "base/strings/utf_string_conversions.h" | 36 #include "base/strings/utf_string_conversions.h" |
36 #include "base/test/histogram_tester.h" | 37 #include "base/test/histogram_tester.h" |
37 #include "base/thread_task_runner_handle.h" | 38 #include "base/thread_task_runner_handle.h" |
39 #include "base/values.h" | |
38 #include "net/base/chunked_upload_data_stream.h" | 40 #include "net/base/chunked_upload_data_stream.h" |
39 #include "net/base/elements_upload_data_stream.h" | 41 #include "net/base/elements_upload_data_stream.h" |
40 #include "net/base/load_flags.h" | 42 #include "net/base/load_flags.h" |
41 #include "net/base/load_timing_info.h" | 43 #include "net/base/load_timing_info.h" |
42 #include "net/base/load_timing_info_test_util.h" | 44 #include "net/base/load_timing_info_test_util.h" |
43 #include "net/base/net_errors.h" | 45 #include "net/base/net_errors.h" |
44 #include "net/base/net_module.h" | 46 #include "net/base/net_module.h" |
45 #include "net/base/net_util.h" | 47 #include "net/base/net_util.h" |
46 #include "net/base/network_quality.h" | 48 #include "net/base/network_quality.h" |
47 #include "net/base/network_quality_estimator.h" | 49 #include "net/base/network_quality_estimator.h" |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
109 using base::Time; | 111 using base::Time; |
110 using std::string; | 112 using std::string; |
111 | 113 |
112 namespace net { | 114 namespace net { |
113 | 115 |
114 namespace { | 116 namespace { |
115 | 117 |
116 const base::string16 kChrome(ASCIIToUTF16("chrome")); | 118 const base::string16 kChrome(ASCIIToUTF16("chrome")); |
117 const base::string16 kSecret(ASCIIToUTF16("secret")); | 119 const base::string16 kSecret(ASCIIToUTF16("secret")); |
118 const base::string16 kUser(ASCIIToUTF16("user")); | 120 const base::string16 kUser(ASCIIToUTF16("user")); |
121 const char kHPKPReportUri[] = "https://hpkp-report.test"; | |
119 | 122 |
120 const base::FilePath::CharType kTestFilePath[] = | 123 const base::FilePath::CharType kTestFilePath[] = |
121 FILE_PATH_LITERAL("net/data/url_request_unittest"); | 124 FILE_PATH_LITERAL("net/data/url_request_unittest"); |
122 | 125 |
123 #if !defined(DISABLE_FTP_SUPPORT) && !defined(OS_ANDROID) | 126 #if !defined(DISABLE_FTP_SUPPORT) && !defined(OS_ANDROID) |
124 // Test file used in most FTP tests. | 127 // Test file used in most FTP tests. |
125 const char kFtpTestFile[] = "BullRunSpeech.txt"; | 128 const char kFtpTestFile[] = "BullRunSpeech.txt"; |
126 #endif | 129 #endif |
127 | 130 |
128 // Tests load timing information in the case a fresh connection was used, with | 131 // Tests load timing information in the case a fresh connection was used, with |
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
611 TestURLRequestContextWithProxy(const std::string& proxy, | 614 TestURLRequestContextWithProxy(const std::string& proxy, |
612 NetworkDelegate* delegate) | 615 NetworkDelegate* delegate) |
613 : TestURLRequestContext(true) { | 616 : TestURLRequestContext(true) { |
614 context_storage_.set_proxy_service(ProxyService::CreateFixed(proxy)); | 617 context_storage_.set_proxy_service(ProxyService::CreateFixed(proxy)); |
615 set_network_delegate(delegate); | 618 set_network_delegate(delegate); |
616 Init(); | 619 Init(); |
617 } | 620 } |
618 ~TestURLRequestContextWithProxy() override {} | 621 ~TestURLRequestContextWithProxy() override {} |
619 }; | 622 }; |
620 | 623 |
624 // A mock ReportSender that just remembers the latest report | |
625 // URI and report to be sent. | |
626 class MockCertificateReportSender | |
627 : public TransportSecurityState::ReportSender { | |
628 public: | |
629 MockCertificateReportSender() {} | |
630 ~MockCertificateReportSender() override {} | |
631 | |
632 void Send(const GURL& report_uri, const std::string& report) override { | |
633 latest_report_uri_ = report_uri; | |
634 latest_report_ = report; | |
635 } | |
636 | |
637 const GURL& latest_report_uri() { return latest_report_uri_; } | |
638 const std::string& latest_report() { return latest_report_; } | |
639 | |
640 private: | |
641 GURL latest_report_uri_; | |
642 std::string latest_report_; | |
643 }; | |
644 | |
621 } // namespace | 645 } // namespace |
622 | 646 |
623 // Inherit PlatformTest since we require the autorelease pool on Mac OS X. | 647 // Inherit PlatformTest since we require the autorelease pool on Mac OS X. |
624 class URLRequestTest : public PlatformTest { | 648 class URLRequestTest : public PlatformTest { |
625 public: | 649 public: |
626 URLRequestTest() : default_context_(true) { | 650 URLRequestTest() : default_context_(true) { |
627 default_context_.set_network_delegate(&default_network_delegate_); | 651 default_context_.set_network_delegate(&default_network_delegate_); |
628 default_context_.set_net_log(&net_log_); | 652 default_context_.set_net_log(&net_log_); |
629 job_factory_impl_ = new URLRequestJobFactoryImpl(); | 653 job_factory_impl_ = new URLRequestJobFactoryImpl(); |
630 job_factory_.reset(job_factory_impl_); | 654 job_factory_.reset(job_factory_impl_); |
(...skipping 4721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5352 TransportSecurityState* security_state = | 5376 TransportSecurityState* security_state = |
5353 default_context_.transport_security_state(); | 5377 default_context_.transport_security_state(); |
5354 TransportSecurityState::STSState sts_state; | 5378 TransportSecurityState::STSState sts_state; |
5355 EXPECT_FALSE( | 5379 EXPECT_FALSE( |
5356 security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); | 5380 security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); |
5357 } | 5381 } |
5358 | 5382 |
5359 // Android's CertVerifyProc does not (yet) handle pins. Therefore, it will | 5383 // Android's CertVerifyProc does not (yet) handle pins. Therefore, it will |
5360 // reject HPKP headers, and a test setting only HPKP headers will fail (no | 5384 // reject HPKP headers, and a test setting only HPKP headers will fail (no |
5361 // PKPState present because header rejected). | 5385 // PKPState present because header rejected). |
5362 #if defined(OS_ANDROID) | 5386 #if defined(OS_ANDROID) |
davidben
2015/08/05 18:23:51
Maybe for a separate CL, but I'm pretty sure you c
estark
2015/08/06 05:50:07
Ack: filed a bug, crbug.com/517311
| |
5363 #define MAYBE_ProcessPKP DISABLED_ProcessPKP | 5387 #define MAYBE_ProcessPKP DISABLED_ProcessPKP |
5388 #define MAYBE_ProcessPKPAndSendReport DISABLED_ProcessPKPAndSendReport | |
5389 #define MAYBE_ProcessPKPReportOnly DISABLED_ProcessPKPReportOnly | |
5364 #else | 5390 #else |
5365 #define MAYBE_ProcessPKP ProcessPKP | 5391 #define MAYBE_ProcessPKP ProcessPKP |
5366 #endif | 5392 #endif |
5367 | 5393 |
5368 // Tests that enabling HPKP on a domain does not affect the HSTS | 5394 // Tests that enabling HPKP on a domain does not affect the HSTS |
5369 // validity/expiration. | 5395 // validity/expiration. |
5370 TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) { | 5396 TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) { |
5397 GURL report_uri(kHPKPReportUri); | |
5371 SpawnedTestServer::SSLOptions ssl_options( | 5398 SpawnedTestServer::SSLOptions ssl_options( |
5372 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); | 5399 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); |
5373 SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS, | 5400 SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS, |
5374 ssl_options, | 5401 ssl_options, |
5375 base::FilePath(kTestFilePath)); | 5402 base::FilePath(kTestFilePath)); |
5376 ASSERT_TRUE(https_test_server.Start()); | 5403 ASSERT_TRUE(https_test_server.Start()); |
5377 | 5404 |
5378 std::string test_server_hostname = https_test_server.GetURL("").host(); | 5405 std::string test_server_hostname = https_test_server.GetURL("").host(); |
5379 | 5406 |
5380 TestDelegate d; | 5407 TestDelegate d; |
5381 scoped_ptr<URLRequest> request(default_context_.CreateRequest( | 5408 scoped_ptr<URLRequest> request(default_context_.CreateRequest( |
5382 https_test_server.GetURL("files/hpkp-headers.html"), DEFAULT_PRIORITY, | 5409 https_test_server.GetURL("files/hpkp-headers.html"), DEFAULT_PRIORITY, |
5383 &d)); | 5410 &d)); |
5384 request->Start(); | 5411 request->Start(); |
5385 base::RunLoop().Run(); | 5412 base::RunLoop().Run(); |
5386 | 5413 |
5387 TransportSecurityState* security_state = | 5414 TransportSecurityState* security_state = |
5388 default_context_.transport_security_state(); | 5415 default_context_.transport_security_state(); |
5389 TransportSecurityState::STSState sts_state; | 5416 TransportSecurityState::STSState sts_state; |
5390 TransportSecurityState::PKPState pkp_state; | 5417 TransportSecurityState::PKPState pkp_state; |
5391 EXPECT_FALSE( | 5418 EXPECT_FALSE( |
5392 security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); | 5419 security_state->GetDynamicSTSState(test_server_hostname, &sts_state)); |
5393 EXPECT_TRUE( | 5420 EXPECT_TRUE( |
5394 security_state->GetDynamicPKPState(test_server_hostname, &pkp_state)); | 5421 security_state->GetDynamicPKPState(test_server_hostname, &pkp_state)); |
5395 EXPECT_EQ(TransportSecurityState::STSState::MODE_DEFAULT, | 5422 EXPECT_EQ(TransportSecurityState::STSState::MODE_DEFAULT, |
5396 sts_state.upgrade_mode); | 5423 sts_state.upgrade_mode); |
5397 EXPECT_FALSE(sts_state.include_subdomains); | 5424 EXPECT_FALSE(sts_state.include_subdomains); |
5398 EXPECT_FALSE(pkp_state.include_subdomains); | 5425 EXPECT_FALSE(pkp_state.include_subdomains); |
5399 EXPECT_TRUE(pkp_state.HasPublicKeyPins()); | 5426 EXPECT_TRUE(pkp_state.HasPublicKeyPins()); |
5427 EXPECT_EQ(report_uri, pkp_state.report_uri); | |
5400 EXPECT_NE(sts_state.expiry, pkp_state.expiry); | 5428 EXPECT_NE(sts_state.expiry, pkp_state.expiry); |
5401 } | 5429 } |
5402 | 5430 |
5431 // Tests that reports get sent on HPKP violations when a report-uri is set. | |
5432 TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPAndSendReport) { | |
5433 GURL report_uri(kHPKPReportUri); | |
5434 SpawnedTestServer::SSLOptions ssl_options( | |
5435 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); | |
5436 SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS, | |
5437 ssl_options, | |
5438 base::FilePath(kTestFilePath)); | |
5439 | |
5440 ASSERT_TRUE(https_test_server.Start()); | |
5441 | |
5442 std::string test_server_hostname = https_test_server.GetURL("").host(); | |
5443 | |
5444 // Set up a pin for |test_server_hostname|. | |
5445 TransportSecurityState security_state; | |
5446 const base::Time current_time(base::Time::Now()); | |
5447 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | |
5448 HashValueVector hashes; | |
5449 HashValue hash1; | |
5450 HashValue hash2; | |
5451 ASSERT_TRUE(hash1.FromString("sha1/m9lHYJYke9k0GtVZ+bXSQYE8nDI=")); | |
5452 ASSERT_TRUE(hash2.FromString("sha1/o5OZxATDsgmwgcIfIWIneMJ0jkw=")); | |
davidben
2015/08/05 18:23:51
These values aren't significant, right? Maybe do s
estark
2015/08/06 05:50:07
Done.
| |
5453 hashes.push_back(hash1); | |
5454 hashes.push_back(hash2); | |
5455 security_state.AddHPKP(test_server_hostname, expiry, | |
5456 false, /* include subdomains */ | |
5457 hashes, report_uri); | |
5458 | |
5459 MockCertificateReportSender mock_report_sender; | |
5460 security_state.SetReportSender(&mock_report_sender); | |
5461 | |
5462 // Set up a MockCertVerifier to trigger a violation of the previously | |
5463 // set pin. | |
5464 base::FilePath certificate_file = ssl_options.GetCertificateFile(); | |
5465 scoped_refptr<X509Certificate> cert = ImportCertFromFile( | |
5466 GetTestCertsDirectory(), certificate_file.BaseName().value()); | |
5467 ASSERT_TRUE(cert); | |
5468 | |
5469 MockCertVerifier cert_verifier; | |
5470 CertVerifyResult verify_result; | |
5471 verify_result.verified_cert = cert; | |
5472 verify_result.is_issued_by_known_root = true; | |
5473 HashValue hash3; | |
5474 ASSERT_TRUE(hash3.FromString("sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=")); | |
5475 verify_result.public_key_hashes.push_back(hash3); | |
5476 cert_verifier.AddResultForCert(cert.get(), verify_result, OK); | |
5477 | |
5478 TestNetworkDelegate network_delegate; | |
5479 TestURLRequestContext context(true); | |
5480 context.set_transport_security_state(&security_state); | |
5481 context.set_network_delegate(&network_delegate); | |
5482 context.set_cert_verifier(&cert_verifier); | |
5483 context.Init(); | |
5484 | |
5485 // Now send a request to trigger the violation. | |
5486 TestDelegate d; | |
5487 scoped_ptr<URLRequest> violating_request( | |
5488 context.CreateRequest(https_test_server.GetURL("files/hpkp-headers.html"), | |
davidben
2015/08/05 18:23:51
Probably best use simple.html or something, since
estark
2015/08/06 05:50:06
Done.
| |
5489 DEFAULT_PRIORITY, &d)); | |
5490 violating_request->Start(); | |
5491 base::RunLoop().Run(); | |
5492 | |
5493 // Check that a report was sent. | |
5494 EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri()); | |
5495 ASSERT_FALSE(mock_report_sender.latest_report().empty()); | |
5496 scoped_ptr<base::Value> value( | |
5497 base::JSONReader::Read(mock_report_sender.latest_report())); | |
5498 ASSERT_TRUE(value); | |
5499 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); | |
5500 base::DictionaryValue* report_dict; | |
5501 ASSERT_TRUE(value->GetAsDictionary(&report_dict)); | |
5502 std::string report_hostname; | |
5503 EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname)); | |
5504 EXPECT_EQ(test_server_hostname, report_hostname); | |
5505 } | |
5506 | |
5507 // Tests that reports get sent on requests with | |
5508 // Public-Key-Pins-Report-Only headers. | |
5509 TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnly) { | |
davidben
2015/08/05 18:23:51
Perhaps add a test that also asserts there is no r
estark
2015/08/06 05:50:07
Done.
| |
5510 GURL report_uri(kHPKPReportUri); | |
5511 SpawnedTestServer::SSLOptions ssl_options( | |
5512 SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); | |
5513 SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS, | |
5514 ssl_options, | |
5515 base::FilePath(kTestFilePath)); | |
5516 | |
5517 ASSERT_TRUE(https_test_server.Start()); | |
5518 | |
5519 std::string test_server_hostname = https_test_server.GetURL("").host(); | |
5520 | |
5521 TransportSecurityState security_state; | |
5522 MockCertificateReportSender mock_report_sender; | |
5523 security_state.SetReportSender(&mock_report_sender); | |
5524 | |
5525 // Set up a MockCertVerifier to violate the pin in the Report-Only | |
5526 // header. | |
5527 base::FilePath certificate_file = ssl_options.GetCertificateFile(); | |
5528 scoped_refptr<X509Certificate> cert = ImportCertFromFile( | |
5529 GetTestCertsDirectory(), certificate_file.BaseName().value()); | |
5530 ASSERT_TRUE(cert); | |
5531 | |
5532 MockCertVerifier cert_verifier; | |
5533 CertVerifyResult verify_result; | |
5534 verify_result.verified_cert = cert; | |
5535 verify_result.is_issued_by_known_root = true; | |
5536 HashValue hash; | |
5537 ASSERT_TRUE(hash.FromString("sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=")); | |
davidben
2015/08/05 18:23:51
Ditto about making fake values obvious.
estark
2015/08/06 05:50:06
Done.
| |
5538 verify_result.public_key_hashes.push_back(hash); | |
5539 cert_verifier.AddResultForCert(cert.get(), verify_result, OK); | |
5540 | |
5541 TestNetworkDelegate network_delegate; | |
5542 TestURLRequestContext context(true); | |
5543 context.set_transport_security_state(&security_state); | |
5544 context.set_network_delegate(&network_delegate); | |
5545 context.set_cert_verifier(&cert_verifier); | |
5546 context.Init(); | |
5547 | |
5548 // Now send a request to trigger the violation. | |
5549 TestDelegate d; | |
5550 scoped_ptr<URLRequest> violating_request(context.CreateRequest( | |
5551 https_test_server.GetURL("files/hpkp-headers-report-only.html"), | |
5552 DEFAULT_PRIORITY, &d)); | |
5553 violating_request->Start(); | |
5554 base::RunLoop().Run(); | |
5555 | |
5556 // Check that a report was sent. | |
5557 EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri()); | |
5558 ASSERT_FALSE(mock_report_sender.latest_report().empty()); | |
5559 scoped_ptr<base::Value> value( | |
5560 base::JSONReader::Read(mock_report_sender.latest_report())); | |
5561 ASSERT_TRUE(value); | |
5562 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); | |
5563 base::DictionaryValue* report_dict; | |
5564 ASSERT_TRUE(value->GetAsDictionary(&report_dict)); | |
5565 std::string report_hostname; | |
5566 EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname)); | |
5567 EXPECT_EQ(test_server_hostname, report_hostname); | |
5568 } | |
5569 | |
5403 TEST_F(URLRequestTestHTTP, PKPNotProcessedOnIP) { | 5570 TEST_F(URLRequestTestHTTP, PKPNotProcessedOnIP) { |
5404 SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS, | 5571 SpawnedTestServer https_test_server(SpawnedTestServer::TYPE_HTTPS, |
5405 SpawnedTestServer::SSLOptions(), | 5572 SpawnedTestServer::SSLOptions(), |
5406 base::FilePath(kTestFilePath)); | 5573 base::FilePath(kTestFilePath)); |
5407 ASSERT_TRUE(https_test_server.Start()); | 5574 ASSERT_TRUE(https_test_server.Start()); |
5408 // Make sure this test fails if the test server is changed to not | 5575 // Make sure this test fails if the test server is changed to not |
5409 // listen on an IP by default. | 5576 // listen on an IP by default. |
5410 ASSERT_TRUE(https_test_server.GetURL("").HostIsIPAddress()); | 5577 ASSERT_TRUE(https_test_server.GetURL("").HostIsIPAddress()); |
5411 std::string test_server_hostname = https_test_server.GetURL("").host(); | 5578 std::string test_server_hostname = https_test_server.GetURL("").host(); |
5412 | 5579 |
(...skipping 3810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9223 | 9390 |
9224 req->Start(); | 9391 req->Start(); |
9225 req->Cancel(); | 9392 req->Cancel(); |
9226 job->DetachRequest(); | 9393 job->DetachRequest(); |
9227 base::RunLoop().RunUntilIdle(); | 9394 base::RunLoop().RunUntilIdle(); |
9228 EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); | 9395 EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status()); |
9229 EXPECT_EQ(0, d.received_redirect_count()); | 9396 EXPECT_EQ(0, d.received_redirect_count()); |
9230 } | 9397 } |
9231 | 9398 |
9232 } // namespace net | 9399 } // namespace net |
OLD | NEW |