/http_server/stack/parser/AWSHttpResponseParser.cpp

http://github.com/jtblatt/duderino · C++ · 269 lines · 173 code · 75 blank · 21 comment · 29 complexity · 5c0ec91217ae6a75f7117e16db636e8e MD5 · raw file

  1. /* Copyright (c) 2009 Yahoo! Inc. All rights reserved.
  2. * The copyrights embodied in the content of this file are licensed by Yahoo! Inc.
  3. * under the BSD (revised) open source license.
  4. */
  5. #ifndef AWS_HTTP_RESPONSE_PARSER_H
  6. #include <AWSHttpResponseParser.h>
  7. #endif
  8. #ifndef AWS_HTTP_UTIL_H
  9. #include <AWSHttpUtil.h>
  10. #endif
  11. #ifndef ESF_ASSERT_H
  12. #include <ESFAssert.h>
  13. #endif
  14. #ifndef AWS_HTTP_ERROR_H
  15. #include <AWSHttpError.h>
  16. #endif
  17. #define AWS_PARSING_VERSION (1 << 0)
  18. #define AWS_PARSING_STATUS_CODE (1 << 1)
  19. #define AWS_PARSING_REASON_PHRASE (1 << 2)
  20. #define AWS_PARSE_COMPLETE (1 << 3)
  21. AWSHttpResponseParser::AWSHttpResponseParser(ESFBuffer *workingBuffer, ESFDiscardAllocator *allocator) :
  22. AWSHttpMessageParser(workingBuffer, allocator),
  23. _responseState(0x00)
  24. {
  25. }
  26. AWSHttpResponseParser::~AWSHttpResponseParser()
  27. {
  28. }
  29. void AWSHttpResponseParser::reset()
  30. {
  31. AWSHttpMessageParser::reset();
  32. _responseState = 0x00;
  33. }
  34. ESFError AWSHttpResponseParser::parseStartLine(ESFBuffer *inputBuffer, AWSHttpMessage *message)
  35. {
  36. // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
  37. if (AWS_PARSE_COMPLETE & _responseState)
  38. {
  39. return ESF_INVALID_STATE;
  40. }
  41. if (0x00 == _responseState)
  42. {
  43. _responseState = AWS_PARSING_VERSION;
  44. inputBuffer->readMark();
  45. _workingBuffer->clear();
  46. }
  47. AWSHttpResponse *response = (AWSHttpResponse *) message;
  48. ESFError error = ESF_SUCCESS;
  49. if (AWS_PARSING_VERSION & _responseState)
  50. {
  51. error = parseVersion(inputBuffer, response, true);
  52. if (ESF_SUCCESS != error)
  53. {
  54. return error;
  55. }
  56. _responseState &= ~AWS_PARSING_VERSION;
  57. _responseState |= AWS_PARSING_STATUS_CODE;
  58. inputBuffer->readMark();
  59. _workingBuffer->clear();
  60. }
  61. if (AWS_PARSING_STATUS_CODE & _responseState)
  62. {
  63. error = parseStatusCode(inputBuffer, response);
  64. if (ESF_SUCCESS != error)
  65. {
  66. return error;
  67. }
  68. _responseState &= ~AWS_PARSING_STATUS_CODE;
  69. _responseState |= AWS_PARSING_REASON_PHRASE;
  70. inputBuffer->readMark();
  71. _workingBuffer->clear();
  72. }
  73. if (AWS_PARSING_REASON_PHRASE & _responseState)
  74. {
  75. error = parseReasonPhrase(inputBuffer, response);
  76. if (ESF_SUCCESS != error)
  77. {
  78. return error;
  79. }
  80. _responseState &= ~AWS_PARSING_REASON_PHRASE;
  81. _responseState |= AWS_PARSE_COMPLETE;
  82. inputBuffer->readMark();
  83. _workingBuffer->clear();
  84. return ESF_SUCCESS;
  85. }
  86. return ESF_INVALID_STATE;
  87. }
  88. ESFError AWSHttpResponseParser::parseStatusCode(ESFBuffer *inputBuffer, AWSHttpResponse *response)
  89. {
  90. // Status-Code = 3DIGIT
  91. ESF_ASSERT(AWS_PARSING_STATUS_CODE & _responseState);
  92. // Clients SHOULD be tolerant in parsing the Status-Line and servers
  93. // tolerant when parsing the Request-Line. In particular, they SHOULD
  94. // accept any amount of SP or HT characters between fields, even though
  95. // only a single SP is required.
  96. AWSHttpUtil::SkipSpaces(inputBuffer);
  97. if (4 > inputBuffer->getReadable())
  98. {
  99. return ESF_AGAIN;
  100. }
  101. int statusCode = 0;
  102. unsigned char octet;
  103. for (int i = 0; i < 3; ++i)
  104. {
  105. ESF_ASSERT(inputBuffer->isReadable());
  106. octet = inputBuffer->getNext();
  107. if (false == AWSHttpUtil::IsDigit(octet))
  108. {
  109. return AWS_HTTP_BAD_STATUS_CODE;
  110. }
  111. statusCode = (statusCode * 10) + (octet - '0');
  112. }
  113. ESF_ASSERT(inputBuffer->isReadable());
  114. if (false == AWSHttpUtil::IsSpace(inputBuffer->getNext()))
  115. {
  116. return AWS_HTTP_BAD_STATUS_CODE;
  117. }
  118. response->setStatusCode(statusCode);
  119. return ESF_SUCCESS;
  120. }
  121. ESFError AWSHttpResponseParser::parseReasonPhrase(ESFBuffer *inputBuffer, AWSHttpResponse *response)
  122. {
  123. // Reason-Phrase = *<TEXT, excluding CR, LF>
  124. ESF_ASSERT(AWS_PARSING_REASON_PHRASE & _responseState);
  125. ESFError error;
  126. unsigned char octet;
  127. while (true)
  128. {
  129. if (false == inputBuffer->isReadable())
  130. {
  131. return ESF_AGAIN;
  132. }
  133. if (false == _workingBuffer->isWritable())
  134. {
  135. return ESF_OVERFLOW;
  136. }
  137. octet = inputBuffer->getNext();
  138. if (AWSHttpUtil::IsLWS(octet))
  139. {
  140. inputBuffer->setReadPosition(inputBuffer->getReadPosition() - 1);
  141. error = AWSHttpUtil::SkipLWS(inputBuffer);
  142. switch (error)
  143. {
  144. case ESF_SUCCESS:
  145. // newline encountered - save reason phrase
  146. {
  147. unsigned char *reasonPhrase = _workingBuffer->duplicate(_allocator, true); // trims trailing whitespace
  148. if (! reasonPhrase)
  149. {
  150. return ESF_OUT_OF_MEMORY;
  151. }
  152. response->setReasonPhrase(reasonPhrase);
  153. }
  154. return ESF_SUCCESS;
  155. case ESF_INPROGRESS:
  156. // LWS encountered - replace with a single space & trim leading white space
  157. if (0 < _workingBuffer->getWritePosition())
  158. {
  159. _workingBuffer->putNext(' ');
  160. }
  161. break;
  162. default:
  163. return error;
  164. }
  165. continue;
  166. }
  167. if (AWSHttpUtil::IsText(octet))
  168. {
  169. _workingBuffer->putNext(octet);
  170. continue;
  171. }
  172. return AWS_HTTP_BAD_REASON_PHRASE;
  173. }
  174. }
  175. bool AWSHttpResponseParser::isBodyNotAllowed(AWSHttpMessage *message)
  176. {
  177. // For response messages, whether or not a message-body is included with
  178. // a message is dependent on both the request method and the response
  179. // status code (section 6.1.1). All responses to the HEAD request method
  180. // MUST NOT include a message-body, even though the presence of entity-
  181. // header fields might lead one to believe they do. All 1xx
  182. // (informational), 204 (no content), and 304 (not modified) responses
  183. // MUST NOT include a message-body. All other responses do include a
  184. // message-body, although it MAY be of zero length
  185. AWSHttpResponse *response = (AWSHttpResponse *) message;
  186. switch (response->getStatusCode())
  187. {
  188. case 204:
  189. case 304:
  190. return true;
  191. default:
  192. return 200 <= response->getStatusCode();
  193. }
  194. }