Tinyhttp Source Code Interpretation

Source: Internet
Author: User

Tinyhttp is the simplest Web server that implements the fundamentals of Web servers. The code is all developed in C language, only more than 500 lines, read the code, you can understand the basic principles of Web server.

Download Connection: http://sourceforge.net/projects/tinyhttpd/

After downloading, you will experience problems compiling. In makefile, the execution of the compilation script is:

Gcc-w-wall-lsocket-lpthread-o httpd HTTPD.C

Where Lsocket is not required, because the author of the development of the Linux version with me, I used Ubuntu Server, do not need this line selection.

-lpthread should be replaced with-pthread, for specific reasons refer here.

There are some caveats, because of the problem with the parameter type.

after I compile, the runtime discovers that the home page is not open. With GDB debugging, the breakpoint is added to the sub-process after the fork, in the GDB mode to be set: Set Follow-fork mode child, so that GDB will debug the sub-process after the fork is executed. Finally found that index.html has execute permission, need to remove this permission to line.

<span style= "FONT-SIZE:14PX;" >/* J David ' s webserver *//* This is a simple webserver. * Created November 1999 by J. David Blackstone. * CSE 4344 (Network Concepts), Prof. Zeigler * University of Texas at Arlington *//* This program compiles for Sparc Solar IS 2.6. * To compile for Linux: * 1) Comment out of the #include <pthread.h> line. * 2) Comment out of the line that defines the variable newthread. * 3) Comment out the lines, that run Pthread_create (). * 4) Uncomment the line that runs Accept_request (). * 5) Remove-lsocket from the Makefile. * * #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h># Include <arpa/inet.h> #include <unistd.h> #include <ctype.h> #include <strings.h> #include < string.h> #include <sys/stat.h> #include <pthread.h> #include <sys/wait.h> #include <stdlib.h > #define ISSPACE (x) ISspace ((int) (x))//check if ' x ' is a white-space#define server_string "server:jdbhttpd/0.1.0\r\n" void accept_request (int), void bad_request (int), void cat (int, FILE *), void Cannot_execute ( int), void Error_die (const char *), void execute_cgi (int, const char *, const char *, 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);/**********************************************************************//* 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 *//****************************************************************** /void accept_request (int client) {char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_ t I, J;      struct STAT St;//record The information about the file int cgi = 0; /* becomes true if server decides this is a CGI * program */char *query_string = NULL; NumChars = Get_line (client, buf, sizeof (BUF)); i = 0; j = 0; while (! ISspace (Buf[j]) && (I < sizeof (method)-1)//' method ' contains the HTTP method (Get/post) {method[i] = Buf[j]  ; i++; j + +; } Method[i] = ' + '; Compares the characters ignoring case of character if (strcasecmp (method, "GET") && strcasecmp (method, "POST"))  {unimplemented (client); Return } if (strcasecmp (method, "POST") = = 0) cgi = 1; i = 0; while (ISspace (Buf[j) && (J < sizeof (BUF))//skip the Header j + +; while (! ISspace (Buf[j]) && (i < sizeof (URL)-1) && (J < sizeof (BUF)))//copy the URL to ' URL ' {url[i] = bu  F[J]; i++; j + +; } Url[i] = ' + ';  if (strcasecmp (method, "GET") = = 0) {query_string = URL;  while (*query_string! = '? ') && (*query_string! = ') ") query_string++;  if (*query_string = = '? ')   {cgi = 1;   *query_string = ' + ';  query_string++; }} sprintf (Path, "htdocs%s", url),//write ' url ' to path and add ' Htdocs ' at the head of path if (PATh[strlen (Path)-1] = = '/') strcat (path, "index.html");  if (stat (path, &st) = =-1) {//check If the file exist or not ((NumChars > 0) && strcmp ("\ n", buf))  /* Read & Discard headers */numchars = get_line (client, buf, sizeof (BUF)); Not_found (client);//file not exist} Else//file exist {if ((St.st_mode & s_ifmt) = = S_ifdir)//a directory strcat (p  Ath, "/index.html"); if ((St.st_mode & s_ixusr) | |      Check the permission owner, group user or other users (St.st_mode & s_ixgrp) | |   (St.st_mode & S_ixoth))  cgi = 1;  if (!cgi)//not a CIG serve_file (client, path); else execute_cgi (client, path, method, query_string); } close (client);} /**********************************************************************//* Inform the client a request it has 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 Soc  Ket.  This function * was 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 *//***************************** /void Cat (int client, FILE *resource) {char buf[1024]; fgets (buf, sizeof (BUF) , resource); while (!feof (Resource))//feof:check End-of-file Indicator {Send (client, buf, strlen (BUF), 0); Fgets (buf, sizeof (BUF), Resource); }}/**********************************************************************//* Inform the client that 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);}  /**********************************************************************//* Execute a CGI script. would need to set environment variables as * appropriate. * Parameters:client Socket Descriptor * Path to the CGI script *//******************************************* /void execute_cgi (int client, const char *path, const char *method, const char *query_string) {char buf[1024]; int cgi_output[2];//pipe to communicate between parent and child int cgi_input[2]; pid_t p Id int status; int i; char c; int numchars = 1; int content_length =-1; Buf[0] = ' A '; Buf[1] = ' + ';  if (strcasecmp (method, "GET") = = 0) while ((NumChars > 0) && strcmp ("\ n", buf)/*/Read & Discard Headers */NumChars = get_line (client, buf, sizeof (BUF));  else/* POST */{NumChars = get_line (client, buf, sizeof (BUF)); while ((NumChars > 0) && strcmp ("\ n", buf)) {buf[15] = ' + ';//seT buf[15]= ' to compare with "Content-length:" If (strcasecmp (buf, "content-length:") = = 0) content_length = atoi (&   amp; (buf[16]));  NumChars = get_line (client, buf, sizeof (BUF));   } if (content_length = =-1) {bad_request (client);  Return }} sprintf (buf, "http/1.0 ok\r\n");  Send (client, buf, strlen (BUF), 0),//send respond status if (pipe (Cgi_output) < 0) {Cannot_execute (client); Return  } if (pipe (Cgi_input) < 0) {Cannot_execute (client); Return  } if (pid = fork ()) < 0) {Cannot_execute (client); Return  } if (pid = = 0)/* child:cgi script */{char meth_env[255];  Char query_env[255];  Char length_env[255]; Dup2 (Cgi_output[1], 1);//redirect cgi_output[1] to standard output dup2 (Cgi_input[0], 0);//redirect Cgi_input[0] to Stan Dard input Close (cgi_output[0])//the parent process use cgi_output[0] to input data close (cgi_input[1]);//the parent PR  Ocess use cig_input[1] to output data sprintf (meth_env, "request_method=%s", METHOD); Putenv (Meth_ENV);   if (strcasecmp (method, "GET") = = 0) {sprintf (query_env, "query_string=%s", query_string);  Putenv (QUERY_ENV);   } else {/* POST */sprintf (length_env, "content_length=%d", content_length); Putenv (length_env);//and value of environment variables} execl (path, path, NULL);//execute the CGI program exit (0);  } else {/* parent */close (cgi_output[1]);  Close (cgi_input[0]);    if (strcasecmp (method, "POST") = = 0) for (i = 0; i < content_length; i++) {recv (client, &c, 1, 0); Write (cgi_input[1], &c, 1),//pass the para to child process} while (read (cgi_output[0], &c, 1) > 0)//read t  He child process result Send (client, &c, 1, 0);  Close (cgi_output[0]);  Close (cgi_input[1]); Waitpid (PID, &status, 0);//wait for child process until it ends}}/************************************************ * Get a line from a socket, whether the line ends in a newline, * carriage return, or a CRLF combi  Nation. 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 above three line terminators are read, the last character of the * string would be a linefeed and the string 'll is terminated with a * null character. * Parameters:the Socket Descriptor * The buffer to save the data in * the size of the buffer * Re Turns:the number of bytes stored (excluding null) *//**************************************************************** /int get_line (int sock, char *buf, int size) {int i = 0; char c = ' n '; 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);//peek, in fact don ' t read the data. /* DEBUG printf ("%02x\n", c);  */if ((n > 0) && (c = = ' \ n '))//if terminated with CRLF recv (sock, &c, 1, 0);  else C = ' \ n ';   } Buf[i] = C;  i++; } else C = ' \ n '; } Buf[i] = ' + ';//the buffer end with null 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:text/html\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, "

Tinyhttp Source Code Interpretation

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.