博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《CSAPP》(第3版)答案(第十一章)
阅读量:4169 次
发布时间:2019-05-26

本文共 34412 字,大约阅读时间需要 114 分钟。

《CSAPP》(第3版)答案(第十一章)

P6

  • A
#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));}
  • B
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
  • C
    HTTP 1.1
  • D

P7

#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));}

以上是源代码。如果不知道怎么跑关注私信我,我把整个工程文件夹发过去。

P8

#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));}

P9

@@ -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); }

P10

  • A
Tiny Server

first number:

second number:

  • B
@@ -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 */

P11

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);

P12

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); }

P13

@@ -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/

你可能感兴趣的文章
商务智能-基本方法-特征与角度
查看>>
软件项目管理系统-项目管理-模块定义-开发笔记
查看>>
工作流审批平台-业务申请-申请书一览
查看>>
商务智能-基本方法-数据钻取
查看>>
C++程序员技术需求规划(发展方向)
查看>>
如何判断变量在内存中如何放置的?低位在前还是高位在前
查看>>
c语言中通过指针将数值赋值到制定内存地址
查看>>
64位与32位linux c开发时默认字节对齐值
查看>>
malloc(malloc在32位编译系统中分配的地址会8字节对齐,64为编译系统中会8或者16字节对齐)
查看>>
初始化时共享内存的key值和信号量初始化的key值可以一样
查看>>
linux创建线程之pthread_create
查看>>
pthread_attr_init线程通俗举例讲解与线程属性
查看>>
进程和线程的区别
查看>>
int main(int argc,char* argv[])详解,以及与int main()有什么区别
查看>>
SourceInsight全工程查找替换方法
查看>>
C语言chdir()函数:改变当前的工作目录
查看>>
Linux下的函数执行时间的统计方法(测试某个函数的执行时间)
查看>>
调整内核printk的打印级别(启动脚本中运行 echo 0 4 0 7 > /proc/sys/kernel/printk 关闭所有内核打印)
查看>>
临时关闭打开console办法
查看>>
Linux中gmtime和localtime的区别(time_t格式转换为tm格式)
查看>>