2323#include < format>
2424#include < memory>
2525#include < print>
26+ #include < ranges>
2627
2728#include < cctype> // to std::tolower
29+ #include < charconv>
2830
2931
3032HTTPMessage::HTTPMessage () : ByteBuffer(4096 ) {
@@ -136,19 +138,19 @@ std::string HTTPMessage::getStrElement(char delim) {
136138 if (startPos > endPos)
137139 return " " ;
138140
139- // Calculate the size based on the found ending position
140- uint32_t size = (endPos + 1 ) - startPos;
141- if (size < = 0 )
141+ // Token spans [startPos, endPos); delimiter sits at endPos
142+ uint32_t tokenLen = static_cast < uint32_t > (endPos - startPos) ;
143+ if (tokenLen = = 0 )
142144 return " " ;
143145
144- // Grab the std::string from the ByteBuffer up to the delimiter
145- auto str = std::make_unique<char []>(size );
146- getBytes (( uint8_t *) str.get (), size );
147- str[size - 1 ] = 0x00 ; // NULL termination
148- std::string ret = str.get ();
146+ // Grab the token bytes (excludes delimiter), then step past the delimiter
147+ auto str = std::make_unique<char []>(tokenLen + 1 );
148+ getBytes (reinterpret_cast < uint8_t *>( str.get ()), tokenLen );
149+ str[tokenLen ] = ' \0 ' ;
150+ std::string ret ( str.get (), tokenLen );
149151
150- // Increment the read position PAST the delimiter
151- setReadPos (endPos + 1 );
152+ // Advance the read position past the delimiter
153+ setReadPos (static_cast < uint32_t >( endPos) + 1 );
152154
153155 return ret;
154156}
@@ -170,7 +172,7 @@ void HTTPMessage::parseHeaders() {
170172 while (hline.size () > 0 ) {
171173 // Case where values are on multiple lines ending with a comma
172174 app = hline;
173- while (app[app.size () - 1 ] == ' ,' ) {
175+ while (!app. empty () && app[app.size () - 1 ] == ' ,' ) {
174176 app = getLine ();
175177 hline += app;
176178 }
@@ -196,16 +198,26 @@ bool HTTPMessage::parseBody() {
196198 return true ;
197199
198200 uint32_t remainingLen = bytesRemaining ();
199- uint32_t contentLen = atoi (hlenstr.c_str ());
201+ uint32_t contentLen = 0 ;
202+ {
203+ auto [ptr, ec] = std::from_chars (hlenstr.data (), hlenstr.data () + hlenstr.size (), contentLen);
204+ if (ec != std::errc{}) {
205+ parseErrorStr = std::format (" Invalid Content-Length value: {}" , hlenstr);
206+ this ->dataLen = 0 ;
207+ return false ;
208+ }
209+ }
200210
201211 // contentLen should NOT exceed the remaining number of bytes in the buffer
202212 // Add 1 to bytesRemaining so it includes the byte at the current read position
203- if (contentLen > remainingLen + 1 ) {
213+ if (static_cast < uint64_t >( contentLen) > static_cast < uint64_t >( remainingLen) + 1 ) {
204214 // If it exceeds, there's a potential security issue and we can't reliably parse
205215 parseErrorStr = std::format (" Content-Length ({}) is greater than remaining bytes ({})" , hlenstr, remainingLen);
216+ this ->dataLen = 0 ;
206217 return false ;
207218 } else if (remainingLen > contentLen) {
208219 parseErrorStr = std::format (" ByteBuffer remaining size to read ({}) is greater than provided Content-Length {}" , remainingLen, contentLen);
220+ this ->dataLen = 0 ;
209221 return false ;
210222 } else if (contentLen == 0 ) {
211223 // Nothing to read, which is fine
@@ -215,15 +227,9 @@ bool HTTPMessage::parseBody() {
215227 this ->dataLen = contentLen;
216228 }
217229
218- // Create a big enough buffer to store the data
219- this ->data = new uint8_t [this ->dataLen ];
220-
221- // Grab all the bytes from the current position to the end
222- uint32_t dIdx = 0 ;
223- for (uint32_t i = getReadPos (); i < remainingLen; i++) {
224- this ->data [dIdx] = get (i);
225- dIdx++;
226- }
230+ // Create a big enough buffer to store the data and read from the current position
231+ this ->data = std::make_unique<uint8_t []>(this ->dataLen );
232+ getBytes (this ->data .get (), this ->dataLen );
227233
228234 // We could handle chunked Request/Response parsing (with footers) here, but, we won't.
229235
@@ -262,7 +268,7 @@ void HTTPMessage::addHeader(std::string const& line) {
262268
263269 // Skip all leading spaces in the value
264270 int32_t i = 0 ;
265- while (i < value.size () && value. at (i) == 0x20 ) {
271+ while (i < static_cast < int32_t >( value.size ()) && value[i] == 0x20 ) {
266272 i++;
267273 }
268274 value = value.substr (i, value.size ());
@@ -308,9 +314,9 @@ std::string HTTPMessage::getHeaderValue(std::string const& key) const {
308314 // Key wasn't found, try an all lowercase variant as some clients won't always use proper capitalization
309315 if (it == headers.end ()) {
310316
311- auto key_lower = std::string ( key);
312- std::ranges ::transform (key_lower. begin (), key_lower. end (), key_lower. begin (),
313- []( unsigned char c){ return std::tolower (c); } );
317+ auto key_lower = key
318+ | std::views ::transform ([]( unsigned char c){ return std::tolower (c); })
319+ | std::ranges::to<std::string>( );
314320
315321 // Still not found, return empty string to indicate the Header value doesnt exist
316322 it = headers.find (key_lower);
@@ -360,4 +366,3 @@ uint32_t HTTPMessage::getNumHeaders() const {
360366void HTTPMessage::clearHeaders () {
361367 headers.clear ();
362368}
363-
0 commit comments