#define _GNU_SOURCE #include #include #include #include "csapp.h" void doit(int fd); void read_requesthdrs(rio_t *rp, int fd); void parseUrl(char **url, 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, (unsigned int *) &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, *hostname, *port, *url, *host; char requestLine[MAXLINE]; int serverfd, bytesRead; rio_t rio, rio2; url = uri; /* Read request line and headers */ rio_readinitb(&rio, fd); rio_readlineb(&rio, buf, MAXLINE); sscanf(buf, "%s %s %s", method, url, version); parseUrl(&url, &hostname, &port, &filename); printf("url --> %s, hostname --> %s, port --> %s, filename --> %s\n", url, hostname, port, filename); serverfd = open_clientfd(hostname, atoi(port)); strcpy(requestLine, method); strcat(requestLine, " "); strcat(requestLine, filename); strcat(requestLine, " HTTP/1.0\r\n"); printf("write: %s\n", requestLine); /* writes the request line */ rio_writen(serverfd, requestLine, strlen(requestLine)); /* then read the rest of the request headers */ read_requesthdrs(&rio, serverfd); printf("-----------------------------------------------------\n"); rio_readinitb(&rio2, serverfd); while ( ((bytesRead = rio_readnb(&rio2, buf, MAXBUF)) > 0) ){ rio_writen(fd, buf, bytesRead); } close(serverfd); } /* * read_requesthdrs - read and parse HTTP request headers */ void read_requesthdrs(rio_t *rp, int fd) { char buf[MAXBUF]; char *connection; int lineLength; lineLength = rio_readlineb(rp, buf, MAXBUF); printf("write: --> %s", buf); rio_writen(fd, buf, lineLength); while(strcmp(buf, "\r\n")) { lineLength = rio_readlineb(rp, buf, MAXBUF); if (strstr(buf, "Proxy-Connection")){ connection = "Proxy-Connection: close\r\n"; printf("write: %s", connection); rio_writen(fd, connection, strlen(connection)); } else if(strstr(buf, "Connection")){ connection = "Connection: close\r\n"; printf("write: %s", connection); rio_writen(fd, connection, strlen(connection)); } else if (!(strstr(buf, "Keep-Alive"))){ printf("write: %s", buf); rio_writen(fd, buf, lineLength); } } } /* * 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, "Proxy 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


Mark and Jon's Proxy\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 parseUrl(char **url, char **hostname, char **port, char **filename){ char * portVal; char *temp = *url + 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); }