+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS HTTP Daemon
- * FILE: httpd.cpp
- * PURPOSE: HTTP daemon
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
- * REVISIONS:
- * CSH 01/09/2000 Created
- */
-#include <debug.h>
-#include <new>
-#include <malloc.h>
-#include <string.h>
-#include <config.h>
-#include <httpd.h>
-#include <error.h>
-
-using namespace std;
-
-CHAR HttpMsg400[] = "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n\r<BODY><H1>400 Bad Request</H1>\n\rThe request had bad syntax.<BR>\n\r</BODY>\n\r\n\r";
-CHAR HttpMsg404[] = "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n\r<BODY><H1>404 Not Found</H1>\n\rThe requested URL was not found on this server.<BR>\n\r</BODY>\n\r\n\r";
-CHAR HttpMsg405[] = "<HEAD><TITLE>405 Method Not Allowed</TITLE></HEAD>\n\r<BODY><H1>405 Method Not Allowed</H1>\n\rThe requested method is not supported on this server.<BR>\n\r</BODY>\n\r\n\r";
-CHAR HttpMsg500[] = "<HEAD><TITLE>500 Internal Server Error</TITLE></HEAD>\n\r<BODY><H1>500 Internal Server Error</H1>\n\rAn internal error occurred.<BR>\n\r</BODY>\n\r\n\r";
-CHAR HttpMsg501[] = "<HEAD><TITLE>501 Not Implemented</TITLE></HEAD>\n\r<BODY><H1>501 Not Implemented</H1>\n\rThe feature is not implemented.<BR>\n\r</BODY>\n\r\n\r";
-
-
-// *************************** CHttpClient ***************************
-
-// Default constructor
-CHttpClient::CHttpClient()
-{
-}
-
-// Constructor with server socket as starter value
-CHttpClient::CHttpClient(CServerSocket *serversocket)
-{
- ServerSocket = serversocket;
-}
-
-// Split URIs into its parts (ie. |http://|www.host.com|/resource|?parameters|)
-VOID CHttpClient::SplitUri(LPSTR lpsUri, LPSTR lpsHost, LPSTR lpsResource, LPSTR lpsParams)
-{
- LPSTR lpsPos;
- LPSTR lpsStr;
- UINT i;
-
- strcpy(lpsHost, "");
- strcpy(lpsResource, "");
- strcpy(lpsParams, "");
-
- lpsPos = strstr(lpsUri, "://");
- if (lpsPos != NULL)
- lpsStr = &lpsPos[3];
- else
- lpsStr = lpsUri;
-
- lpsPos = strstr(lpsStr, "/");
- if (lpsPos != NULL) {
- strncat(lpsHost, lpsPos, lpsPos - lpsStr);
- lpsStr = &lpsPos[1];
-
- lpsPos = strstr(lpsStr, "?");
- if (lpsPos != NULL) {
- strncat(lpsResource, lpsStr, lpsPos - lpsStr);
- strcpy(lpsParams, &lpsPos[1]);
- } else {
- strcpy(lpsResource, lpsStr);
- strcpy(lpsParams, "");
- }
-
- // Replace "/" with "\"
- for (i = 0; i < strlen(lpsResource); i++) {
- if (lpsResource[i] == '/')
- lpsResource[i] = '\\';
- }
- }
-}
-
-// Split resource into its parts (ie. |/path/|filename|.extension|)
-VOID CHttpClient::SplitResource(LPSTR lpsResource, LPSTR lpsPath, LPSTR lpsFilename, LPSTR lpsExtension)
-{
- INT i,len,fileptr,extptr;
-
- strcpy(lpsPath, "");
- strcpy(lpsFilename, "");
- strcpy(lpsExtension, "");
-
- len = strlen(lpsResource);
- if (len != 0) {
- if (lpsResource[len - 1] == '/') {
- // There is only a path
- strcpy(lpsPath, lpsResource);
- } else {
- // Find extension
- i = len - 1;
- while ((i >= 0) && (lpsResource[i] != '.')) i--;
- extptr = i;
- while ((i >= 0) && (lpsResource[i] != '/')) i--;
- if (i > 0) {
- // There is at least one directory in the path (besides root directory)
- fileptr = i + 1;
- strncat(lpsPath, lpsResource, fileptr);
- } else
- fileptr = 1;
-
- // Get filename and possibly extension
- if (extptr != 0) {
- strncat(lpsFilename, &lpsResource[fileptr], extptr - fileptr);
- // Get extension
- strncat(lpsExtension, &lpsResource[extptr + 1], len - extptr - 1);
- } else
- strncat(lpsFilename, &lpsResource[fileptr], len - fileptr);
- }
- }
-}
-
-// Process HTTP request
-VOID CHttpClient::ProcessRequest()
-{
- CHAR sStr[255];
- CHAR sHost[255];
- CHAR sResource[255];
- CHAR sParams[255];
-
- // Which method?
- switch (Parser.nMethodNo) {
- case hmGET: {
- SplitUri(Parser.sUri, sHost, sResource, sParams);
-
- // Default resource?
- if (strlen(sResource) == 0) {
- CIterator<LPSTR> *i = pConfiguration->GetDefaultResources()->CreateIterator();
-
- // FIXME: All default resources should be tried
- // Iterate through all strings
- //for (i->First(); !i->IsDone(); i->Next())
- i->First();
- if (!i->IsDone()) {
- strcat(sResource, i->CurrentItem());
- delete i;
- } else {
- // File not found
- Report("404 Not Found", HttpMsg404);
- break;
- }
- }
- strcpy(sStr, pConfiguration->GetHttpBase());
- strcat(sStr, sResource);
- SendFile(sStr);
- break;
- }
- default: {
- // Method is not implemented
- Report("501 Not Implemented", HttpMsg501);
- }
- }
-}
-
-// Send a file to socket
-VOID CHttpClient::SendFile(LPSTR lpsFilename)
-{
- CHAR str[255];
- CHAR str2[32];
- union BigNum {
- // unsigned __int64 Big;
- unsigned long long Big;
- struct {
- DWORD Low;
- DWORD High;
- } u;
- } nTotalBytes;
- DWORD nBytesToRead;
- DWORD nBytesRead;
- BOOL bStatus;
-
- // Try to open file
- hFile = CreateFileA(lpsFilename,
- GENERIC_READ, // Open for reading
- FILE_SHARE_READ, // Share for reading
- NULL, // No security
- OPEN_EXISTING, // Existing file only
- FILE_ATTRIBUTE_NORMAL, // Normal file
- NULL); // No attr. template
- if (hFile == INVALID_HANDLE_VALUE) {
- // File not found
- Report("404 Not Found", HttpMsg404);
- return;
- }
- // Get file size
- nTotalBytes.u.Low = GetFileSize(hFile, &nTotalBytes.u.High);
- if ((nTotalBytes.u.Low == 0xFFFFFFFF) && ((GetLastError()) != NO_ERROR)) {
- // Internal server error
- Report("500 Internal Server Error", HttpMsg500);
- // Close file
- CloseHandle(hFile);
- return;
- }
-
- // Determine buffer size
- if (nTotalBytes.Big < 65536)
- nBufferSize = 1024;
- else
- nBufferSize = 32768;
- // Allocate memory on heap
- lpsBuffer = (PCHAR) malloc(nBufferSize);
-
- if (lpsBuffer == NULL) {
- // Internal server error
- Report("500 Internal Server Error", HttpMsg500);
- // Close file
- CloseHandle(hFile);
- return;
- }
-
- SendText("HTTP/1.1 200 OK");
- SendText("Server: ROSHTTPD");
- SendText("MIME-version: 1.0");
- SendText("Content-Type: text/plain");
- SendText("Accept-Ranges: bytes");
- strcpy(str, "Content-Length: ");
- _itoa(nTotalBytes.u.Low, str2, 10);
- strcat(str, str2);
- SendText(str);
- SendText("");
- // Read and transmit file
- nTotalRead = 0;
- nFileSize = nTotalBytes.Big;
- bStop = FALSE;
-
- fd_set wfds;
- FD_ZERO(&wfds);
- FD_SET(Socket, &wfds);
- do {
- MessageLoop();
-
- if (nTotalRead + nBufferSize < nFileSize)
- nBytesToRead = nBufferSize;
- else nBytesToRead = nFileSize - nTotalRead;
-
- bStatus = ReadFile(hFile, lpsBuffer, nBytesToRead, &nBytesRead, NULL);
- if (bStatus) {
- select(0, NULL, &wfds, NULL, NULL);
- bStatus = (Transmit(lpsBuffer, nBytesRead) == (INT)nBytesRead);
- nTotalRead += nBytesRead;
- }
- } while ((!bStop) && (bStatus) && (nTotalRead < nFileSize));
-
- if (bStatus)
- SendText("");
- else
- // We can't send an error message here as we are in the process of sending a file.
- // We have to terminate the connection instead
- Close();
-
- // Free allocated memory
- free(lpsBuffer);
-
- // Close file
- CloseHandle(hFile);
-}
-
-// Report something to client
-VOID CHttpClient::Report(LPSTR lpsCode, LPSTR lpsStr)
-{
- CHAR sTmp[128];
- CHAR sTmp2[16];
-
- strcpy(sTmp, "HTTP/1.1 ");
- strcat(sTmp, lpsCode);
- SendText(sTmp);
- SendText("Server: ROSHTTPD");
- SendText("MIME-version: 1.0");
- SendText("Content-Type: text/html");
- SendText("Accept-Ranges: bytes");
- strcpy(sTmp, "Content-Length: ");
- if (lpsStr != NULL) {
- _itoa(strlen(lpsStr), sTmp2, 10);
- strcat(sTmp, sTmp2);
- } else
- strcat(sTmp, "0");
- SendText(sTmp);
- SendText("");
- if (lpsStr != NULL)
- SendText(lpsStr);
- SendText("");
-}
-
-// OnRead event handler
-VOID CHttpClient::OnRead()
-{
- LONG nCount;
-
- nCount = Receive((LPSTR) &Parser.sBuffer[Parser.nHead],
- sizeof(Parser.sBuffer) - Parser.nHead);
-
- Parser.nHead += nCount;
- if (Parser.nHead >= sizeof(Parser.sBuffer))
- Parser.nHead = 0;
-
- if (Parser.Complete()) {
- ProcessRequest();
- }
-
- if (Parser.bUnknownMethod) {
- // Method Not Allowed
- Report("405 Method Not Allowed", HttpMsg405);
- // Terminate connection
- Close();
- }
-}
-/*
-// OnWrite event handler
-VOID CHttpClient::OnWrite()
-{
- DWORD nBytesToRead;
- DWORD nBytesRead;
-
- OutputDebugString(TS("Can write\n"));
-
- if (bSendingFile) {
- if (nTotalRead + nBufferSize < nFileSize)
- nBytesToRead = nBufferSize;
- else nBytesToRead = nFileSize - nTotalRead;
-
- bError = ReadFile(hFile, Buffer, nBytesToRead, &nBytesRead, NULL);
- if (!bError) {
- Transmit(Buffer, nBytesRead);
- nTotalRead += nBytesRead;
- }
- }
-}
-*/
-// OnClose event handler
-VOID CHttpClient::OnClose()
-{
- // Stop sending file if we are doing that now
- bStop = TRUE;
-}
-
-
-// ************************ CHttpClientThread ************************
-
-// Constructor with client socket as starter value
-CHttpClientThread::CHttpClientThread(LPCServerClientSocket lpSocket)
-{
- ClientSocket = lpSocket;
-}
-
-// Execute client thread code
-VOID CHttpClientThread::Execute()
-{
- MSG Msg;
-
- while (!Terminated()) {
- (( CHttpClient *) ClientSocket)->MessageLoop();
- if (PeekMessage(&Msg, 0, 0, 0, PM_REMOVE) != 0) {
- switch (Msg.message) {
- case HTTPD_START: {
- // TODO: Start thread
- break;
- }
- case HTTPD_STOP: {
- // TODO: Stop thread
- break;
- }
- default:
- DispatchMessage(&Msg);
- }
-
- }
- }
-
- if (ClientSocket != NULL) {
- delete ClientSocket;
- ClientSocket = NULL;
- }
-}
-
-
-// *************************** CHttpDaemon ***************************
-
-// Default constructor
-CHttpDaemon::CHttpDaemon()
-{
- State = hsStopped;
- Start();
-}
-
-// Default destructor
-CHttpDaemon::~CHttpDaemon()
-{
- if (State==hsRunning)
- Stop();
-}
-
-// Return daemon state
-HTTPdState CHttpDaemon::GetState() const
-{
- return State;
-}
-
-// Start HTTP daemon
-BOOL CHttpDaemon::Start()
-{
- assert(State==hsStopped);
-
- SetPort(pConfiguration->GetPort());
-
- Open();
-
- State = hsRunning;
-
- return TRUE;
-}
-
-// Stop HTTP daemon
-BOOL CHttpDaemon::Stop()
-{
- assert(State==hsRunning);
-
- Close();
-
- State = hsStopped;
-
- return TRUE;
-}
-
-// OnGetSocket event handler
-LPCServerClientSocket CHttpDaemon::OnGetSocket(LPCServerSocket lpServerSocket)
-{
- return new CHttpClient(lpServerSocket);
-}
-
-// OnGetThread event handler
-LPCServerClientThread CHttpDaemon::OnGetThread(LPCServerClientSocket lpSocket)
-{
- return new CHttpClientThread(lpSocket);
-}
-
-// OnAccept event handler
-VOID CHttpDaemon::OnAccept(LPCServerClientThread lpThread)
-{
-}
-
-
-// ************************ CHttpDaemonThread ************************
-
-// Execute daemon thread code
-VOID CHttpDaemonThread::Execute()
-{
- MSG Msg;
-
- try {
- Daemon = NULL;
- Daemon = new CHttpDaemon;
-
- while (!Terminated()) {
- Daemon->MessageLoop();
- if (PeekMessage(&Msg, 0, 0, 0, PM_REMOVE) != 0) {
- switch (Msg.message) {
- case HTTPD_START: {
- if (Daemon->GetState() == hsStopped)
- Daemon->Start();
- break;
- }
- case HTTPD_STOP: {
- if (Daemon->GetState() == hsRunning)
- Daemon->Stop();
- break;
- }
- case HTTPD_SUSPEND: {
- if (Daemon->GetState() == hsRunning){}
- // FIXME: Suspend service
- break;
- }
- case HTTPD_RESUME: {
- if (Daemon->GetState() != hsSuspended){}
- // FIXME: Resume service
- break;
- }
- default:
- DispatchMessage(&Msg);
- }
- }
- }
- delete Daemon;
- } catch (ESocket e) {
- ReportErrorStr(e.what());
- } catch (bad_alloc e) {
- ReportErrorStr(TS("Insufficient resources."));
- }
-}