Path: blob/master/concurrency-webserver/src/request.c
909 views
#include "io_helper.h"1#include "request.h"23//4// Some of this code stolen from Bryant/O'Halloran5// Hopefully this is not a problem ... :)6//78#define MAXBUF (8192)910void request_error(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) {11char buf[MAXBUF], body[MAXBUF];1213// Create the body of error message first (have to know its length for header)14sprintf(body, ""15"<!doctype html>\r\n"16"<head>\r\n"17" <title>OSTEP WebServer Error</title>\r\n"18"</head>\r\n"19"<body>\r\n"20" <h2>%s: %s</h2>\r\n"21" <p>%s: %s</p>\r\n"22"</body>\r\n"23"</html>\r\n", errnum, shortmsg, longmsg, cause);2425// Write out the header information for this response26sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);27write_or_die(fd, buf, strlen(buf));2829sprintf(buf, "Content-Type: text/html\r\n");30write_or_die(fd, buf, strlen(buf));3132sprintf(buf, "Content-Length: %lu\r\n\r\n", strlen(body));33write_or_die(fd, buf, strlen(buf));3435// Write out the body last36write_or_die(fd, body, strlen(body));37}3839//40// Reads and discards everything up to an empty text line41//42void request_read_headers(int fd) {43char buf[MAXBUF];4445readline_or_die(fd, buf, MAXBUF);46while (strcmp(buf, "\r\n")) {47readline_or_die(fd, buf, MAXBUF);48}49return;50}5152//53// Return 1 if static, 0 if dynamic content54// Calculates filename (and cgiargs, for dynamic) from uri55//56int request_parse_uri(char *uri, char *filename, char *cgiargs) {57char *ptr;5859if (!strstr(uri, "cgi")) {60// static61strcpy(cgiargs, "");62sprintf(filename, ".%s", uri);63if (uri[strlen(uri)-1] == '/') {64strcat(filename, "index.html");65}66return 1;67} else {68// dynamic69ptr = index(uri, '?');70if (ptr) {71strcpy(cgiargs, ptr+1);72*ptr = '\0';73} else {74strcpy(cgiargs, "");75}76sprintf(filename, ".%s", uri);77return 0;78}79}8081//82// Fills in the filetype given the filename83//84void request_get_filetype(char *filename, char *filetype) {85if (strstr(filename, ".html"))86strcpy(filetype, "text/html");87else if (strstr(filename, ".gif"))88strcpy(filetype, "image/gif");89else if (strstr(filename, ".jpg"))90strcpy(filetype, "image/jpeg");91else92strcpy(filetype, "text/plain");93}9495void request_serve_dynamic(int fd, char *filename, char *cgiargs) {96char buf[MAXBUF], *argv[] = { NULL };9798// The server does only a little bit of the header.99// The CGI script has to finish writing out the header.100sprintf(buf, ""101"HTTP/1.0 200 OK\r\n"102"Server: OSTEP WebServer\r\n");103104write_or_die(fd, buf, strlen(buf));105106if (fork_or_die() == 0) { // child107setenv_or_die("QUERY_STRING", cgiargs, 1); // args to cgi go here108dup2_or_die(fd, STDOUT_FILENO); // make cgi writes go to socket (not screen)109extern char **environ; // defined by libc110execve_or_die(filename, argv, environ);111} else {112wait_or_die(NULL);113}114}115116void request_serve_static(int fd, char *filename, int filesize) {117int srcfd;118char *srcp, filetype[MAXBUF], buf[MAXBUF];119120request_get_filetype(filename, filetype);121srcfd = open_or_die(filename, O_RDONLY, 0);122123// Rather than call read() to read the file into memory,124// which would require that we allocate a buffer, we memory-map the file125srcp = mmap_or_die(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);126close_or_die(srcfd);127128// put together response129sprintf(buf, ""130"HTTP/1.0 200 OK\r\n"131"Server: OSTEP WebServer\r\n"132"Content-Length: %d\r\n"133"Content-Type: %s\r\n\r\n",134filesize, filetype);135136write_or_die(fd, buf, strlen(buf));137138// Writes out to the client socket the memory-mapped file139write_or_die(fd, srcp, filesize);140munmap_or_die(srcp, filesize);141}142143// handle a request144void request_handle(int fd) {145int is_static;146struct stat sbuf;147char buf[MAXBUF], method[MAXBUF], uri[MAXBUF], version[MAXBUF];148char filename[MAXBUF], cgiargs[MAXBUF];149150readline_or_die(fd, buf, MAXBUF);151sscanf(buf, "%s %s %s", method, uri, version);152printf("method:%s uri:%s version:%s\n", method, uri, version);153154if (strcasecmp(method, "GET")) {155request_error(fd, method, "501", "Not Implemented", "server does not implement this method");156return;157}158request_read_headers(fd);159160is_static = request_parse_uri(uri, filename, cgiargs);161if (stat(filename, &sbuf) < 0) {162request_error(fd, filename, "404", "Not found", "server could not find this file");163return;164}165166if (is_static) {167if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {168request_error(fd, filename, "403", "Forbidden", "server could not read this file");169return;170}171request_serve_static(fd, filename, sbuf.st_size);172} else {173if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {174request_error(fd, filename, "403", "Forbidden", "server could not run this CGI program");175return;176}177request_serve_dynamic(fd, filename, cgiargs);178}179}180181182