Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(525)

Unified Diff: ios/net/protocol_handler_util.mm

Issue 994823004: [iOS] Upstream //ios/net (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/net/protocol_handler_util.mm
diff --git a/ios/net/protocol_handler_util.mm b/ios/net/protocol_handler_util.mm
new file mode 100644
index 0000000000000000000000000000000000000000..d1878c54bbc3dc66ba324ed4335198c784b44b5d
--- /dev/null
+++ b/ios/net/protocol_handler_util.mm
@@ -0,0 +1,213 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/net/protocol_handler_util.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/i18n/icu_encoding_detection.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/time/time.h"
+#include "ios/net/crn_http_url_response.h"
+#import "net/base/mac/url_conversions.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_version.h"
+#include "net/url_request/url_request.h"
+#include "url/gurl.h"
+
+namespace {
+
+// "Content-Type" HTTP header.
+NSString* const kContentType = @"Content-Type";
+
+} // namespace
+
+namespace net {
+
+NSError* GetIOSError(NSInteger ns_error_code,
+ int net_error_code,
+ NSString* url,
+ const base::Time& creation_time) {
+ // The error we pass through has the domain NSURLErrorDomain, an IOS error
+ // code, and a userInfo dictionary in which we smuggle more detailed info
+ // about the error from our network stack. This dictionary contains the
+ // failing URL, and a nested error in which we deposit the original error code
+ // passed in from the Chrome network stack.
+ // The nested error has domain:kErrorDomain, code:|original_error_code|, and
+ // userInfo:nil; this NSError is keyed in the dictionary with
+ // NSUnderlyingErrorKey.
+ NSDate* creation_date = [NSDate
+ dateWithTimeIntervalSinceReferenceDate:creation_time.ToCFAbsoluteTime()];
+ DCHECK(creation_date);
+ NSError* underlying_error =
+ [NSError errorWithDomain:base::SysUTF8ToNSString(kErrorDomain)
+ code:net_error_code
+ userInfo:nil];
+ DCHECK(url);
+ NSDictionary* dictionary = @{
+ NSURLErrorFailingURLStringErrorKey : url,
+ @"CreationDate" : creation_date,
+ NSUnderlyingErrorKey : underlying_error,
+ };
+ return [NSError errorWithDomain:NSURLErrorDomain
+ code:ns_error_code
+ userInfo:dictionary];
+}
+
+NSURLResponse* GetNSURLResponseForRequest(URLRequest* request) {
+ NSURL* url = NSURLWithGURL(request->url());
+ DCHECK(url);
+
+ // The default iOS stack returns a NSURLResponse when the request has a data
+ // scheme, and a NSHTTPURLResponse otherwise.
+ if (request->url().SchemeIs("data")) {
+ std::string mt;
+ request->GetMimeType(&mt);
+ NSString* mime_type = base::SysUTF8ToNSString(mt);
+ DCHECK(mime_type);
+ std::string cs;
+ request->GetCharset(&cs);
+ NSString* charset = base::SysUTF8ToNSString(cs);
+ DCHECK(charset);
+ // The default iOS stack computes the length of the decoded string. If we
+ // wanted to do that we would have to decode the string now. However, using
+ // the unknown length (-1) seems to be working.
+ return [[[NSURLResponse alloc] initWithURL:url
+ MIMEType:mime_type
+ expectedContentLength:-1
+ textEncodingName:charset] autorelease];
+ } else {
+ // Iterate over all the headers and copy them.
+ bool has_content_type_header = false;
+ NSMutableDictionary* header_fields = [NSMutableDictionary dictionary];
+ HttpResponseHeaders* headers = request->response_headers();
+ if (headers != nullptr) {
+ void* iter = nullptr;
+ std::string name, value;
+ while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ NSString* key = base::SysUTF8ToNSString(name);
+ if (!key) {
+ DLOG(ERROR) << "Header name is not in UTF8: " << name;
+ // Skip the invalid header.
+ continue;
+ }
+ // Do not copy "Cache-Control" headers as we provide our own controls.
+ if ([key caseInsensitiveCompare:@"cache-control"] == NSOrderedSame)
+ continue;
+ if ([key caseInsensitiveCompare:kContentType] == NSOrderedSame) {
+ key = kContentType;
+ has_content_type_header = true;
+ }
+
+ // Handle bad encoding.
+ NSString* v = base::SysUTF8ToNSString(value);
+ if (!v) {
+ DLOG(ERROR) << "Header \"" << name << "\" is not in UTF8: " << value;
+ // Infer the encoding, or skip the header if it's not possible.
+ std::string encoding;
+ if (!base::DetectEncoding(value, &encoding))
+ continue;
+ std::string value_utf8;
+ if (!base::ConvertToUtf8AndNormalize(value, encoding, &value_utf8))
+ continue;
+ v = base::SysUTF8ToNSString(value_utf8);
+ DCHECK(v);
+ }
+
+ // Duplicate keys are appended using a comma separator (RFC 2616).
+ NSMutableString* existing = [header_fields objectForKey:key];
+ if (existing) {
+ [existing appendFormat:@",%@", v];
+ } else {
+ [header_fields setObject:[NSMutableString stringWithString:v]
+ forKey:key];
+ }
+ }
+ }
+
+ // WebUI does not define a "Content-Type" header. Use the MIME type instead.
+ if (!has_content_type_header) {
+ std::string mime_type = "";
+ request->GetMimeType(&mime_type);
+ NSString* type = base::SysUTF8ToNSString(mime_type);
+ if ([type length])
+ [header_fields setObject:type forKey:kContentType];
+ }
+ NSString* content_type = [header_fields objectForKey:kContentType];
+ if (content_type) {
+ NSRange range = [content_type rangeOfString:@","];
+ // If there are several "Content-Type" headers, keep only the first one.
+ if (range.location != NSNotFound) {
+ [header_fields setObject:[content_type substringToIndex:range.location]
+ forKey:kContentType];
+ }
+ }
+
+ // Use a "no-store" cache control to ensure that the response is not cached
+ // by the system. See b/7045043.
+ [header_fields setObject:@"no-store" forKey:@"Cache-Control"];
+
+ // Parse the HTTP version.
+ NSString* version_string = @"HTTP/1.1";
+ if (headers) {
+ const HttpVersion& http_version = headers->GetHttpVersion();
+ version_string = [NSString stringWithFormat:@"HTTP/%hu.%hu",
+ http_version.major_value(),
+ http_version.minor_value()];
+ }
+
+ return [[[CRNHTTPURLResponse alloc] initWithURL:url
+ statusCode:request->GetResponseCode()
+ HTTPVersion:version_string
+ headerFields:header_fields] autorelease];
+ }
+}
+
+void CopyHttpHeaders(NSURLRequest* in_request, URLRequest* out_request) {
+ DCHECK(out_request->extra_request_headers().IsEmpty());
+ NSDictionary* headers = [in_request allHTTPHeaderFields];
+ HttpRequestHeaders net_headers;
+ NSString* key;
+ for (key in headers) {
+ if ([key isEqualToString:@"Referer"]) {
+ // The referrer must be set through the set_referrer method rather than as
+ // a header.
+ out_request->SetReferrer(
+ base::SysNSStringToUTF8([headers objectForKey:key]));
+ // If the referrer is explicitly set, we don't want the network stack to
+ // strip it.
+ out_request->set_referrer_policy(URLRequest::NEVER_CLEAR_REFERRER);
+ continue;
+ }
+ if (![key isEqualToString:@"User-Agent"]) {
+ // The user agent string is added by the network stack, and might be
+ // different from the one provided by UIWebView. Do not copy it.
+ NSString* value = [headers objectForKey:key];
+ net_headers.SetHeader(base::SysNSStringToUTF8(key),
+ base::SysNSStringToUTF8(value));
+ }
+ }
+ // Set default values for some missing headers.
+ // The "Accept" header is defined by Webkit on the desktop version.
+ net_headers.SetHeaderIfMissing("Accept", "*/*");
+ // The custom NSURLProtocol example from Apple adds a default "Content-Type"
+ // header for non-empty POST requests. This suggests that this header can be
+ // missing, and Chrome network stack does not add it by itself.
+ if (out_request->has_upload() && out_request->method() == "POST") {
+ DLOG_IF(WARNING, !net_headers.HasHeader(HttpRequestHeaders::kContentType))
+ << "Missing \"Content-Type\" header in POST request.";
+ net_headers.SetHeaderIfMissing(HttpRequestHeaders::kContentType,
+ "application/x-www-form-urlencoded");
+ }
+ out_request->SetExtraRequestHeaders(net_headers);
+}
+
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698