Skip to content

Instantly share code, notes, and snippets.

@freecnjet
Created October 26, 2012 10:40
Show Gist options
  • Save freecnjet/3958117 to your computer and use it in GitHub Desktop.
Save freecnjet/3958117 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <WinSock2.h>
#include "HttpServer.hpp"
#define HTTP_HEADER_BUFSIZE 1024
#define MAX_REQUEST_BACKLOG 64
static DWORD WINAPI ListenThreadFunction( LPVOID lpParam );
namespace WebServer
{
class Win32HTTPServer : public HTTPServer
{
public:
Win32HTTPServer();
virtual ~Win32HTTPServer();
int Start(unsigned short port);
int Stop();
bool IsListening();
void SetHTTPConnectResponser(HTTPConnectResponser* responser);
void SetHTTPGETResponser(HTTPGETResponser* responser);
///////////////////////////////////////////
// call by listen thread
void WaitInternal();
private:
SOCKET m_ListenSocket;
HANDLE m_hTread;
HTTPConnectResponser* m_ConnectResponser;
HTTPGETResponser* m_GETResponser;
void ResultInternal(SOCKET client, int result, const char* content_type, const char* content, size_t content_len );
};
Win32HTTPServer::Win32HTTPServer():m_ListenSocket(INVALID_SOCKET), m_hTread(NULL)
{
}
Win32HTTPServer::~Win32HTTPServer()
{
if( IsListening ) {
Stop();
}
}
bool Win32HTTPServer::IsListening()
{
return INVALID_SOCKET!=m_ListenSocket;
}
void Win32HTTPServer::ResultInternal(SOCKET client, int result, const char* content_type, const char* content, size_t content_len )
{
assert( INVALID_SOCKET!=client );
char buffer[HTTP_HEADER_BUFSIZE+1];
sprintf_s(buffer, HTTP_HEADER_BUFSIZE, "HTTP/1.1 200 OK\nServer: httpserver0.1\nContent-Length: %ld\nConnection: close\nContent-Type: %s\n\n%s", SizeToSend, "text/html", hello );
return;
}
int Win32HTTPServer::Start(unsigned short port)
{
if( IsListening ) {
Stop();
}
int ret = 0;
while( true )
{
m_ListenSocket = socket( AF_INET, SOCK_STREAM, 0 );
if( INVALID_SOCKET==m_ListenSocket )
{
ret = -1;
break;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
if( bind(m_ListenSocket, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0 ) {
ret = -2;
break;
}
if( listen(m_ListenSocket, MAX_REQUEST_BACKLOG) < 0 ) {
ret = -3;
break;
}
DWORD dwThreadID;
m_hTread = CreateThread(NULL, 0, ListenThreadFunction, static_cast<LPVOID(this), 0, &dwThreadID );
if( NULL==m_hTread ) {
ret = -4;
break;
}
return 0;
}
// error
if( m_ListenSocket ) {
closesocket(m_ListenSocket);
m_ListenSocket = NULL;
}
return ret;
}
void Win32HTTPServer::WaitInternal()
{
char geturl[MAX_HTTP_URL_PATH_SIZE+1];
char buffer[HTTP_HEADER_BUFSIZE+1];
struct sockaddr_in client_addr;
int length = sizeof(client_addr);
while( true )
{
Sleep(1);
SOCKET client_socket = accept(m_ListenSocket, (struct sockaddr *)&client_addr, &length);
if( INVALID_SOCKET==client_socket )
continue;
m_ConnectResponser->ClientConnected();
long recved = 0;
geturl[0] = '\0';
char* pword = &geturl[0];
bool got_get = false;
do {
recved = recv(client_socket, buffer, HTTP_HEADER_BUFSIZE, 0);
if( 0>=recved )
break;
buffer[recved] = '\0';
// parser HTTP header
for( char* pchar=&buffer[0]; *pchar; ++pchar )
{
if( '\r'==*pchar ) {
continue;
}
// end of a word
if( ' '==*pchar || '\n'==*pchar )
{
*pword = '\0';
if( got_get ) { // this should be GET url path
break; // GET url path
}
// blank line, end of header
if( 0==strlen(geturl) ){
break;
}
// GET head
if( 0==strncmp(geturl, "GET", 3) ) {
got_get = true;
}
geturl[0] = '\0';
pword = &geturl[0];
continue;
}
*(pword++) = *pchar;
}
} while( recved>0 );
// no GET head or GET url path not set
if( 0==strlen(geturl) ) {
//logger(FORBIDDEN,"Only simple GET operation supported",buffer,fd);
} else {
HTTPGETContext get_context;
strcpy(get_context.m_Path, geturl);
int get_ret = m_GETResponser->Get(&get_context);
switch( get_ret )
{
case EWebServerStatus_OK:
break;
case EWebServerStatus_BadRequest:
break;
case EWebServerStatus_Forbidden:
break;
case EWebServerStatus_InternalServerError:
break;
}
}
closesocket(client_socket);
m_ConnectResponser->ClientDisconnected();
}
}
int Win32HTTPServer::Stop()
{
if( m_hTread ) {
TerminateThread(m_hTread);
m_hTread = NULL;
}
if( INVALID_SOCKET!=m_ListenSocket ) {
int ret = shutdown(m_ListenSocket, SD_BOTH);
assert(0==ret);
int ret = closesocket(m_ListenSocket);
assert(0==ret);
m_ListenSocket = INVALID_SOCKET;
}
return 0;
}
void Win32HTTPServer::SetHTTPConnectResponser(HTTPConnectResponser* responser)
{
assert( NULL==m_hTread && INVALID_SOCKET==m_ListenSocket );
m_ConnectResponser = responser;
}
void Win32HTTPServer::SetHTTPGETResponser(HTTPGETResponser* responser)
{
assert( NULL==m_hTread && INVALID_SOCKET==m_ListenSocket );
m_GETResponser = responser;
}
} //WebService
DWORD WINAPI ListenThreadFunction( LPVOID lpParam )
{
WebServer::Win32HTTPServer* pServer = static_cast<WebServer::Win32HTTPServer*>(lpParam);
pServer->WaitInternal();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment