void *request_handler(void *ptr) { #ifdef DEBUG printf("enter request_handler\n"); #endif int client_fd = ((Thread_Input*)ptr)->client_fd; Request request; Response response; parse_request_header(client_fd, &request); modify_request_header(&request); if (check_cache(&request, &response)) { send_client(client_fd, &response); } else { if (forward_request(client_fd, &request, &response) < 0) { Close(client_fd); return NULL; } else { if (response.content_size <= MAX_OBJECT_SIZE) save_to_cache(&request, &response); } } free(ptr); Close(client_fd); #ifdef DEBUG printf("connection close\n\n"); printf("leave request_handler\n"); #endif return NULL; }
static int extract_request(struct http_connection *c, struct http_request *r) { int ret = 0; while(1) { /* Parse a request header from the connection buf. */ parse_request_header(r, c->buf, c->buf_length); /* If we found one, extract the rest of the request based on the length, * and return to process it. */ int len = r->length; if(len > 0) { /* Prepare r->buf to receive the extracted request. */ if (len > sizeof(r->static_buf)) r->buf = malloc(len); /* If the length is <= the size of the connection buffer, we can just * copy it out into the request buffer, and we are done. */ if (len <= c->buf_length) { memcpy(r->buf, c->buf, len); c->buf_length = c->buf_length - len; memmove(c->buf, &c->buf[len], c->buf_length); /* Otherwise, we need to read in the rest of the request from the wire. */ } else { memcpy(r->buf, c->buf, c->buf_length); len -= c->buf_length; c->buf_length = 0; while (len) { ret = timed_read(c, &r->buf[r->length - len], len); len -= ret; if(ret <= 0) return ret; } return r->length; } /* Honor some non-persistent clients */ if (strstr(r->buf, "Connection: close")) c->should_close = 1; return len; } /* Otherwise, try and read in the next request from the socket */ ret = timed_read(c, &c->buf[c->buf_length], sizeof(c->buf) - c->buf_length); /* If the return code is invalid or marks the end of a connection, just * return it. */ if(ret <= 0) return ret; /* Otherwise, update the buf_length and loop back around to try and * extract the request again. */ c->buf_length += ret; } }
/** @brief Handles HTTP GET requests. * Reads and parses the request, the uri, and dispatches the appropriate * functions to serve content. * @param conn_fd The connection file descriptor. * @return none. */ void handle_request(int conn_fd) { rio_t rio; char request[MAXLINE], uri[MAXLINE]; char file_name[MAXLINE], cgi_args[MAXLINE]; int is_static; struct stat st_buf; Rio_readinitb(&rio, conn_fd); /* Read first header line of incoming request. */ if (rio_readlineb(&rio, request, MAXLINE) < 0) { dbg_printf("rio_readlineb error\n"); return; } dbg_printf("Request: %s", request); if (parse_request_header(conn_fd, request, uri) != SUCCESS) { return; } if (read_request_headers(&rio) != SUCCESS) { return; } find_file(uri, file_name, cgi_args, &is_static); if (stat(file_name, &st_buf) < 0) { dbg_printf("404: File not found: %s\n", file_name); send_error_msg(conn_fd, "404", "File not found"); return; } /* Handle static content */ if (is_static) { if (!(S_ISREG(st_buf.st_mode)) || !(S_IRUSR & st_buf.st_mode)) { dbg_printf("403: Can't read the file: %s\n", file_name); send_error_msg(conn_fd, "403", "Can't read the file."); return; } serve_static(conn_fd, file_name, st_buf.st_size); } /* Handle dynamic content */ else { if (!(S_ISREG(st_buf.st_mode)) || !(S_IXUSR & st_buf.st_mode)) { dbg_printf("403: Can't run the CGI program: %s\n", file_name); send_error_msg(conn_fd, "403", "Can't run the CGI program."); return; } serve_dynamic(conn_fd, file_name, cgi_args); } }
/* * request_handler - general function to handler each client request */ void *request_handler(int client_fd) { #ifdef DEBUG printf("enter request_handler\n"); #endif Request request; Response response; parse_request_header(client_fd, &request); modify_request_header(&request); if (check_cache(&request, &response)) { #ifdef DEBUG printf("in cache ! \n"); #endif send_client(client_fd, &response); } else { #ifdef DEBUG printf("not in cache !\n"); #endif if (forward_request(client_fd, &request, &response) < 0) { close(client_fd); return NULL; } else { /* save to cache if status code 2XX and < max size */ if (response.content_size <= MAX_OBJECT_SIZE && response.header[state_ofs] == '2') save_to_cache(&request, &response); } } close(client_fd); #ifdef DEBUG printf("connection close\n"); printf("leave request_handler\n"); #endif return NULL; }