Split class files

This commit is contained in:
Pierre-Olivier Latour
2014-04-06 11:32:07 -07:00
parent 81638ad086
commit 1f9a0d38d0
24 changed files with 1316 additions and 846 deletions
-292
View File
@@ -25,14 +25,12 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <sys/stat.h>
#import <zlib.h>
#import "GCDWebServerPrivate.h"
#define kZlibErrorDomain @"ZlibErrorDomain"
#define kGZipInitialBufferSize (256 * 1024)
#define kFileReadBufferSize (32 * 1024)
@interface GCDWebServerBodyEncoder : NSObject <GCDWebServerBodyReader>
- (id)initWithResponse:(GCDWebServerResponse*)response reader:(id<GCDWebServerBodyReader>)reader;
@@ -332,293 +330,3 @@
}
@end
@interface GCDWebServerDataResponse () {
@private
NSData* _data;
BOOL _done;
}
@end
@implementation GCDWebServerDataResponse
+ (GCDWebServerDataResponse*)responseWithData:(NSData*)data contentType:(NSString*)type {
return ARC_AUTORELEASE([[[self class] alloc] initWithData:data contentType:type]);
}
- (id)initWithData:(NSData*)data contentType:(NSString*)type {
if (data == nil) {
DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
if ((self = [super init])) {
_data = ARC_RETAIN(data);
self.contentType = type;
self.contentLength = data.length;
}
return self;
}
- (void)dealloc {
ARC_RELEASE(_data);
ARC_DEALLOC(super);
}
- (NSData*)readData:(NSError**)error {
NSData* data;
if (_done) {
data = [NSData data];
} else {
data = _data;
_done = YES;
}
return data;
}
@end
@implementation GCDWebServerDataResponse (Extensions)
+ (GCDWebServerDataResponse*)responseWithText:(NSString*)text {
return ARC_AUTORELEASE([[self alloc] initWithText:text]);
}
+ (GCDWebServerDataResponse*)responseWithHTML:(NSString*)html {
return ARC_AUTORELEASE([[self alloc] initWithHTML:html]);
}
+ (GCDWebServerDataResponse*)responseWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
return ARC_AUTORELEASE([[self alloc] initWithHTMLTemplate:path variables:variables]);
}
+ (GCDWebServerDataResponse*)responseWithJSONObject:(id)object {
return ARC_AUTORELEASE([[self alloc] initWithJSONObject:object]);
}
+ (GCDWebServerDataResponse*)responseWithJSONObject:(id)object contentType:(NSString*)type {
return ARC_AUTORELEASE([[self alloc] initWithJSONObject:object contentType:type]);
}
- (id)initWithText:(NSString*)text {
NSData* data = [text dataUsingEncoding:NSUTF8StringEncoding];
if (data == nil) {
DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
return [self initWithData:data contentType:@"text/plain; charset=utf-8"];
}
- (id)initWithHTML:(NSString*)html {
NSData* data = [html dataUsingEncoding:NSUTF8StringEncoding];
if (data == nil) {
DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
return [self initWithData:data contentType:@"text/html; charset=utf-8"];
}
- (id)initWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
NSMutableString* html = [[NSMutableString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
[variables enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop) {
[html replaceOccurrencesOfString:[NSString stringWithFormat:@"%%%@%%", key] withString:value options:0 range:NSMakeRange(0, html.length)];
}];
id response = [self initWithHTML:html];
ARC_RELEASE(html);
return response;
}
- (id)initWithJSONObject:(id)object {
return [self initWithJSONObject:object contentType:@"application/json"];
}
- (id)initWithJSONObject:(id)object contentType:(NSString*)type {
NSData* data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL];
if (data == nil) {
ARC_RELEASE(self);
return nil;
}
return [self initWithData:data contentType:type];
}
@end
@interface GCDWebServerFileResponse () {
@private
NSString* _path;
NSUInteger _offset;
NSUInteger _size;
int _file;
}
@end
@implementation GCDWebServerFileResponse
+ (GCDWebServerFileResponse*)responseWithFile:(NSString*)path {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path]);
}
+ (GCDWebServerFileResponse*)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path isAttachment:attachment]);
}
+ (GCDWebServerFileResponse*)responseWithFile:(NSString*)path byteRange:(NSRange)range {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path byteRange:range]);
}
+ (GCDWebServerFileResponse*)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path byteRange:range isAttachment:attachment]);
}
- (id)initWithFile:(NSString*)path {
return [self initWithFile:path byteRange:NSMakeRange(NSNotFound, 0) isAttachment:NO];
}
- (id)initWithFile:(NSString*)path isAttachment:(BOOL)attachment {
return [self initWithFile:path byteRange:NSMakeRange(NSNotFound, 0) isAttachment:attachment];
}
- (id)initWithFile:(NSString*)path byteRange:(NSRange)range {
return [self initWithFile:path byteRange:range isAttachment:NO];
}
- (id)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
struct stat info;
if (lstat([path fileSystemRepresentation], &info) || !(info.st_mode & S_IFREG)) {
DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
if ((range.location != NSNotFound) || (range.length > 0)) {
if (range.location != NSNotFound) {
range.location = MIN(range.location, (NSUInteger)info.st_size);
range.length = MIN(range.length, (NSUInteger)info.st_size - range.location);
} else {
range.length = MIN(range.length, (NSUInteger)info.st_size);
range.location = (NSUInteger)info.st_size - range.length;
}
if (range.length == 0) {
ARC_RELEASE(self);
return nil; // TODO: Return 416 status code and "Content-Range: bytes */{file length}" header
}
}
if ((self = [super init])) {
_path = [path copy];
if (range.location != NSNotFound) {
_offset = range.location;
_size = range.length;
[self setStatusCode:206];
[self setValue:[NSString stringWithFormat:@"bytes %i-%i/%i", (int)range.location, (int)(range.location + range.length - 1), (int)info.st_size] forAdditionalHeader:@"Content-Range"];
LOG_DEBUG(@"Using content bytes range [%i-%i] for file \"%@\"", (int)range.location, (int)(range.location + range.length - 1), path);
} else {
_offset = 0;
_size = (NSUInteger)info.st_size;
}
if (attachment) { // TODO: Use http://tools.ietf.org/html/rfc5987 to encode file names with special characters instead of using lossy conversion to ISO 8859-1
NSData* data = [[path lastPathComponent] dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:YES];
NSString* fileName = data ? [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding] : nil;
if (fileName) {
[self setValue:[NSString stringWithFormat:@"attachment; filename=\"%@\"", fileName] forAdditionalHeader:@"Content-Disposition"];
ARC_RELEASE(fileName);
} else {
DNOT_REACHED();
}
}
self.contentType = GCDWebServerGetMimeTypeForExtension([path pathExtension]);
self.contentLength = (range.location != NSNotFound ? range.length : (NSUInteger)info.st_size);
}
return self;
}
- (void)dealloc {
DCHECK(_file <= 0);
ARC_RELEASE(_path);
ARC_DEALLOC(super);
}
static inline NSError* _MakePosixError(int code) {
return [NSError errorWithDomain:NSPOSIXErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%s", strerror(code)]}];
}
- (BOOL)open:(NSError**)error {
DCHECK(_file <= 0);
_file = open([_path fileSystemRepresentation], O_NOFOLLOW | O_RDONLY);
if (_file <= 0) {
*error = _MakePosixError(errno);
return NO;
}
if (lseek(_file, _offset, SEEK_SET) != (off_t)_offset) {
*error = _MakePosixError(errno);
close(_file);
_file = 0;
return NO;
}
return YES;
}
- (NSData*)readData:(NSError**)error {
DCHECK(_file > 0);
size_t length = MIN((NSUInteger)kFileReadBufferSize, _size);
NSMutableData* data = [[NSMutableData alloc] initWithLength:length];
ssize_t result = read(_file, data.mutableBytes, length);
if (result < 0) {
*error = _MakePosixError(errno);
return nil;
}
if (result > 0) {
[data setLength:result];
_size -= result;
}
return ARC_AUTORELEASE(data);
}
- (void)close {
DCHECK(_file > 0);
close(_file);
_file = 0;
}
@end
@interface GCDWebServerStreamResponse () {
@private
GCDWebServerStreamBlock _block;
}
@end
@implementation GCDWebServerStreamResponse
+ (GCDWebServerStreamResponse*)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type streamBlock:block]);
}
- (id)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
if ((self = [super init])) {
_block = [block copy];
self.contentType = type;
self.chunkedTransferEncoding = YES;
}
return self;
}
- (void)dealloc {
ARC_RELEASE(_block);
ARC_DEALLOC(super);
}
- (NSData*)readData:(NSError**)error {
return _block(error);
}
@end