#define _GNU_SOURCE #include #include #include #include "csapp.h" void doit(int fd); void read_requesthdrs(rio_t *rp, int fd); void parse_uri(char **uri, char **hostname, char **port, char **filename); void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg); int main(int argc, char **argv) { int listenfd, connfd, port, clientlen; struct sockaddr_in clientaddr; /* Check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } port = atoi(argv[1]); listenfd = open_listenfd(port); while (1) { clientlen = sizeof(clientaddr); connfd = accept(listenfd, (SA *)&clientaddr, &clientlen); doit(connfd); close(connfd); } } /* * doit - handle one HTTP request/response transaction */ void doit(int fd) { char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char filename[MAXLINE], hostname[MAXLINE], port[MAXLINE]; char requestLine[MAXLINE]; int proxyfd; rio_t rio; /* Read request line and headers */ rio_readinitb(&rio, fd); rio_readlineb(&rio, buf, MAXLINE); sscanf(buf, "%s %s %s", method, uri, version); if (strcasecmp(method, "GET")) { clienterror(fd, method, "501", "Not Implemented", "Proxy does not implement this method"); return; } parseUri(&uri, &hostname, &port, &filename); proxyfd = open_clientfd(hostname, port); strcpy(requestLine, method); strcat(requestLine, " "); strcat(requestLine, filename); strcat(requestLine, " HTTP:/1.0"); rio_writen(proxyfd, requestLine, strlen(requestLine)); read_requesthdrs(&rio, fd); } /* * read_requesthdrs - read and parse HTTP request headers */ void read_requesthdrs(rio_t *rp, int fd) { char buf[MAXLINE]; int lineLength; rio_readlineb(rp, buf, MAXLINE); while(strcmp(buf, "\r\n")) { lineLength = rio_readlineb(rp, buf, MAXLINE); printf("%s\n", buf); rio_writen(fd, buf, lineLength); } return; } /* * 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)); } void parseUri(char **uri, char **hostname, char **port, char **filename){ char *ptr; char * portVal; char *temp = *uri + 7; int totLen = 0; int uriLen = 0; int portLen = 0; int hostLen = 0; *filename = strstr(temp, "/"); *port = strstr(temp, ":"); totLen = strlen(temp); if(*filename) uriLen = strlen(*filename); else *filename = "/"; /* return the port */ if(*port){ portLen = strlen(*port) - uriLen; portVal = strndup(*port, portLen); portVal++; *port = portVal; } else *port = "80"; /* default is to return the hostname */ hostLen = totLen - (portLen + uriLen); *hostname = strndup(temp, hostLen); }