/* Partner Names: Jonathan Beebe - Mark Loh - Description: This is our proxy that uses concurrent processes. It does not implement a cache (although we have spent many many hours trying to get it to work). */ #define _GNU_SOURCE #include #include #include #include "csapp.h" #define MAX_CACHE_SIZE (1<<20) #define MAX_OBJECT_SIZE (100*(1<<10)) /* function prototypes */ void *doit(void *fdp); void read_requesthdrs(rio_t *rp, int fd); void parseUrl(char **url, char **hostname, char **port, char **filename); /* main function */ int main(int argc, char **argv) { int listenfd, port, clientlen = sizeof(struct sockaddr_in); int *connfdp; struct sockaddr_in clientaddr; pthread_t tid; /* Check command line args */ if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } port = atoi(argv[1]); /* handle the SIGPIPE signal */ signal(SIGPIPE, SIG_IGN); /* open the neccessary ports */ listenfd = Open_listenfd(port); while (1) { connfdp = Malloc(sizeof(int)); *connfdp = Accept(listenfd, (SA *)&clientaddr, (unsigned int *) &clientlen); /* spawn the new threads */ pthread_create(&tid, NULL, doit, connfdp); pthread_detach(tid); } } /* * doit - handle one HTTP request/response transaction */ void *doit(void *fdp) { char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char *filename, *hostname, *port, *url; char requestLine[MAXLINE]; int serverfd, bytesRead; int fd = *((int *) fdp); rio_t rio, rio2; /* stored it in the file descriptor - fd, thus free the pointer */ Free(fdp); url = uri; /* Read request line and headers */ Rio_readinitb(&rio, fd); Rio_readlineb(&rio, buf, MAXLINE); sscanf(buf, "%s %s %s", method, url, version); /* calls our parse Url function */ parseUrl(&url, &hostname, &port, &filename); /* open connection to correct host and port */ serverfd = Open_clientfd(hostname, atoi(port)); /* parse the request line, and create string */ strcpy(requestLine, method); strcat(requestLine, " "); strcat(requestLine, filename); strcat(requestLine, " HTTP/1.0\r\n"); /* writes the request line */ Rio_writen(serverfd, requestLine, strlen(requestLine)); /* then read the rest of the request headers */ read_requesthdrs(&rio, serverfd); /* writes information back to the server */ Rio_readinitb(&rio2, serverfd); while ( ((bytesRead = Rio_readnb(&rio2, buf, MAXBUF)) > 0) ){ Rio_writen(fd, buf, bytesRead); } Close(serverfd); Close(fd); return NULL; } /* * read_requesthdrs - read and parse HTTP request headers */ void read_requesthdrs(rio_t *rp, int fd) { char buf[MAXBUF]; char *connection; int lineLength; /* read in the Host: line */ lineLength = Rio_readlineb(rp, buf, MAXBUF); Rio_writen(fd, buf, lineLength); /* reads in request headers until last line */ while(strcmp(buf, "\r\n")) { lineLength = Rio_readlineb(rp, buf, MAXBUF); /* handle header cases described in write-up */ if (strstr(buf, "Proxy-Connection")){ connection = "Proxy-Connection: close\r\n"; Rio_writen(fd, connection, strlen(connection)); } else if(strstr(buf, "Connection")){ connection = "Connection: close\r\n"; Rio_writen(fd, connection, strlen(connection)); } else if (!(strstr(buf, "Keep-Alive"))){ Rio_writen(fd, buf, lineLength); } } } /* parses the given URL */ void parseUrl(char **url, char **hostname, char **port, char **filename){ char * portVal; /* move past the http:// */ 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); /* check to see if there is a filename at the end */ 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); }