?
Ich zeig dir mal wie ich das in C++ gemacht gemacht habe. Ist aber nicht so gut getestet. An die Funktion processChunk kannst du den Puffer den dir recv befüllt hat übergeben.
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
class LineBuffer
{
public:
LineBuffer(std::size_t maximumLineLength)
: maximumLineLength_(maximumLineLength)
, isLineComplete_(false)
{
}
std::size_t consumeChunk(const char* pBuffer, std::size_t bufferSize)
{
if(isLineComplete_) { return 0; }
std::size_t newlineCharacterPosition;
bool newlineCharacterFound = findNewlineCharacter(pBuffer, bufferSize, newlineCharacterPosition);
std::size_t bytesToConsume = newlineCharacterFound ? newlineCharacterPosition + 1 : bufferSize;
if(line_.length() + bytesToConsume > maximumLineLength_)
{
throw LineTooLongException();
}
line_ += std::string(pBuffer, bytesToConsume);
if(newlineCharacterFound)
{
isLineComplete_ = true;
removeLineTerminator();
}
return bytesToConsume;
}
bool isLineComplete() const
{
return isLineComplete_;
}
const std::string& getLine() const
{
return line_;
}
void reset()
{
line_.erase();
isLineComplete_ = false;
}
private:
std::size_t getLineTerminatorLength() const
{
assert(isLineComplete());
assert(line_.length() >= 1 && line_[line_.length() - 1] == '\n');
if(line_.length() >= 2 && line_[line_.length() - 2] == '\r')
{
return 2;
}
else
{
return 1;
}
}
void removeLineTerminator()
{
assert(isLineComplete());
line_.erase(line_.length() - getLineTerminatorLength(), std::string::npos);
}
bool findNewlineCharacter(const char* pBuffer,
std::size_t bufferSize,
std::size_t& newlineCharacterPosition) const
{
const char* pNewlineCharacter = static_cast<const char*>(std::memchr(pBuffer, '\n', bufferSize));
if(pNewlineCharacter == NULL)
{
return false;
}
else
{
newlineCharacterPosition = pNewlineCharacter - pBuffer;
return true;
}
}
private:
std::string line_;
bool isLineComplete_;
const std::size_t maximumLineLength_;
public:
class LineTooLongException
{
};
};
LineBuffer lineBuffer(4096);
enum State
{
HEADERS,
BODY
};
State state = HEADERS;
void processLine(const std::string& line)
{
if(line.empty())
{
state = BODY;
}
/*else
{
std::cout << "|" << line << "|" << std::endl;
}*/
}
std::size_t processLineChunk(const char* pBuffer, std::size_t bufferSize)
{
std::size_t bytesConsumed = lineBuffer.consumeChunk(pBuffer, bufferSize);
if(lineBuffer.isLineComplete())
{
processLine(lineBuffer.getLine());
lineBuffer.reset();
}
return bytesConsumed;
}
std::size_t processBodyChunk(const char* pBuffer, std::size_t bufferSize)
{
std::cout << std::string(pBuffer, bufferSize);
return bufferSize;
}
void processChunk(const char* pBuffer, std::size_t bufferSize)
{
std::size_t totalBytesConsumed = 0;
while(totalBytesConsumed < bufferSize)
{
switch(state)
{
case HEADERS:
totalBytesConsumed += processLineChunk(pBuffer + totalBytesConsumed, bufferSize - totalBytesConsumed);
break;
case BODY:
totalBytesConsumed += processBodyChunk(pBuffer + totalBytesConsumed, bufferSize - totalBytesConsumed);
break;
}
}
}
int main()
{
try
{
std::string input = "HTTP/1.1 200 OK\r\n"
"Server: Apache\r\n"
"Connection: close\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html>Hallo Welt</html>";
processChunk(input.data(), input.length());
}
catch(LineBuffer::LineTooLongException&)
{
std::cout << "Line too long" << std::endl;
}
}