#include #include #include "http.h" #include "hashfunctionstring.h" Http::Http( Connection *pConnection ) : hReqHeader( new HashFunctionString(), 100 ) { pCon = pConnection; nParseState = parseInit; } Http::~Http() { for( int j = 0; j < lStrings.getSize(); j++ ) { delete (std::string *)lStrings[j]; } } bool Http::parseRequest() { for(;;) { pCon->readInput(); switch( nParseState ) { case parseInit: { int nLen = pCon->scanInputFor( CR ); if( nLen == -1 ) { return false; } else { nReqType = getRequestType( pCon->getInput() ); pCon->usedInput( pCon->scanInputFor(' ')+1 ); nLen = pCon->scanInputFor(' '); sReqURI.append( pCon->getInput(), nLen ); pCon->usedInput( nLen+1 ); if( !strncmp( pCon->getInput(), "HTTP/", 5 ) ) { char mbuf[2]={'\0','\0'}; unsigned char major, minor; pCon->usedInput( 5 ); mbuf[0] = pCon->getInput()[0]; major = (unsigned char)atoi(mbuf); mbuf[0] = pCon->getInput()[2]; minor = (unsigned char)atoi(mbuf); setRequestVersion( major, minor ); if( checkRequestVer() ) { nParseState = parseHeader; } else { setResponseStatus( statusHTTPVersionNotSupported ); //printf("Verson not supported.\n"); return true; } pCon->usedInput( 5 ); } else { setResponseStatus( statusBadRequest ); } //return false; } } break; case parseHeader: { int nLen = pCon->scanInputFor( CR ); //printf("nLen = %d: :::%s:::\n", nLen, pCon->getInput() ); if( nLen == -1 ) { pCon->readInput( 1, 0); } else if( nLen == 0 ) { // We've got our double-newline, time for content. pCon->usedInput( 2 ); setResponseStatus( statusOK ); return true; } else { nLen = pCon->scanInputFor(':'); if( nLen == -1 ) { //printf("No colon? what are you trying to pull?\n"); } else { std::string *pName = new std::string( pCon->getInput(), nLen ); lStrings.append( pName ); pCon->usedInput( nLen+1 ); nLen = pCon->scanInputFor( CR ); std::string *pValue = convSpaceString( pCon->getInput(), nLen ); lStrings.append( pValue ); pCon->usedInput( nLen+2 ); hReqHeader.insert( pName->c_str(), pValue->c_str() ); //printf("::%s = \"%s\"\n", // pName->c_str(), // pValue->c_str() // ); } } } break; case parseFinished: break; } } } bool Http::buildResponse( short nResponseCode, const char *sResponse ) { if( nResponseCode > 0 ) { nResStatus = nResponseCode; } if( sResponse == NULL ) { sResStatusStr = "uh yeah"; } else { sResStatusStr = sResponse; } time_t curTime; time( &curTime ); gmtime_r( &curTime, &tResTime ); sServerStr = "libbu++ Http/0.0.1"; bResPersistant = false; //char buf[30]; //strftime( buf, 30, "%a, %d %b %Y %H:%M:%S GMT", &tResponseTime ); return true; } bool Http::sendResponse() { char buf[256]; sprintf( buf, "HTTP/1.1 %d %s\r\n", nResStatus, sResStatusStr.c_str() ); pCon->appendOutput( buf ); strftime( buf, 256, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", &tResTime ); pCon->appendOutput( buf ); sprintf( buf, "Server: %s\r\n", sServerStr.c_str() ); pCon->appendOutput( buf ); if( bResPersistant ) { } else { pCon->appendOutput("Connection: close\r\n"); } sprintf( buf, "Content-Type: %s\r\n", sResMime.c_str() ); pCon->appendOutput( buf ); sprintf( buf, "Content-Length: %d\r\n", sResContent.size() ); pCon->appendOutput( buf ); pCon->appendOutput("\r\n"); pCon->appendOutput( sResContent.c_str(), sResContent.size() ); return true; } void Http::setResponsePersistant( bool bPersistant ) { bResPersistant = bPersistant; } void Http::setResponseContent( const char *sMime, const char *sContent, int nLen ) { sResMime = sMime; sResContent.erase(); sResContent.append( sContent, nLen ); } std::string *Http::convSpaceString( const char *sStr, int nLen ) { int nNewLen = 0; bool bStart = true; bool bSpace = false; for( int j = 0; j < nLen; j++ ) { if( sStr[j] == ' ' || sStr[j] == '\t' ) { if( bStart ) { } else if( bSpace == false ) { bSpace = true; nNewLen++; } } else { bStart = false; bSpace = false; nNewLen++; } } if( bSpace ) { nNewLen--; } std::string *pSStr = new std::string; //char *pStr = pSStr->c_str(); nNewLen = 0; bStart = true; bSpace = false; for( int j = 0; j < nLen; j++ ) { if( sStr[j] == ' ' || sStr[j] == '\t' ) { if( bStart ) { } else if( bSpace == false ) { bSpace = true; *pSStr += ' '; //pStr[nNewLen++] = ' '; } } else { bStart = false; bSpace = false; *pSStr += sStr[j]; //pStr[nNewLen++] = sStr[j]; } } if( bSpace == true ) { nNewLen--; // pStr[nNewLen] = '\0'; } return pSStr; } const char *Http::getRequestURI() { return sReqURI.c_str(); } short Http::getRequestType( const char *sType ) { if( !strncmp( sType, "OPTIONS", 7 ) ) { return reqOptions; } else if( !strncmp( sType, "GET", 3 ) ) { return reqGet; } else if( !strncmp( sType, "HEAD", 4 ) ) { return reqHead; } else if( !strncmp( sType, "POST", 4 ) ) { return reqPost; } else if( !strncmp( sType, "PUT", 3 ) ) { return reqPut; } else if( !strncmp( sType, "DELETE", 6 ) ) { return reqDelete; } else if( !strncmp( sType, "TRACE", 5 ) ) { return reqTrace; } else if( !strncmp( sType, "CONNECT", 7 ) ) { return reqConnect; } else { printf(" Uh oh, extension!\n"); return reqExtension; } } const char *Http::getRequestType( short nType ) { switch( nType ) { case reqOptions: return "OPTIONS"; case reqGet: return "GET"; case reqHead: return "HEAD"; case reqPost: return "POST"; case reqPut: return "PUT"; case reqDelete: return "DELETE"; case reqTrace: return "TRACE"; case reqConnect: return "CONNECT"; case reqExtension: return "EXTENSION"; default: return "INVALID VALUE"; } } short Http::getRequestType() { return nReqType; } const char *Http::getRequestTypeStr() { return getRequestType( nReqType ); } void Http::setResponseStatus( short nStatus ) { nResStatus = nStatus; } void Http::setRequestVersion( unsigned char nMajor, unsigned char nMinor ) { cReqVersion = (nMajor<<4)|nMinor; } unsigned char Http::getRequestMinorVer() { return cReqVersion&0x0F; } unsigned char Http::getRequestMajorVer() { return cReqVersion>>4; } bool Http::checkRequestVer() { if( cReqVersion == HTTP11 ) return true; return false; } const char *Http::getHeader( const char *lpStr ) { return (const char *)hReqHeader[lpStr]; }