// HTTPMessage.cpp // Declares the cHTTPMessage class representing the common ancestor for HTTP request and response classes #include "Globals.h" #include "HTTPMessage.h" // Disable MSVC warnings: #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4355) // 'this' : used in base member initializer list #endif //////////////////////////////////////////////////////////////////////////////// // cHTTPMessage: cHTTPMessage::cHTTPMessage(eKind a_Kind) : m_Kind(a_Kind), m_ContentLength(AString::npos) { } void cHTTPMessage::AddHeader(const AString & a_Key, const AString & a_Value) { auto Key = StrToLower(a_Key); auto itr = m_Headers.find(Key); if (itr == m_Headers.end()) { m_Headers[Key] = a_Value; } else { // The header-field key is specified multiple times, combine into comma-separated list (RFC 2616 @ 4.2) itr->second.append(", "); itr->second.append(a_Value); } // Special processing for well-known headers: if (Key == "content-type") { m_ContentType = m_Headers[Key]; } else if (Key == "content-length") { if (!StringToInteger(m_Headers[Key], m_ContentLength)) { m_ContentLength = 0; } } } //////////////////////////////////////////////////////////////////////////////// // cHTTPOutgoingResponse: cHTTPOutgoingResponse::cHTTPOutgoingResponse(void) : Super(mkResponse) { } void cHTTPOutgoingResponse::AppendToData(AString & a_DataStream) const { a_DataStream.append("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: "); a_DataStream.append(m_ContentType); a_DataStream.append("\r\n"); for (auto itr = m_Headers.cbegin(), end = m_Headers.cend(); itr != end; ++itr) { if ((itr->first == "Content-Type") || (itr->first == "Content-Length")) { continue; } a_DataStream.append(itr->first); a_DataStream.append(": "); a_DataStream.append(itr->second); a_DataStream.append("\r\n"); } // for itr - m_Headers[] a_DataStream.append("\r\n"); } //////////////////////////////////////////////////////////////////////////////// // cHTTPIncomingRequest: cHTTPIncomingRequest::cHTTPIncomingRequest(const AString & a_Method, const AString & a_URL): Super(mkRequest), m_Method(a_Method), m_URL(a_URL), m_HasAuth(false) { } AString cHTTPIncomingRequest::GetURLPath(void) const { auto idxQuestionMark = m_URL.find('?'); if (idxQuestionMark == AString::npos) { return m_URL; } else { return m_URL.substr(0, idxQuestionMark); } } void cHTTPIncomingRequest::AddHeader(const AString & a_Key, const AString & a_Value) { if ( (NoCaseCompare(a_Key, "Authorization") == 0) && (strncmp(a_Value.c_str(), "Basic ", 6) == 0) ) { AString UserPass = Base64Decode(a_Value.substr(6)); size_t idxCol = UserPass.find(':'); if (idxCol != AString::npos) { m_AuthUsername = UserPass.substr(0, idxCol); m_AuthPassword = UserPass.substr(idxCol + 1); m_HasAuth = true; } } if ((a_Key == "Connection") && (NoCaseCompare(a_Value, "keep-alive") == 0)) { m_AllowKeepAlive = true; } Super::AddHeader(a_Key, a_Value); }