//----------------------------------------------------------------------------- /// SendHTTPErrorResponse /// /// Sends an error page back /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param nErrorCode numeric identifier of the error to return /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendHTTPErrorResponse(CommunicationID& requestID, int nErrorCode) { // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { return false; } if (OutputHTTPError(pResponse->client_socket, nErrorCode) == false) { DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendRedirectResponse /// /// Redirects the browser to a different URL than the one requested /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param pNewURL The url that the browser is being redirected to /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendRedirectResponse(CommunicationID& requestID, const char* pNewURL) { if (pNewURL == NULL) { return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { return false; } // generate the redirect html static char headerBuffer[COMM_BUFFER_SIZE]; static char htmlBuffer[COMM_BUFFER_SIZE]; sprintf_s(htmlBuffer, COMM_BUFFER_SIZE, "<html><body><a href=\"%s\">%s</a></body></html>", pNewURL, pNewURL); sprintf_s(headerBuffer, COMM_BUFFER_SIZE, "HTTP/1.0 301\r\nContent-Type: text/html\r\nContent-Length: %zd\r\nLocation: %s\r\n\r\n", strlen(htmlBuffer), pNewURL); bool nRes1; bool nRes2; nRes1 = pResponse->client_socket->Send(headerBuffer, (DWORD)strlen(headerBuffer)); nRes2 = pResponse->client_socket->Send(htmlBuffer, (DWORD)strlen(htmlBuffer)); pResponse->client_socket->close(); if ((nRes1 == false) || (nRes2 == false)) { DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendMimeResponse /// /// Sends a single buffer of raw data as the response which should be /// interpreted by the recipient as being of the indicated MIME type /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpMimeType A string identifying which MIME type to use for /// interpreting the data /// \param cpData pointer to the data that should be sent as a response /// \param uSizeInBytes number of bytes of data pointed to by cpData /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendMimeResponse(CommunicationID& requestID, const char* cpMimeType, const char* cpData, unsigned int uSizeInBytes) { if (cpMimeType == NULL) { Log(logERROR, "Failed to send %s response because data is NULL\n", cpMimeType); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { return false; } // if Data is NULL then close streaming connection if (pResponse->m_bStreamingEnabled == true) { if (cpData == NULL) { const char* pstr = "--BoundaryString\r\n"; pResponse->client_socket->Send(pstr, (unsigned int)strlen(pstr)); CloseConnection(*pResponse); DestroyResponse(requestID, &pResponse); return true; } } if (Send(*pResponse, cpMimeType, cpData, uSizeInBytes) == false) { DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendFormattedTextResponse /// /// Send a formatted string to be interpreted as text by the recipient. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpFormat pointer to a character format that should be send as a /// response; it is expected that this format consumes the remaining /// parameters to this function /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendFormattedTextResponse(CommunicationID& requestID, const char* cpFormat, ...) { if (cpFormat == NULL) { Log(logERROR, "Failed to send formatted response because data is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d\n", requestID); return false; } static char string[ 10240 ]; va_list arg_ptr; va_start(arg_ptr, cpFormat); vsprintf_s(string, 10240, cpFormat, arg_ptr); va_end(arg_ptr); if (Send(*pResponse, "text/plain", string, (unsigned long)strlen(string)) == false) { Log(logERROR, "Failed to 'Send' response for requestID %d\n", requestID); DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
String HTTP::HandleRequest(const String& request) { u32 line = 0; u32 pos = 0; String requestLine = NextSubstring(request, line); String verb = NextSubstring(requestLine, pos, " "); if(verb == "GET" || verb == "HEAD") { LOG("Verb: " << verb); String requestedResource = NextSubstring(requestLine, pos, " "); String requestVersion = NextSubstring(requestLine, pos, " "); LOG("resource: " << requestedResource); LOG("version: " << requestVersion); return MakeResponse(OK, TextHTML, "<html><body><p>hai</p></body><html>", verb == "GET"); } //MakeResponse(NotFound, TextHTML, "<html><body><h1>NotFound!</h1></body></html>"); return EMPTY_STRING; }
//----------------------------------------------------------------------------- /// SendBinaryResponse /// /// Sends a single buffer of raw data as the response. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpData pointer to the data that should be sent as a response /// \param uSizeInBytes number of bytes of data pointed to by cpData /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendBinaryResponse(CommunicationID& requestID, const char* cpData, unsigned int uSizeInBytes) { if (cpData == NULL) { Log(logERROR, "Failed to send binary response because data is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d\n", requestID); return false; } if (Send(*pResponse, "application/octet-stream", cpData, uSizeInBytes) == false) { Log(logERROR, "Failed to 'Send' response for requestID %d\n", requestID); if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return false; } return true; }
//----------------------------------------------------------------------------- /// SendTextResponse /// /// Sends a character string to be interpreted as text by the recipient. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpData pointer to the text that should be sent as a response /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendTextResponse(CommunicationID& requestID, const char* cpData) { if (cpData == NULL) { Log(logERROR, "Failed to send text response because data is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d to send content: %s\n", requestID, cpData); return false; } if (Send(*pResponse, "text/plain", cpData, (unsigned long)strlen(cpData)) == false) { Log(logERROR, "Failed to 'Send' response for requestID %d with content: %s\n", requestID, cpData); DestroyResponse(requestID, &pResponse); return false; } if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return true; }
//----------------------------------------------------------------------------- /// SendFileResponse /// /// Sends the binary contents of a file to be interpreted by the recipient as /// the type of file indicated by the file's extension. /// /// \param requestID An ID for a particular request; the plugin will get this /// id as a parameter to the ProcessRequest( ) function /// \param cpData pointer to the filename that should be sent as a response /// /// \return true if the response could be sent; false otherwise //----------------------------------------------------------------------------- bool SendFileResponse(CommunicationID& requestID, const char* cpFile) { if (cpFile == NULL) { Log(logERROR, "Failed to send file response because filename is NULL\n"); return false; } // see if the response is streaming and rate limited if (ShouldResponseBeSent(requestID, true) == true) { // the message shouldn't be sent because of the rate limiting // return true though so the server thinks it was sent successfully return true; } Response* pResponse = NULL; if (MakeResponse(requestID, &pResponse) == false) { Log(logERROR, "Failed to make a response for requestID %d to send file: %s\n", requestID, cpFile); return false; } // collect file data and generate response FILE* in; long fileSize; char* fileBuffer; fopen_s(&in, cpFile, "rb"); // read binary if (!in) { // file error, not found? OutputHTTPError(pResponse->client_socket, 404); // 404 - not found return false; } // determine file size fseek(in, 0, SEEK_END); fileSize = ftell(in); fseek(in, 0, SEEK_SET); // allocate Buffer_ and read in file contents fileBuffer = new char[fileSize]; fread(fileBuffer, sizeof(char), fileSize, in); fclose(in); bool bRes = Send(*pResponse, mimetypes[ FindMimeType(cpFile)].mime, fileBuffer, fileSize); if (bRes == false) { Log(logERROR, "Failed to 'Send' response for requestID %d\n", requestID); DestroyResponse(requestID, &pResponse); } delete [] fileBuffer; if (pResponse->m_bStreamingEnabled == false) { DestroyResponse(requestID, &pResponse); } return bRes; }