/* Kamil Kaminski * kkamin8@uic.edu * * * Note: implement content-size, if index.html is not present, generate a page * that lists root directory, you can use select() to deal with multiple * requests instead of forking * */ #include #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } int server_sockfd, ret; if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); close(server_sockfd); exit(-1); } /* allow fast reuse of ports */ int reuse_true = 1; setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_true, sizeof(reuse_true)); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(atoi(argv[1])); addr.sin_addr.s_addr = INADDR_ANY; if (bind(server_sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) { perror("bind"); exit(-1); } if (listen(server_sockfd, 0) == -1) { perror("listen"); exit(-1); } while (1) { int sockfd; struct sockaddr_in remote_addr; unsigned int socklen = sizeof(remote_addr); sockfd = accept(server_sockfd, (struct sockaddr *) &remote_addr, &socklen); if (sockfd == -1) { perror("accept"); continue; } char ipstr[INET6_ADDRSTRLEN]; inet_ntop(remote_addr.sin_family, &remote_addr.sin_addr, ipstr, sizeof(ipstr)); printf("got connection from %s\n", ipstr); /* read the http header request from the client */ char recv_buff[512] = { 0 }; if ((ret = recv(sockfd, recv_buff, sizeof(recv_buff), 0)) < 0) { perror("recv"); shutdown(sockfd, SHUT_RDWR); close(sockfd); continue; } /* printf("%s", recv_buff); */ char *p; if (!(p = strstr(recv_buff, "GET"))) continue; char filereq[100] = { 0 }; sscanf(p, "GET %s HTTP/1.*[01]\r\n", filereq); printf("requested file: \"%s\"\n", filereq); char path[200] = { 0 }; sprintf(path, "%s%s", argv[2], filereq[strlen(filereq) - 1] == '/' ? "/index.html" : filereq); printf("path is: \"%s\"\n", path); struct stat stat_buff; if (stat(path, &stat_buff) == -1) { perror("stat"); char err[] = "HTTP/1.0 404 Not Found\r\n\r\n"; send(sockfd, err, sizeof(err), 0); } else { pid_t pid; if ((pid = fork()) == 0) { char http_header[100] = { 0 }; char *p = strstr(path, "."), *type = NULL; if (p) { if (strcmp(p, ".html") == 0) type = "Content-Type: text/html\r\n"; else if (strcmp(p, ".gif") == 0) type = "Content-Type: image/gif\r\n"; else if (strcmp(p, ".png") == 0) type = "Content-Type: image/png\r\n"; else if (strcmp(p, ".jpeg") == 0 || strcmp(p, ".jpg") == 0) type = "Content-Type: image/jpeg\r\n"; else if (strcmp(p, ".pdf") == 0) type = "Content-Type: application/pdf\r\n"; } sprintf(http_header, "%s%s\r\n", "HTTP/1.1 200 OK\r\n", type ? type : "\r\n"); /* printf("http header:\n\"%s\"\n", http_header); */ FILE *fp = fopen(path, "r"); char *file = (char *) malloc(sizeof(char) * (stat_buff.st_size + strlen(http_header))); if (file && fp) { memcpy(file, http_header, strlen(http_header)); fread(file + strlen(http_header), stat_buff.st_size, sizeof(char), fp); send(sockfd, file, stat_buff.st_size + strlen(http_header), 0); free(file); } fclose(fp); shutdown(sockfd, SHUT_RDWR); close(sockfd); exit(0); } else if (pid > 0) { wait(NULL); } else { perror("fork"); shutdown(sockfd, SHUT_RDWR); close(sockfd); } } } shutdown(server_sockfd, SHUT_RDWR); close(server_sockfd); }