本文共 34412 字,大约阅读时间需要 114 分钟。
#include "csapp.h"void doit(int fd);void read_requesthdrs(rio_t *rp);int parse_uri(char *uri, char *filename, char *cgiargs);void serve_static(int fd, char *filename, int filesize);void get_filetype(char *filename, char *filetype);void serve_dynamic(int fd, char *filename, char *cgiargs);void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg);void echo(int connfd);int main(int argc, char **argv){ int listenfd, connfd; char hostname[MAXLINE], port[MAXLINE]; socklen_t clientlen; struct sockaddr_storage clientaddr; /* Check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s\n", argv[0]); exit(1); } listenfd = Open_listenfd(argv[1]); while (1) { clientlen = sizeof(clientaddr); connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); //line:netp:tiny:accept Getnameinfo((SA *) &clientaddr, clientlen, hostname, MAXLINE, port, MAXLINE, 0); printf("Accepted connection from (%s, %s)\n", hostname, port); echo(connfd); Close(connfd); //line:netp:tiny:close }}void echo(int connfd) { size_t n; char buf[MAXLINE]; rio_t rio; Rio_readinitb(&rio, connfd); while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { if (strcmp(buf, "\r\n") == 0) break; Rio_writen(connfd, buf, n); }}/* * doit - handle one HTTP request/response transaction */void doit(int fd){ int is_static; struct stat sbuf; char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char filename[MAXLINE], cgiargs[MAXLINE]; rio_t rio; /* Read request line and headers */ Rio_readinitb(&rio, fd); if (!Rio_readlineb(&rio, buf, MAXLINE)) //line:netp:doit:readrequest return; printf("%s", buf); sscanf(buf, "%s %s %s", method, uri, version); //line:netp:doit:parserequest if (strcasecmp(method, "GET")) { //line:netp:doit:beginrequesterr clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } //line:netp:doit:endrequesterr read_requesthdrs(&rio); //line:netp:doit:readrequesthdrs /* Parse URI from GET request */ is_static = parse_uri(uri, filename, cgiargs); //line:netp:doit:staticcheck if (stat(filename, &sbuf) < 0) { //line:netp:doit:beginnotfound clienterror(fd, filename, "404", "Not found", "Tiny couldn't find this file"); return; } //line:netp:doit:endnotfound if (is_static) { /* Serve static content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { //line:netp:doit:readable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't read the file"); return; } serve_static(fd, filename, sbuf.st_size); //line:netp:doit:servestatic } else { /* Serve dynamic content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { //line:netp:doit:executable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't run the CGI program"); return; } serve_dynamic(fd, filename, cgiargs); //line:netp:doit:servedynamic }}/* * read_requesthdrs - read HTTP request headers */void read_requesthdrs(rio_t *rp){ char buf[MAXLINE]; Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); while(strcmp(buf, "\r\n")) { //line:netp:readhdrs:checkterm Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); } return;}/* * parse_uri - parse URI into filename and CGI args * return 0 if dynamic content, 1 if static */int parse_uri(char *uri, char *filename, char *cgiargs){ char *ptr; if (!strstr(uri, "cgi-bin")) { /* Static content */ //line:netp:parseuri:isstatic strcpy(cgiargs, ""); //line:netp:parseuri:clearcgi strcpy(filename, "."); //line:netp:parseuri:beginconvert1 strcat(filename, uri); //line:netp:parseuri:endconvert1 if (uri[strlen(uri)-1] == '/') //line:netp:parseuri:slashcheck strcat(filename, "home.html"); //line:netp:parseuri:appenddefault return 1; } else { /* Dynamic content */ //line:netp:parseuri:isdynamic ptr = index(uri, '?'); //line:netp:parseuri:beginextract if (ptr) { strcpy(cgiargs, ptr+1); *ptr = '\0'; } else strcpy(cgiargs, ""); //line:netp:parseuri:endextract strcpy(filename, "."); //line:netp:parseuri:beginconvert2 strcat(filename, uri); //line:netp:parseuri:endconvert2 return 0; }}/* * serve_static - copy a file back to the client */void serve_static(int fd, char *filename, int filesize){ int srcfd; char *srcp, filetype[MAXLINE], buf[MAXBUF]; /* Send response headers to client */ get_filetype(filename, filetype); //line:netp:servestatic:getfiletype sprintf(buf, "HTTP/1.0 200 OK\r\n"); //line:netp:servestatic:beginserve sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); sprintf(buf, "%sConnection: close\r\n", buf); sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); Rio_writen(fd, buf, strlen(buf)); //line:netp:servestatic:endserve printf("Response headers:\n"); printf("%s", buf); /* Send response body to client */ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap Close(srcfd); //line:netp:servestatic:close Rio_writen(fd, srcp, filesize); //line:netp:servestatic:write Munmap(srcp, filesize); //line:netp:servestatic:munmap}/* * get_filetype - derive file type from file name */void get_filetype(char *filename, char *filetype){ if (strstr(filename, ".html")) strcpy(filetype, "text/html"); else if (strstr(filename, ".gif")) strcpy(filetype, "image/gif"); else if (strstr(filename, ".png")) strcpy(filetype, "image/png"); else if (strstr(filename, ".jpg")) strcpy(filetype, "image/jpeg"); else strcpy(filetype, "text/plain");}/* * serve_dynamic - run a CGI program on behalf of the client */void serve_dynamic(int fd, char *filename, char *cgiargs){ char buf[MAXLINE], *emptylist[] = { NULL }; /* Return first part of HTTP response */ sprintf(buf, "HTTP/1.0 200 OK\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Server: Tiny Web Server\r\n"); Rio_writen(fd, buf, strlen(buf)); if (Fork() == 0) { /* Child */ //line:netp:servedynamic:fork /* Real server would set all CGI vars here */ setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ //line:netp:servedynamic:dup2 Execve(filename, emptylist, environ); /* Run CGI program */ //line:netp:servedynamic:execve } Wait(NULL); /* Parent waits for and reaps child */ //line:netp:servedynamic:wait}/* * clienterror - returns an error message to the client */void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg){ char buf[MAXLINE], body[MAXBUF]; /* Build the HTTP response body */ sprintf(body, " Tiny Error "); sprintf(body, "%s\r\n", body); sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); sprintf(body, "%s%s: %s\r\n", body, longmsg, cause); sprintf(body, "%s
The Tiny Web server\r\n", body); /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-type: text/html\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body)); Rio_writen(fd, buf, strlen(buf)); Rio_writen(fd, body, strlen(body));}
GET / HTTP/1.1Host: localhost:5000User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: keep-alive
#include "csapp.h"void doit(int fd);void read_requesthdrs(rio_t *rp);int parse_uri(char *uri, char *filename, char *cgiargs);void serve_static(int fd, char *filename, int filesize);void get_filetype(char *filename, char *filetype);void serve_dynamic(int fd, char *filename, char *cgiargs);void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg);int main(int argc, char **argv){ int listenfd, connfd; char hostname[MAXLINE], port[MAXLINE]; socklen_t clientlen; struct sockaddr_storage clientaddr; /* Check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s\n", argv[0]); exit(1); } listenfd = Open_listenfd(argv[1]); while (1) { clientlen = sizeof(clientaddr); connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); //line:netp:tiny:accept Getnameinfo((SA *) &clientaddr, clientlen, hostname, MAXLINE, port, MAXLINE, 0); printf("Accepted connection from (%s, %s)\n", hostname, port); doit(connfd); //line:netp:tiny:doit Close(connfd); //line:netp:tiny:close }}/* * doit - handle one HTTP request/response transaction */void doit(int fd){ int is_static; struct stat sbuf; char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char filename[MAXLINE], cgiargs[MAXLINE]; rio_t rio; /* Read request line and headers */ Rio_readinitb(&rio, fd); if (!Rio_readlineb(&rio, buf, MAXLINE)) //line:netp:doit:readrequest return; printf("%s", buf); sscanf(buf, "%s %s %s", method, uri, version); //line:netp:doit:parserequest if (strcasecmp(method, "GET")) { //line:netp:doit:beginrequesterr clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } //line:netp:doit:endrequesterr read_requesthdrs(&rio); //line:netp:doit:readrequesthdrs /* Parse URI from GET request */ is_static = parse_uri(uri, filename, cgiargs); //line:netp:doit:staticcheck if (stat(filename, &sbuf) < 0) { //line:netp:doit:beginnotfound clienterror(fd, filename, "404", "Not found", "Tiny couldn't find this file"); return; } //line:netp:doit:endnotfound if (is_static) { /* Serve static content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { //line:netp:doit:readable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't read the file"); return; } serve_static(fd, filename, sbuf.st_size); //line:netp:doit:servestatic } else { /* Serve dynamic content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { //line:netp:doit:executable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't run the CGI program"); return; } serve_dynamic(fd, filename, cgiargs); //line:netp:doit:servedynamic }}/* * read_requesthdrs - read HTTP request headers */void read_requesthdrs(rio_t *rp){ char buf[MAXLINE]; Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); while(strcmp(buf, "\r\n")) { //line:netp:readhdrs:checkterm Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); } return;}/* * parse_uri - parse URI into filename and CGI args * return 0 if dynamic content, 1 if static */int parse_uri(char *uri, char *filename, char *cgiargs){ char *ptr; if (!strstr(uri, "cgi-bin")) { /* Static content */ //line:netp:parseuri:isstatic strcpy(cgiargs, ""); //line:netp:parseuri:clearcgi strcpy(filename, "."); //line:netp:parseuri:beginconvert1 strcat(filename, uri); //line:netp:parseuri:endconvert1 if (uri[strlen(uri)-1] == '/') //line:netp:parseuri:slashcheck strcat(filename, "home.html"); //line:netp:parseuri:appenddefault return 1; } else { /* Dynamic content */ //line:netp:parseuri:isdynamic ptr = index(uri, '?'); //line:netp:parseuri:beginextract if (ptr) { strcpy(cgiargs, ptr+1); *ptr = '\0'; } else strcpy(cgiargs, ""); //line:netp:parseuri:endextract strcpy(filename, "."); //line:netp:parseuri:beginconvert2 strcat(filename, uri); //line:netp:parseuri:endconvert2 return 0; }}/* * serve_static - copy a file back to the client */void serve_static(int fd, char *filename, int filesize){ int srcfd; char *srcp, filetype[MAXLINE], buf[MAXBUF]; /* Send response headers to client */ get_filetype(filename, filetype); //line:netp:servestatic:getfiletype sprintf(buf, "HTTP/1.0 200 OK\r\n"); //line:netp:servestatic:beginserve sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); sprintf(buf, "%sConnection: close\r\n", buf); sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); Rio_writen(fd, buf, strlen(buf)); //line:netp:servestatic:endserve printf("Response headers:\n"); printf("%s", buf); /* Send response body to client */ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap Close(srcfd); //line:netp:servestatic:close Rio_writen(fd, srcp, filesize); //line:netp:servestatic:write Munmap(srcp, filesize); //line:netp:servestatic:munmap}/* * get_filetype - derive file type from file name */void get_filetype(char *filename, char *filetype){ if (strstr(filename, ".html")) strcpy(filetype, "text/html"); else if (strstr(filename, ".gif")) strcpy(filetype, "image/gif"); else if (strstr(filename, ".png")) strcpy(filetype, "image/png"); else if (strstr(filename, ".jpg")) strcpy(filetype, "image/jpeg"); else if (strstr(filename, ".mpeg")) strcpy(filetype, "video/mpeg"); else strcpy(filetype, "text/plain");}/* * serve_dynamic - run a CGI program on behalf of the client */void serve_dynamic(int fd, char *filename, char *cgiargs){ char buf[MAXLINE], *emptylist[] = { NULL }; /* Return first part of HTTP response */ sprintf(buf, "HTTP/1.0 200 OK\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Server: Tiny Web Server\r\n"); Rio_writen(fd, buf, strlen(buf)); if (Fork() == 0) { /* Child */ //line:netp:servedynamic:fork /* Real server would set all CGI vars here */ setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ //line:netp:servedynamic:dup2 Execve(filename, emptylist, environ); /* Run CGI program */ //line:netp:servedynamic:execve } Wait(NULL); /* Parent waits for and reaps child */ //line:netp:servedynamic:wait}/* * clienterror - returns an error message to the client */void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg){ char buf[MAXLINE], body[MAXBUF]; /* Build the HTTP response body */ sprintf(body, " Tiny Error "); sprintf(body, "%s\r\n", body); sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); sprintf(body, "%s%s: %s\r\n", body, longmsg, cause); sprintf(body, "%s
The Tiny Web server\r\n", body); /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-type: text/html\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body)); Rio_writen(fd, buf, strlen(buf)); Rio_writen(fd, body, strlen(body));}
以上是源代码。如果不知道怎么跑关注私信我,我把整个工程文件夹发过去。
#include "csapp.h"void doit(int fd);void read_requesthdrs(rio_t *rp);int parse_uri(char *uri, char *filename, char *cgiargs);void serve_static(int fd, char *filename, int filesize);void get_filetype(char *filename, char *filetype);void serve_dynamic(int fd, char *filename, char *cgiargs);void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg);void sigchild_handler(int sig);int main(int argc, char **argv){ int listenfd, connfd; char hostname[MAXLINE], port[MAXLINE]; socklen_t clientlen; struct sockaddr_storage clientaddr; /* Check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s\n", argv[0]); exit(1); } if (Signal(SIGCHLD, sigchild_handler) == SIG_ERR) unix_error("signal child handler error"); listenfd = Open_listenfd(argv[1]); while (1) { clientlen = sizeof(clientaddr); connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); //line:netp:tiny:accept Getnameinfo((SA *) &clientaddr, clientlen, hostname, MAXLINE, port, MAXLINE, 0); printf("Accepted connection from (%s, %s)\n", hostname, port); doit(connfd); //line:netp:tiny:doit Close(connfd); //line:netp:tiny:close }}void sigchild_handler(int sig) { int old_errno = errno; int status; pid_t pid; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { } errno = old_errno;}/* * doit - handle one HTTP request/response transaction */void doit(int fd){ int is_static; struct stat sbuf; char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char filename[MAXLINE], cgiargs[MAXLINE]; rio_t rio; /* Read request line and headers */ Rio_readinitb(&rio, fd); if (!Rio_readlineb(&rio, buf, MAXLINE)) //line:netp:doit:readrequest return; printf("%s", buf); sscanf(buf, "%s %s %s", method, uri, version); //line:netp:doit:parserequest if (strcasecmp(method, "GET")) { //line:netp:doit:beginrequesterr clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } //line:netp:doit:endrequesterr read_requesthdrs(&rio); //line:netp:doit:readrequesthdrs /* Parse URI from GET request */ is_static = parse_uri(uri, filename, cgiargs); //line:netp:doit:staticcheck if (stat(filename, &sbuf) < 0) { //line:netp:doit:beginnotfound clienterror(fd, filename, "404", "Not found", "Tiny couldn't find this file"); return; } //line:netp:doit:endnotfound if (is_static) { /* Serve static content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { //line:netp:doit:readable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't read the file"); return; } serve_static(fd, filename, sbuf.st_size); //line:netp:doit:servestatic } else { /* Serve dynamic content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { //line:netp:doit:executable clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't run the CGI program"); return; } serve_dynamic(fd, filename, cgiargs); //line:netp:doit:servedynamic }}/* * read_requesthdrs - read HTTP request headers */void read_requesthdrs(rio_t *rp){ char buf[MAXLINE]; Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); while(strcmp(buf, "\r\n")) { //line:netp:readhdrs:checkterm Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf); } return;}/* * parse_uri - parse URI into filename and CGI args * return 0 if dynamic content, 1 if static */int parse_uri(char *uri, char *filename, char *cgiargs){ char *ptr; if (!strstr(uri, "cgi-bin")) { /* Static content */ //line:netp:parseuri:isstatic strcpy(cgiargs, ""); //line:netp:parseuri:clearcgi strcpy(filename, "."); //line:netp:parseuri:beginconvert1 strcat(filename, uri); //line:netp:parseuri:endconvert1 if (uri[strlen(uri)-1] == '/') //line:netp:parseuri:slashcheck strcat(filename, "home.html"); //line:netp:parseuri:appenddefault return 1; } else { /* Dynamic content */ //line:netp:parseuri:isdynamic ptr = index(uri, '?'); //line:netp:parseuri:beginextract if (ptr) { strcpy(cgiargs, ptr+1); *ptr = '\0'; } else strcpy(cgiargs, ""); //line:netp:parseuri:endextract strcpy(filename, "."); //line:netp:parseuri:beginconvert2 strcat(filename, uri); //line:netp:parseuri:endconvert2 return 0; }}/* * serve_static - copy a file back to the client */void serve_static(int fd, char *filename, int filesize){ int srcfd; char *srcp, filetype[MAXLINE], buf[MAXBUF]; /* Send response headers to client */ get_filetype(filename, filetype); //line:netp:servestatic:getfiletype sprintf(buf, "HTTP/1.0 200 OK\r\n"); //line:netp:servestatic:beginserve sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); sprintf(buf, "%sConnection: close\r\n", buf); sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); Rio_writen(fd, buf, strlen(buf)); //line:netp:servestatic:endserve printf("Response headers:\n"); printf("%s", buf); /* Send response body to client */ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap Close(srcfd); //line:netp:servestatic:close Rio_writen(fd, srcp, filesize); //line:netp:servestatic:write Munmap(srcp, filesize); //line:netp:servestatic:munmap}/* * get_filetype - derive file type from file name */void get_filetype(char *filename, char *filetype){ if (strstr(filename, ".html")) strcpy(filetype, "text/html"); else if (strstr(filename, ".gif")) strcpy(filetype, "image/gif"); else if (strstr(filename, ".png")) strcpy(filetype, "image/png"); else if (strstr(filename, ".jpg")) strcpy(filetype, "image/jpeg"); else strcpy(filetype, "text/plain");}/* * serve_dynamic - run a CGI program on behalf of the client */void serve_dynamic(int fd, char *filename, char *cgiargs){ char buf[MAXLINE], *emptylist[] = { NULL }; /* Return first part of HTTP response */ sprintf(buf, "HTTP/1.0 200 OK\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Server: Tiny Web Server\r\n"); Rio_writen(fd, buf, strlen(buf)); if (Fork() == 0) { /* Child */ //line:netp:servedynamic:fork /* Real server would set all CGI vars here */ setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ //line:netp:servedynamic:dup2 Execve(filename, emptylist, environ); /* Run CGI program */ //line:netp:servedynamic:execve }}/* * clienterror - returns an error message to the client */void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg){ char buf[MAXLINE], body[MAXBUF]; /* Build the HTTP response body */ sprintf(body, " Tiny Error "); sprintf(body, "%s\r\n", body); sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg); sprintf(body, "%s%s: %s\r\n", body, longmsg, cause); sprintf(body, "%s
The Tiny Web server\r\n", body); /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-type: text/html\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body)); Rio_writen(fd, buf, strlen(buf)); Rio_writen(fd, body, strlen(body));}
@@ -152,12 +152,12 @@ printf("Response headers:\n"); printf("%s", buf); - /* Send response body to client */ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open- srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap+ srcp = (char*)Malloc(filesize);+ Rio_readn(srcfd, srcp, filesize); Close(srcfd); //line:netp:servestatic:close Rio_writen(fd, srcp, filesize); //line:netp:servestatic:write- Munmap(srcp, filesize); //line:netp:servestatic:munmap+ free(srcp); }
Tiny Server
@@ -1,5 +1,5 @@ /*- * adder.c - a minimal CGI program that adds two numbers together+ * form-adder.c - a minimal CGI program that adds two numbers together */ #include "../csapp.h" @@ -12,10 +12,8 @@ if ((buf = getenv("QUERY_STRING")) != NULL) { p = strchr(buf, '&'); *p = '\0';- strcpy(arg1, buf);- strcpy(arg2, p+1);- n1 = atoi(arg1);- n2 = atoi(arg2);+ sscanf(buf, "first=%d", &n1);+ sscanf(p+1, "second=%d", &n2); } /* Make the response body */
tiny.c更改:
@@ -7,9 +7,9 @@ void doit(int fd); void read_requesthdrs(rio_t *rp); int parse_uri(char *uri, char *filename, char *cgiargs);-void serve_static(int fd, char *filename, int filesize);+void serve_static(int fd, char *filename, int filesize, char *method); void get_filetype(char *filename, char *filetype);-void serve_dynamic(int fd, char *filename, char *cgiargs);+void serve_dynamic(int fd, char *filename, char *cgiargs, char *method); void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg); @@ -55,7 +55,7 @@ return; printf("%s", buf); sscanf(buf, "%s %s %s", method, uri, version); //line:netp:doit:parserequest- if (strcasecmp(method, "GET")) { //line:netp:doit:beginrequesterr+ if (!(strcasecmp(method, "GET") == 0 || strcasecmp(method, "HEAD") == 0)) { clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return;@@ -76,7 +76,7 @@ "Tiny couldn't read the file"); return; }- serve_static(fd, filename, sbuf.st_size); //line:netp:doit:servestatic+ serve_static(fd, filename, sbuf.st_size, method); //line:netp:doit:servestatic } else { /* Serve dynamic content */ if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { //line:netp:doit:executable@@ -84,7 +84,7 @@ "Tiny couldn't run the CGI program"); return; }- serve_dynamic(fd, filename, cgiargs); //line:netp:doit:servedynamic+ serve_dynamic(fd, filename, cgiargs, method); //line:netp:doit:servedynamic } } @@ -136,7 +136,7 @@ /* * serve_static - copy a file back to the client */-void serve_static(int fd, char *filename, int filesize)+void serve_static(int fd, char *filename, int filesize, char *method) { int srcfd; char *srcp, filetype[MAXLINE], buf[MAXBUF];@@ -152,6 +152,9 @@ printf("Response headers:\n"); printf("%s", buf); + if (strcasecmp(method, "HEAD") == 0)+ return;+ /* Send response body to client */ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap@@ -180,7 +183,7 @@ /* * serve_dynamic - run a CGI program on behalf of the client */-void serve_dynamic(int fd, char *filename, char *cgiargs)+void serve_dynamic(int fd, char *filename, char *cgiargs, char *method) { char buf[MAXLINE], *emptylist[] = { NULL }; @@ -193,6 +196,7 @@ if (Fork() == 0) { /* Child */ //line:netp:servedynamic:fork /* Real server would set all CGI vars here */ setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv+ setenv("REQUEST_METHOD", method, 1); Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ //line:netp:servedynamic:dup2 Execve(filename, emptylist, environ); /* Run CGI program */ //line:netp:servedynamic:execve }
addr.c更改:
@@ -1,10 +1,10 @@ /*- * adder.c - a minimal CGI program that adds two numbers together+ * head-adder.c - a minimal CGI program that adds two numbers together */ #include "../csapp.h" int main(void) { - char *buf, *p;+ char *buf, *p, *method; char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE]; int n1=0, n2=0; @@ -18,6 +18,8 @@ n2 = atoi(arg2); } + method = getenv("REQUEST_METHOD");+ /* Make the response body */ sprintf(content, "Welcome to add.com: "); sprintf(content, "%sTHE Internet addition portal.\r\n", content);@@ -29,7 +31,10 @@ printf("Connection: close\r\n"); printf("Content-length: %d\r\n", (int)strlen(content)); printf("Content-type: text/html\r\n\r\n");- printf("%s", content);++ if (strcasecmp(method, "HEAD") != 0)+ printf("%s", content);+ fflush(stdout); exit(0);
tiny.c
@@ -5,7 +5,7 @@ #include "csapp.h" void doit(int fd);-void read_requesthdrs(rio_t *rp);+int read_requesthdrs(rio_t *rp, char *method); int parse_uri(char *uri, char *filename, char *cgiargs); void serve_static(int fd, char *filename, int filesize); void get_filetype(char *filename, char *filetype);@@ -55,12 +55,14 @@ return; printf("%s", buf); sscanf(buf, "%s %s %s", method, uri, version); //line:netp:doit:parserequest- if (strcasecmp(method, "GET")) { //line:netp:doit:beginrequesterr+ if (!(strcasecmp(method, "GET") == 0 || strcasecmp(method, "POST") == 0)) { clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } //line:netp:doit:endrequesterr- read_requesthdrs(&rio); //line:netp:doit:readrequesthdrs+ int param_len = read_requesthdrs(&rio, method);++ Rio_readnb(&rio, buf, param_len); /* Parse URI from GET request */ is_static = parse_uri(uri, filename, cgiargs); //line:netp:doit:staticcheck@@ -84,24 +86,29 @@ "Tiny couldn't run the CGI program"); return; }- serve_dynamic(fd, filename, cgiargs); //line:netp:doit:servedynamic+ if (strcasecmp(method, "GET") == 0)+ serve_dynamic(fd, filename, cgiargs);+ else+ serve_dynamic(fd, filename, buf); } } /* * read_requesthdrs - read HTTP request headers */-void read_requesthdrs(rio_t *rp)+int read_requesthdrs(rio_t *rp, char *method) { char buf[MAXLINE];+ int len = 0; - Rio_readlineb(rp, buf, MAXLINE);- printf("%s", buf);- while(strcmp(buf, "\r\n")) { //line:netp:readhdrs:checkterm+ do { Rio_readlineb(rp, buf, MAXLINE); printf("%s", buf);- }- return;+ if (strcasecmp(method, "POST") == 0 && strncasecmp(buf, "Content-Length:", 15) == 0)+ sscanf(buf, "Content-Length: %d", &len);+ } while(strcmp(buf, "\r\n"));++ return len;
post-addr
@@ -1,5 +1,5 @@ /*- * adder.c - a minimal CGI program that adds two numbers together+ * post-adder.c - a minimal CGI program that adds two numbers together */ #include "../csapp.h" @@ -12,10 +12,8 @@ if ((buf = getenv("QUERY_STRING")) != NULL) { p = strchr(buf, '&'); *p = '\0';- strcpy(arg1, buf);- strcpy(arg2, p+1);- n1 = atoi(arg1);- n2 = atoi(arg2);+ sscanf(buf, "first=%d", &n1);+ sscanf(p+1, "second=%d", &n2); }
@@ -13,6 +13,17 @@ void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg); +// improved rio written+void Im_rio_writen(int fd, void *usrbuf, size_t n) { + if (rio_writen(fd, usrbuf, n) != n) { + if (errno == EPIPE)+ fprintf(stderr, "EPIPE error");++ fprintf(stderr, "%s ", strerror(errno));+ unix_error("client side has ended connection");+ }+}+ int main(int argc, char **argv) { int listenfd, connfd;@@ -26,6 +37,9 @@ exit(1); } + if (Signal(SIGPIPE, SIG_IGN) == SIG_ERR)+ unix_error("mask signal pipe error");+ listenfd = Open_listenfd(argv[1]); while (1) { clientlen = sizeof(clientaddr);@@ -148,7 +162,7 @@ sprintf(buf, "%sConnection: close\r\n", buf); sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);- Rio_writen(fd, buf, strlen(buf)); //line:netp:servestatic:endserve+ Im_rio_writen(fd, buf, strlen(buf)); //line:netp:servestatic:endserve printf("Response headers:\n"); printf("%s", buf); @@ -156,7 +170,7 @@ srcfd = Open(filename, O_RDONLY, 0); //line:netp:servestatic:open srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap Close(srcfd); //line:netp:servestatic:close- Rio_writen(fd, srcp, filesize); //line:netp:servestatic:write+ Im_rio_writen(fd, srcp, filesize); //line:netp:servestatic:write Munmap(srcp, filesize); //line:netp:servestatic:munmap } @@ -186,11 +200,13 @@ /* Return first part of HTTP response */ sprintf(buf, "HTTP/1.0 200 OK\r\n");- Rio_writen(fd, buf, strlen(buf));+ Im_rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Server: Tiny Web Server\r\n");- Rio_writen(fd, buf, strlen(buf));+ Im_rio_writen(fd, buf, strlen(buf)); if (Fork() == 0) { /* Child */ //line:netp:servedynamic:fork+ if (Signal(SIGPIPE, SIG_DFL) == SIG_ERR)+ unix_error("unmask signal pipe error"); /* Real server would set all CGI vars here */ setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */ //line:netp:servedynamic:dup2@@ -216,10 +232,10 @@ /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);- Rio_writen(fd, buf, strlen(buf));+ Im_rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-type: text/html\r\n");- Rio_writen(fd, buf, strlen(buf));+ Im_rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));- Rio_writen(fd, buf, strlen(buf));- Rio_writen(fd, body, strlen(body));+ Im_rio_writen(fd, buf, strlen(buf));+ Im_rio_writen(fd, body, strlen(body)); }
转载地址:http://zfwai.baihongyu.com/