HTTPResponse.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #import <Foundation/Foundation.h>
  2. @protocol HTTPResponse
  3. /**
  4. * Returns the length of the data in bytes.
  5. * If you don't know the length in advance, implement the isChunked method and have it return YES.
  6. **/
  7. - (UInt64)contentLength;
  8. /**
  9. * The HTTP server supports range requests in order to allow things like
  10. * file download resumption and optimized streaming on mobile devices.
  11. **/
  12. - (UInt64)offset;
  13. - (void)setOffset:(UInt64)offset;
  14. /**
  15. * Returns the data for the response.
  16. * You do not have to return data of the exact length that is given.
  17. * You may optionally return data of a lesser length.
  18. * However, you must never return data of a greater length than requested.
  19. * Doing so could disrupt proper support for range requests.
  20. *
  21. * To support asynchronous responses, read the discussion at the bottom of this header.
  22. **/
  23. - (NSData *)readDataOfLength:(NSUInteger)length;
  24. /**
  25. * Should only return YES after the HTTPConnection has read all available data.
  26. * That is, all data for the response has been returned to the HTTPConnection via the readDataOfLength method.
  27. **/
  28. - (BOOL)isDone;
  29. @optional
  30. /**
  31. * If you need time to calculate any part of the HTTP response headers (status code or header fields),
  32. * this method allows you to delay sending the headers so that you may asynchronously execute the calculations.
  33. * Simply implement this method and return YES until you have everything you need concerning the headers.
  34. *
  35. * This method ties into the asynchronous response architecture of the HTTPConnection.
  36. * You should read the full discussion at the bottom of this header.
  37. *
  38. * If you return YES from this method,
  39. * the HTTPConnection will wait for you to invoke the responseHasAvailableData method.
  40. * After you do, the HTTPConnection will again invoke this method to see if the response is ready to send the headers.
  41. *
  42. * You should only delay sending the headers until you have everything you need concerning just the headers.
  43. * Asynchronously generating the body of the response is not an excuse to delay sending the headers.
  44. * Instead you should tie into the asynchronous response architecture, and use techniques such as the isChunked method.
  45. *
  46. * Important: You should read the discussion at the bottom of this header.
  47. **/
  48. - (BOOL)delayResponseHeaders;
  49. /**
  50. * Status code for response.
  51. * Allows for responses such as redirect (301), etc.
  52. **/
  53. - (NSInteger)status;
  54. /**
  55. * If you want to add any extra HTTP headers to the response,
  56. * simply return them in a dictionary in this method.
  57. **/
  58. - (NSDictionary *)httpHeaders;
  59. /**
  60. * If you don't know the content-length in advance,
  61. * implement this method in your custom response class and return YES.
  62. *
  63. * Important: You should read the discussion at the bottom of this header.
  64. **/
  65. - (BOOL)isChunked;
  66. /**
  67. * This method is called from the HTTPConnection class when the connection is closed,
  68. * or when the connection is finished with the response.
  69. * If your response is asynchronous, you should implement this method so you know not to
  70. * invoke any methods on the HTTPConnection after this method is called (as the connection may be deallocated).
  71. **/
  72. - (void)connectionDidClose;
  73. @end
  74. /**
  75. * Important notice to those implementing custom asynchronous and/or chunked responses:
  76. *
  77. * HTTPConnection supports asynchronous responses. All you have to do in your custom response class is
  78. * asynchronously generate the response, and invoke HTTPConnection's responseHasAvailableData method.
  79. * You don't have to wait until you have all of the response ready to invoke this method. For example, if you
  80. * generate the response in incremental chunks, you could call responseHasAvailableData after generating
  81. * each chunk. Please see the HTTPAsyncFileResponse class for an example of how to do this.
  82. *
  83. * The normal flow of events for an HTTPConnection while responding to a request is like this:
  84. * - Send http resopnse headers
  85. * - Get data from response via readDataOfLength method.
  86. * - Add data to asyncSocket's write queue.
  87. * - Wait for asyncSocket to notify it that the data has been sent.
  88. * - Get more data from response via readDataOfLength method.
  89. * - ... continue this cycle until the entire response has been sent.
  90. *
  91. * With an asynchronous response, the flow is a little different.
  92. *
  93. * First the HTTPResponse is given the opportunity to postpone sending the HTTP response headers.
  94. * This allows the response to asynchronously execute any code needed to calculate a part of the header.
  95. * An example might be the response needs to generate some custom header fields,
  96. * or perhaps the response needs to look for a resource on network-attached storage.
  97. * Since the network-attached storage may be slow, the response doesn't know whether to send a 200 or 404 yet.
  98. * In situations such as this, the HTTPResponse simply implements the delayResponseHeaders method and returns YES.
  99. * After returning YES from this method, the HTTPConnection will wait until the response invokes its
  100. * responseHasAvailableData method. After this occurs, the HTTPConnection will again query the delayResponseHeaders
  101. * method to see if the response is ready to send the headers.
  102. * This cycle will continue until the delayResponseHeaders method returns NO.
  103. *
  104. * You should only delay sending the response headers until you have everything you need concerning just the headers.
  105. * Asynchronously generating the body of the response is not an excuse to delay sending the headers.
  106. *
  107. * After the response headers have been sent, the HTTPConnection calls your readDataOfLength method.
  108. * You may or may not have any available data at this point. If you don't, then simply return nil.
  109. * You should later invoke HTTPConnection's responseHasAvailableData when you have data to send.
  110. *
  111. * You don't have to keep track of when you return nil in the readDataOfLength method, or how many times you've invoked
  112. * responseHasAvailableData. Just simply call responseHasAvailableData whenever you've generated new data, and
  113. * return nil in your readDataOfLength whenever you don't have any available data in the requested range.
  114. * HTTPConnection will automatically detect when it should be requesting new data and will act appropriately.
  115. *
  116. * It's important that you also keep in mind that the HTTP server supports range requests.
  117. * The setOffset method is mandatory, and should not be ignored.
  118. * Make sure you take into account the offset within the readDataOfLength method.
  119. * You should also be aware that the HTTPConnection automatically sorts any range requests.
  120. * So if your setOffset method is called with a value of 100, then you can safely release bytes 0-99.
  121. *
  122. * HTTPConnection can also help you keep your memory footprint small.
  123. * Imagine you're dynamically generating a 10 MB response. You probably don't want to load all this data into
  124. * RAM, and sit around waiting for HTTPConnection to slowly send it out over the network. All you need to do
  125. * is pay attention to when HTTPConnection requests more data via readDataOfLength. This is because HTTPConnection
  126. * will never allow asyncSocket's write queue to get much bigger than READ_CHUNKSIZE bytes. You should
  127. * consider how you might be able to take advantage of this fact to generate your asynchronous response on demand,
  128. * while at the same time keeping your memory footprint small, and your application lightning fast.
  129. *
  130. * If you don't know the content-length in advanced, you should also implement the isChunked method.
  131. * This means the response will not include a Content-Length header, and will instead use "Transfer-Encoding: chunked".
  132. * There's a good chance that if your response is asynchronous and dynamic, it's also chunked.
  133. * If your response is chunked, you don't need to worry about range requests.
  134. **/