161 lines
5.6 KiB
Objective-C
161 lines
5.6 KiB
Objective-C
#import "DAVConnection.h"
|
|
#import "HTTPMessage.h"
|
|
#import "HTTPFileResponse.h"
|
|
#import "HTTPAsyncFileResponse.h"
|
|
#import "PUTResponse.h"
|
|
#import "DELETEResponse.h"
|
|
#import "DAVResponse.h"
|
|
#import "HTTPLogging.h"
|
|
|
|
#define HTTP_BODY_MAX_MEMORY_SIZE (1024 * 1024)
|
|
#define HTTP_ASYNC_FILE_RESPONSE_THRESHOLD (16 * 1024 * 1024)
|
|
|
|
static const int httpLogLevel = HTTP_LOG_LEVEL_WARN;
|
|
|
|
@implementation DAVConnection
|
|
|
|
- (void) dealloc {
|
|
[requestContentStream close];
|
|
|
|
}
|
|
|
|
- (BOOL) supportsMethod:(NSString*)method atPath:(NSString*)path {
|
|
// HTTPFileResponse & HTTPAsyncFileResponse
|
|
if ([method isEqualToString:@"GET"]) return YES;
|
|
if ([method isEqualToString:@"HEAD"]) return YES;
|
|
|
|
// PUTResponse
|
|
if ([method isEqualToString:@"PUT"]) return YES;
|
|
|
|
// DELETEResponse
|
|
if ([method isEqualToString:@"DELETE"]) return YES;
|
|
|
|
// DAVResponse
|
|
if ([method isEqualToString:@"OPTIONS"]) return YES;
|
|
if ([method isEqualToString:@"PROPFIND"]) return YES;
|
|
if ([method isEqualToString:@"MKCOL"]) return YES;
|
|
if ([method isEqualToString:@"MOVE"]) return YES;
|
|
if ([method isEqualToString:@"COPY"]) return YES;
|
|
if ([method isEqualToString:@"LOCK"]) return YES;
|
|
if ([method isEqualToString:@"UNLOCK"]) return YES;
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL) expectsRequestBodyFromMethod:(NSString*)method atPath:(NSString*)path {
|
|
// PUTResponse
|
|
if ([method isEqualToString:@"PUT"]) {
|
|
return YES;
|
|
}
|
|
|
|
// DAVResponse
|
|
if ([method isEqual:@"PROPFIND"] || [method isEqual:@"MKCOL"]) {
|
|
return [request headerField:@"Content-Length"] ? YES : NO;
|
|
}
|
|
if ([method isEqual:@"LOCK"]) {
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void) prepareForBodyWithSize:(UInt64)contentLength {
|
|
NSAssert(requestContentStream == nil, @"requestContentStream should be nil");
|
|
NSAssert(requestContentBody == nil, @"requestContentBody should be nil");
|
|
|
|
if (contentLength > HTTP_BODY_MAX_MEMORY_SIZE) {
|
|
requestContentBody = [[NSTemporaryDirectory() stringByAppendingString:[[NSProcessInfo processInfo] globallyUniqueString]] copy];
|
|
requestContentStream = [[NSOutputStream alloc] initToFileAtPath:requestContentBody append:NO];
|
|
[requestContentStream open];
|
|
} else {
|
|
requestContentBody = [[NSMutableData alloc] initWithCapacity:(NSUInteger)contentLength];
|
|
requestContentStream = nil;
|
|
}
|
|
}
|
|
|
|
- (void) processBodyData:(NSData*)postDataChunk {
|
|
NSAssert(requestContentBody != nil, @"requestContentBody should not be nil");
|
|
if (requestContentStream) {
|
|
[requestContentStream write:[postDataChunk bytes] maxLength:[postDataChunk length]];
|
|
} else {
|
|
[(NSMutableData*)requestContentBody appendData:postDataChunk];
|
|
}
|
|
}
|
|
|
|
- (void) finishBody {
|
|
NSAssert(requestContentBody != nil, @"requestContentBody should not be nil");
|
|
if (requestContentStream) {
|
|
[requestContentStream close];
|
|
requestContentStream = nil;
|
|
}
|
|
}
|
|
|
|
- (void)finishResponse {
|
|
NSAssert(requestContentStream == nil, @"requestContentStream should be nil");
|
|
requestContentBody = nil;
|
|
|
|
[super finishResponse];
|
|
}
|
|
|
|
- (NSObject<HTTPResponse>*) httpResponseForMethod:(NSString*)method URI:(NSString*)path {
|
|
if ([method isEqualToString:@"HEAD"] || [method isEqualToString:@"GET"]) {
|
|
NSString* filePath = [self filePathForURI:path allowDirectory:NO];
|
|
if (filePath) {
|
|
NSDictionary* fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL];
|
|
if (fileAttributes) {
|
|
if ([[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue] > HTTP_ASYNC_FILE_RESPONSE_THRESHOLD) {
|
|
return [[HTTPAsyncFileResponse alloc] initWithFilePath:filePath forConnection:self];
|
|
} else {
|
|
return [[HTTPFileResponse alloc] initWithFilePath:filePath forConnection:self];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([method isEqualToString:@"PUT"]) {
|
|
NSString* filePath = [self filePathForURI:path allowDirectory:YES];
|
|
if (filePath) {
|
|
if ([requestContentBody isKindOfClass:[NSString class]]) {
|
|
return [[PUTResponse alloc] initWithFilePath:filePath headers:[request allHeaderFields] bodyFile:requestContentBody];
|
|
} else if ([requestContentBody isKindOfClass:[NSData class]]) {
|
|
return [[PUTResponse alloc] initWithFilePath:filePath headers:[request allHeaderFields] bodyData:requestContentBody];
|
|
} else {
|
|
HTTPLogError(@"Internal error");
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([method isEqualToString:@"DELETE"]) {
|
|
NSString* filePath = [self filePathForURI:path allowDirectory:YES];
|
|
if (filePath) {
|
|
return [[DELETEResponse alloc] initWithFilePath:filePath];
|
|
}
|
|
}
|
|
|
|
if ([method isEqualToString:@"OPTIONS"] || [method isEqualToString:@"PROPFIND"] || [method isEqualToString:@"MKCOL"] ||
|
|
[method isEqualToString:@"MOVE"] || [method isEqualToString:@"COPY"] || [method isEqualToString:@"LOCK"] || [method isEqualToString:@"UNLOCK"]) {
|
|
NSString* filePath = [self filePathForURI:path allowDirectory:YES];
|
|
if (filePath) {
|
|
NSString* rootPath = [config documentRoot];
|
|
NSString* resourcePath = [filePath substringFromIndex:([rootPath length] + 1)];
|
|
if (requestContentBody) {
|
|
if ([requestContentBody isKindOfClass:[NSString class]]) {
|
|
requestContentBody = [NSData dataWithContentsOfFile:requestContentBody];
|
|
} else if (![requestContentBody isKindOfClass:[NSData class]]) {
|
|
HTTPLogError(@"Internal error");
|
|
return nil;
|
|
}
|
|
}
|
|
return [[DAVResponse alloc] initWithMethod:method
|
|
headers:[request allHeaderFields]
|
|
bodyData:requestContentBody
|
|
resourcePath:resourcePath
|
|
rootPath:rootPath];
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
@end
|