📄 ghttp.cpp
字号:
{ if(m_status != Done) { GimmeWhatYouGot(); if(m_status == Done) { //GAssert(false, "todo: why are we giving it out early?"); } } if(m_status != Done) { // it's really not done, so don't return anything [rdp] *pnSize = 0; return NULL; } *pnSize = m_nContentSize; return m_pData;}unsigned char* GHttpClient::DropData(int* pnSize){ unsigned char* pData = GetData(pnSize); if(!pData) return NULL; m_pData = NULL; return pData;}// -----------------------------------------------------------------------class GHttpServerBuffer{public: enum RequestType { None, Get, Head, Post, }; int m_nPos; char m_szLine[MAX_SERVER_LINE_SIZE]; char m_szUrl[MAX_SERVER_LINE_SIZE]; char m_szParams[MAX_SERVER_LINE_SIZE]; char m_szDate[MAX_SERVER_LINE_SIZE]; char m_szCookie[MAX_COOKIE_SIZE]; unsigned char* m_pPostBuffer; RequestType m_eRequestType; int m_nContentLength; GHttpServerBuffer() { m_eRequestType = None; m_nPos = 0; m_nContentLength = 0; m_pPostBuffer = NULL; } ~GHttpServerBuffer() { delete[] m_pPostBuffer; } void Reset() { m_szUrl[0] = '\0'; m_szParams[0] = '\0'; m_szDate[0] = '\0'; m_szCookie[0] = '\0'; m_nContentLength = 0; delete[] m_pPostBuffer; m_pPostBuffer = NULL; }};GHttpServer::GHttpServer(int nPort){ m_pBuffers = new GPointerArray(16); m_pSocket = GSocketServer::HostTCPSocket(nPort); if(!m_pSocket) throw("failed to open port"); m_pQ = new GQueue(); SetContentType("text/html"); SetCookie("", false); m_time = 0;}GHttpServer::~GHttpServer(){ int nCount = m_pBuffers->GetSize(); int n; for(n = 0; n < nCount; n++) delete((GHttpServerBuffer*)m_pBuffers->GetPointer(n)); delete(m_pBuffers); delete(m_pSocket); delete(m_pQ);}bool GHttpServer::Process(){ int nMessageSize; int nConnection; unsigned char* pMessage; unsigned char* pIn; char c; GHttpServerBuffer* pBuffer; bool bDidSomething = false; while(m_pSocket->GetMessageCount() > 0) { bDidSomething = true; pMessage = m_pSocket->GetNextMessage(&nMessageSize, &nConnection); pIn = pMessage; while(m_pBuffers->GetSize() <= nConnection) m_pBuffers->AddPointer(new GHttpServerBuffer()); pBuffer = (GHttpServerBuffer*)m_pBuffers->GetPointer(nConnection); while(nMessageSize > 0) { if(pBuffer->m_pPostBuffer) { ProcessPostData(nConnection, pBuffer, pIn, nMessageSize); break; } else { // Obtain a single header line while(nMessageSize > 0) { c = *pIn; pBuffer->m_szLine[pBuffer->m_nPos++] = c; pIn++; nMessageSize--; if(c == '\n' || pBuffer->m_nPos >= MAX_SERVER_LINE_SIZE - 1) { pBuffer->m_szLine[pBuffer->m_nPos] = '\0'; ProcessHeaderLine(nConnection, pBuffer, pBuffer->m_szLine); pBuffer->m_nPos = 0; break; } } } } delete(pMessage); } return bDidSomething;}void GHttpServer::BeginRequest(GHttpServerBuffer* pClient, int eType, const char* szIn){ pClient->Reset(); pClient->m_eRequestType = (GHttpServerBuffer::RequestType)eType; char* szOut = pClient->m_szUrl; while(*szIn > ' ' && *szIn != '?') { *szOut = *szIn; szIn++; szOut++; } *szOut = '\0'; if(eType == GHttpServerBuffer::Get && *szIn == '?') { szIn++; szOut = pClient->m_szParams; while(*szIn > ' ') { *szOut = *szIn; szIn++; szOut++; } *szOut = '\0'; } else pClient->m_szParams[0] = '\0';}void GHttpServer::ProcessPostData(int nConnection, GHttpServerBuffer* pClient, const unsigned char* pData, int nDataSize){ if(nDataSize > pClient->m_nContentLength - pClient->m_nPos) nDataSize = pClient->m_nContentLength - pClient->m_nPos; memcpy(pClient->m_pPostBuffer + pClient->m_nPos, pData, nDataSize); pClient->m_nPos += nDataSize; if(pClient->m_nPos >= pClient->m_nContentLength) { pClient->m_pPostBuffer[pClient->m_nContentLength] = '\0'; char* szCookie = NULL; if(pClient->m_szCookie[0] != '\0') szCookie = pClient->m_szCookie; m_time = 0; DoPost(pClient->m_szUrl, pClient->m_pPostBuffer, pClient->m_nContentLength, szCookie, m_pQ); pClient->m_pPostBuffer = NULL; pClient->m_nPos = 0; SendResponse(pClient, nConnection); }}#define MAX_POST_SIZE 49152void GHttpServer::ProcessHeaderLine(int nConnection, GHttpServerBuffer* pClient, const char* szLine){ OnProcessLine(nConnection, szLine); // Skip whitespace while(*szLine > '\0' && *szLine <= ' ') szLine++; if(*szLine == '\0') { if(pClient->m_eRequestType == GHttpServerBuffer::Get) { bool bModified = true; if(pClient->m_szDate[0] != '\0') bModified = HasBeenModifiedSince(pClient->m_szUrl, pClient->m_szDate); if(bModified) { char* szCookie = NULL; if(pClient->m_szCookie[0] != '\0') szCookie = pClient->m_szCookie; m_time = 0; DoGet(pClient->m_szUrl, pClient->m_szParams, strlen(pClient->m_szParams), szCookie, m_pQ); SendResponse(pClient, nConnection); } else SendNotModifiedResponse(pClient, nConnection); } else if(pClient->m_eRequestType == GHttpServerBuffer::Head) { m_time = 0; SetHeaders(pClient->m_szUrl, pClient->m_szParams); SendResponse(pClient, nConnection); } else if(pClient->m_eRequestType == GHttpServerBuffer::Post) { if(pClient->m_nContentLength >= 0 && pClient->m_nContentLength <= MAX_POST_SIZE) { if(pClient->m_nContentLength > 0) pClient->m_pPostBuffer = new unsigned char[pClient->m_nContentLength + 1]; else pClient->m_pPostBuffer = NULL; pClient->m_nPos = 0; } else { GAssert(false, "bad post data size"); m_pSocket->Disconnect(nConnection); } } } else if(strnicmp(szLine, "GET ", 4) == 0) BeginRequest(pClient, GHttpServerBuffer::Get, szLine + 4); else if(strnicmp(szLine, "HEAD ", 5) == 0) BeginRequest(pClient, GHttpServerBuffer::Head, szLine + 5); else if(strnicmp(szLine, "POST ", 5) == 0) BeginRequest(pClient, GHttpServerBuffer::Post, szLine + 5); else if(strnicmp(szLine, "Content-Length: ", 16) == 0) pClient->m_nContentLength = atoi(szLine + 16); else if(strnicmp(szLine, "Cookie: ", 8) == 0) { int i = 17; // strlen("Cookie: attribute") while(szLine[i] != '=' && szLine[i] != '\0') i++; if(szLine[i] == '=') i++; strcpy(pClient->m_szCookie, szLine + i); } else if(strnicmp(szLine, "If-Modified-Since: ", 19) == 0) { const char* szIn = szLine + 19; char* szOut = pClient->m_szDate; while(*szIn >= ' ') { *szOut = *szIn; szIn++; szOut++; } *szOut = '\0'; }}void GHttpServer::SetContentType(const char* szContentType){ GString::StrCpy(m_szContentType, szContentType, 64);}void GHttpServer::SetCookie(const char* szPayload, bool bPersist){ m_bPersistCookie = bPersist; GString::StrCpy(m_szCookie, szPayload, MAX_COOKIE_SIZE);}void AscTimeToGMT(const char* szIn, char* szOut){ // Copy the day while(*szIn > ' ') *(szOut++) = *(szIn++); *(szOut++) = ','; *(szOut++) = ' '; while(*szIn == ' ') szIn++; // Copy the day of the month const char* pMonth = szIn; while(*szIn > ' ') szIn++; while(*szIn == ' ') szIn++; while(*szIn > ' ') *(szOut++) = *(szIn++); *(szOut++) = ' '; while(*szIn == ' ') szIn++; const char* pTime = szIn; // Copy the month while(*pMonth > ' ') *(szOut++) = *(pMonth++); *(szOut++) = ' '; // Copy the year while(*szIn > ' ') szIn++; while(*szIn == ' ') szIn++; while(*szIn > ' ') *(szOut++) = *(szIn++); *(szOut++) = ' '; // Copy the time while(*pTime > ' ') *(szOut++) = *(pTime++); *(szOut++) = ' '; // Add "GMT" strcpy(szOut, "GMT");}void GHttpServer::SendResponse(GHttpServerBuffer* pClient, int nConnection){ // Make the header GQueue q; q.Push("HTTP/1.1 200 OK\r\nContent-Type: "); q.Push(m_szContentType); if(pClient->m_eRequestType != GHttpServerBuffer::Head) { q.Push("\r\nContent-Length: "); char szPayloadSize[32]; itoa(m_pQ->GetSize(), szPayloadSize, 10); q.Push(szPayloadSize); q.Push("\r\n"); } // Set the date header if(m_time != 0) { q.Push("Date: "); struct tm* pTime = gmtime(&m_time); const char* szAscTime = asctime(pTime); char szGMT[40]; AscTimeToGMT(szAscTime, szGMT); q.Push(szGMT); q.Push("\r\n"); } // Set cookie if(m_szCookie[0] != '\0') { q.Push("Set-Cookie: attribute="); q.Push(m_szCookie); q.Push("; path=/"); if(m_bPersistCookie) q.Push("; expires=Sat, 01-Jan-2050 00:00:00 GMT"); q.Push("\r\n"); } // Send it q.Push("\r\n"); // blank line int nHeaderSize = q.GetSize(); int nPayloadSize = (pClient->m_eRequestType == GHttpServerBuffer::Head ? 0 : m_pQ->GetSize()); char* pSendBuffer = new char[nHeaderSize + nPayloadSize]; ArrayHolder<char*> hSendBuffer(pSendBuffer); q.Pop((unsigned char*)pSendBuffer, nHeaderSize); if(pClient->m_eRequestType != GHttpServerBuffer::Head) m_pQ->Pop((unsigned char*)pSendBuffer + nHeaderSize, nPayloadSize); m_pSocket->Send(pSendBuffer, nHeaderSize + nPayloadSize, nConnection);}void GHttpServer::SendNotModifiedResponse(GHttpServerBuffer* pClient, int nConnection){ GQueue q; q.Push("HTTP/1.1 304 Not Modified\r\nDate: "); q.Push(pClient->m_szDate); q.Push("\r\n\r\n"); int nSize = q.GetSize(); char* szHeader = q.DumpToString(); ArrayHolder<char*> hHeader(szHeader); m_pSocket->Send(szHeader, nSize, nConnection);}/*static*/ void GHttpServer::UnescapeUrl(char* szOut, const char* szIn){ int c1, c2, n1, n2; while(*szIn != '\0') { if(*szIn == '%') { szIn++; n1 = *szIn; szIn++; n2 = *szIn; if(n1 >= '0' && n1 <= '9') c1 = n1 - '0'; else if(n1 >= 'a' && n1 <= 'z') c1 = n1 - 'a' + 10; else if(n1 >= 'A' && n1 <= 'Z') c1 = n1 - 'A' + 10; else c1 = 2; if(n2 >= '0' && n2 <= '9') c2 = n2 - '0'; else if(n2 >= 'a' && n2 <= 'z') c2 = n2 - 'a' + 10; else if(n2 >= 'A' && n2 <= 'Z') c2 = n2 - 'A' + 10; else c2 = 0; *szOut = 16 * c1 + c2; } else if(*szIn == '+') *szOut = ' '; else *szOut = *szIn; szIn++; szOut++; } *szOut = '\0';}/*static*/ void GHttpServer::ParseParams(GStringHeap* pStringHeap, GConstStringHashTable* pTable, const char* szParams){ GTEMPBUF(char, szTmp, strlen(szParams) + 1); UnescapeUrl(szTmp, szParams); int nNameStart = 0; int nNameLen, nValueStart, nValueLen; while(true) { for(nNameLen = 0; szTmp[nNameStart + nNameLen] != '=' && szTmp[nNameStart + nNameLen] != '\0'; nNameLen++) { } if(szTmp[nNameStart + nNameLen] == '\0') return; nValueStart = nNameStart + nNameLen + 1; for(nValueLen = 0; szTmp[nValueStart + nValueLen] != '&' && szTmp[nValueStart + nValueLen] != '\0'; nValueLen++) { } const char* szName = pStringHeap->Add(&szTmp[nNameStart], nNameLen); const char* szValue = pStringHeap->Add(&szTmp[nValueStart], nValueLen); pTable->Add(szName, szValue); if(szTmp[nValueStart + nValueLen] == '\0') return; nNameStart = nValueStart + nValueLen + 1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -