Index: util/net/http_transport_mac.mm |
diff --git a/util/net/http_transport_mac.mm b/util/net/http_transport_mac.mm |
index 135fd280d2eb111cc03fece50b2e2f1619c344d9..9688d18cbabb2bf83ee32359ae4b8f6d1eacdb4c 100644 |
--- a/util/net/http_transport_mac.mm |
+++ b/util/net/http_transport_mac.mm |
@@ -14,102 +14,128 @@ |
#include "util/net/http_transport.h" |
+#include <CoreFoundation/CoreFoundation.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 "third_party/apple_cf/CFStreamAbstract.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 |
+namespace crashpad { |
-@implementation CrashpadHTTPBodyStreamTransport |
+namespace { |
-- (instancetype)initWithBodyStream:(crashpad::HTTPBodyStream*)bodyStream { |
- if ((self = [super init])) { |
- streamStatus_ = NSStreamStatusNotOpen; |
- bodyStream_ = bodyStream; |
+// An implementation of CFReadStream. This implements the V0 callback |
+// scheme. |
+class HTTPBodyStreamCFReadStream { |
+ public: |
+ explicit HTTPBodyStreamCFReadStream(HTTPBodyStream* body_stream) |
+ : body_stream_(body_stream) { |
} |
- 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; |
+ // Creates a new NSInputStream, which the caller owns. |
+ NSInputStream* CreateInputStream() { |
+ CFStreamClientContext context = { |
+ .version = 0, |
+ .info = this, |
+ .retain = nullptr, |
+ .release = nullptr, |
+ .copyDescription = nullptr |
+ }; |
+ const CFReadStreamCallBacksV0 callbacks = { |
+ .version = 0, |
+ .open = &Open, |
+ .openCompleted = &OpenCompleted, |
+ .read = &Read, |
+ .getBuffer = &GetBuffer, |
+ .canRead = &CanRead, |
+ .close = &Close, |
+ .copyProperty = &CopyProperty, |
+ .schedule = &Schedule, |
+ .unschedule = &Unschedule |
+ }; |
+ CFReadStreamRef read_stream = CFReadStreamCreate(nullptr, |
+ reinterpret_cast<const CFReadStreamCallBacks*>(&callbacks), &context); |
+ return base::mac::CFToNSCast(read_stream); |
} |
-} |
- |
-- (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; |
-} |
+ private: |
+ static HTTPBodyStream* GetStream(void* info) { |
+ return static_cast<HTTPBodyStreamCFReadStream*>(info)->body_stream_; |
+ } |
-- (BOOL)getBuffer:(uint8_t**)buffer length:(NSUInteger*)length { |
- return NO; |
-} |
+ static Boolean Open(CFReadStreamRef stream, |
+ CFStreamError* error, |
+ Boolean* open_complete, |
+ void* info) { |
+ *open_complete = TRUE; |
+ return TRUE; |
+ } |
-// NSStream: |
+ static Boolean OpenCompleted(CFReadStreamRef stream, |
+ CFStreamError* error, |
+ void* info) { |
+ return TRUE; |
+ } |
-- (void)scheduleInRunLoop:(NSRunLoop*)runLoop |
- forMode:(NSString*)mode { |
-} |
+ static CFIndex Read(CFReadStreamRef stream, |
+ UInt8* buffer, |
+ CFIndex buffer_length, |
+ CFStreamError* error, |
+ Boolean* at_eof, |
+ void* info) { |
+ if (buffer_length == 0) |
+ return 0; |
+ |
+ ssize_t bytes_read = GetStream(info)->GetBytesBuffer(buffer, buffer_length); |
+ if (bytes_read == 0) { |
+ *at_eof = TRUE; |
+ } else if (bytes_read < 0) { |
+ error->error = -1; |
+ error->domain = kCFStreamErrorDomainCustom; |
+ } |
-- (void)removeFromRunLoop:(NSRunLoop*)runLoop |
- forMode:(NSString*)mode { |
-} |
+ return bytes_read; |
+ } |
-- (void)open { |
- streamStatus_ = NSStreamStatusOpen; |
-} |
+ static const UInt8* GetBuffer(CFReadStreamRef stream, |
+ CFIndex max_bytes_to_read, |
+ CFIndex* num_bytes_read, |
+ CFStreamError* error, |
+ Boolean* at_eof, |
+ void* info) { |
+ return nullptr; |
+ } |
-- (void)close { |
- streamStatus_ = NSStreamStatusClosed; |
-} |
+ static Boolean CanRead(CFReadStreamRef stream, void* info) { |
+ return TRUE; |
+ } |
-- (NSStreamStatus)streamStatus { |
- return streamStatus_; |
-} |
+ static void Close(CFReadStreamRef stream, void* info) {} |
-- (id<NSStreamDelegate>)delegate { |
- return delegate_; |
-} |
+ static CFTypeRef CopyProperty(CFReadStreamRef stream, |
+ CFStringRef property_name, |
+ void* info) { |
+ return nullptr; |
+ } |
-- (void)setDelegate:(id)delegate { |
- delegate_ = delegate; |
-} |
+ static void Schedule(CFReadStreamRef stream, |
+ CFRunLoopRef run_loop, |
+ CFStringRef run_loop_mode, |
+ void* info) {} |
-@end |
+ static void Unschedule(CFReadStreamRef stream, |
+ CFRunLoopRef run_loop, |
+ CFStringRef run_loop_mode, |
+ void* info) {} |
-namespace crashpad { |
+ HTTPBodyStream* body_stream_; // weak |
-namespace { |
+ DISALLOW_COPY_AND_ASSIGN(HTTPBodyStreamCFReadStream); |
+}; |
class HTTPTransportMac final : public HTTPTransport { |
public: |
@@ -145,10 +171,10 @@ bool HTTPTransportMac::ExecuteSynchronously(std::string* response_body) { |
forHTTPHeaderField:base::SysUTF8ToNSString(pair.first)]; |
} |
- base::scoped_nsobject<CrashpadHTTPBodyStreamTransport> transport( |
- [[CrashpadHTTPBodyStreamTransport alloc] initWithBodyStream: |
- body_stream()]); |
- [request setHTTPBodyStream:transport.get()]; |
+ HTTPBodyStreamCFReadStream body_stream_cf(body_stream()); |
+ base::scoped_nsobject<NSInputStream> input_stream( |
+ body_stream_cf.CreateInputStream()); |
+ [request setHTTPBodyStream:input_stream.get()]; |
NSURLResponse* response = nil; |
NSError* error = nil; |