Index: util/net/http_transport_mac.mm |
diff --git a/util/net/http_transport_mac.mm b/util/net/http_transport_mac.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a56499a60b6a3ca8e1fd1dbe19e057e522814bb8 |
--- /dev/null |
+++ b/util/net/http_transport_mac.mm |
@@ -0,0 +1,192 @@ |
+// Copyright 2014 The Crashpad Authors. All rights reserved. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+ |
+#include "util/net/http_transport.h" |
+ |
+#import <Foundation/Foundation.h> |
+ |
+#include "base/mac/foundation_util.h" |
+#import "base/mac/scoped_nsobject.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "util/net/http_body.h" |
+ |
+@interface CrashpadHTTPBodyStreamTransport : NSInputStream { |
+ @private |
+ NSStreamStatus streamStatus_; |
+ id<NSStreamDelegate> delegate_; |
+ crashpad::HTTPBodyStream* bodyStream_; // weak |
+} |
+- (instancetype)initWithBodyStream:(crashpad::HTTPBodyStream*)bodyStream; |
+@end |
+ |
+@implementation CrashpadHTTPBodyStreamTransport |
+ |
+- (instancetype)initWithBodyStream:(crashpad::HTTPBodyStream*)bodyStream { |
+ if ((self = [super init])) { |
+ streamStatus_ = NSStreamStatusNotOpen; |
+ bodyStream_ = bodyStream; |
+ } |
+ return self; |
+} |
+ |
+// NSInputStream: |
+ |
+- (BOOL)hasBytesAvailable { |
+ // Per Apple's documentation: "May also return YES if a read must be attempted |
+ // in order to determine the availability of bytes." |
+ switch (streamStatus_) { |
+ case NSStreamStatusAtEnd: |
+ case NSStreamStatusClosed: |
+ case NSStreamStatusError: |
+ return NO; |
+ default: |
+ return YES; |
+ } |
+} |
+ |
+- (NSInteger)read:(uint8_t*)buffer maxLength:(NSUInteger)maxLen { |
+ streamStatus_ = NSStreamStatusReading; |
+ |
+ NSInteger rv = bodyStream_->GetBytesBuffer(buffer, maxLen); |
+ |
+ if (rv == 0) |
+ streamStatus_ = NSStreamStatusAtEnd; |
+ else if (rv < 0) |
+ streamStatus_ = NSStreamStatusError; |
+ else |
+ streamStatus_ = NSStreamStatusOpen; |
+ |
+ return rv; |
+} |
+ |
+- (BOOL)getBuffer:(uint8_t**)buffer length:(NSUInteger*)length { |
+ return NO; |
+} |
+ |
+// NSStream: |
+ |
+- (void)scheduleInRunLoop:(NSRunLoop*)runLoop |
+ forMode:(NSString*)mode { |
+} |
+ |
+- (void)removeFromRunLoop:(NSRunLoop*)runLoop |
+ forMode:(NSString*)mode { |
+} |
+ |
+- (void)open { |
+ streamStatus_ = NSStreamStatusOpen; |
+} |
+ |
+- (void)close { |
+ streamStatus_ = NSStreamStatusClosed; |
+} |
+ |
+- (NSStreamStatus)streamStatus { |
+ return streamStatus_; |
+} |
+ |
+- (id<NSStreamDelegate>)delegate { |
+ return delegate_; |
+} |
+ |
+- (void)setDelegate:(id)delegate { |
+ delegate_ = delegate; |
+} |
+ |
+@end |
+ |
+namespace crashpad { |
+ |
+namespace { |
+ |
+class HTTPTransportMac final : public HTTPTransport { |
+ public: |
+ HTTPTransportMac(); |
+ ~HTTPTransportMac() override; |
+ |
+ bool ExecuteSynchronously() override; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(HTTPTransportMac); |
+}; |
+ |
+HTTPTransportMac::HTTPTransportMac() : HTTPTransport() { |
+} |
+ |
+HTTPTransportMac::~HTTPTransportMac() { |
+} |
+ |
+bool HTTPTransportMac::ExecuteSynchronously() { |
+ DCHECK(body_stream()); |
+ |
+ @autoreleasepool { |
+ NSString* url_ns_string = base::SysUTF8ToNSString(url()); |
+ NSURL* url = [NSURL URLWithString:url_ns_string]; |
+ NSMutableURLRequest* request = |
+ [NSMutableURLRequest requestWithURL:url |
+ cachePolicy:NSURLRequestUseProtocolCachePolicy |
+ timeoutInterval:timeout()]; |
+ [request setHTTPMethod:base::SysUTF8ToNSString(method())]; |
+ |
+ for (const auto& pair : headers()) { |
+ [request setValue:base::SysUTF8ToNSString(pair.second) |
+ forHTTPHeaderField:base::SysUTF8ToNSString(pair.first)]; |
+ } |
+ |
+ base::scoped_nsobject<CrashpadHTTPBodyStreamTransport> transport( |
+ [[CrashpadHTTPBodyStreamTransport alloc] initWithBodyStream: |
+ body_stream()]); |
+ [request setHTTPBodyStream:transport.get()]; |
+ |
+ NSURLResponse* response = nil; |
+ NSError* error = nil; |
+ [NSURLConnection sendSynchronousRequest:request |
+ returningResponse:&response |
+ error:&error]; |
+ |
+ if (error) { |
+ LOG(ERROR) << [[error localizedDescription] UTF8String] << " (" |
+ << [[error domain] UTF8String] << " " << [error code] << ")"; |
+ return false; |
+ } |
+ if (!response) { |
+ LOG(ERROR) << "no response"; |
+ return false; |
+ } |
+ NSHTTPURLResponse* http_response = |
+ base::mac::ObjCCast<NSHTTPURLResponse>(response); |
+ if (!http_response) { |
+ LOG(ERROR) << "no http_response"; |
+ return false; |
+ } |
+ NSInteger http_status = [http_response statusCode]; |
+ if (http_status != 200) { |
+ LOG(ERROR) << base::StringPrintf("HTTP status %ld", |
+ static_cast<long>(http_status)); |
+ return false; |
+ } |
+ |
+ return true; |
+ } |
+} |
+ |
+} // namespace |
+ |
+// static |
+scoped_ptr<HTTPTransport> HTTPTransport::Create() { |
+ return scoped_ptr<HTTPTransport>(new HTTPTransportMac()); |
+} |
+ |
+} // namespace crashpad |