mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Small HTTP daemon
svn path=/trunk/; revision=1515
This commit is contained in:
parent
05ccbb2696
commit
52f51dc4b9
18 changed files with 2303 additions and 0 deletions
94
reactos/apps/utils/net/roshttpd/common/list.cpp
Normal file
94
reactos/apps/utils/net/roshttpd/common/list.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: list.cpp
|
||||||
|
* PURPOSE: A doubly linked list implementation
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
* NOTES: The linked list does it's own heap management for
|
||||||
|
* better performance
|
||||||
|
* TODO: - InsertBefore(), InsertAfter(), Move()
|
||||||
|
*/
|
||||||
|
#include <windows.h>
|
||||||
|
#include <list.h>
|
||||||
|
|
||||||
|
// **************************** CListNode ****************************
|
||||||
|
|
||||||
|
HANDLE CListNode::hHeap = NULL;
|
||||||
|
INT CListNode::nRef = 0;
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CListNode::CListNode()
|
||||||
|
{
|
||||||
|
Element = NULL;
|
||||||
|
Next = NULL;
|
||||||
|
Prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor with element and next as starter values
|
||||||
|
CListNode::CListNode(PVOID element, CListNode *next, CListNode *prev)
|
||||||
|
{
|
||||||
|
Element = element;
|
||||||
|
Next = next;
|
||||||
|
Prev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
PVOID CListNode::operator new(/*size_t*/ UINT size)
|
||||||
|
{
|
||||||
|
PVOID p;
|
||||||
|
if (hHeap == NULL) {
|
||||||
|
SYSTEM_INFO inf;
|
||||||
|
GetSystemInfo(&inf);
|
||||||
|
hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
|
||||||
|
}
|
||||||
|
if ((p = HeapAlloc(hHeap, 0, size)) != NULL)
|
||||||
|
nRef++;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID CListNode::operator delete(PVOID p)
|
||||||
|
{
|
||||||
|
if (HeapFree(hHeap, 0, p) != FALSE)
|
||||||
|
nRef--;
|
||||||
|
if (nRef == 0) {
|
||||||
|
HeapDestroy(hHeap);
|
||||||
|
hHeap = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set element
|
||||||
|
VOID CListNode::SetElement(PVOID element)
|
||||||
|
{
|
||||||
|
Element = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set pointer to next node in list
|
||||||
|
VOID CListNode::SetNext(CListNode *next)
|
||||||
|
{
|
||||||
|
Next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set pointer to previous node in list
|
||||||
|
VOID CListNode::SetPrev(CListNode *prev)
|
||||||
|
{
|
||||||
|
Prev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get element of node
|
||||||
|
PVOID CListNode::GetElement()
|
||||||
|
{
|
||||||
|
return Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pointer to next node in list
|
||||||
|
CListNode *CListNode::GetNext()
|
||||||
|
{
|
||||||
|
return Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pointer to previous node in list
|
||||||
|
CListNode *CListNode::GetPrev()
|
||||||
|
{
|
||||||
|
return Prev;
|
||||||
|
}
|
343
reactos/apps/utils/net/roshttpd/common/socket.cpp
Normal file
343
reactos/apps/utils/net/roshttpd/common/socket.cpp
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: socket.cpp
|
||||||
|
* PURPOSE: Socket classes
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
*/
|
||||||
|
#include <error.h>
|
||||||
|
#include <socket.h>
|
||||||
|
#include <iterator.h>
|
||||||
|
|
||||||
|
// ***************************** CSocket *****************************
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CSocket::CSocket()
|
||||||
|
{
|
||||||
|
Active = FALSE;
|
||||||
|
Event = WSA_INVALID_EVENT;
|
||||||
|
Events = 0;
|
||||||
|
Socket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
// INET address family
|
||||||
|
SockAddrIn.sin_family = AF_INET;
|
||||||
|
|
||||||
|
// Any address will do
|
||||||
|
SockAddrIn.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
// Convert to network ordering
|
||||||
|
SockAddrIn.sin_port = htons(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destructor
|
||||||
|
CSocket::~CSocket()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return winsock socket handle
|
||||||
|
SOCKET CSocket::GetSocket()
|
||||||
|
{
|
||||||
|
return Socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set winsock socket handle
|
||||||
|
VOID CSocket::SetSocket(SOCKET socket)
|
||||||
|
{
|
||||||
|
Socket = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return socket address
|
||||||
|
SOCKADDR_IN CSocket::GetSockAddrIn()
|
||||||
|
{
|
||||||
|
return SockAddrIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set socket address
|
||||||
|
VOID CSocket::SetSockAddrIn(SOCKADDR_IN sockaddrin)
|
||||||
|
{
|
||||||
|
SockAddrIn = sockaddrin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Associate winsock events with socket
|
||||||
|
VOID CSocket::SetEvents(LONG lEvents)
|
||||||
|
{
|
||||||
|
if (Event == WSA_INVALID_EVENT) {
|
||||||
|
// Create socket event
|
||||||
|
Event = WSACreateEvent();
|
||||||
|
if (Event == WSA_INVALID_EVENT)
|
||||||
|
throw ESocketOpen(TS("Unable to create event."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lEvents != Events) {
|
||||||
|
// Associate network events with socket
|
||||||
|
if (WSAEventSelect(Socket, Event, lEvents) == SOCKET_ERROR)
|
||||||
|
throw ESocketOpen(TS("Unable to select socket events."));
|
||||||
|
Events = lEvents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return associated winsock events
|
||||||
|
LONG CSocket::GetEvents()
|
||||||
|
{
|
||||||
|
return Events;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open socket
|
||||||
|
VOID CSocket::Open()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close socket
|
||||||
|
VOID CSocket::Close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *********************** CServerClientSocket ***********************
|
||||||
|
|
||||||
|
// Constructor with serversocket as parameter
|
||||||
|
CServerClientSocket::CServerClientSocket(LPCServerSocket lpServerSocket)
|
||||||
|
{
|
||||||
|
ServerSocket = lpServerSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit data to socket
|
||||||
|
INT CServerClientSocket::Transmit( LPSTR lpsBuffer, UINT nLength)
|
||||||
|
{
|
||||||
|
return send(Socket, lpsBuffer, nLength, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a string to socket
|
||||||
|
INT CServerClientSocket::SendText( LPSTR lpsText)
|
||||||
|
{
|
||||||
|
static CHAR crlf[3] = {0x0D, 0x0A, 0x00};
|
||||||
|
INT nCount;
|
||||||
|
|
||||||
|
nCount = Transmit(lpsText, strlen(lpsText));
|
||||||
|
nCount += Transmit(crlf, strlen(crlf));
|
||||||
|
return nCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive data from socket
|
||||||
|
INT CServerClientSocket::Receive(LPSTR lpsBuffer, UINT nLength)
|
||||||
|
{
|
||||||
|
return recv(Socket, lpsBuffer, nLength, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process winsock messages if any
|
||||||
|
VOID CServerClientSocket::MessageLoop()
|
||||||
|
{
|
||||||
|
UINT nStatus;
|
||||||
|
WSANETWORKEVENTS NetworkEvents;
|
||||||
|
|
||||||
|
nStatus = WSAWaitForMultipleEvents(1, &Event, FALSE, 0, FALSE);
|
||||||
|
if ((nStatus == 0) && (WSAEnumNetworkEvents(Socket, Event, &NetworkEvents) != SOCKET_ERROR)) {
|
||||||
|
if ((NetworkEvents.lNetworkEvents & FD_READ) != 0) {
|
||||||
|
OnRead();
|
||||||
|
}
|
||||||
|
if ((NetworkEvents.lNetworkEvents & FD_CLOSE) != 0) {
|
||||||
|
OnClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return server socket that own this socket
|
||||||
|
LPCServerSocket CServerClientSocket::GetServerSocket()
|
||||||
|
{
|
||||||
|
return ServerSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *********************** CServerClientThread ***********************
|
||||||
|
|
||||||
|
CServerClientThread::CServerClientThread(LPCServerClientSocket lpSocket)
|
||||||
|
{
|
||||||
|
ClientSocket = lpSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerClientThread::~CServerClientThread()
|
||||||
|
{
|
||||||
|
ClientSocket->GetServerSocket()->RemoveClient((LPCServerClientThread) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************** CServerSocket **************************
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CServerSocket::CServerSocket()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destructor
|
||||||
|
CServerSocket::~CServerSocket()
|
||||||
|
{
|
||||||
|
if (Active)
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open server socket so clients can connect
|
||||||
|
VOID CServerSocket::Open()
|
||||||
|
{
|
||||||
|
assert(!Active);
|
||||||
|
|
||||||
|
// Convert to network ordering
|
||||||
|
SockAddrIn.sin_port = htons(Port);
|
||||||
|
|
||||||
|
if (Socket == INVALID_SOCKET) {
|
||||||
|
// Create socket
|
||||||
|
Socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (Socket == INVALID_SOCKET)
|
||||||
|
throw ESocketOpen(TS("Unable to allocate a socket."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Associate an address with server socket
|
||||||
|
if (bind(Socket, (struct sockaddr FAR *) &SockAddrIn, sizeof(SockAddrIn)) == SOCKET_ERROR)
|
||||||
|
throw ESocketOpen(TS("Unable to associate address with socket."));
|
||||||
|
|
||||||
|
// Listen for incoming connections
|
||||||
|
if (listen(Socket, MAX_PENDING_CONNECTS) != 0)
|
||||||
|
throw ESocketOpen(TS("Unable to listen on socket."));
|
||||||
|
|
||||||
|
// Associate network events with socket
|
||||||
|
SetEvents(FD_ACCEPT | FD_CONNECT | FD_CLOSE);
|
||||||
|
|
||||||
|
Active = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close server socket and all current connections
|
||||||
|
VOID CServerSocket::Close()
|
||||||
|
{
|
||||||
|
assert(Active);
|
||||||
|
|
||||||
|
if (Event != WSA_INVALID_EVENT) {
|
||||||
|
// Tell winsock not to notify us about any events
|
||||||
|
if (WSAEventSelect(Socket, Event, 0) == SOCKET_ERROR)
|
||||||
|
throw ESocketClose(TS("Unable to select socket events."));
|
||||||
|
|
||||||
|
if (!WSACloseEvent(Event))
|
||||||
|
throw ESocketClose(TS("Unable to close socket event."));
|
||||||
|
Event = WSA_INVALID_EVENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIterator<LPCServerClientThread> *i = Connections.CreateIterator();
|
||||||
|
|
||||||
|
// Terminate and free all client threads
|
||||||
|
for (i->First(); !i->IsDone(); i->Next()) {
|
||||||
|
//i->CurrentItem()->Terminate();
|
||||||
|
delete i->CurrentItem();
|
||||||
|
}
|
||||||
|
delete i;
|
||||||
|
Connections.RemoveAll();
|
||||||
|
|
||||||
|
closesocket(Socket);
|
||||||
|
Socket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
Active = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set port number to listen on
|
||||||
|
VOID CServerSocket::SetPort(UINT nPort)
|
||||||
|
{
|
||||||
|
assert(!Active);
|
||||||
|
|
||||||
|
Port = nPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process messages from winsock if any
|
||||||
|
VOID CServerSocket::MessageLoop()
|
||||||
|
{
|
||||||
|
UINT nStatus;
|
||||||
|
INT nAddrLen;
|
||||||
|
SOCKET ClientSocket;
|
||||||
|
SOCKADDR_IN SockAddrIn;
|
||||||
|
WSANETWORKEVENTS NetworkEvents;
|
||||||
|
LPCServerClientSocket lpClient;
|
||||||
|
LPCServerClientThread lpThread;
|
||||||
|
|
||||||
|
nStatus = WSAWaitForMultipleEvents(1, &Event, FALSE, 0, FALSE);
|
||||||
|
if ((nStatus == 0) && (WSAEnumNetworkEvents(Socket, Event, &NetworkEvents) != SOCKET_ERROR)) {
|
||||||
|
if ((NetworkEvents.lNetworkEvents & FD_ACCEPT) != 0) {
|
||||||
|
lpClient = OnGetSocket(this);
|
||||||
|
nAddrLen = sizeof(SockAddrIn);
|
||||||
|
ClientSocket = accept(Socket, (SOCKADDR *) &SockAddrIn, &nAddrLen);
|
||||||
|
if (ClientSocket != INVALID_SOCKET) {
|
||||||
|
// Set socket handle
|
||||||
|
lpClient->SetSocket(ClientSocket);
|
||||||
|
// Set socket address
|
||||||
|
lpClient->SetSockAddrIn(SockAddrIn);
|
||||||
|
// Set winsock events
|
||||||
|
lpClient->SetEvents(FD_READ | FD_CLOSE);
|
||||||
|
// Create client connection thread
|
||||||
|
lpThread = OnGetThread(lpClient);
|
||||||
|
// Add client thread to connection list
|
||||||
|
InsertClient(lpThread);
|
||||||
|
// Call OnAccept event handler
|
||||||
|
OnAccept(lpThread);
|
||||||
|
} else {
|
||||||
|
delete lpClient;
|
||||||
|
lpClient = NULL;
|
||||||
|
throw ESocketOpen(TS("No more sockets available."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*if ((NetworkEvents.lNetworkEvents & FD_CONNECT) != 0) {
|
||||||
|
}
|
||||||
|
if ((NetworkEvents.lNetworkEvents & FD_CLOSE) != 0) {
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert client into connection list
|
||||||
|
VOID CServerSocket::InsertClient(LPCServerClientThread lpClient)
|
||||||
|
{
|
||||||
|
Connections.Insert(lpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove client from connection list
|
||||||
|
VOID CServerSocket::RemoveClient(LPCServerClientThread lpClient)
|
||||||
|
{
|
||||||
|
Connections.Remove(lpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnGetSocket event handler
|
||||||
|
LPCServerClientSocket CServerSocket::OnGetSocket(LPCServerSocket lpServerSocket)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnGetThread event handler
|
||||||
|
LPCServerClientThread CServerSocket::OnGetThread(LPCServerClientSocket lpSocket)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize WinSock DLL
|
||||||
|
VOID InitWinsock()
|
||||||
|
{
|
||||||
|
WORD wVersionRequested;
|
||||||
|
WSADATA wsaData;
|
||||||
|
|
||||||
|
wVersionRequested = MAKEWORD(2, 0);
|
||||||
|
|
||||||
|
if (WSAStartup(wVersionRequested, &wsaData) != 0)
|
||||||
|
// Return FALSE as we couldn't find a usable WinSock DLL
|
||||||
|
throw ESocketWinsock(TS("Unable to initialize winsock dll."));
|
||||||
|
|
||||||
|
/* Confirm that the WinSock DLL supports 2.0 */
|
||||||
|
|
||||||
|
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) {
|
||||||
|
// We couldn't find a usable winsock dll
|
||||||
|
WSACleanup();
|
||||||
|
throw ESocketDll(TS("Winsock dll version is not 2.0 or higher."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deinitialize WinSock DLL
|
||||||
|
VOID DeinitWinsock()
|
||||||
|
{
|
||||||
|
if (WSACleanup() != 0)
|
||||||
|
throw ESocketWinsock(TS("Unable to deinitialize winsock dll."));
|
||||||
|
}
|
80
reactos/apps/utils/net/roshttpd/common/thread.cpp
Normal file
80
reactos/apps/utils/net/roshttpd/common/thread.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: thread.cpp
|
||||||
|
* PURPOSE: Generic thread class
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
*/
|
||||||
|
#include <debug.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <thread.h>
|
||||||
|
|
||||||
|
// This is the thread entry code
|
||||||
|
DWORD WINAPI ThreadEntry(LPVOID parameter)
|
||||||
|
{
|
||||||
|
ThreadData *p = (ThreadData*) parameter;
|
||||||
|
|
||||||
|
p->ClassPtr->Execute();
|
||||||
|
|
||||||
|
SetEvent(p->hFinished);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CThread::CThread()
|
||||||
|
{
|
||||||
|
bTerminated = FALSE;
|
||||||
|
// Points to the class that is executed within thread
|
||||||
|
Data.ClassPtr = this;
|
||||||
|
// Create synchronization event
|
||||||
|
Data.hFinished = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
|
// FIXME: Do some error handling
|
||||||
|
assert(Data.hFinished != NULL);
|
||||||
|
|
||||||
|
// Create thread
|
||||||
|
hThread = CreateThread(NULL, 0, ThreadEntry, &Data, 0, &dwThreadId);
|
||||||
|
|
||||||
|
// FIXME: Do some error handling
|
||||||
|
assert(hThread != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destructor
|
||||||
|
CThread::~CThread()
|
||||||
|
{
|
||||||
|
if ((hThread != NULL) && (Data.hFinished != NULL)) {
|
||||||
|
if (!bTerminated)
|
||||||
|
Terminate();
|
||||||
|
WaitForSingleObject(Data.hFinished, INFINITE);
|
||||||
|
CloseHandle(Data.hFinished);
|
||||||
|
CloseHandle(hThread);
|
||||||
|
hThread = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute thread code
|
||||||
|
void CThread::Execute()
|
||||||
|
{
|
||||||
|
while (!bTerminated) Sleep(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post a message to the thread's message queue
|
||||||
|
BOOL CThread::PostMessage(UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return PostThreadMessage(dwThreadId, Msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gracefully terminate thread
|
||||||
|
void CThread::Terminate()
|
||||||
|
{
|
||||||
|
bTerminated = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns TRUE if thread is terminated, FALSE if not
|
||||||
|
BOOL CThread::Terminated()
|
||||||
|
{
|
||||||
|
return bTerminated;
|
||||||
|
}
|
130
reactos/apps/utils/net/roshttpd/config.cpp
Normal file
130
reactos/apps/utils/net/roshttpd/config.cpp
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: config.cpp
|
||||||
|
* PURPOSE: Daemon configuration
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
*/
|
||||||
|
#include <new>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
LPCConfig pConfiguration;
|
||||||
|
LPCHttpDaemonThread pDaemonThread;
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CConfig::CConfig()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destructor
|
||||||
|
CConfig::~CConfig()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear configuration
|
||||||
|
void CConfig::Reset()
|
||||||
|
{
|
||||||
|
MainBase = NULL;
|
||||||
|
HttpBase = NULL;
|
||||||
|
DefaultResources.RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create default configuration. Can throw bad_alloc
|
||||||
|
void CConfig::Default()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
MainBase = (LPWSTR)_wcsdup(dcfgMainBase);
|
||||||
|
HttpBase = _strdup(dcfgHttpBase);
|
||||||
|
|
||||||
|
LPSTR lpsStr;
|
||||||
|
try {
|
||||||
|
lpsStr = _strdup(dcfgDefaultResource);
|
||||||
|
DefaultResources.Insert(lpsStr);
|
||||||
|
} catch (bad_alloc e) {
|
||||||
|
free((void *)lpsStr);
|
||||||
|
Clear();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
Port = dcfgDefaultPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear configuration
|
||||||
|
void CConfig::Clear()
|
||||||
|
{
|
||||||
|
if (MainBase != NULL)
|
||||||
|
free((void *)MainBase);
|
||||||
|
if (HttpBase != NULL)
|
||||||
|
free((void *)HttpBase);
|
||||||
|
|
||||||
|
// Free memory for all strings
|
||||||
|
CIterator<LPSTR> *i = DefaultResources.CreateIterator();
|
||||||
|
for (i->First(); !i->IsDone(); i->Next())
|
||||||
|
free((void *)i->CurrentItem());
|
||||||
|
delete i;
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
BOOL CConfig::Load()
|
||||||
|
{
|
||||||
|
Default();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save configuration
|
||||||
|
BOOL CConfig::Save()
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return MainBase
|
||||||
|
LPWSTR CConfig::GetMainBase()
|
||||||
|
{
|
||||||
|
return MainBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set MainBase
|
||||||
|
void CConfig::SetMainBase(LPWSTR lpwsMainBase)
|
||||||
|
{
|
||||||
|
MainBase = lpwsMainBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return HttpBase
|
||||||
|
LPSTR CConfig::GetHttpBase()
|
||||||
|
{
|
||||||
|
return HttpBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set HttpBase
|
||||||
|
void CConfig::SetHttpBase(LPSTR lpsHttpBase)
|
||||||
|
{
|
||||||
|
HttpBase = lpsHttpBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return DefaultResources
|
||||||
|
CList<LPSTR>* CConfig::GetDefaultResources()
|
||||||
|
{
|
||||||
|
return &DefaultResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return bound port
|
||||||
|
USHORT CConfig::GetPort()
|
||||||
|
{
|
||||||
|
return Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set port
|
||||||
|
VOID CConfig::SetPort(USHORT wPort)
|
||||||
|
{
|
||||||
|
Port = wPort;
|
||||||
|
}
|
16
reactos/apps/utils/net/roshttpd/error.cpp
Normal file
16
reactos/apps/utils/net/roshttpd/error.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: error.cpp
|
||||||
|
* PURPOSE: Error reporting
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
*/
|
||||||
|
#include <error.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void ReportErrorStr(LPTSTR lpsText)
|
||||||
|
{
|
||||||
|
wprintf((__wchar_t*)lpsText);
|
||||||
|
}
|
380
reactos/apps/utils/net/roshttpd/http.cpp
Normal file
380
reactos/apps/utils/net/roshttpd/http.cpp
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: http.cpp
|
||||||
|
* PURPOSE: HTTP 1.1 parser engine
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
* TODO: - Implement message-body
|
||||||
|
* - Implement more generel-header entries
|
||||||
|
* - Implement more request-header entries
|
||||||
|
* - Implement more entity-header entries
|
||||||
|
*/
|
||||||
|
#include <debug.h>
|
||||||
|
#include <iostream.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <http.h>
|
||||||
|
|
||||||
|
CHAR MethodTable[NUMMETHODS][8] = {"OPTIONS", "GET", "HEAD", "POST", "PUT",
|
||||||
|
"DELETE", "TRACE"};
|
||||||
|
|
||||||
|
CHAR GenerelTable[NUMGENERELS][18] = {"Cache-Control", "Connection", "Date", "Pragma",
|
||||||
|
"Transfer-Encoding", "Upgrade", "Via"};
|
||||||
|
|
||||||
|
CHAR RequestTable[NUMREQUESTS][20] = {"Accept", "Accept-Charset", "Accept-Encoding",
|
||||||
|
"Accept-Language", "Authorization", "From", "Host", "If-Modified-Since", "If-Match",
|
||||||
|
"If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards",
|
||||||
|
"Proxy-Authorization", "Range", "Referer", "User-Agent"};
|
||||||
|
|
||||||
|
CHAR EntityTable[NUMENTITIES][17] = {"Allow", "Content-Base", "Content-Encoding",
|
||||||
|
"Content-Language", "Content-Length", "Content-Location", "Content-MD5",
|
||||||
|
"Content-Range", "Content-Type", "ETag", "Expires", "Last-Modified"};
|
||||||
|
|
||||||
|
// *************************** CHttpParser ***************************
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
CHttpParser::CHttpParser()
|
||||||
|
{
|
||||||
|
nHead = 0;
|
||||||
|
nTail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destructor
|
||||||
|
CHttpParser::~CHttpParser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns TRUE if a complete HTTP message is in buffer
|
||||||
|
BOOL CHttpParser::Complete()
|
||||||
|
{
|
||||||
|
UINT nTmp;
|
||||||
|
|
||||||
|
/*DPRINT("--1:-%d---\n", sBuffer[nHead-2]);
|
||||||
|
DPRINT("--2:-%d---\n", sBuffer[nHead-1]);
|
||||||
|
|
||||||
|
sBuffer[nHead] = '!';
|
||||||
|
sBuffer[nHead+1] = 0;
|
||||||
|
DPRINT("Examining buffer: (Head: %d, Tail: %d)\n", nHead, nTail);
|
||||||
|
DPRINT("%s\n", (LPSTR)&sBuffer[nTail]);*/
|
||||||
|
|
||||||
|
nTmp = nTail;
|
||||||
|
if (!Parse()) {
|
||||||
|
if (!bUnknownMethod)
|
||||||
|
nTail = nTmp;
|
||||||
|
return FALSE;
|
||||||
|
} else
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read a character from buffer
|
||||||
|
BOOL CHttpParser::ReadChar(LPSTR lpsStr)
|
||||||
|
{
|
||||||
|
if (nTail <= nHead) {
|
||||||
|
if (nTail != nHead) {
|
||||||
|
lpsStr[0] = sBuffer[nTail];
|
||||||
|
nTail++;
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
lpsStr[0] = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nTail == sizeof(sBuffer))
|
||||||
|
nTail = 0;
|
||||||
|
if (nTail != nHead) {
|
||||||
|
lpsStr[0] = sBuffer[nTail];
|
||||||
|
nTail++;
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
lpsStr[0] = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek at a character in the buffer
|
||||||
|
BOOL CHttpParser::PeekChar(LPSTR lpsStr)
|
||||||
|
{
|
||||||
|
UINT nFakeTail;
|
||||||
|
|
||||||
|
if (nTail == sizeof(sBuffer))
|
||||||
|
nFakeTail = 0;
|
||||||
|
else
|
||||||
|
nFakeTail = nTail;
|
||||||
|
if (nFakeTail != nHead) {
|
||||||
|
lpsStr[0] = sBuffer[nFakeTail];
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
lpsStr[0] = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string from buffer. Only A-Z, a-z, 0-9 and '-' are valid characters
|
||||||
|
BOOL CHttpParser::ReadString(LPSTR lpsStr, UINT nLength)
|
||||||
|
{
|
||||||
|
UINT i = 0;
|
||||||
|
CHAR sTmp;
|
||||||
|
|
||||||
|
while (PeekChar(&sTmp)) {
|
||||||
|
if (((sTmp >= 'A') && (sTmp <= 'Z')) || ((sTmp >= 'a') && (sTmp <= 'z')) ||
|
||||||
|
((sTmp >= '0') && (sTmp <= '9')) || (sTmp == '-')) {
|
||||||
|
if (i >= (nLength - 1)) {
|
||||||
|
lpsStr[0] = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
ReadChar(&sTmp);
|
||||||
|
lpsStr[i] = sTmp;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
lpsStr[i] = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lpsStr[0] = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string from buffer. Stop if SP or CR is found or when there are no more
|
||||||
|
// characters
|
||||||
|
BOOL CHttpParser::ReadSpecial(LPSTR lpsStr, UINT nLength)
|
||||||
|
{
|
||||||
|
UINT i = 0;
|
||||||
|
CHAR sTmp;
|
||||||
|
|
||||||
|
while (PeekChar(&sTmp) && (sTmp != ' ') && (sTmp != 13)) {
|
||||||
|
if (i >= (nLength - 1)) {
|
||||||
|
lpsStr[nLength - 1] = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
ReadChar(&sTmp);
|
||||||
|
lpsStr[i] = sTmp;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
lpsStr[i] = 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip until "sCh" is found
|
||||||
|
VOID CHttpParser::Skip(CHAR sCh)
|
||||||
|
{
|
||||||
|
CHAR sTmp;
|
||||||
|
|
||||||
|
while (PeekChar(&sTmp) && (sTmp != sCh))
|
||||||
|
ReadChar(&sTmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return TRUE if sCh is the next character
|
||||||
|
BOOL CHttpParser::Expect(CHAR sCh)
|
||||||
|
{
|
||||||
|
CHAR sTmp;
|
||||||
|
|
||||||
|
if (PeekChar(&sTmp)) {
|
||||||
|
if (sTmp == sCh) {
|
||||||
|
ReadChar(&sTmp);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return TRUE if CRLF are the next characters
|
||||||
|
BOOL CHttpParser::ExpectCRLF()
|
||||||
|
{
|
||||||
|
return (Expect(13) && Expect(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request = RequestLine | *( GenerelHeader | RequestHeader | EntityHeader )
|
||||||
|
// CRLF [ MessageBody ]
|
||||||
|
BOOL CHttpParser::Parse()
|
||||||
|
{
|
||||||
|
BOOL bStatus;
|
||||||
|
|
||||||
|
|
||||||
|
CHAR ch;
|
||||||
|
|
||||||
|
if (RequestLine()) {
|
||||||
|
do {
|
||||||
|
if (!ReadString(sHeader, sizeof(sHeader)))
|
||||||
|
break;
|
||||||
|
bStatus = (GenerelHeader());
|
||||||
|
bStatus = (RequestHeader() || bStatus);
|
||||||
|
bStatus = (EntityHeader() || bStatus);
|
||||||
|
} while (bStatus);
|
||||||
|
// CRLF
|
||||||
|
if (!ExpectCRLF())
|
||||||
|
return FALSE;
|
||||||
|
MessageBody();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestLine = Method SP RequestURI SP HTTP-Version CRLF
|
||||||
|
BOOL CHttpParser::RequestLine()
|
||||||
|
{
|
||||||
|
CHAR sCh;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
bUnknownMethod = FALSE;
|
||||||
|
|
||||||
|
// RFC 2068 states that servers SHOULD ignore any empty nine(s) received where a
|
||||||
|
// Request-Line is expected
|
||||||
|
while (PeekChar(&sCh) && ((sCh == 13) || (sCh == 10)));
|
||||||
|
|
||||||
|
if (!ReadString(sMethod, sizeof(sMethod)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < NUMMETHODS; i++) {
|
||||||
|
if (strcmp(MethodTable[i], sMethod) == 0) {
|
||||||
|
nMethodNo = i;
|
||||||
|
if (!Expect(' '))
|
||||||
|
return FALSE;
|
||||||
|
// URI (ie. host/directory/resource)
|
||||||
|
if (!ReadSpecial(sUri, sizeof(sUri)))
|
||||||
|
return FALSE;
|
||||||
|
if (!Expect(' '))
|
||||||
|
return FALSE;
|
||||||
|
// HTTP version (eg. HTTP/1.1)
|
||||||
|
if (!ReadSpecial(sVersion, sizeof(sVersion)))
|
||||||
|
return FALSE;
|
||||||
|
// CRLF
|
||||||
|
if (!ExpectCRLF())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bUnknownMethod = TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerelHeader = Cache-Control | Connection | Date | Pragma | Transfer-Encoding |
|
||||||
|
// Upgrade | Via
|
||||||
|
BOOL CHttpParser::GenerelHeader()
|
||||||
|
{
|
||||||
|
INT i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUMGENERELS; i++) {
|
||||||
|
if (strcmp(GenerelTable[i], sHeader) == 0) {
|
||||||
|
switch (i) {
|
||||||
|
case 1: {
|
||||||
|
//Connection
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestHeader = Accept | Accept-Charset | Accept-Encoding | Accept-Language |
|
||||||
|
// Authorization | From | Host | If-Modified-Since | If-Match |
|
||||||
|
// If-None-Match | If-Range | If-Unmodified-Since | Max-Forwards |
|
||||||
|
// Proxy-Authorization | Range | Referer | User-Agent
|
||||||
|
BOOL CHttpParser::RequestHeader()
|
||||||
|
{
|
||||||
|
INT i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUMREQUESTS; i++) {
|
||||||
|
if (strcmp(RequestTable[i], sHeader) == 0) {
|
||||||
|
switch (i) {
|
||||||
|
case 0: {
|
||||||
|
//Accept
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
//Accept-Encoding
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
//Accept-Language
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
//Host
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 16: {
|
||||||
|
//User-Agent
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EntityHeader = Allow | Content-Base | Content-Encoding | Content-Language |
|
||||||
|
// Content-Length | Content-Location | Content-MD5 |
|
||||||
|
// Content-Range | Content-Type | ETag | Expires |
|
||||||
|
// Last-Modified | extension-header
|
||||||
|
BOOL CHttpParser::EntityHeader()
|
||||||
|
{
|
||||||
|
INT i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUMENTITIES; i++) {
|
||||||
|
if (strcmp(EntityTable[i], sHeader) == 0) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
default: {
|
||||||
|
//cout << "<Entity-Header>: #" << i << endl;
|
||||||
|
Expect(':');
|
||||||
|
Expect(' ');
|
||||||
|
Skip(13);
|
||||||
|
ExpectCRLF();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageBody = *OCTET
|
||||||
|
BOOL CHttpParser::MessageBody()
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
491
reactos/apps/utils/net/roshttpd/httpd.cpp
Normal file
491
reactos/apps/utils/net/roshttpd/httpd.cpp
Normal file
|
@ -0,0 +1,491 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
struct {
|
||||||
|
DWORD Low;
|
||||||
|
DWORD High;
|
||||||
|
};
|
||||||
|
} 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.Low = GetFileSize(hFile, &nTotalBytes.High);
|
||||||
|
if ((nTotalBytes.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.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(_T("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."));
|
||||||
|
}
|
||||||
|
}
|
49
reactos/apps/utils/net/roshttpd/include/config.h
Normal file
49
reactos/apps/utils/net/roshttpd/include/config.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/config.h
|
||||||
|
*/
|
||||||
|
#ifndef __CONFIG_H
|
||||||
|
#define __CONFIG_H
|
||||||
|
|
||||||
|
#include <list.h>
|
||||||
|
#include <httpd.h>
|
||||||
|
|
||||||
|
// General constants
|
||||||
|
#define APP_DESCRIPTION _T("ReactOS HTTP Daemon")
|
||||||
|
|
||||||
|
// Default configuration
|
||||||
|
#define dcfgDescription _T("Default configuration")
|
||||||
|
#define dcfgMainBase _T("C:\\roshttpd\\")
|
||||||
|
#define dcfgHttpBase "C:\\roshttpd\\HttpBase\\"
|
||||||
|
#define dcfgDefaultResource "index.html"
|
||||||
|
#define dcfgDefaultPort 80
|
||||||
|
|
||||||
|
class CConfig {
|
||||||
|
public:
|
||||||
|
CConfig();
|
||||||
|
~CConfig();
|
||||||
|
VOID Default();
|
||||||
|
VOID Clear();
|
||||||
|
BOOL Load();
|
||||||
|
BOOL Save();
|
||||||
|
LPWSTR GetMainBase();
|
||||||
|
VOID SetMainBase(LPWSTR lpwsMainBase);
|
||||||
|
LPSTR GetHttpBase();
|
||||||
|
VOID SetHttpBase(LPSTR lpsHttpBase);
|
||||||
|
CList<LPSTR>* GetDefaultResources();
|
||||||
|
USHORT GetPort();
|
||||||
|
VOID SetPort(USHORT wPort);
|
||||||
|
private:
|
||||||
|
VOID Reset();
|
||||||
|
LPWSTR MainBase;
|
||||||
|
LPSTR HttpBase;
|
||||||
|
CList<LPSTR> DefaultResources;
|
||||||
|
USHORT Port;
|
||||||
|
};
|
||||||
|
typedef CConfig* LPCConfig;
|
||||||
|
|
||||||
|
extern LPCConfig pConfiguration;
|
||||||
|
extern LPCHttpDaemonThread pDaemonThread;
|
||||||
|
|
||||||
|
#endif /* __CONFIG_H */
|
17
reactos/apps/utils/net/roshttpd/include/debug.h
Normal file
17
reactos/apps/utils/net/roshttpd/include/debug.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/debug.h
|
||||||
|
*/
|
||||||
|
#ifndef __DEBUG_H
|
||||||
|
#define __DEBUG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef DBG
|
||||||
|
#define DPRINT(x...) printf(x)
|
||||||
|
#else
|
||||||
|
#define DPRINT(x...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __DEBUG_H */
|
15
reactos/apps/utils/net/roshttpd/include/error.h
Normal file
15
reactos/apps/utils/net/roshttpd/include/error.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/error.h
|
||||||
|
*/
|
||||||
|
#ifndef __ERROR_H
|
||||||
|
#define __ERROR_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#define TS(x) (LPTSTR)_T(x)
|
||||||
|
|
||||||
|
void ReportErrorStr(LPTSTR lpsText);
|
||||||
|
|
||||||
|
#endif /* __ERROR_H */
|
57
reactos/apps/utils/net/roshttpd/include/http.h
Normal file
57
reactos/apps/utils/net/roshttpd/include/http.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/http.h
|
||||||
|
*/
|
||||||
|
#ifndef __HTTP_H
|
||||||
|
#define __HTTP_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// Generel HTTP related constants
|
||||||
|
#define NUMMETHODS 7
|
||||||
|
#define NUMGENERELS 7
|
||||||
|
#define NUMREQUESTS 17
|
||||||
|
#define NUMENTITIES 12
|
||||||
|
|
||||||
|
// HTTP method constants
|
||||||
|
#define hmOPTIONS 0
|
||||||
|
#define hmGET 1
|
||||||
|
#define hmHEAD 2
|
||||||
|
#define hmPOST 3
|
||||||
|
#define hmPUT 4
|
||||||
|
#define hmDELETE 5
|
||||||
|
#define hmTRACE 6
|
||||||
|
|
||||||
|
class CHttpParser {
|
||||||
|
public:
|
||||||
|
CHAR sBuffer[2048];
|
||||||
|
UINT nHead;
|
||||||
|
UINT nTail;
|
||||||
|
CHAR sUri[255];
|
||||||
|
CHAR sVersion[15];
|
||||||
|
CHAR sHeader[63];
|
||||||
|
CHAR sMethod[63];
|
||||||
|
UINT nMethodNo;
|
||||||
|
BOOL bUnknownMethod;
|
||||||
|
BOOL bBadRequest;
|
||||||
|
CHttpParser();
|
||||||
|
~CHttpParser();
|
||||||
|
BOOL Complete();
|
||||||
|
BOOL Parse();
|
||||||
|
private:
|
||||||
|
BOOL ReadChar(LPSTR lpsStr);
|
||||||
|
BOOL PeekChar(LPSTR lpsStr);
|
||||||
|
BOOL ReadString(LPSTR lpsStr, UINT nLength);
|
||||||
|
BOOL ReadSpecial(LPSTR lpStr, UINT nLength);
|
||||||
|
VOID Skip(CHAR sStr);
|
||||||
|
BOOL Expect(CHAR sStr);
|
||||||
|
BOOL ExpectCRLF();
|
||||||
|
BOOL RequestLine();
|
||||||
|
BOOL GenerelHeader();
|
||||||
|
BOOL RequestHeader();
|
||||||
|
BOOL EntityHeader();
|
||||||
|
BOOL MessageBody();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __HTTP_H */
|
83
reactos/apps/utils/net/roshttpd/include/httpd.h
Normal file
83
reactos/apps/utils/net/roshttpd/include/httpd.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/httpd.h
|
||||||
|
*/
|
||||||
|
#ifndef __HTTPD_H
|
||||||
|
#define __HTTPD_H
|
||||||
|
|
||||||
|
#include <thread.h>
|
||||||
|
#include <socket.h>
|
||||||
|
#include <http.h>
|
||||||
|
|
||||||
|
#define HTTPD_START WM_USER + 1
|
||||||
|
#define HTTPD_STOP WM_USER + 2
|
||||||
|
#define HTTPD_SUSPEND WM_USER + 3
|
||||||
|
#define HTTPD_RESUME WM_USER + 4
|
||||||
|
|
||||||
|
enum HTTPdState {
|
||||||
|
hsStopped = 0,
|
||||||
|
hsRunning,
|
||||||
|
hsSuspended
|
||||||
|
};
|
||||||
|
|
||||||
|
class CHttpDaemon;
|
||||||
|
|
||||||
|
class CHttpClient : public CServerClientSocket {
|
||||||
|
public:
|
||||||
|
CHttpClient();
|
||||||
|
CHttpClient(LPCServerSocket lpServerSocket);
|
||||||
|
virtual void OnRead();
|
||||||
|
//virtual void OnWrite();
|
||||||
|
virtual void OnClose();
|
||||||
|
HANDLE ThreadHandle;
|
||||||
|
DWORD ThreadId;
|
||||||
|
CHttpParser Parser;
|
||||||
|
void SplitUri(const LPSTR lpsUri, LPSTR lpsHost, LPSTR lpsResource, LPSTR lpsParams);
|
||||||
|
void SplitResource(const LPSTR lpsResource, LPSTR lpsPath, LPSTR lpsFilename, LPSTR lpsExtension);
|
||||||
|
void ProcessRequest();
|
||||||
|
void SendFile(const LPSTR lpsFilename);
|
||||||
|
void Report(const LPSTR lpsCode, const LPSTR lpsStr);
|
||||||
|
private:
|
||||||
|
BOOL bStop;
|
||||||
|
LPSTR lpsBuffer;
|
||||||
|
LONG nBufferSize;
|
||||||
|
unsigned __int64 nTotalRead;
|
||||||
|
unsigned __int64 nFileSize;
|
||||||
|
HANDLE hFile;
|
||||||
|
};
|
||||||
|
typedef CHttpClient* LPCHttpClient;
|
||||||
|
|
||||||
|
class CHttpClientThread : public CServerClientThread {
|
||||||
|
public:
|
||||||
|
CHttpClientThread() {};
|
||||||
|
CHttpClientThread(LPCServerClientSocket Socket);
|
||||||
|
virtual void Execute();
|
||||||
|
};
|
||||||
|
typedef CHttpClientThread* LPCHttpClientThread;
|
||||||
|
|
||||||
|
class CHttpDaemon : public CServerSocket {
|
||||||
|
public:
|
||||||
|
CHttpDaemon();
|
||||||
|
virtual ~CHttpDaemon();
|
||||||
|
HTTPdState GetState() const;
|
||||||
|
virtual BOOL Start();
|
||||||
|
virtual BOOL Stop();
|
||||||
|
virtual LPCServerClientSocket OnGetSocket(LPCServerSocket lpServerSocket);
|
||||||
|
virtual LPCServerClientThread OnGetThread(LPCServerClientSocket Socket);
|
||||||
|
virtual void OnAccept(const LPCServerClientThread lpThread);
|
||||||
|
private:
|
||||||
|
HTTPdState State;
|
||||||
|
};
|
||||||
|
typedef CHttpDaemon* LPCHttpDaemon;
|
||||||
|
|
||||||
|
class CHttpDaemonThread : public CThread {
|
||||||
|
public:
|
||||||
|
CHttpDaemonThread() {};
|
||||||
|
virtual void Execute();
|
||||||
|
private:
|
||||||
|
CHttpDaemon *Daemon;
|
||||||
|
};
|
||||||
|
typedef CHttpDaemonThread* LPCHttpDaemonThread;
|
||||||
|
|
||||||
|
#endif /* __HTTPD_H */
|
20
reactos/apps/utils/net/roshttpd/include/iterator.h
Normal file
20
reactos/apps/utils/net/roshttpd/include/iterator.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/iterator.h
|
||||||
|
*/
|
||||||
|
#ifndef __ITERATOR_H
|
||||||
|
#define __ITERATOR_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
template <class Item>
|
||||||
|
class CIterator {
|
||||||
|
public:
|
||||||
|
virtual VOID First() = 0;
|
||||||
|
virtual VOID Next() = 0;
|
||||||
|
virtual BOOL IsDone() const = 0;
|
||||||
|
virtual Item CurrentItem() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __ITERATOR_H */
|
233
reactos/apps/utils/net/roshttpd/include/list.h
Normal file
233
reactos/apps/utils/net/roshttpd/include/list.h
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/list.h
|
||||||
|
*/
|
||||||
|
#ifndef __LIST_H
|
||||||
|
#define __LIST_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <iterator.h>
|
||||||
|
|
||||||
|
class CListNode {
|
||||||
|
public:
|
||||||
|
CListNode();
|
||||||
|
CListNode(VOID *element, CListNode *next, CListNode *prev);
|
||||||
|
~CListNode() {};
|
||||||
|
PVOID operator new(/*size_t s*/ UINT s);
|
||||||
|
VOID operator delete(PVOID p);
|
||||||
|
|
||||||
|
VOID SetElement(PVOID element);
|
||||||
|
VOID SetNext(CListNode *next);
|
||||||
|
VOID SetPrev(CListNode *prev);
|
||||||
|
PVOID GetElement();
|
||||||
|
CListNode *GetNext();
|
||||||
|
CListNode *GetPrev();
|
||||||
|
private:
|
||||||
|
PVOID Element;
|
||||||
|
CListNode *Next;
|
||||||
|
CListNode *Prev;
|
||||||
|
static HANDLE hHeap;
|
||||||
|
static INT nRef;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Item> class CList {
|
||||||
|
public:
|
||||||
|
//CList(CList&);
|
||||||
|
CList();
|
||||||
|
~CList();
|
||||||
|
CList& operator=(CList&);
|
||||||
|
|
||||||
|
CIterator<Item> *CreateIterator() const;
|
||||||
|
LONG Count() const;
|
||||||
|
Item& Get(const LONG index) const;
|
||||||
|
// Can throw bad_alloc
|
||||||
|
VOID Insert(Item& element);
|
||||||
|
VOID Remove(Item& element);
|
||||||
|
VOID RemoveAll();
|
||||||
|
CListNode *GetHeader() const;
|
||||||
|
CListNode *GetTrailer() const;
|
||||||
|
private:
|
||||||
|
CListNode *Search(Item& element) const;
|
||||||
|
LONG NodeCount;
|
||||||
|
CListNode *Header;
|
||||||
|
CListNode *Trailer;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Item> class CListIterator : public CIterator<Item> {
|
||||||
|
public:
|
||||||
|
CListIterator(const CList<Item> *list);
|
||||||
|
virtual VOID First();
|
||||||
|
virtual VOID Next();
|
||||||
|
virtual BOOL IsDone() const;
|
||||||
|
virtual Item CurrentItem() const;
|
||||||
|
private:
|
||||||
|
const CList<Item> *List;
|
||||||
|
CListNode *Current;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ****************************** CList ******************************
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
template <class Item>
|
||||||
|
CList<Item>::CList()
|
||||||
|
{
|
||||||
|
// Create dummy nodes
|
||||||
|
Trailer = new CListNode;
|
||||||
|
Header = new CListNode;
|
||||||
|
Header->SetNext(Trailer);
|
||||||
|
Trailer->SetPrev(Header);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default destructor
|
||||||
|
template <class Item>
|
||||||
|
CList<Item>::~CList()
|
||||||
|
{
|
||||||
|
RemoveAll();
|
||||||
|
delete Trailer;
|
||||||
|
delete Header;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an iterator for the list
|
||||||
|
template <class Item>
|
||||||
|
CIterator<Item> *CList<Item>::CreateIterator() const
|
||||||
|
{
|
||||||
|
return new CListIterator<Item>((CList<Item> *) this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of elements in list
|
||||||
|
template <class Item>
|
||||||
|
LONG CList<Item>::Count() const
|
||||||
|
{
|
||||||
|
return NodeCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return element at index
|
||||||
|
template <class Item>
|
||||||
|
Item& CList<Item>::Get(const LONG index) const
|
||||||
|
{
|
||||||
|
CListNode *node;
|
||||||
|
|
||||||
|
if ((index < 0) || (index >= NodeCount))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = Header;
|
||||||
|
for (i = 0; i <= index; i++)
|
||||||
|
node = node->GetNext();
|
||||||
|
|
||||||
|
return (Item *) node->GetElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert an element into the list
|
||||||
|
template <class Item>
|
||||||
|
VOID CList<Item>::Insert(Item& element)
|
||||||
|
{
|
||||||
|
CListNode *node;
|
||||||
|
|
||||||
|
node = new CListNode((PVOID)element, Trailer, Trailer->GetPrev());
|
||||||
|
Trailer->GetPrev()->SetNext(node);
|
||||||
|
Trailer->SetPrev(node);
|
||||||
|
NodeCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove an element from the list
|
||||||
|
template <class Item>
|
||||||
|
VOID CList<Item>::Remove(Item& element)
|
||||||
|
{
|
||||||
|
CListNode *node;
|
||||||
|
|
||||||
|
node = Search(element);
|
||||||
|
if (node != NULL) {
|
||||||
|
node->GetPrev()->SetNext(node->GetNext());
|
||||||
|
node->GetNext()->SetPrev(node->GetPrev());
|
||||||
|
NodeCount--;
|
||||||
|
delete node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all elements in list
|
||||||
|
template <class Item>
|
||||||
|
VOID CList<Item>::RemoveAll()
|
||||||
|
{
|
||||||
|
CListNode *node;
|
||||||
|
CListNode *tmp;
|
||||||
|
|
||||||
|
node = Header->GetNext();
|
||||||
|
while (node != Trailer) {
|
||||||
|
tmp = node->GetNext();
|
||||||
|
delete node;
|
||||||
|
node = tmp;
|
||||||
|
}
|
||||||
|
Header->SetNext(Trailer);
|
||||||
|
Trailer->SetPrev(Header);
|
||||||
|
NodeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return header node
|
||||||
|
template <class Item>
|
||||||
|
CListNode *CList<Item>::GetHeader() const
|
||||||
|
{
|
||||||
|
return Header;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return trailer node
|
||||||
|
template <class Item>
|
||||||
|
CListNode *CList<Item>::GetTrailer() const
|
||||||
|
{
|
||||||
|
return Trailer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches for a node that contains the element. Returns NULL if element is not found
|
||||||
|
template <class Item>
|
||||||
|
CListNode *CList<Item>::Search(Item& element) const
|
||||||
|
{
|
||||||
|
CListNode *node;
|
||||||
|
|
||||||
|
node = Header;
|
||||||
|
while (((node = node->GetNext()) != Trailer) && (node->GetElement() != element));
|
||||||
|
if (node != Trailer)
|
||||||
|
return node;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************** CListIterator **************************
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
template <class Item>
|
||||||
|
CListIterator<Item>::CListIterator(const CList<Item> *list) : List(list)
|
||||||
|
{
|
||||||
|
First();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to first element in list
|
||||||
|
template <class Item>
|
||||||
|
VOID CListIterator<Item>::First()
|
||||||
|
{
|
||||||
|
Current = List->GetHeader()->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to next element in list
|
||||||
|
template <class Item>
|
||||||
|
VOID CListIterator<Item>::Next()
|
||||||
|
{
|
||||||
|
if (!IsDone())
|
||||||
|
Current = Current->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return FALSE when there are more elements in list and TRUE when there are no more
|
||||||
|
template <class Item>
|
||||||
|
BOOL CListIterator<Item>::IsDone() const
|
||||||
|
{
|
||||||
|
return (Current == List->GetTrailer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return current element
|
||||||
|
template <class Item>
|
||||||
|
Item CListIterator<Item>::CurrentItem() const
|
||||||
|
{
|
||||||
|
return IsDone()? NULL : (Item) Current->GetElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __LIST_H */
|
141
reactos/apps/utils/net/roshttpd/include/socket.h
Normal file
141
reactos/apps/utils/net/roshttpd/include/socket.h
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/socket.h
|
||||||
|
*/
|
||||||
|
#ifndef __SOCKET_H
|
||||||
|
#define __SOCKET_H
|
||||||
|
#include <crtdll/stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <list.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define MAX_PENDING_CONNECTS 4 // The backlog allowed for listen()
|
||||||
|
|
||||||
|
VOID InitWinsock();
|
||||||
|
VOID DeinitWinsock();
|
||||||
|
|
||||||
|
class CSocket;
|
||||||
|
class CClientSocket;
|
||||||
|
class CServerClientSocket;
|
||||||
|
class CServerClientThread;
|
||||||
|
class CServerSocket;
|
||||||
|
|
||||||
|
typedef CSocket* LPCSocket;
|
||||||
|
typedef CClientSocket* LPCClientSocket;
|
||||||
|
typedef CServerClientSocket* LPCServerClientSocket;
|
||||||
|
typedef CServerClientThread* LPCServerClientThread;
|
||||||
|
typedef CServerSocket* LPCServerSocket;
|
||||||
|
|
||||||
|
class ESocket {
|
||||||
|
public:
|
||||||
|
ESocket() { Description = NULL; }
|
||||||
|
ESocket(LPTSTR description) { Description = description; }
|
||||||
|
LPTSTR what() { return Description; }
|
||||||
|
protected:
|
||||||
|
LPTSTR Description;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ESocketWinsock : public ESocket {
|
||||||
|
public:
|
||||||
|
ESocketWinsock(LPTSTR description) { Description = description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ESocketDll : public ESocket {
|
||||||
|
public:
|
||||||
|
ESocketDll(LPTSTR description) { Description = description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ESocketOpen : public ESocket {
|
||||||
|
public:
|
||||||
|
ESocketOpen(LPTSTR description) { Description = description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ESocketClose : public ESocket {
|
||||||
|
public:
|
||||||
|
ESocketClose(LPTSTR description) { Description = description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ESocketSend : public ESocket {
|
||||||
|
public:
|
||||||
|
ESocketSend(LPTSTR description) { Description = description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ESocketReceive : public ESocket {
|
||||||
|
public:
|
||||||
|
ESocketReceive(LPTSTR description) { Description = description; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CSocket {
|
||||||
|
public:
|
||||||
|
CSocket();
|
||||||
|
virtual ~CSocket();
|
||||||
|
virtual SOCKET GetSocket();
|
||||||
|
virtual VOID SetSocket(SOCKET socket);
|
||||||
|
virtual SOCKADDR_IN GetSockAddrIn();
|
||||||
|
virtual VOID SetSockAddrIn(SOCKADDR_IN sockaddrin);
|
||||||
|
virtual VOID SetEvents(LONG lEvents);
|
||||||
|
virtual LONG GetEvents();
|
||||||
|
virtual VOID SetPort( UINT nPort) {};
|
||||||
|
virtual VOID Open();
|
||||||
|
virtual VOID Close();
|
||||||
|
virtual INT Transmit( LPSTR lpsBuffer, UINT nLength) { return 0; };
|
||||||
|
virtual INT Receive(LPSTR lpsBuffer, UINT nLength) { return 0; };
|
||||||
|
virtual INT SendText( LPSTR lpsStr) { return 0; };
|
||||||
|
protected:
|
||||||
|
SOCKET Socket;
|
||||||
|
SOCKADDR_IN SockAddrIn;
|
||||||
|
WSAEVENT Event;
|
||||||
|
UINT Port;
|
||||||
|
BOOL Active;
|
||||||
|
private:
|
||||||
|
LONG Events;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CServerClientSocket : public CSocket {
|
||||||
|
public:
|
||||||
|
CServerClientSocket() {};
|
||||||
|
CServerClientSocket(LPCServerSocket lpServerSocket);
|
||||||
|
CServerSocket *GetServerSocket();
|
||||||
|
virtual INT Transmit( LPSTR lpsBuffer, UINT nLength);
|
||||||
|
virtual INT Receive(LPSTR lpsBuffer, UINT nLength);
|
||||||
|
virtual INT SendText( LPSTR lpsText);
|
||||||
|
virtual VOID MessageLoop();
|
||||||
|
virtual VOID OnRead() {};
|
||||||
|
//virtual VOID OnWrite() {};
|
||||||
|
virtual VOID OnClose() {};
|
||||||
|
protected:
|
||||||
|
LPCServerSocket ServerSocket;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CServerClientThread : public CThread {
|
||||||
|
public:
|
||||||
|
CServerClientThread() {};
|
||||||
|
CServerClientThread(CServerClientSocket *socket);
|
||||||
|
virtual ~CServerClientThread();
|
||||||
|
protected:
|
||||||
|
CServerClientSocket *ClientSocket;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CServerSocket : public CSocket {
|
||||||
|
public:
|
||||||
|
CServerSocket();
|
||||||
|
virtual ~CServerSocket();
|
||||||
|
virtual VOID SetPort( UINT nPort);
|
||||||
|
virtual VOID Open();
|
||||||
|
virtual VOID Close();
|
||||||
|
virtual LPCServerClientSocket OnGetSocket(LPCServerSocket lpServerSocket);
|
||||||
|
virtual LPCServerClientThread OnGetThread(LPCServerClientSocket lpSocket);
|
||||||
|
virtual VOID OnAccept( LPCServerClientThread lpThread) {};
|
||||||
|
virtual VOID MessageLoop();
|
||||||
|
VOID InsertClient(LPCServerClientThread lpClient);
|
||||||
|
VOID RemoveClient(LPCServerClientThread lpClient);
|
||||||
|
protected:
|
||||||
|
CList<LPCServerClientThread> Connections;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __SOCKET_H */
|
34
reactos/apps/utils/net/roshttpd/include/thread.h
Normal file
34
reactos/apps/utils/net/roshttpd/include/thread.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: include/thread.h
|
||||||
|
*/
|
||||||
|
#ifndef __THREAD_H
|
||||||
|
#define __THREAD_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
class CThread;
|
||||||
|
|
||||||
|
struct ThreadData {
|
||||||
|
CThread *ClassPtr;
|
||||||
|
HANDLE hFinished;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CThread {
|
||||||
|
public:
|
||||||
|
CThread();
|
||||||
|
virtual ~CThread();
|
||||||
|
BOOL PostMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
virtual void Execute();
|
||||||
|
virtual void Terminate();
|
||||||
|
BOOL Terminated();
|
||||||
|
protected:
|
||||||
|
BOOL bTerminated;
|
||||||
|
DWORD dwThreadId;
|
||||||
|
HANDLE hThread;
|
||||||
|
ThreadData Data;
|
||||||
|
};
|
||||||
|
typedef CThread *LPCThread;
|
||||||
|
|
||||||
|
#endif /* __THREAD_H */
|
54
reactos/apps/utils/net/roshttpd/makefile
Normal file
54
reactos/apps/utils/net/roshttpd/makefile
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#
|
||||||
|
# ReactOS HTTP Daemon
|
||||||
|
#
|
||||||
|
PATH_TO_TOP = ../../..
|
||||||
|
|
||||||
|
TARGETNAME=roshttpd
|
||||||
|
|
||||||
|
CFLAGS = -Iinclude -DUNICODE -D_UNICODE -DDBG
|
||||||
|
|
||||||
|
MAIN_OBJECTS = $(TARGETNAME).o config.o error.o http.o httpd.o
|
||||||
|
COMMON_OBJECTS = common/list.o common/socket.o common/thread.o
|
||||||
|
|
||||||
|
OBJECTS = $(MAIN_OBJECTS) $(COMMON_OBJECTS)
|
||||||
|
PROGS = $(TARGETNAME).exe
|
||||||
|
LIBS = ../../../lib/kernel32/kernel32.a \
|
||||||
|
../../../lib/ws2_32/ws2_32.a
|
||||||
|
|
||||||
|
ifeq ($(DOSCLI), yes)
|
||||||
|
CLEAN_FILES = *.o $(TARGETNAME).exe $(TARGETNAME).sym common\*.o
|
||||||
|
else
|
||||||
|
CLEAN_FILES = *.o $(TARGETNAME).exe $(TARGETNAME).sym common/*.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(TARGETNAME).exe
|
||||||
|
|
||||||
|
clean: $(CLEAN_FILES:%=%_clean)
|
||||||
|
|
||||||
|
$(CLEAN_FILES:%=%_clean): %_clean:
|
||||||
|
- $(RM) $*
|
||||||
|
|
||||||
|
.phony: clean $(CLEAN_FILES:%=%_clean)
|
||||||
|
|
||||||
|
install: $(PROGS:%=$(FLOPPY_DIR)/apps/%)
|
||||||
|
|
||||||
|
$(PROGS:%=$(FLOPPY_DIR)/apps/%): $(FLOPPY_DIR)/apps/%: %
|
||||||
|
ifeq ($(DOSCLI),yes)
|
||||||
|
$(CP) $* $(FLOPPY_DIR)\apps\$*
|
||||||
|
else
|
||||||
|
$(CP) $* $(FLOPPY_DIR)/apps/$*
|
||||||
|
endif
|
||||||
|
|
||||||
|
dist: $(PROGS:%=../../$(DIST_DIR)/apps/%)
|
||||||
|
|
||||||
|
$(PROGS:%=../../$(DIST_DIR)/apps/%): ../../$(DIST_DIR)/apps/%: %
|
||||||
|
ifeq ($(DOSCLI),yes)
|
||||||
|
$(CP) $* ..\..\$(DIST_DIR)\apps\$*
|
||||||
|
else
|
||||||
|
$(CP) $* ../../$(DIST_DIR)/apps/$*
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(TARGETNAME).exe: $(OBJECTS) $(LIBS)
|
||||||
|
$(CC) $(OBJECTS) $(LIBS) -o $(TARGETNAME).exe
|
||||||
|
|
||||||
|
include ../../../rules.mak
|
66
reactos/apps/utils/net/roshttpd/roshttpd.cpp
Normal file
66
reactos/apps/utils/net/roshttpd/roshttpd.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS HTTP Daemon
|
||||||
|
* FILE: roshttpd.cpp
|
||||||
|
* PURPOSE: Main program
|
||||||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||||
|
* REVISIONS:
|
||||||
|
* CSH 01/09/2000 Created
|
||||||
|
*/
|
||||||
|
#include <debug.h>
|
||||||
|
#include <new>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <error.h>
|
||||||
|
#include <httpd.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
VOID Run()
|
||||||
|
{
|
||||||
|
InitWinsock();
|
||||||
|
|
||||||
|
pDaemonThread = NULL;
|
||||||
|
pConfiguration = NULL;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create configuration object
|
||||||
|
pConfiguration = new CConfig;
|
||||||
|
pConfiguration->Default();
|
||||||
|
|
||||||
|
// Create daemon object
|
||||||
|
pDaemonThread = new CHttpDaemonThread;
|
||||||
|
|
||||||
|
MSG Msg;
|
||||||
|
BOOL bQuit = FALSE;
|
||||||
|
while ((!bQuit) && (!pDaemonThread->Terminated())) {
|
||||||
|
bQuit = PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE);
|
||||||
|
if (!bQuit)
|
||||||
|
DispatchMessage(&Msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pDaemonThread;
|
||||||
|
|
||||||
|
if (pConfiguration != NULL)
|
||||||
|
delete pConfiguration;
|
||||||
|
} catch (bad_alloc e) {
|
||||||
|
if (pConfiguration != NULL)
|
||||||
|
delete pConfiguration;
|
||||||
|
ReportErrorStr(TS("Insufficient resources."));
|
||||||
|
}
|
||||||
|
|
||||||
|
DeinitWinsock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Program entry point */
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
printf("ReactOS HTTP Daemon\n");
|
||||||
|
printf("Type Control-C to stop.\n");
|
||||||
|
|
||||||
|
Run();
|
||||||
|
|
||||||
|
printf("Daemon stopped.\n");
|
||||||
|
}
|
Loading…
Reference in a new issue