forked from rsms/kod
-
Notifications
You must be signed in to change notification settings - Fork 0
/
KHTTPURLHandler.mm
129 lines (104 loc) · 3.7 KB
/
KHTTPURLHandler.mm
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
// Copyright (c) 2010-2011, Rasmus Andersson. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
#import "common.h"
#import "KHTTPURLHandler.h"
#import "NSStringICUAdditions.h"
@implementation KHTTPURLHandler
- (BOOL)canReadURL:(NSURL*)url {
NSString *scheme = [url scheme];
if (scheme) {
if (scheme.length == 5) {
return [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame;
} else if (scheme.length == 4) {
return [scheme caseInsensitiveCompare:@"http"] == NSOrderedSame;
}
}
return NO;
}
- (void)readURL:(NSURL*)absoluteURL
ofType:(NSString*)typeName
inTab:(KDocument*)tab {
// set state to "waiting"
tab.isLoading = YES;
tab.isWaitingForResponse = YES;
// set text view to be read-only
tab.isEditable = NO;
// set type (might change when we receive a response)
tab.fileType = typeName;
__block NSString *textEncodingNameFromResponse = nil;
HURLConnection *conn = [absoluteURL
fetchWithOnResponseBlock:^(NSURLResponse *response) {
NSError *error = nil;
NSDate *fileModificationDate = nil;
// change state from waiting to loading
tab.isWaitingForResponse = NO;
// handle HTTP response
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
// check status
NSInteger status = [(NSHTTPURLResponse*)response statusCode];
if (status < 200 || status > 299) {
error = [NSError kodErrorWithHTTPStatusCode:status];
}
// TODO: get fileModificationDate from response headers
}
// try to derive UTI and read filename, unless error
if (!error) {
// get UTI based on MIME type
CFStringRef mimeType = (CFStringRef)[response MIMEType];
if (mimeType) {
NSString *uti = (NSString*)
UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,
mimeType, NULL);
if (uti)
tab.fileType = uti;
}
// get text encoding
textEncodingNameFromResponse = [response textEncodingName];
}
// update URL, if needed (might have been redirected)
tab.fileURL = response.URL;
// set suggested title
tab.title = response.suggestedFilename;
// set modification date
tab.fileModificationDate = fileModificationDate ? fileModificationDate
: [NSDate date];
return error;
}
onCompleteBlock:^(NSError *err, NSData *data) {
// Read data unless an error occured while reading URL
if (err) {
tab.isLoading = NO;
tab.isCrashed = YES; // FIXME
data = nil;
} else {
// if we got a charset, try to convert it into a NSStringEncoding symbol
if (textEncodingNameFromResponse) {
tab.textEncoding = CFStringConvertEncodingToNSStringEncoding(
CFStringConvertIANACharSetNameToEncoding(
(CFStringRef)textEncodingNameFromResponse));
}
}
// finalize
[tab urlHandler:self
finishedReadingURL:absoluteURL
data:data
ofType:typeName
error:err
callback:^(NSError *err) {
if (!err) {
// done -- enable editing
tab.isEditable = YES;
}
}];
}
startImmediately:NO];
kassert(conn);
// we want the blocks to be invoked on the main thread, thank you
[conn scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[conn start];
// TODO: keep a reference to the connection so we can cancel it if the tab is
// prematurely closed.
}
@end