-
Notifications
You must be signed in to change notification settings - Fork 588
/
DAVConnection.m
160 lines (135 loc) · 5.62 KB
/
DAVConnection.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#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