Published on

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide


  1. 1. Networking Programming
  2. 2. Outline <ul><li>Web servers </li></ul><ul><ul><li>HTTP Protocol </li></ul></ul><ul><ul><li>Web Content </li></ul></ul><ul><ul><li>CGI </li></ul></ul><ul><li>The Tiny Web Server </li></ul><ul><li>Suggested Reading: </li></ul><ul><ul><li>12.5~12.6 </li></ul></ul>
  3. 3. <ul><li>Clients and servers communicate using the HyperText Transfer Protocol (HTTP) </li></ul><ul><ul><li>client and server establish TCP connection </li></ul></ul><ul><ul><li>Client requests content </li></ul></ul><ul><ul><li>Server responds with requested content </li></ul></ul><ul><ul><li>client and server close connection (usually) </li></ul></ul><ul><li>Current version is HTTP/1.1 </li></ul><ul><ul><li>RFC 2616, June, 1999. </li></ul></ul>Web servers
  4. 4. Web servers web server HTTP request HTTP response (content) web client (browser)
  5. 5. <ul><li>Web servers return content to clients </li></ul><ul><ul><li>content: a sequence of bytes with an associated MIME (Multipurpose Internet Mail Extensions) type </li></ul></ul>Web content
  6. 6. <ul><li>Example MIME types </li></ul><ul><ul><li>text/html HTML page </li></ul></ul><ul><ul><li>text/plain Unformatted text </li></ul></ul><ul><ul><li>application/postscript Postcript document </li></ul></ul><ul><ul><li>image/gif Binary image encoded in GIF format </li></ul></ul><ul><ul><li>image/jpg Binary image encoded in JPG format </li></ul></ul>Web content
  7. 7. <ul><li>The content returned in HTTP responses can be either static or dynamic </li></ul><ul><ul><li>Static content: </li></ul></ul><ul><ul><ul><li>content stored in files and retrieved in response to an HTTP request </li></ul></ul></ul><ul><ul><ul><li>Examples: HTML files, images, audio clips. </li></ul></ul></ul><ul><ul><li>Dynamic content: </li></ul></ul><ul><ul><ul><li>content produced on-the-fly in response to an HTTP request </li></ul></ul></ul><ul><ul><ul><li>Example: content produced by a program executed by the server on behalf of the client. </li></ul></ul></ul>Static and dynamic content
  8. 8. <ul><li>Each file managed by a server has a unique name called a URL (Universal Resource Locator) </li></ul><ul><li>URLs for static content: </li></ul><ul><ul><li>http://www.cs.cmu.edu:80/index.html </li></ul></ul><ul><ul><li>http://www.cs.cmu.edu/index.html </li></ul></ul><ul><ul><li>http://www.cs.cmu.edu </li></ul></ul><ul><ul><ul><li>identifies a file called index.html, managed by a Web server at www.cs.cmu.edu that is listening on port 80. </li></ul></ul></ul>URLs
  9. 9. <ul><li>URLs for dynamic content: </li></ul><ul><ul><li>http://www.cs.cmu.edu:8000/cgi-bin/adder?15000&213 </li></ul></ul><ul><ul><ul><li>identifies an executable file called adder , managed by a Web server at www.cs.cmu.edu that is listening on port 8000, that should be called with two argument strings: 15000 and 213 . </li></ul></ul></ul>URLs
  10. 10. <ul><li>Example URL: http://www.aol.com:80/index.html </li></ul><ul><li>Clients use prefix (http://www.aol.com:80) to infer: </li></ul><ul><ul><li>What kind of server to contact (Web server) </li></ul></ul><ul><ul><li>Where the server is (www.aol.com) </li></ul></ul><ul><ul><li>What port it is listening on (80) </li></ul></ul>How clients and servers use URLs
  11. 11. <ul><li>Servers use suffix (/index.html) to: </li></ul><ul><ul><li>Determine if request is for static or dynamic content. </li></ul></ul><ul><ul><ul><li>No hard and fast rules for this. </li></ul></ul></ul><ul><ul><ul><li>Convention: executables reside in cgi-bin directory </li></ul></ul></ul><ul><ul><li>Find file on filesystem </li></ul></ul><ul><ul><ul><li>Initial “/” in suffix denotes home directory for requested content. </li></ul></ul></ul><ul><ul><ul><li>Minimal suffix is “/”, which all servers expand to some default home page (e.g., index.html). </li></ul></ul></ul>How clients and servers use URLs
  12. 12. <ul><li>//Client: open connection to server </li></ul><ul><li>unix> telnet www.aol.com 80 </li></ul><ul><li>//Telnet prints 3 lines to the terminal </li></ul><ul><li>Trying </li></ul><ul><li>Connected to aol.com. </li></ul><ul><li>Escape character is '^]'. </li></ul><ul><li>//Client: request line </li></ul><ul><li>GET / HTTP/1.1 </li></ul><ul><li>//Client: required HTTP/1.1 HOST header </li></ul><ul><li>host: www.aol.com </li></ul><ul><li>//Client: empty line terminates headers </li></ul>Anatomy of an HTTP transaction
  13. 13. <ul><li>//Server: response line </li></ul><ul><li>HTTP/1.0 200 OK </li></ul><ul><li>//Server: followed by five response headers </li></ul><ul><li>MIME-Version: 1.0 </li></ul><ul><li>Date: Mon, 08 Jan 2001 04:59:42 GMT </li></ul><ul><li>Server: NaviServer/2.0 AOLserver/2.3.3 </li></ul><ul><li>//Server: expect HTML in the response body </li></ul><ul><li>Content-Type: text/html </li></ul><ul><li>//Server: expect 42,092 bytes in the resp body </li></ul><ul><li>Content-Length: 42092 </li></ul><ul><li>//Server: empty line (“ ”) terminates hdrs </li></ul>Anatomy of an HTTP transaction
  14. 14. <ul><li>//Server: first HTML line in response body </li></ul><ul><li><html> </li></ul><ul><li>... //Server: 766 lines of HTML not shown. </li></ul><ul><li></html> </li></ul><ul><li>//Server: last HTML line in response body </li></ul><ul><li>//Server: closes connection </li></ul><ul><li>Connection closed by foreign host. </li></ul><ul><li>Client: closes connection and terminates </li></ul><ul><li>unix> </li></ul>Anatomy of an HTTP transaction
  15. 15. <ul><li>Client sends request to server </li></ul><ul><li>If request URI contains the string “/cgi-bin”, then the server assumes that the request is for dynamic content. </li></ul>Serving dynamic content client server GET /cgi-bin/env.pl HTTP/1.1
  16. 16. <ul><li>The server creates a child process and runs the program identified by the URI in that process </li></ul>Serving dynamic content client server env.pl fork/exec
  17. 17. <ul><li>The child runs and generates the dynamic content. </li></ul><ul><li>The server captures the content of the child and forwards it without modification to the client </li></ul>Serving dynamic content client server env.pl content content
  18. 18. <ul><li>How does the client pass program arguments to the server? </li></ul><ul><li>How does the server pass these arguments to the child? </li></ul><ul><li>How does the server pass other info relevant to the request to the child? </li></ul>Serving dynamic content
  19. 19. <ul><li>How does the server capture the content produced by the child? </li></ul><ul><li>These issues are addressed by the Common Gateway Interface (CGI) specification. </li></ul>Serving dynamic content
  20. 20. Serving dynamic content client server content content request create env.pl
  21. 21. <ul><li>Question: </li></ul><ul><ul><li>How does the client pass arguments to the server? </li></ul></ul><ul><li>Answer: </li></ul><ul><ul><li>The arguments are appended to the URI </li></ul></ul><ul><ul><ul><li>http://add.com/cgi-bin/adder?1&2 </li></ul></ul></ul><ul><ul><ul><li>adder is the CGI program on the server that will do the addition. </li></ul></ul></ul><ul><ul><ul><li>argument list starts with “?” </li></ul></ul></ul><ul><ul><ul><li>arguments separated by “&” </li></ul></ul></ul><ul><ul><ul><li>spaces represented by “%20” </li></ul></ul></ul>Serving dynamic content
  22. 22. <ul><li>Question : </li></ul><ul><ul><li>How does the server pass these arguments to the child? </li></ul></ul><ul><li>Answer: </li></ul><ul><ul><li>In environment variable QUERY_STRING </li></ul></ul><ul><ul><ul><li>a single string containing everything after the “?” </li></ul></ul></ul><ul><ul><ul><li>for add.com: QUERY_STRING = “1&2” </li></ul></ul></ul>Serving dynamic content
  23. 23. Serving dynamic content if ((buf = getenv(&quot;QUERY_STRING&quot;)) != NULL) { p = strchr(buf, ’&’); *p = ’’; strcpy(arg1, buf); strcpy(arg2, p+1); n1 = atoi(arg1); n2 = atoi(arg2); }
  24. 24. <ul><li>Question: </li></ul><ul><ul><li>How does the server pass other info relevant to the request to the child? </li></ul></ul><ul><li>Answer: </li></ul><ul><ul><li>in a collection of environment variables defined by the CGI spec. </li></ul></ul>Serving dynamic content
  25. 25. <ul><li>Request-specific </li></ul><ul><ul><li>QUERY_STRING (contains GET args) </li></ul></ul><ul><ul><li>SERVER_PORT </li></ul></ul><ul><ul><li>REQUEST_METHOD ( GET , POST , etc) </li></ul></ul><ul><ul><li>REMOTE_HOST (domain name of client) </li></ul></ul><ul><ul><li>REMOTE_ADDR (IP address of client) </li></ul></ul><ul><ul><li>CONTENT_TYPE (for POST , MIME type of the request body ) </li></ul></ul><ul><ul><li>CONTENT_LENGTH (for POST , length in bytes) </li></ul></ul>Some CGI environment variables
  26. 26. <ul><li>Question: </li></ul><ul><ul><li>How does the server capture the content produced by the child? </li></ul></ul><ul><li>Answer: </li></ul><ul><ul><li>The child generates its output on stdout . Server uses dup2 to redirect stdout to its connected socket. </li></ul></ul><ul><ul><li>Notice that only the child knows the type and size of the content. </li></ul></ul><ul><ul><li>Thus the child (not the server) must generate the corresponding headers. </li></ul></ul>Serving dynamic content
  27. 27. <ul><li>/* Domain Name Service (DNS) host entry */ </li></ul><ul><li>struct hostent { </li></ul><ul><li>/* official name of host */ </li></ul><ul><li>char *h_name; </li></ul><ul><li>/* alias list */ </li></ul><ul><li>char **h_aliases; </li></ul><ul><li>/* host address type */ </li></ul><ul><li>int h_addrtype; </li></ul><ul><li>/* length of address */ </li></ul><ul><li>int h_length; </li></ul><ul><li>/* list of addresses */ </li></ul><ul><li>char **h_addr_list; </li></ul><ul><li>} </li></ul>
  28. 28. <ul><li>/* Internet address */ </li></ul><ul><li>struct in_addr { </li></ul><ul><li>/* 32-bit IP address */ </li></ul><ul><li>unsigned int s_addr; </li></ul><ul><li>}; </li></ul><ul><li>/* Generic socket address structure </li></ul><ul><li>(for connect, bind, and accept) */ </li></ul><ul><li>struct sockaddr { </li></ul><ul><li>/* protocol family */ </li></ul><ul><li>unsigned short sa_family ; </li></ul><ul><li>/* address data */ </li></ul><ul><li>char sa_data[14]; </li></ul><ul><li>} </li></ul>
  29. 29. <ul><li>/* Internet style socket address */ </li></ul><ul><li>struct sockaddr_in { </li></ul><ul><li>/* Address family (AF_INET) */ </li></ul><ul><li>unsigned short sin_family; </li></ul><ul><li>/* Port number */ </li></ul><ul><li>unsigned short sin_port; </li></ul><ul><li>/* IP address */ </li></ul><ul><li>struct in_addr sin_addr; </li></ul><ul><li>/* Pad to sizeof “struct sockaddr” */ </li></ul><ul><li>unsigned char sin_zero[8]; </li></ul><ul><li>}; </li></ul>
  30. 30. <ul><li>struct hostent *genhostbyname( </li></ul><ul><li>const char *name); </li></ul><ul><li>struct hostent *genhostbyaddr( </li></ul><ul><li>const char *addr, int len,0); </li></ul><ul><li>int socket( </li></ul><ul><li>int domain, int type, int protocol); </li></ul><ul><li>clientfd = socekt(AF_INET,SOCKET_STREAM, 0) ; </li></ul><ul><li>int connect(int sockfd, </li></ul><ul><li>struct sockaddr *serv_addr, </li></ul><ul><li>int addr_len); </li></ul>
  31. 31. <ul><li>int bind(int sockfd, </li></ul><ul><li> struct sockaddr *my_addr, </li></ul><ul><li> int addrlen); </li></ul><ul><li>int listen(int sockfd, int backlog) ; </li></ul><ul><li>int accept(int listenfd, </li></ul><ul><li> struct sockaddr *addr, </li></ul><ul><li> int addrlen) ; </li></ul>
  32. 32. <ul><li>1 /* </li></ul><ul><li>2 * tiny.c - A simple HTTP/1.0 Web server that uses the GET method </li></ul><ul><li>3 * to serve static and dynamic content. </li></ul><ul><li>4 */ </li></ul><ul><li>5 #include &quot;csapp.h&quot; </li></ul><ul><li>6 </li></ul><ul><li>7 void doit(int fd); </li></ul><ul><li>8 void read_requesthdrs(int fd); </li></ul>The Tiny Web Server
  33. 33. <ul><li>9 int parse_uri( char *uri, char *filename, char *cgiargs ); </li></ul><ul><li>10 void serve_static( rio_t *rio, char *filename, int filesize ); </li></ul><ul><li>11 void get_filetype( char *filename, char *filetype ); </li></ul><ul><li>12 void serve_dynamic( rio_t *rio,char *filename,char*cgiargs ); </li></ul><ul><li>13 void clienterror( rio_t *rio, char *cause, char *errnum, </li></ul><ul><li>14 char *shortmsg, char *longmsg ); </li></ul><ul><li>15 </li></ul>The Tiny Web Server
  34. 34. <ul><li>16 int main(int argc, char **argv) </li></ul><ul><li>17 { </li></ul><ul><li>18 int listenfd, connfd, port, clientlen; </li></ul><ul><li>19 struct sockaddr_in clientaddr; </li></ul><ul><li>20 </li></ul><ul><li>21 /* check command line args */ </li></ul><ul><li>22 if (argc != 2) { </li></ul><ul><li>23 fprintf(stderr,&quot;usage: %s <port> &quot;, argv [0]); </li></ul><ul><li>24 exit(1); </li></ul><ul><li>25 } </li></ul><ul><li>26 port = atoi(argv[1]); </li></ul><ul><li>27 </li></ul>The Tiny Web Server
  35. 35. <ul><li>28 listenfd = open_listenfd(port); </li></ul><ul><li>29 while (1) { </li></ul><ul><li>30 clientlen = sizeof(clientaddr); </li></ul><ul><li>31 connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen); </li></ul><ul><li>32 doit(connfd); </li></ul><ul><li>33 Close(connfd); </li></ul><ul><li>34 } </li></ul><ul><li>35 } </li></ul>The Tiny Web Server
  36. 36. <ul><li>1 void doit(int fd) </li></ul><ul><li>2 { </li></ul><ul><li>3 int is_static; </li></ul><ul><li>4 struct stat sbuf; </li></ul><ul><li>5 char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; </li></ul><ul><li>6 char filename[MAXLINE], cgiargs[MAXLINE]; </li></ul><ul><li>rio_t rio; </li></ul>The Tiny Web Server
  37. 37. <ul><li>9 /* read request line and headers */ </li></ul><ul><li>10 Rio_readinitb(&rio, fd) </li></ul><ul><li>11 Rio_readlineb(&rio, buf, MAXLINE); </li></ul><ul><li>12 sscanf(buf, &quot;%s %s %s &quot;, method, uri, version); </li></ul><ul><li>13 if (strcasecmp(method, &quot;GET&quot;)) { </li></ul><ul><li>14 clienterror(fd, method, &quot;501&quot;, &quot;Not Implemented&quot;, </li></ul><ul><li>15 &quot;Tiny does not implement this method&quot;); </li></ul><ul><li>16 return; </li></ul><ul><li>17 } </li></ul><ul><li>18 read_requesthdrs(&rio); </li></ul><ul><li>19 </li></ul>The Tiny Web Server
  38. 38. <ul><li>20 /* parse URI from GET request */ </li></ul><ul><li>21 is_static = parse_uri(uri, filename, cgiargs); </li></ul><ul><li>22 if (stat(filename, &sbuf) < 0) { </li></ul><ul><li>23 clienterror(fd, filename, &quot;404&quot;, &quot;Not found&quot;, </li></ul><ul><li>24 &quot;Tiny couldn’t find this file&quot;); </li></ul><ul><li>25 return; </li></ul><ul><li>26 } </li></ul><ul><li>27 </li></ul>The Tiny Web Server
  39. 39. <ul><li>28 if (is_static) { /* serve static content */ </li></ul><ul><li>29 if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { </li></ul><ul><li>30 clienterror(fd, filename, &quot;403&quot;, </li></ul><ul><li>31 &quot;Forbidden&quot;,&quot;Tiny couldn’t read the file&quot;); </li></ul><ul><li>32 return; </li></ul><ul><li>33 } </li></ul><ul><li>34 serve_static(&rio, filename, sbuf.st_size); </li></ul><ul><li>35 } </li></ul>The Tiny Web Server
  40. 40. <ul><li>34 else { /* serve dynamic content */ </li></ul><ul><li>35 if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { </li></ul><ul><li>36 clienterror(fd, filename, &quot;403&quot;, &quot;Forbidden&quot;, </li></ul><ul><li>37 &quot;Tiny couldn’t run the CGI program&quot;); </li></ul><ul><li>38 return; </li></ul><ul><li>39 } </li></ul><ul><li>40 serve_dynamic(&rio, filename, cgiargs); </li></ul><ul><li>41 } </li></ul><ul><li>42 } </li></ul>The Tiny Web Server
  41. 41. <ul><li>1 void clienterror(rio_t *fd, char *cause, char *errnum, </li></ul><ul><li>2 char *shortmsg, char *longmsg) </li></ul><ul><li>3 { </li></ul><ul><li>4 char buf[MAXLINE], body[MAXBUF]; </li></ul><ul><li>5 </li></ul><ul><li>6 /* build the HTTP response body */ </li></ul><ul><li>7 sprintf(body, &quot;<html><title>Tiny Error</title>&quot;); </li></ul><ul><li>8 sprintf(body, &quot;%s<body bgcolor=&quot;&quot;ffffff&quot;&quot;> &quot;, body); </li></ul><ul><li>9 sprintf(body, &quot;%s%s: %s &quot;, body, errnum, shortmsg); </li></ul><ul><li>10 sprintf(body, &quot;%s<p>%s: %s &quot;, body, longmsg, cause); </li></ul><ul><li>11 sprintf(body, &quot;%s<hr><em>The Tiny Web server</em> &quot;, body); </li></ul><ul><li>12 </li></ul><ul><li>13 /* print the HTTP response */ </li></ul><ul><li>14 sprintf(buf, &quot;HTTP/1.0 %s %s &quot;, errnum, shortmsg); </li></ul><ul><li>15 Rio_writen(fd, buf, strlen(buf)); </li></ul><ul><li>16 sprintf(buf, &quot;Content-type: text/html &quot;); </li></ul><ul><li>17 Rio_writen(fd, buf, strlen(buf)); </li></ul><ul><li>18 sprintf(buf, &quot;Content-length: %d &quot;, strlen(body)); </li></ul><ul><li>19 Rio_writen(fd, buf, strlen(buf)); </li></ul><ul><li>20 Rio_writen(fd, body, strlen(body)); </li></ul><ul><li>21 } </li></ul>
  42. 42. <ul><li>1 void read_requesthdrs(rio_t *fd) </li></ul><ul><li>2 { </li></ul><ul><li>3 char buf[MAXLINE]; </li></ul><ul><li>4 </li></ul><ul><li>5 Readline(fd, buf, MAXLINE); </li></ul><ul><li>6 while(strcmp(buf, &quot; &quot;)) </li></ul><ul><li>7 Rio_readlineb(fd, buf, MAXLINE); </li></ul><ul><li>8 return; </li></ul><ul><li>9 } </li></ul>The Tiny Web Server
  43. 43. <ul><li>1 int parse_uri(char *uri, char *filename, char *cgiargs) </li></ul><ul><li>2 { </li></ul><ul><li>3 char *ptr; </li></ul><ul><li>4 </li></ul><ul><li>5 if (!strstr(uri, &quot;cgi-bin&quot;)) { /* static content */ </li></ul><ul><li>6 strcpy(cgiargs, &quot;&quot;); </li></ul><ul><li>7 strcpy(filename, &quot;.&quot;); </li></ul><ul><li>8 strcat(filename, uri); </li></ul><ul><li>9 if (uri[strlen(uri)-1] == ’/’) </li></ul><ul><li>10 strcat(filename, &quot;home.html&quot;); </li></ul><ul><li>11 return 1; </li></ul><ul><li>12 } </li></ul><ul><li>13 else { /* dynamic content */ </li></ul><ul><li>14 ptr = index(uri, ’?’); </li></ul><ul><li>15 if (ptr) { </li></ul><ul><li>16 strcpy(cgiargs, ptr+1); </li></ul><ul><li>17 *ptr = ’’; </li></ul><ul><li>18 } </li></ul><ul><li>19 else </li></ul><ul><li>20 strcpy(cgiargs, &quot;&quot;); </li></ul><ul><li>21 strcpy(filename, &quot;.&quot;); </li></ul><ul><li>22 strcat(filename, uri); </li></ul><ul><li>23 return 0; </li></ul><ul><li>24 } </li></ul><ul><li>25 } </li></ul>
  44. 44. <ul><li>1 void serve_static(int fd, char *filename, int filesize) </li></ul><ul><li>2 { </li></ul><ul><li>3 int srcfd; </li></ul><ul><li>4 char *srcp, filetype[MAXLINE], buf[MAXBUF]; </li></ul><ul><li>5 </li></ul><ul><li>6 /* send response headers to client */ </li></ul><ul><li>7 get_filetype(filename, filetype); </li></ul><ul><li>8 sprintf(buf, &quot;HTTP/1.0 200 OK &quot;); </li></ul><ul><li>9 sprintf(buf, &quot;%sServer: Tiny Web Server &quot;, buf); </li></ul><ul><li>10 sprintf(buf, &quot;%sContent-length: %d &quot;, buf, filesize); </li></ul><ul><li>11 sprintf(buf, &quot;%sContent-type: %s &quot;, buf, filetype); </li></ul><ul><li>12 Rio_writen(fd, buf, strlen(buf)); </li></ul><ul><li>13 </li></ul><ul><li>14 /* send response body to client */ </li></ul><ul><li>15 srcfd = Open(filename, O_RDONLY, 0); </li></ul><ul><li>16 srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); </li></ul><ul><li>17 Close(srcfd); </li></ul><ul><li>18 Rio_writen(fd, srcp, filesize); </li></ul><ul><li>19 Munmap(srcp, filesize); </li></ul><ul><li>20 } </li></ul><ul><li>21 </li></ul>
  45. 45. <ul><li>22 /* </li></ul><ul><li>23 * get_filetype - derive file type from file name </li></ul><ul><li>24 */ </li></ul><ul><li>25 void get_filetype(char *filename, char *filetype) </li></ul><ul><li>26 { </li></ul><ul><li>27 if (strstr(filename, &quot;.html&quot;)) </li></ul><ul><li>28 strcpy(filetype, &quot;text/html&quot;); </li></ul><ul><li>29 else if (strstr(filename, &quot;.gif&quot;)) </li></ul><ul><li>30 strcpy(filetype, &quot;image/gif&quot;); </li></ul><ul><li>31 else if (strstr(filename, &quot;.jpg&quot;)) </li></ul><ul><li>32 strcpy(filetype, &quot;image/jpg&quot;); </li></ul><ul><li>33 else </li></ul><ul><li>34 strcpy(filetype, &quot;text/plain&quot;); </li></ul><ul><li>35 } </li></ul>The Tiny Web Server
  46. 46. The Tiny Web Server <ul><li>1 void serve_dynamic(int fd, char *filename, char *cgiargs) </li></ul><ul><li>2 { </li></ul><ul><li>3 char buf[MAXLINE]; </li></ul><ul><li>4 </li></ul><ul><li>5 /* return first part of HTTP response */ </li></ul><ul><li>6 sprintf(buf, &quot;HTTP/1.0 200 OK &quot;); </li></ul><ul><li>7 Rio_writen(fd, buf, strlen(buf)); </li></ul><ul><li>8 sprintf(buf, &quot;Server: Tiny Web Server &quot;); </li></ul><ul><li>9 Rio_writen(fd, buf, strlen(buf)); </li></ul><ul><li>10 </li></ul><ul><li>11 if (Fork() == 0) { /* child */ </li></ul><ul><li>12 /* real server would set all CGI vars here */ </li></ul><ul><li>13 setenv(&quot;QUERY_STRING&quot;, cgiargs, 1); </li></ul><ul><li>14 Dup2(fd, STDOUT_FILENO); /* redirect output to client*/ </li></ul><ul><li>15 Execve(filename, NULL, environ); /* run CGI program */ </li></ul><ul><li>16 } </li></ul><ul><li>17 Wait(NULL); /* parent reaps child */ </li></ul><ul><li>18 } </li></ul>