* Reads data from a stream in netstring format. * * @param stream The stream to read from. * @param[out] str The String that has been read from the IOQueue. * @returns true if a complete String was read from the IOQueue, false otherwise. * @exception invalid_argument The input stream is invalid. * @see https://github.com/PeterScott/netstring-c/blob/master/netstring.c */
| 25 | * @see https://github.com/PeterScott/netstring-c/blob/master/netstring.c |
| 26 | */ |
| 27 | StreamReadStatus NetString::ReadStringFromStream(const Stream::Ptr& stream, String *str, StreamReadContext& context, |
| 28 | bool may_wait, ssize_t maxMessageLength) |
| 29 | { |
| 30 | if (context.Eof) |
| 31 | return StatusEof; |
| 32 | |
| 33 | if (context.MustRead) { |
| 34 | if (!context.FillFromStream(stream, may_wait)) { |
| 35 | context.Eof = true; |
| 36 | return StatusEof; |
| 37 | } |
| 38 | |
| 39 | context.MustRead = false; |
| 40 | } |
| 41 | |
| 42 | size_t header_length = 0; |
| 43 | |
| 44 | for (size_t i = 0; i < context.Size; i++) { |
| 45 | if (context.Buffer[i] == ':') { |
| 46 | header_length = i; |
| 47 | |
| 48 | /* make sure there's a header */ |
| 49 | if (header_length == 0) |
| 50 | BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (no length specifier)")); |
| 51 | |
| 52 | break; |
| 53 | } else if (i > 16) |
| 54 | BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (missing :)")); |
| 55 | } |
| 56 | |
| 57 | if (header_length == 0) { |
| 58 | context.MustRead = true; |
| 59 | return StatusNeedData; |
| 60 | } |
| 61 | |
| 62 | /* no leading zeros allowed */ |
| 63 | if (context.Buffer[0] == '0' && isdigit(context.Buffer[1])) |
| 64 | BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (leading zero)")); |
| 65 | |
| 66 | size_t len, i; |
| 67 | |
| 68 | len = 0; |
| 69 | for (i = 0; i < header_length && isdigit(context.Buffer[i]); i++) { |
| 70 | /* length specifier must have at most 9 characters */ |
| 71 | if (i >= 9) |
| 72 | BOOST_THROW_EXCEPTION(std::invalid_argument("Length specifier must not exceed 9 characters")); |
| 73 | |
| 74 | len = len * 10 + (context.Buffer[i] - '0'); |
| 75 | } |
| 76 | |
| 77 | /* read the whole message */ |
| 78 | size_t data_length = len + 1; |
| 79 | |
| 80 | if (maxMessageLength >= 0 && data_length > (size_t)maxMessageLength) { |
| 81 | std::stringstream errorMessage; |
| 82 | errorMessage << "Max data length exceeded: " << (maxMessageLength / 1024) << " KB"; |
| 83 | |
| 84 | BOOST_THROW_EXCEPTION(std::invalid_argument(errorMessage.str())); |