Forráskód Böngészése

Added GCDWebServerChunkedResponse

Pierre-Olivier Latour 11 éve
szülő
commit
6a4f74c2e4

+ 7 - 0
CGDWebServer/GCDWebServerResponse.h

@@ -27,6 +27,8 @@
 
 #import <Foundation/Foundation.h>
 
+typedef NSData* (^GCDWebServerChunkBlock)();
+
 @interface GCDWebServerResponse : NSObject
 @property(nonatomic, copy) NSString* contentType;  // Default is nil i.e. no body
 @property(nonatomic) NSUInteger contentLength;  // Default is NSNotFound i.e. undefined
@@ -80,3 +82,8 @@
 - (id)initWithFile:(NSString*)path byteRange:(NSRange)range;  // Pass [NSNotFound, 0] to disable byte range entirely, [offset, length] to enable byte range from beginning of file or [NSNotFound, -bytes] from end of file
 - (id)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment;
 @end
+
+@interface GCDWebServerChunkedResponse : GCDWebServerResponse  // Use chunked transfer encoding
++ (GCDWebServerChunkedResponse*)responseWithContentType:(NSString*)type chunkBlock:(GCDWebServerChunkBlock)block;
+- (id)initWithContentType:(NSString*)type chunkBlock:(GCDWebServerChunkBlock)block;  // Return nil when done
+@end

+ 80 - 0
CGDWebServer/GCDWebServerResponse.m

@@ -55,6 +55,15 @@
 }
 @end
 
+@interface GCDWebServerChunkedResponse () {
+@private
+  GCDWebServerChunkBlock _block;
+  NSData* _chunk;
+  NSUInteger _offset;
+  BOOL _terminated;
+}
+@end
+
 @implementation GCDWebServerResponse
 
 @synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, additionalHeaders=_headers;
@@ -378,3 +387,74 @@
 }
 
 @end
+
+@implementation GCDWebServerChunkedResponse
+
++ (GCDWebServerChunkedResponse*)responseWithContentType:(NSString*)type chunkBlock:(GCDWebServerChunkBlock)block {
+  return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type chunkBlock:block]);
+}
+
+- (id)initWithContentType:(NSString*)type chunkBlock:(GCDWebServerChunkBlock)block {
+  if ((self = [super init])) {
+    _block = [block copy];
+    
+    self.contentType = type;
+    [self setValue:@"chunked" forAdditionalHeader:@"Transfer-Encoding"];
+  }
+  return self;
+}
+
+- (BOOL)open {
+  DCHECK(_chunk == nil);
+  return YES;
+}
+
+- (NSInteger)read:(void*)buffer maxLength:(NSUInteger)length {
+  if (_offset >= _chunk.length) {
+    ARC_RELEASE(_chunk);
+    _chunk = nil;
+  }
+  if (_chunk == nil) {
+    if (_terminated) {
+      return 0;
+    }
+    NSData* data = _block();
+    if (data.length > 0) {
+      const char* hexString = [[NSString stringWithFormat:@"%lx", (unsigned long)data.length] UTF8String];
+      size_t hexLength = strlen(hexString);
+      _chunk = [[NSMutableData alloc] initWithLength:(hexLength + 2 + data.length + 2)];
+      char* ptr = (char*)_chunk.bytes;
+      bcopy(hexString, ptr, hexLength);
+      ptr += hexLength;
+      *ptr++ = '\r';
+      *ptr++ = '\n';
+      bcopy(data.bytes, ptr, data.length);
+      ptr += data.length;
+      *ptr++ = '\r';
+      *ptr = '\n';
+    } else {
+      _chunk = [[NSData alloc] initWithBytes:"0\r\n\r\n" length:5];
+      _terminated = YES;
+    }
+    _offset = 0;
+  }
+  NSInteger size = MIN(_chunk.length - _offset, length);
+  bcopy((char*)_chunk.bytes + _offset, buffer, size);
+  _offset += size;
+  return size;
+}
+
+- (BOOL)close {
+  ARC_RELEASE(_chunk);
+  _chunk = nil;
+  return YES;
+}
+
+- (void)dealloc {
+  DCHECK(_chunk == nil);
+  ARC_RELEASE(_chunk);
+  
+  ARC_DEALLOC(super);
+}
+
+@end