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
3 // found in the LICENSE file.
5 #import "ios/web/net/clients/crw_csp_network_client.h"
7 #import <Foundation/Foundation.h>
9 #include "base/mac/scoped_nsobject.h"
10 #import "ios/net/clients/crn_forwarding_network_client.h"
11 #import "ios/web/net/crw_url_verifying_protocol_handler.h"
12 #include "ios/web/public/test/test_web_thread_bundle.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/gtest_mac.h"
16 @interface CRWCspMockClient : CRNForwardingNetworkClient
19 @implementation CRWCspMockClient {
20 base::scoped_nsobject<NSURLResponse> _response;
23 - (void)didReceiveResponse:(NSURLResponse*)response {
24 _response.reset([response retain]);
27 - (NSURLResponse*)response {
33 class CRWCspNetworkClientTest : public testing::Test {
35 CRWCspNetworkClientTest() {
36 mock_client_.reset([[CRWCspMockClient alloc] init]);
37 csp_client_.reset([[CRWCspNetworkClient alloc] init]);
38 [csp_client_ setUnderlyingClient:mock_client_];
41 web::TestWebThreadBundle thread_bundle_;
42 base::scoped_nsobject<CRWCspNetworkClient> csp_client_;
43 base::scoped_nsobject<CRWCspMockClient> mock_client_;
46 TEST_F(CRWCspNetworkClientTest, FixCspHeaders) {
47 base::scoped_nsobject<NSDictionary> input_headers([@{
49 @"coNteNt-seCuRity-POLicy" : @"coNNect-sRc foo.com; script-src 'self'",
50 @"X-WebKit-CSP" : @"frame-src 'self'"
53 base::scoped_nsobject<NSHTTPURLResponse> input_response(
54 [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://foo"]
56 HTTPVersion:@"HTTP/1.1"
57 headerFields:input_headers]);
59 [csp_client_ didReceiveResponse:input_response];
61 [[mock_client_ response] isKindOfClass:[NSHTTPURLResponse class]]);
62 base::scoped_nsobject<NSDictionary> output_headers(
63 [[static_cast<NSHTTPURLResponse*>([mock_client_ response])
64 allHeaderFields] retain]);
66 // Check that unrelated headers are copied.
67 EXPECT_NSEQ(@"Bar", [output_headers objectForKey:@"Foo"]);
69 base::scoped_nsobject<NSString> csp_header(
70 [[output_headers objectForKey:@"coNteNt-seCuRity-POLicy"] retain]);
72 EXPECT_TRUE(csp_header.get());
74 // frame-src is not created because there were no frame-src and no
76 // 'self' and |kURLForVerification| are prepended to the connect-src value.
77 NSString* expected_csp_header = [NSString stringWithFormat:
78 @"coNNect-sRc 'self' %s foo.com; " @"script-src 'self'",
79 web::kURLForVerification];
80 EXPECT_NSEQ(expected_csp_header, csp_header);
82 // X-WebKit-CSP is handled as well.
83 // crwebinvoke: crwebinvokeimmediate: and crwebnull: are prepended to the
84 // existing frame-src value.
85 // connect-src is not created because there were no connect-src and no
87 csp_header.reset([[output_headers objectForKey:@"X-WebKit-CSP"] retain]);
88 EXPECT_NSEQ(@"frame-src crwebinvoke: crwebinvokeimmediate: crwebnull: 'self'",
92 TEST_F(CRWCspNetworkClientTest, FixCspHeadersWithDefault) {
93 base::scoped_nsobject<NSDictionary> input_headers([@{
94 @"Content-Security-Policy" : @"default-src foo.com; connect-src *"
97 base::scoped_nsobject<NSHTTPURLResponse> input_response(
98 [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://foo"]
100 HTTPVersion:@"HTTP/1.1"
101 headerFields:input_headers]);
103 [csp_client_ didReceiveResponse:input_response];
105 [[mock_client_ response] isKindOfClass:[NSHTTPURLResponse class]]);
106 base::scoped_nsobject<NSDictionary> output_headers(
107 [[static_cast<NSHTTPURLResponse*>([mock_client_ response])
108 allHeaderFields] retain]);
110 base::scoped_nsobject<NSString> csp_header(
111 [[output_headers objectForKey:@"Content-Security-Policy"] retain]);
113 EXPECT_TRUE(csp_header.get());
115 // crwebinvoke: crwebinvokeimmediate: and crwebnull: are prepended to the
116 // existing default-src value because there was no frame-src.
117 // 'self' and |kURLForVerification| are prepended to the connect-src value.
118 NSString* expected_csp_header = [NSString stringWithFormat:
119 @"default-src crwebinvoke: crwebinvokeimmediate: crwebnull: foo.com; "
120 @"connect-src 'self' %s *", web::kURLForVerification];
121 EXPECT_NSEQ(expected_csp_header, csp_header);
124 TEST_F(CRWCspNetworkClientTest, NonHTTPResponse) {
125 base::scoped_nsobject<NSURLResponse> response([[NSURLResponse alloc] init]);
126 [csp_client_ didReceiveResponse:response];
127 // The client is a pass-through, compare the pointers.
128 EXPECT_EQ(response, [mock_client_ response]);