mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-04-24 00:00:04 +08:00
Added support for asynchronous reading in GCDWebServerBodyReader
This commit is contained in:
@@ -280,54 +280,56 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
|
|
||||||
- (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block {
|
- (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block {
|
||||||
GWS_DCHECK([_response hasBody]);
|
GWS_DCHECK([_response hasBody]);
|
||||||
NSError* error = nil;
|
[_response performReadDataWithCompletion:^(NSData* data, NSError* error) {
|
||||||
NSData* data = [_response performReadData:&error];
|
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data.length) {
|
if (data.length) {
|
||||||
if (_response.usesChunkedTransferEncoding) {
|
if (_response.usesChunkedTransferEncoding) {
|
||||||
const char* hexString = [[NSString stringWithFormat:@"%lx", (unsigned long)data.length] UTF8String];
|
const char* hexString = [[NSString stringWithFormat:@"%lx", (unsigned long)data.length] UTF8String];
|
||||||
size_t hexLength = strlen(hexString);
|
size_t hexLength = strlen(hexString);
|
||||||
NSData* chunk = [NSMutableData dataWithLength:(hexLength + 2 + data.length + 2)];
|
NSData* chunk = [NSMutableData dataWithLength:(hexLength + 2 + data.length + 2)];
|
||||||
if (chunk == nil) {
|
if (chunk == nil) {
|
||||||
GWS_LOG_ERROR(@"Failed allocating memory for response body chunk for socket %i: %@", _socket, error);
|
GWS_LOG_ERROR(@"Failed allocating memory for response body chunk for socket %i: %@", _socket, error);
|
||||||
block(NO);
|
block(NO);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
char* ptr = (char*)[(NSMutableData*)chunk mutableBytes];
|
||||||
|
bcopy(hexString, ptr, hexLength);
|
||||||
|
ptr += hexLength;
|
||||||
|
*ptr++ = '\r';
|
||||||
|
*ptr++ = '\n';
|
||||||
|
bcopy(data.bytes, ptr, data.length);
|
||||||
|
ptr += data.length;
|
||||||
|
*ptr++ = '\r';
|
||||||
|
*ptr = '\n';
|
||||||
|
data = chunk;
|
||||||
}
|
}
|
||||||
char* ptr = (char*)[(NSMutableData*)chunk mutableBytes];
|
[self _writeData:data withCompletionBlock:^(BOOL success) {
|
||||||
bcopy(hexString, ptr, hexLength);
|
|
||||||
ptr += hexLength;
|
|
||||||
*ptr++ = '\r';
|
|
||||||
*ptr++ = '\n';
|
|
||||||
bcopy(data.bytes, ptr, data.length);
|
|
||||||
ptr += data.length;
|
|
||||||
*ptr++ = '\r';
|
|
||||||
*ptr = '\n';
|
|
||||||
data = chunk;
|
|
||||||
}
|
|
||||||
[self _writeData:data withCompletionBlock:^(BOOL success) {
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
[self _writeBodyWithCompletionBlock:block];
|
[self _writeBodyWithCompletionBlock:block];
|
||||||
} else {
|
} else {
|
||||||
block(NO);
|
block(NO);
|
||||||
}
|
}
|
||||||
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
if (_response.usesChunkedTransferEncoding) {
|
|
||||||
[self _writeData:_lastChunkData withCompletionBlock:^(BOOL success) {
|
|
||||||
|
|
||||||
block(success);
|
|
||||||
|
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
block(YES);
|
if (_response.usesChunkedTransferEncoding) {
|
||||||
|
[self _writeData:_lastChunkData withCompletionBlock:^(BOOL success) {
|
||||||
|
|
||||||
|
block(success);
|
||||||
|
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
block(YES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
GWS_LOG_ERROR(@"Failed reading response body for socket %i: %@", _socket, error);
|
||||||
|
block(NO);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
GWS_LOG_ERROR(@"Failed reading response body for socket %i: %@", _socket, error);
|
}];
|
||||||
block(NO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -249,6 +249,6 @@ extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOO
|
|||||||
@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
|
@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
|
||||||
- (void)prepareForReading;
|
- (void)prepareForReading;
|
||||||
- (BOOL)performOpen:(NSError**)error;
|
- (BOOL)performOpen:(NSError**)error;
|
||||||
- (NSData*)performReadData:(NSError**)error;
|
- (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block;
|
||||||
- (void)performClose;
|
- (void)performClose;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -27,6 +27,12 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServerBodyReaderCompletionBlock is passed by GCDWebServer to the
|
||||||
|
* GCDWebServerBodyReader object when reading data from it asynchronously.
|
||||||
|
*/
|
||||||
|
typedef void (^GCDWebServerBodyReaderCompletionBlock)(NSData* data, NSError* error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This protocol is used by the GCDWebServerConnection to communicate with
|
* This protocol is used by the GCDWebServerConnection to communicate with
|
||||||
* the GCDWebServerResponse and read the HTTP body data to send.
|
* the GCDWebServerResponse and read the HTTP body data to send.
|
||||||
@@ -39,6 +45,8 @@
|
|||||||
*/
|
*/
|
||||||
@protocol GCDWebServerBodyReader <NSObject>
|
@protocol GCDWebServerBodyReader <NSObject>
|
||||||
|
|
||||||
|
@required
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called before any body data is sent.
|
* This method is called before any body data is sent.
|
||||||
*
|
*
|
||||||
@@ -61,6 +69,17 @@
|
|||||||
*/
|
*/
|
||||||
- (void)close;
|
- (void)close;
|
||||||
|
|
||||||
|
@optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this method is implemented, it will be preferred over -readData:.
|
||||||
|
*
|
||||||
|
* It must call the passed block when data is available, passing a non-empty
|
||||||
|
* NSData if there is body data available, or an empty NSData there is no more
|
||||||
|
* body data, or nil on error and pass an NSError along.
|
||||||
|
*/
|
||||||
|
- (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -244,9 +244,14 @@
|
|||||||
return [_reader open:error];
|
return [_reader open:error];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData*)performReadData:(NSError**)error {
|
- (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
|
||||||
GWS_DCHECK(_opened);
|
if ([_reader respondsToSelector:@selector(asyncReadDataWithCompletion:)]) {
|
||||||
return [_reader readData:error];
|
[_reader asyncReadDataWithCompletion:block];
|
||||||
|
} else {
|
||||||
|
NSError* error = nil;
|
||||||
|
NSData* data = [_reader readData:&error];
|
||||||
|
block(data, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performClose {
|
- (void)performClose {
|
||||||
|
|||||||
Reference in New Issue
Block a user