PageRenderTime 22ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/http/chunked.cpp

http://github.com/mozy/mordor
C++ | 97 lines | 85 code | 11 blank | 1 comment | 22 complexity | 2e4c54f8caa90c0453b36b2f1e50bff5 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "chunked.h"
  3. #include <sstream>
  4. #include <stdexcept>
  5. #include "mordor/assert.h"
  6. #include "mordor/streams/buffer.h"
  7. #include "mordor/version.h"
  8. namespace Mordor {
  9. namespace HTTP {
  10. static Logger::ptr g_log = Log::lookup("mordor:http:chunked");
  11. InvalidChunkException::InvalidChunkException(const std::string &line,
  12. Type type)
  13. : m_line(line),
  14. m_type(type)
  15. {}
  16. ChunkedStream::ChunkedStream(Stream::ptr parent, bool own)
  17. : MutatingFilterStream(parent, own),
  18. m_nextChunk(~0)
  19. {
  20. if (parent->supportsRead())
  21. MORDOR_ASSERT(parent->supportsFind());
  22. }
  23. void
  24. ChunkedStream::close(Stream::CloseType type)
  25. {
  26. if (supportsWrite() && (type & WRITE)) {
  27. MORDOR_LOG_VERBOSE(g_log) << this << " writing EOF";
  28. parent()->write("0\r\n", 3);
  29. }
  30. if (ownsParent())
  31. parent()->close(type);
  32. }
  33. size_t
  34. ChunkedStream::read(Buffer &b, size_t len)
  35. {
  36. if (m_nextChunk == ~0ull - 1) {
  37. std::string chunk = parent()->getDelimited();
  38. MORDOR_ASSERT(!chunk.empty());
  39. chunk.resize(chunk.size() - 1);
  40. if (!chunk.empty() && chunk[chunk.size() - 1] == '\r')
  41. chunk.resize(chunk.size() - 1);
  42. MORDOR_LOG_TRACE(g_log) << this << " read CRLF '" << chunk << "'";
  43. if (!chunk.empty())
  44. MORDOR_THROW_EXCEPTION(InvalidChunkException(chunk, InvalidChunkException::FOOTER));
  45. m_nextChunk = ~0;
  46. }
  47. if (m_nextChunk == ~0ull) {
  48. std::string chunk = parent()->getDelimited();
  49. MORDOR_ASSERT(!chunk.empty());
  50. chunk.resize(chunk.size() - 1);
  51. if (!chunk.empty() && chunk[chunk.size() - 1] == '\r')
  52. chunk.resize(chunk.size() - 1);
  53. MORDOR_LOG_DEBUG(g_log) << this << " read chunk header '" << chunk
  54. << "'";
  55. char *end;
  56. m_nextChunk = strtoull(chunk.c_str(), &end, 16);
  57. if (end == chunk.c_str())
  58. MORDOR_THROW_EXCEPTION(InvalidChunkException(chunk, InvalidChunkException::HEADER));
  59. }
  60. if (m_nextChunk == 0)
  61. return 0;
  62. size_t toRead = (size_t)std::min<unsigned long long>(len, m_nextChunk);
  63. size_t result = parent()->read(b, toRead);
  64. m_nextChunk -= result;
  65. if (m_nextChunk == 0)
  66. m_nextChunk = ~0ull - 1;
  67. return result;
  68. }
  69. size_t
  70. ChunkedStream::write(const Buffer &b, size_t len)
  71. {
  72. std::ostringstream os;
  73. os << std::hex << len << "\r\n";
  74. std::string str = os.str();
  75. MORDOR_LOG_DEBUG(g_log) << this << " writing chunk header " << str;
  76. parent()->write(str.c_str(), str.size());
  77. Buffer copy;
  78. copy.copyIn(b, len);
  79. while (copy.readAvailable()) {
  80. size_t result = parent()->write(copy, copy.readAvailable());
  81. copy.consume(result);
  82. }
  83. parent()->write("\r\n", 2);
  84. return len;
  85. }
  86. }}