Avi Drissman | ea1be23 | 2022-09-14 23:29:06 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
dcheng | 5e05b43 | 2016-01-14 04:41:45 | [diff] [blame] | 5 | #import "ios/net/protocol_handler_util.h" |
| 6 | |
Sylvain Defresne | a383a75 | 2025-01-22 15:23:20 | [diff] [blame] | 7 | #import <memory> |
| 8 | #import <utility> |
dcheng | 5e05b43 | 2016-01-14 04:41:45 | [diff] [blame] | 9 | |
Sylvain Defresne | a383a75 | 2025-01-22 15:23:20 | [diff] [blame] | 10 | #import "base/memory/ptr_util.h" |
| 11 | #import "base/run_loop.h" |
| 12 | #import "base/strings/sys_string_conversions.h" |
| 13 | #import "base/test/task_environment.h" |
Tiago Vignatti | dd0987b | 2024-01-25 14:56:46 | [diff] [blame] | 14 | #import "net/base/apple/url_conversions.h" |
Sylvain Defresne | a383a75 | 2025-01-22 15:23:20 | [diff] [blame] | 15 | #import "net/base/elements_upload_data_stream.h" |
| 16 | #import "net/base/upload_bytes_element_reader.h" |
| 17 | #import "net/http/http_request_headers.h" |
| 18 | #import "net/http/http_response_headers.h" |
| 19 | #import "net/url_request/url_request.h" |
| 20 | #import "net/url_request/url_request_context.h" |
| 21 | #import "net/url_request/url_request_context_builder.h" |
| 22 | #import "net/url_request/url_request_filter.h" |
| 23 | #import "net/url_request/url_request_interceptor.h" |
| 24 | #import "net/url_request/url_request_job.h" |
| 25 | #import "net/url_request/url_request_test_util.h" |
| 26 | #import "testing/gtest/include/gtest/gtest.h" |
| 27 | #import "testing/gtest_mac.h" |
| 28 | #import "testing/platform_test.h" |
| 29 | #import "url/gurl.h" |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 30 | |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 31 | namespace net { |
| 32 | namespace { |
| 33 | |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 34 | const char* kTextHtml = "text/html"; |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 35 | |
| 36 | class HeadersURLRequestJob : public URLRequestJob { |
| 37 | public: |
Matt Menke | fd97885 | 2020-09-15 16:00:57 | [diff] [blame] | 38 | explicit HeadersURLRequestJob(URLRequest* request) : URLRequestJob(request) {} |
| 39 | |
| 40 | ~HeadersURLRequestJob() override {} |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 41 | |
| 42 | void Start() override { |
| 43 | // Fills response headers and returns immediately. |
| 44 | NotifyHeadersComplete(); |
| 45 | } |
| 46 | |
| 47 | bool GetMimeType(std::string* mime_type) const override { |
| 48 | *mime_type = GetContentTypeValue(); |
| 49 | return true; |
| 50 | } |
| 51 | |
| 52 | void GetResponseInfo(HttpResponseInfo* info) override { |
| 53 | // This is called by NotifyHeadersComplete(). |
| 54 | std::string header_string("HTTP/1.0 200 OK"); |
| 55 | header_string.push_back('\0'); |
| 56 | header_string += std::string("Cache-Control: max-age=600"); |
| 57 | header_string.push_back('\0'); |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 58 | if (request()->url().path_piece() == "/multiplecontenttype") { |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 59 | header_string += std::string( |
| 60 | "coNteNt-tYPe: text/plain; charset=iso-8859-4, image/png"); |
| 61 | header_string.push_back('\0'); |
| 62 | } |
| 63 | header_string += std::string("Content-Type: ") + GetContentTypeValue(); |
| 64 | header_string.push_back('\0'); |
| 65 | header_string += std::string("Foo: A"); |
| 66 | header_string.push_back('\0'); |
| 67 | header_string += std::string("Bar: B"); |
| 68 | header_string.push_back('\0'); |
| 69 | header_string += std::string("Baz: C"); |
| 70 | header_string.push_back('\0'); |
| 71 | header_string += std::string("Foo: D"); |
| 72 | header_string.push_back('\0'); |
| 73 | header_string += std::string("Foo: E"); |
| 74 | header_string.push_back('\0'); |
| 75 | header_string += std::string("Bar: F"); |
| 76 | header_string.push_back('\0'); |
| 77 | info->headers = new HttpResponseHeaders(header_string); |
| 78 | } |
| 79 | |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 80 | protected: |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 81 | std::string GetContentTypeValue() const { |
Sylvain Defresne | cc2980bd | 2025-01-22 22:39:04 | [diff] [blame] | 82 | if (request()->url().path_piece() == "/badcontenttype") { |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 83 | return "\xff"; |
Sylvain Defresne | cc2980bd | 2025-01-22 22:39:04 | [diff] [blame] | 84 | } |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 85 | return kTextHtml; |
| 86 | } |
| 87 | }; |
| 88 | |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 89 | class NetURLRequestInterceptor : public URLRequestInterceptor { |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 90 | public: |
Matt Menke | fd97885 | 2020-09-15 16:00:57 | [diff] [blame] | 91 | std::unique_ptr<URLRequestJob> MaybeInterceptRequest( |
| 92 | URLRequest* request) const override { |
| 93 | return std::make_unique<HeadersURLRequestJob>(request); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 94 | } |
| 95 | }; |
| 96 | |
Sylvain Defresne | 64778080 | 2017-10-09 14:59:27 | [diff] [blame] | 97 | class ProtocolHandlerUtilTest : public PlatformTest, |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 98 | public URLRequest::Delegate { |
| 99 | public: |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 100 | ProtocolHandlerUtilTest() |
| 101 | : task_environment_(base::test::TaskEnvironment::MainThreadType::IO), |
Yutaka Hirano | d81ac3f | 2022-03-23 15:08:34 | [diff] [blame] | 102 | request_context_(net::CreateTestURLRequestContextBuilder()->Build()) { |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 103 | URLRequestFilter::GetInstance()->AddHostnameInterceptor( |
| 104 | "http", "foo.test", std::make_unique<NetURLRequestInterceptor>()); |
| 105 | } |
| 106 | |
| 107 | ~ProtocolHandlerUtilTest() override { |
| 108 | URLRequestFilter::GetInstance()->ClearHandlers(); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 109 | } |
| 110 | |
maksim.sisov | 5af9098 | 2016-09-05 11:26:28 | [diff] [blame] | 111 | void OnResponseStarted(URLRequest* request, int net_error) override {} |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 112 | void OnReadCompleted(URLRequest* request, int bytes_read) override {} |
| 113 | |
| 114 | protected: |
Gabriel Charette | 7bde04d | 2019-09-05 12:57:30 | [diff] [blame] | 115 | base::test::SingleThreadTaskEnvironment task_environment_; |
dcheng | 942f39d7 | 2016-04-07 21:11:23 | [diff] [blame] | 116 | std::unique_ptr<URLRequestContext> request_context_; |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 117 | }; |
| 118 | |
| 119 | } // namespace |
| 120 | |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 121 | TEST_F(ProtocolHandlerUtilTest, GetResponseHttpTest) { |
| 122 | // Create a request. |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 123 | GURL url("http://foo.test/"); |
dcheng | 942f39d7 | 2016-04-07 21:11:23 | [diff] [blame] | 124 | std::unique_ptr<URLRequest> request( |
davidben | 151423e | 2015-03-23 18:48:36 | [diff] [blame] | 125 | request_context_->CreateRequest(url, DEFAULT_PRIORITY, this)); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 126 | request->Start(); |
| 127 | // Create a response from the request. |
| 128 | NSURLResponse* response = GetNSURLResponseForRequest(request.get()); |
| 129 | EXPECT_NSEQ([NSString stringWithUTF8String:kTextHtml], [response MIMEType]); |
| 130 | ASSERT_TRUE([response isKindOfClass:[NSHTTPURLResponse class]]); |
| 131 | NSHTTPURLResponse* http_response = (NSHTTPURLResponse*)response; |
| 132 | NSDictionary* headers = [http_response allHeaderFields]; |
| 133 | // Check the headers, duplicates must be appended. |
| 134 | EXPECT_EQ(5u, [headers count]); |
| 135 | NSString* foo_header = [headers objectForKey:@"Foo"]; |
| 136 | EXPECT_NSEQ(@"A,D,E", foo_header); |
| 137 | NSString* bar_header = [headers objectForKey:@"Bar"]; |
| 138 | EXPECT_NSEQ(@"B,F", bar_header); |
| 139 | NSString* baz_header = [headers objectForKey:@"Baz"]; |
| 140 | EXPECT_NSEQ(@"C", baz_header); |
| 141 | NSString* cache_header = [headers objectForKey:@"Cache-Control"]; |
| 142 | EXPECT_NSEQ(@"no-store", cache_header); // Cache-Control is overridden. |
| 143 | // Check the status. |
| 144 | EXPECT_EQ(request->GetResponseCode(), [http_response statusCode]); |
| 145 | } |
| 146 | |
| 147 | TEST_F(ProtocolHandlerUtilTest, BadHttpContentType) { |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 148 | // Create a request using the magic path that triggers a garbage |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 149 | // content-type in the test framework. |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 150 | GURL url("http://foo.test/badcontenttype"); |
dcheng | 942f39d7 | 2016-04-07 21:11:23 | [diff] [blame] | 151 | std::unique_ptr<URLRequest> request( |
davidben | 151423e | 2015-03-23 18:48:36 | [diff] [blame] | 152 | request_context_->CreateRequest(url, DEFAULT_PRIORITY, this)); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 153 | request->Start(); |
| 154 | // Create a response from the request. |
| 155 | @try { |
| 156 | GetNSURLResponseForRequest(request.get()); |
Sylvain Defresne | cc2980bd | 2025-01-22 22:39:04 | [diff] [blame] | 157 | } @catch (id exception) { |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 158 | FAIL() << "Exception while creating response"; |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | TEST_F(ProtocolHandlerUtilTest, MultipleHttpContentType) { |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 163 | // Create a request using the magic path that triggers a garbage |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 164 | // content-type in the test framework. |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 165 | GURL url("http://foo.test/multiplecontenttype"); |
dcheng | 942f39d7 | 2016-04-07 21:11:23 | [diff] [blame] | 166 | std::unique_ptr<URLRequest> request( |
davidben | 151423e | 2015-03-23 18:48:36 | [diff] [blame] | 167 | request_context_->CreateRequest(url, DEFAULT_PRIORITY, this)); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 168 | request->Start(); |
| 169 | // Create a response from the request. |
| 170 | NSURLResponse* response = GetNSURLResponseForRequest(request.get()); |
| 171 | EXPECT_NSEQ(@"text/plain", [response MIMEType]); |
| 172 | EXPECT_NSEQ(@"iso-8859-4", [response textEncodingName]); |
| 173 | NSHTTPURLResponse* http_response = (NSHTTPURLResponse*)response; |
| 174 | NSDictionary* headers = [http_response allHeaderFields]; |
| 175 | NSString* content_type_header = [headers objectForKey:@"Content-Type"]; |
| 176 | EXPECT_NSEQ(@"text/plain; charset=iso-8859-4", content_type_header); |
| 177 | } |
| 178 | |
| 179 | TEST_F(ProtocolHandlerUtilTest, CopyHttpHeaders) { |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 180 | GURL url("http://foo.test/"); |
marq | 8e82dba | 2017-06-19 16:09:20 | [diff] [blame] | 181 | NSMutableURLRequest* in_request = |
| 182 | [[NSMutableURLRequest alloc] initWithURL:NSURLWithGURL(url)]; |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 183 | [in_request setAllHTTPHeaderFields:@{ |
Sylvain Defresne | cc2980bd | 2025-01-22 22:39:04 | [diff] [blame] | 184 | @"Referer" : @"referrer", |
| 185 | @"User-Agent" : @"secret", |
| 186 | @"Accept" : @"money/cash", |
| 187 | @"Foo" : @"bar", |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 188 | }]; |
dcheng | 942f39d7 | 2016-04-07 21:11:23 | [diff] [blame] | 189 | std::unique_ptr<URLRequest> out_request( |
davidben | 151423e | 2015-03-23 18:48:36 | [diff] [blame] | 190 | request_context_->CreateRequest(url, DEFAULT_PRIORITY, nullptr)); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 191 | CopyHttpHeaders(in_request, out_request.get()); |
| 192 | |
| 193 | EXPECT_EQ("referrer", out_request->referrer()); |
| 194 | const HttpRequestHeaders& headers = out_request->extra_request_headers(); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 195 | EXPECT_FALSE(headers.HasHeader("Content-Type")); // Only in POST requests. |
Chris Fredrickson | 31c9e54 | 2024-08-14 15:47:03 | [diff] [blame] | 196 | EXPECT_EQ("money/cash", headers.GetHeader("Accept")); |
| 197 | EXPECT_EQ("bar", headers.GetHeader("Foo")); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | TEST_F(ProtocolHandlerUtilTest, AddMissingHeaders) { |
Matt Menke | 7ca3f7c | 2020-09-08 17:06:58 | [diff] [blame] | 201 | GURL url("http://foo.test/"); |
marq | 8e82dba | 2017-06-19 16:09:20 | [diff] [blame] | 202 | NSMutableURLRequest* in_request = |
| 203 | [[NSMutableURLRequest alloc] initWithURL:NSURLWithGURL(url)]; |
dcheng | 942f39d7 | 2016-04-07 21:11:23 | [diff] [blame] | 204 | std::unique_ptr<URLRequest> out_request( |
davidben | 151423e | 2015-03-23 18:48:36 | [diff] [blame] | 205 | request_context_->CreateRequest(url, DEFAULT_PRIORITY, nullptr)); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 206 | out_request->set_method("POST"); |
kelsen liu | 0562217 | 2024-08-31 03:05:34 | [diff] [blame] | 207 | auto reader = std::make_unique<UploadBytesElementReader>( |
| 208 | base::byte_span_from_cstring("")); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 209 | out_request->set_upload( |
Andrew Williams | 3fac258 | 2024-09-18 18:37:39 | [diff] [blame] | 210 | ElementsUploadDataStream::CreateWithReader(std::move(reader))); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 211 | CopyHttpHeaders(in_request, out_request.get()); |
| 212 | |
| 213 | // Some headers are added by default if missing. |
| 214 | const HttpRequestHeaders& headers = out_request->extra_request_headers(); |
Chris Fredrickson | 31c9e54 | 2024-08-14 15:47:03 | [diff] [blame] | 215 | EXPECT_EQ("*/*", headers.GetHeader("Accept")); |
| 216 | EXPECT_EQ("application/x-www-form-urlencoded", |
| 217 | headers.GetHeader("Content-Type")); |
droger | 476922e0 | 2015-03-10 17:17:52 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | } // namespace net |