forked from pixmeo/osirix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HTTPResponse.h
124 lines (99 loc) · 5.72 KB
/
HTTPResponse.h
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
#import <Foundation/Foundation.h>
@protocol HTTPResponse
// Returns the length of the data in bytes.
// If you don't know the length in advance, implement the iChunked method and have it return YES.
- (UInt64)contentLength;
- (UInt64)offset;
- (void)setOffset:(UInt64)offset;
- (NSData *)readDataOfLength:(unsigned int)length;
// Should only return YES after the HTTPConnection has read all available data.
- (BOOL)isDone;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
@optional
// If you want to add any extra HTTP headers to the response,
// simply return them in a dictionary in this method.
- (NSDictionary *)httpHeaders;
// If you want to generate your response asynchronously (e.g. in a background thread),
// implement this method in your custom response class and return YES.
// As you generate the data, call HTTPConnection's responseHasAvailableData method.
//
// Important: You should read the discussion at the bottom of this header.
- (BOOL)isAsynchronous;
// This method is called from the HTTPConnection when the connection is closed,
// or when the connection is finished with the response.
// If your response is asynchronous, you should implement this method so you can be sure not to
// invoke HTTPConnection's responseHasAvailableData method after this method is called.
- (void)connectionDidClose;
// If you don't know the content-length in advance,
// implement this method in your custom response class and return YES.
//
// Important: You should read the discussion at the bottom of this header.
- (BOOL)isChunked;
- (int)statusCode;
#endif
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface HTTPFileResponse : NSObject <HTTPResponse>
{
NSString *filePath;
NSFileHandle *fileHandle;
UInt64 fileLength;
}
- (id)initWithFilePath:(NSString *)filePath;
- (NSString *)filePath;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface HTTPDataResponse : NSObject <HTTPResponse>
{
unsigned offset;
NSData *data;
}
- (id)initWithData:(NSData *)data;
@end
// Important notice to those implementing custom asynchronous and/or chunked responses:
//
// HTTPConnection supports asynchronous responses. All you have to do in your custom response class is
// asynchronously generate the response, and invoke HTTPConnection's responseHasAvailableData method.
// You don't have to wait until you have all of the response ready to invoke this method. For example, if you
// generate the response in incremental chunks, you could call responseHasAvailableData after generating
// each chunk. You MUST invoke the responseHasAvailableData method on the proper thread/runloop. That is,
// the thread/runloop that the HTTPConnection is operating in. Please see the HTTPAsyncFileResponse class
// for an example of how to properly do this.
//
// The normal flow of events for an HTTPConnection while responding to a request is like this:
// - Get data from response via readDataOfLength method.
// - Add data to asyncSocket's write queue.
// - Wait for asyncSocket to notify it that the data has been sent.
// - Get more data from response via readDataOfLength method.
// ... continue this cycle until it has sent the entire response.
//
// With an asynchronous response, the flow is a little different. When HTTPConnection calls your
// readDataOfLength method, you may or may not have any available data. If you don't, then simply return nil.
// You should later invoke HTTPConnection's responseHasAvailableData when you have data to send.
//
// You don't have to keep track of when you return nil in the readDataOfLength method, or how many times you've invoked
// responseHasAvailableData. Just simply call responseHasAvailableData whenever you've generated new data, and
// return nil in your readDataOfLength whenever you don't have any available data in the requested range.
// HTTPConnection will automatically detect when it should be requesting new data and will act appropriately.
//
// It's important that you also keep in mind that the HTTP server supports range requests.
// The setOffset method is mandatory, and should not be ignored.
// Make sure you take into account the offset within the readDataOfLength method.
// You should also be aware that the HTTPConnection automatically sorts any range requests.
// So if your setOffset method is called with a value of 100, then you can safely release bytes 0-98.
//
// HTTPConnection can also help you keep your memory footprint small.
// Imagine you're dynamically generating a 10 MB response. You probably don't want to load all this data into
// RAM, and sit around waiting for HTTPConnection to slowly send it out over the network. All you need to do
// is pay attention to when HTTPConnection requests more data via readDataOfLength. This is because HTTPConnection
// will never allow asyncSocket's write queue to get much bigger than READ_CHUNKSIZE bytes. You should
// consider how you might be able to take advantage of this fact to generate your asynchronous response on demand,
// while at the same time keeping your memory footprint small, and your application lightning fast.
//
// If you don't know the content-length in advanced, you should also implement the isChunked method.
// This means the response will not include a Content-Length header, and will instead use "Transfer-Encoding: chunked".
// There's a good chance that if your response is asynchronous, it's also chunked.