mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 13:13:00 +00:00
- Delete mc (stoneage old, there is a standalone win32 port now).
- Fit apps better in dir structure. - Move old_wordpad to templates (Ged said it's a great framework). svn path=/trunk/; revision=34308
This commit is contained in:
parent
d61945b6cc
commit
a92216f309
276 changed files with 16 additions and 101812 deletions
492
rosapps/applications/net/roshttpd/httpd.cpp
Normal file
492
rosapps/applications/net/roshttpd/httpd.cpp
Normal file
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* 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(LPCSTR 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."));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue