TINYHTTPD is a lightweight HTTP server, the original Linux code, support CGI script, I changed the version of Windows, remove CGI script support. Added support for two-level file download, so you can test downloads locally.
Tinyhttpd.cpp: Defines the entry point of the console application.
//
#include "stdafx.h"
#include "Windows.h"
#include "Winsock2.h"
#include "WS2tcpip.h"
#include <cstring>
#include <io.h>
#pragma comment (lib, "Ws2_32.lib")
#define ISSPACE (x) ((x) = = ")
#define Server_string "server:jdbhttpd/0.1.0\r\n"
DWORD WINAPI accept_request (void*);
void bad_request (int);
void Cat (int, FILE *);
void Cannot_execute (int);
void Error_die (const char *);
int get_line (int, char *, int);
void headers (int, const char *);
void Not_found (int);
void Serve_file (int, const char *);
int startup (U_short *);
void unimplemented (int);
int strcasecmp (const char *psrc,const char *PDST)
{
Return stricmp (PSRC,PDST);
}
/**********************************************************************/
/* A request has caused A call to accept () on the server port to
* return. Process the request appropriately.
* Parameters:the socket connected to the client */
/**********************************************************************/
DWORD WINAPI accept_request (void *para)
{
int client = (int) para;
Char buf[1024];
int numchars;
Char method[255];
Char url[255];
Char path[512];
size_t I, J;
char *query_string = NULL;
NumChars = get_line (client, buf, sizeof (BUF));
i = 0; j = 0;
while (! ISspace (Buf[j]) && (I < sizeof (method)-1))
{
Method[i] = Buf[j];
i++; j + +;
}
Method[i] = ' + ';
if (strcasecmp (method, "GET") && strcasecmp (method, "POST"))
{
unimplemented (client);
return 0;
}
i = 0;
while (ISspace (Buf[j) && (J < sizeof (BUF)))
j + +;
while (! ISspace (Buf[j]) && (i < sizeof (URL)-1) && (J < sizeof (BUF)))
{
Url[i] = Buf[j];
i++; j + +;
}
Url[i] = ' + ';
if (strcasecmp (method, "GET") = = 0)
{
query_string = URL;
while (*query_string! = '? ') && (*query_string! = ') ")
query_string++;
if (*query_string = = '? ')
{
*query_string = ' + ';
query_string++;
}
}
sprintf (Path, "htdocs%s", url);
if (Path[strlen (path)-1] = = '/')
strcat (Path, "index.html");
if (0! = _access (path,0))
{
while ((NumChars > 0) && strcmp ("\ n", buf)/*/Read & Discard Headers */
NumChars = get_line (client, buf, sizeof (BUF));
Not_found (client);
}
Else
{
Serve_file (client, path);
}
Closesocket (client);
return 0;
}
/**********************************************************************/
/* Inform the client that a request it had made has a problem.
* Parameters:client Socket */
/**********************************************************************/
void bad_request (int client)
{
Char buf[1024];
sprintf (buf, "http/1.0 request\r\n");
Send (client, buf, sizeof (BUF), 0);
sprintf (buf, "content-type:text/html\r\n");
Send (client, buf, sizeof (BUF), 0);
sprintf (buf, "\ r \ n");
Send (client, buf, sizeof (BUF), 0);
sprintf (buf, "<p>your browser sent a bad request,");
Send (client, buf, sizeof (BUF), 0);
sprintf (BUF, "such as a POST without a content-length.\r\n");
Send (client, buf, sizeof (BUF), 0);
}
/**********************************************************************/
/* Put The entire contents of a file out on a socket. This function
* is named after the UNIX "cat" command, because it might has been
* Easier just to does something like pipe, fork, and exec ("cat").
* Parameters:the Client Socket Descriptor
* File pointer for the file to cat */
#include ". /.. /.. /COM/CFILE.HPP "
/**********************************************************************/
void Cat (int client, const char *resource)
{
Buf Buf = myreadfile (Resource);
if (BUF.P)
{
Send (client, buf.p,buf.size, 0);
}
}
/**********************************************************************/
/* Inform the client, a CGI script could not being executed.
* Parameter:the Client Socket descriptor. */
/**********************************************************************/
void Cannot_execute (int client)
{
Char buf[1024];
sprintf (buf, "http/1.0 Internal Server error\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "content-type:text/html\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "\ r \ n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "<p>error prohibited CGI execution.\r\n");
Send (client, buf, strlen (BUF), 0);
}
/**********************************************************************/
/* Print out a error message with Perror () (for system errors; based
* On value of errno, which indicates system call errors) and exit the
* Program indicating an error. */
/**********************************************************************/
void Error_die (const char *SC)
{
Perror (SC);
Exit (1);
}
/**********************************************************************/
/* Get a line from a socket, Whether the line ends in a newline,
* carriage return, or a CRLF combination. Terminates the string read
* with a null character. If No newline indicator is found before the
* end of the buffer, the string was terminated with a null. If any of the
* The above three line terminators are read, the last character of the
* string would be a linefeed and the String would be terminated with a
* null character.
* Parameters:the Socket Descriptor
* The buffer to save the data in
* The size of the buffer
* returns:the numb Er of bytes stored (excluding null) */
/**********************************************************************/
int get_line (int sock, char *buf, int size)
{
int i = 0;
char c = ' + ';
int n;
while ((I < size-1) && (c! = ' \ n '))
{
n = recv (sock, &c, 1, 0);
/* DEBUG printf ("%02x\n", c); */
if (n > 0)
{
if (c = = ' \ r ')
{
n = recv (sock, &c, 1, Msg_peek);
/* DEBUG printf ("%02x\n", c); */
if ((n > 0) && (c = = ' \ n '))
Recv (sock, &c, 1, 0);
Else
c = ' \ n ';
}
Buf[i] = c;
i++;
}
Else
c = ' \ n ';
}
Buf[i] = ' + ';
return (i);
}
/**********************************************************************/
/* Return The informational HTTP headers about a file. */
/* parameters:the socket to print the headers on
* The name of the file * *
/**********************************************************************/
void headers (int client, const char *filename)
{
Char buf[1024];
(void) filename; /* could use filename to determine file type */
strcpy (buf, "http/1.0 ok\r\n");
Send (client, buf, strlen (BUF), 0);
strcpy (buf, server_string);
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "content-type:application/octet-stream\r\n");
Send (client, buf, strlen (BUF), 0);
strcpy (buf, "\ r \ n");
Send (client, buf, strlen (BUF), 0);
}
/**********************************************************************/
/* Give a client a 404 Not Found status message. */
/**********************************************************************/
void Not_found (int client)
{
Char buf[1024];
sprintf (buf, "http/1.0 404 Not Found\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, server_string);
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "content-type:text/html\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "\ r \ n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, " Send (client, buf, strlen (BUF), 0);
sprintf (buf, "<body><p>the server could not fulfill\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "Your request because the resource specified\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (BUF, "is unavailable or nonexistent.\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "</body> Send (client, buf, strlen (BUF), 0);
}
/**********************************************************************/
/* Send a regular file to the client. Use headers, and report
* Errors to client if they occur.
* parameters:a Pointer to a file structure produced from the socket
* File descriptor
* The name of the file to serve */
/**********************************************************************/
void Serve_file (int client, const char *filename)
{
FILE *resource = NULL;
int numchars = 1;
Char buf[1024];
Buf[0] = ' A '; Buf[1] = ' + ';
while ((NumChars > 0) && strcmp ("\ n", buf)/*/Read & Discard Headers */
NumChars = get_line (client, buf, sizeof (BUF));
Resource = fopen (filename, "RB");
if (resource = = NULL)
Not_found (client);
Else
{
Headers (client, filename);
Cat (client, filename);
}
Fclose (Resource);
}
/**********************************************************************/
/* This function starts the process of listening for Web connections
* on a specified port. If the port is 0, then dynamically allocate a
* port and modify the original port variable to reflect the actual
* p Ort.
* parameters:pointer to variable containing the port to connect on
* returns:the socket */
/****************** /
int Startup (U_short *port)
{
int httpd = 0;
struct sockaddr_in name;
httpd = socket (pf_inet, sock_stream, 0);
if (httpd = =-1)
Error_die ("socket");
memset (&name, 0, sizeof (name));
name.sin_family = af_inet;
Name.sin_port = htons (*port);
NAME.SIN_ADDR.S_ADDR = htonl (Inaddr_any);
if (Bind (httpd, (struct sockaddr *) &name, sizeof (name)) < 0)
Error_die ("bind");
if (*port = = 0)/* If dynamically allocating a port */
{
int namelen = sizeof (name);
if (GetSockName (httpd, (struct sockaddr *) &name, &namelen) = =-1)
Error_die ("GetSockName");
*port = Ntohs (Name.sin_port);
}
if (Listen (httpd, 5) < 0)
Error_die ("Listen");
return (HTTPD);
}
/**********************************************************************/
/* Inform The client, the requested Web method has not been
* implemented.
* Parameter:the Client Socket */
/**********************************************************************/
void unimplemented (int client)
{
Char buf[1024];
sprintf (BUF, "http/1.0 501 Method not implemented\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, server_string);
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "content-type:text/html\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "\ r \ n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "Send (client, buf, strlen (BUF), 0);
sprintf (buf, "</title>Send (client, buf, strlen (BUF), 0);
sprintf (buf, "<body><p>http request method not supported.\r\n");
Send (client, buf, strlen (BUF), 0);
sprintf (buf, "</body>Send (client, buf, strlen (BUF), 0);
}
/**********************************************************************/
static void Initwinsock ()
{
Wsadata Wsadata;
WSAStartup (Makeword (2, 1), &wsadata);
}
int main (void)
{
Initwinsock ();
int server_sock =-1;
U_short port = 80;
int client_sock =-1;
struct sockaddr_in client_name;
int client_name_len = sizeof (client_name);
Server_sock = Startup (&port);
printf ("HTTPd running on port%d\n", port);
while (1)
{
Client_sock = Accept (Server_sock,
(struct sockaddr *) &client_name,
&client_name_len);
if (Client_sock = =-1)
Error_die ("accept");
CreateThread (0,0,accept_request, (void*) client_sock,0,0);
}
Closesocket (Server_sock);
return (0);
}
Open Source Learning: tinyhttpd