150 lines
7.6 KiB
Objective-C
150 lines
7.6 KiB
Objective-C
#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 isChunked method and have it return YES.
|
|
**/
|
|
- (UInt64)contentLength;
|
|
|
|
/**
|
|
* The HTTP server supports range requests in order to allow things like
|
|
* file download resumption and optimized streaming on mobile devices.
|
|
**/
|
|
- (UInt64)offset;
|
|
- (void)setOffset:(UInt64)offset;
|
|
|
|
/**
|
|
* Returns the data for the response.
|
|
* You do not have to return data of the exact length that is given.
|
|
* You may optionally return data of a lesser length.
|
|
* However, you must never return data of a greater length than requested.
|
|
* Doing so could disrupt proper support for range requests.
|
|
*
|
|
* To support asynchronous responses, read the discussion at the bottom of this header.
|
|
**/
|
|
- (NSData *)readDataOfLength:(NSUInteger)length;
|
|
|
|
/**
|
|
* Should only return YES after the HTTPConnection has read all available data.
|
|
* That is, all data for the response has been returned to the HTTPConnection via the readDataOfLength method.
|
|
**/
|
|
- (BOOL)isDone;
|
|
|
|
@optional
|
|
|
|
/**
|
|
* If you need time to calculate any part of the HTTP response headers (status code or header fields),
|
|
* this method allows you to delay sending the headers so that you may asynchronously execute the calculations.
|
|
* Simply implement this method and return YES until you have everything you need concerning the headers.
|
|
*
|
|
* This method ties into the asynchronous response architecture of the HTTPConnection.
|
|
* You should read the full discussion at the bottom of this header.
|
|
*
|
|
* If you return YES from this method,
|
|
* the HTTPConnection will wait for you to invoke the responseHasAvailableData method.
|
|
* After you do, the HTTPConnection will again invoke this method to see if the response is ready to send the headers.
|
|
*
|
|
* You should only delay sending the headers until you have everything you need concerning just the headers.
|
|
* Asynchronously generating the body of the response is not an excuse to delay sending the headers.
|
|
* Instead you should tie into the asynchronous response architecture, and use techniques such as the isChunked method.
|
|
*
|
|
* Important: You should read the discussion at the bottom of this header.
|
|
**/
|
|
- (BOOL)delayResponseHeaders;
|
|
|
|
/**
|
|
* Status code for response.
|
|
* Allows for responses such as redirect (301), etc.
|
|
**/
|
|
- (NSInteger)status;
|
|
|
|
/**
|
|
* 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 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;
|
|
|
|
/**
|
|
* This method is called from the HTTPConnection class 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 know not to
|
|
* invoke any methods on the HTTPConnection after this method is called (as the connection may be deallocated).
|
|
**/
|
|
- (void)connectionDidClose;
|
|
|
|
@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. Please see the HTTPAsyncFileResponse class for an example of how to do this.
|
|
*
|
|
* The normal flow of events for an HTTPConnection while responding to a request is like this:
|
|
* - Send http resopnse headers
|
|
* - 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 the entire response has been sent.
|
|
*
|
|
* With an asynchronous response, the flow is a little different.
|
|
*
|
|
* First the HTTPResponse is given the opportunity to postpone sending the HTTP response headers.
|
|
* This allows the response to asynchronously execute any code needed to calculate a part of the header.
|
|
* An example might be the response needs to generate some custom header fields,
|
|
* or perhaps the response needs to look for a resource on network-attached storage.
|
|
* Since the network-attached storage may be slow, the response doesn't know whether to send a 200 or 404 yet.
|
|
* In situations such as this, the HTTPResponse simply implements the delayResponseHeaders method and returns YES.
|
|
* After returning YES from this method, the HTTPConnection will wait until the response invokes its
|
|
* responseHasAvailableData method. After this occurs, the HTTPConnection will again query the delayResponseHeaders
|
|
* method to see if the response is ready to send the headers.
|
|
* This cycle will continue until the delayResponseHeaders method returns NO.
|
|
*
|
|
* You should only delay sending the response headers until you have everything you need concerning just the headers.
|
|
* Asynchronously generating the body of the response is not an excuse to delay sending the headers.
|
|
*
|
|
* After the response headers have been sent, the HTTPConnection calls your readDataOfLength method.
|
|
* You may or may not have any available data at this point. 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-99.
|
|
*
|
|
* 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 and dynamic, it's also chunked.
|
|
* If your response is chunked, you don't need to worry about range requests.
|
|
**/
|