DAVConnection.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #import "DAVConnection.h"
  2. #import "HTTPMessage.h"
  3. #import "HTTPFileResponse.h"
  4. #import "HTTPAsyncFileResponse.h"
  5. #import "PUTResponse.h"
  6. #import "DELETEResponse.h"
  7. #import "DAVResponse.h"
  8. #import "HTTPLogging.h"
  9. #define HTTP_BODY_MAX_MEMORY_SIZE (1024 * 1024)
  10. #define HTTP_ASYNC_FILE_RESPONSE_THRESHOLD (16 * 1024 * 1024)
  11. static const int httpLogLevel = HTTP_LOG_LEVEL_WARN;
  12. @implementation DAVConnection
  13. - (void) dealloc {
  14. [requestContentStream close];
  15. }
  16. - (BOOL) supportsMethod:(NSString*)method atPath:(NSString*)path {
  17. // HTTPFileResponse & HTTPAsyncFileResponse
  18. if ([method isEqualToString:@"GET"]) return YES;
  19. if ([method isEqualToString:@"HEAD"]) return YES;
  20. // PUTResponse
  21. if ([method isEqualToString:@"PUT"]) return YES;
  22. // DELETEResponse
  23. if ([method isEqualToString:@"DELETE"]) return YES;
  24. // DAVResponse
  25. if ([method isEqualToString:@"OPTIONS"]) return YES;
  26. if ([method isEqualToString:@"PROPFIND"]) return YES;
  27. if ([method isEqualToString:@"MKCOL"]) return YES;
  28. if ([method isEqualToString:@"MOVE"]) return YES;
  29. if ([method isEqualToString:@"COPY"]) return YES;
  30. if ([method isEqualToString:@"LOCK"]) return YES;
  31. if ([method isEqualToString:@"UNLOCK"]) return YES;
  32. return NO;
  33. }
  34. - (BOOL) expectsRequestBodyFromMethod:(NSString*)method atPath:(NSString*)path {
  35. // PUTResponse
  36. if ([method isEqualToString:@"PUT"]) {
  37. return YES;
  38. }
  39. // DAVResponse
  40. if ([method isEqual:@"PROPFIND"] || [method isEqual:@"MKCOL"]) {
  41. return [request headerField:@"Content-Length"] ? YES : NO;
  42. }
  43. if ([method isEqual:@"LOCK"]) {
  44. return YES;
  45. }
  46. return NO;
  47. }
  48. - (void) prepareForBodyWithSize:(UInt64)contentLength {
  49. NSAssert(requestContentStream == nil, @"requestContentStream should be nil");
  50. NSAssert(requestContentBody == nil, @"requestContentBody should be nil");
  51. if (contentLength > HTTP_BODY_MAX_MEMORY_SIZE) {
  52. requestContentBody = [[NSTemporaryDirectory() stringByAppendingString:[[NSProcessInfo processInfo] globallyUniqueString]] copy];
  53. requestContentStream = [[NSOutputStream alloc] initToFileAtPath:requestContentBody append:NO];
  54. [requestContentStream open];
  55. } else {
  56. requestContentBody = [[NSMutableData alloc] initWithCapacity:(NSUInteger)contentLength];
  57. requestContentStream = nil;
  58. }
  59. }
  60. - (void) processBodyData:(NSData*)postDataChunk {
  61. NSAssert(requestContentBody != nil, @"requestContentBody should not be nil");
  62. if (requestContentStream) {
  63. [requestContentStream write:[postDataChunk bytes] maxLength:[postDataChunk length]];
  64. } else {
  65. [(NSMutableData*)requestContentBody appendData:postDataChunk];
  66. }
  67. }
  68. - (void) finishBody {
  69. NSAssert(requestContentBody != nil, @"requestContentBody should not be nil");
  70. if (requestContentStream) {
  71. [requestContentStream close];
  72. requestContentStream = nil;
  73. }
  74. }
  75. - (void)finishResponse {
  76. NSAssert(requestContentStream == nil, @"requestContentStream should be nil");
  77. requestContentBody = nil;
  78. [super finishResponse];
  79. }
  80. - (NSObject<HTTPResponse>*) httpResponseForMethod:(NSString*)method URI:(NSString*)path {
  81. if ([method isEqualToString:@"HEAD"] || [method isEqualToString:@"GET"]) {
  82. NSString* filePath = [self filePathForURI:path allowDirectory:NO];
  83. if (filePath) {
  84. NSDictionary* fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL];
  85. if (fileAttributes) {
  86. if ([[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue] > HTTP_ASYNC_FILE_RESPONSE_THRESHOLD) {
  87. return [[HTTPAsyncFileResponse alloc] initWithFilePath:filePath forConnection:self];
  88. } else {
  89. return [[HTTPFileResponse alloc] initWithFilePath:filePath forConnection:self];
  90. }
  91. }
  92. }
  93. }
  94. if ([method isEqualToString:@"PUT"]) {
  95. NSString* filePath = [self filePathForURI:path allowDirectory:YES];
  96. if (filePath) {
  97. if ([requestContentBody isKindOfClass:[NSString class]]) {
  98. return [[PUTResponse alloc] initWithFilePath:filePath headers:[request allHeaderFields] bodyFile:requestContentBody];
  99. } else if ([requestContentBody isKindOfClass:[NSData class]]) {
  100. return [[PUTResponse alloc] initWithFilePath:filePath headers:[request allHeaderFields] bodyData:requestContentBody];
  101. } else {
  102. HTTPLogError(@"Internal error");
  103. }
  104. }
  105. }
  106. if ([method isEqualToString:@"DELETE"]) {
  107. NSString* filePath = [self filePathForURI:path allowDirectory:YES];
  108. if (filePath) {
  109. return [[DELETEResponse alloc] initWithFilePath:filePath];
  110. }
  111. }
  112. if ([method isEqualToString:@"OPTIONS"] || [method isEqualToString:@"PROPFIND"] || [method isEqualToString:@"MKCOL"] ||
  113. [method isEqualToString:@"MOVE"] || [method isEqualToString:@"COPY"] || [method isEqualToString:@"LOCK"] || [method isEqualToString:@"UNLOCK"]) {
  114. NSString* filePath = [self filePathForURI:path allowDirectory:YES];
  115. if (filePath) {
  116. NSString* rootPath = [config documentRoot];
  117. NSString* resourcePath = [filePath substringFromIndex:([rootPath length] + 1)];
  118. if (requestContentBody) {
  119. if ([requestContentBody isKindOfClass:[NSString class]]) {
  120. requestContentBody = [NSData dataWithContentsOfFile:requestContentBody];
  121. } else if (![requestContentBody isKindOfClass:[NSData class]]) {
  122. HTTPLogError(@"Internal error");
  123. return nil;
  124. }
  125. }
  126. return [[DAVResponse alloc] initWithMethod:method
  127. headers:[request allHeaderFields]
  128. bodyData:requestContentBody
  129. resourcePath:resourcePath
  130. rootPath:rootPath];
  131. }
  132. }
  133. return nil;
  134. }
  135. @end