Open Source Learning: tinyhttpd

Source: Internet
Author: User

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.