📄 get.c
字号:
/* * Boa, an http server * Copyright (C) 1995 Paul Phillips <paulp@go2net.com> * Some changes Copyright (C) 1996,99 Larry Doolittle <ldoolitt@boa.org> * Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *//* $Id: get.c,v 1.76.2.5 2002/07/26 03:05:59 jnelson Exp $*/#include "boa.h"/* local prototypes */int get_cachedir_file(request * req, struct stat *statbuf);int index_directory(request * req, char *dest_filename);/* * Name: init_get * Description: Initializes a non-script GET or HEAD request. * * Return values: * 0: finished or error, request will be freed * 1: successfully initialized, added to ready queue */int init_get(request * req){ int data_fd, saved_errno; struct stat statbuf; volatile int bytes; data_fd = open(req->pathname, O_RDONLY); saved_errno = errno; /* might not get used */#ifdef GUNZIP if (data_fd == -1 && errno == ENOENT) { /* cannot open */ /* it's either a gunzipped file or a directory */ char gzip_pathname[MAX_PATH_LENGTH]; int len; len = strlen(req->pathname); memcpy(gzip_pathname, req->pathname, len); memcpy(gzip_pathname + len, ".gz", 3); gzip_pathname[len + 3] = '\0'; data_fd = open(gzip_pathname, O_RDONLY); if (data_fd != -1) { close(data_fd); req->response_status = R_REQUEST_OK; if (req->pathname) free(req->pathname); req->pathname = strdup(gzip_pathname); if (!req->pathname) { log_error_time(); perror("strdup"); send_r_error(req); return 0; } if (!req->simple) { req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n"); print_http_headers(req); print_content_type(req); print_last_modified(req); req_write(req, "\r\n"); req_flush(req); } if (req->method == M_HEAD) return 0; return init_cgi(req); } }#endif if (data_fd == -1) { log_error_doc(req); errno = saved_errno; perror("document open"); if (saved_errno == ENOENT) send_r_not_found(req); else if (saved_errno == EACCES) send_r_forbidden(req); else send_r_bad_request(req); return 0; } fstat(data_fd, &statbuf); if (S_ISDIR(statbuf.st_mode)) { /* directory */ close(data_fd); /* close dir */ if (req->pathname[strlen(req->pathname) - 1] != '/') { char buffer[3 * MAX_PATH_LENGTH + 128]; if (server_port != 80) sprintf(buffer, "http://%s:%d%s/", server_name, server_port, req->request_uri); else sprintf(buffer, "http://%s%s/", server_name, req->request_uri); send_r_moved_perm(req, buffer); return 0; } data_fd = get_dir(req, &statbuf); /* updates statbuf */ if (data_fd == -1) /* couldn't do it */ return 0; /* errors reported by get_dir */ else if (data_fd <= 1) /* data_fd == 0 -> close it down, 1 -> continue */ return data_fd; /* else, data_fd contains the fd of the file... */ } if (req->if_modified_since && !modified_since(&(statbuf.st_mtime), req->if_modified_since)) { send_r_not_modified(req); close(data_fd); return 0; } req->filesize = statbuf.st_size; req->last_modified = statbuf.st_mtime; if (req->method == M_HEAD || req->filesize == 0) { send_r_request_ok(req); close(data_fd); return 0; } if (req->filesize > MAX_FILE_MMAP) { send_r_request_ok(req); /* All's well */ req->status = PIPE_READ; req->cgi_status = CGI_BUFFER; req->data_fd = data_fd; req_flush(req); /* this should *always* complete due to the size of the I/O buffers */ req->header_line = req->header_end = req->buffer; return 1; } if (req->filesize == 0) { /* done */ send_r_request_ok(req); /* All's well *so far* */ close(data_fd); return 1; } /* NOTE: I (Jon Nelson) tried performing a read(2) * into the output buffer provided the file data would * fit, before mmapping, and if successful, writing that * and stopping there -- all to avoid the cost * of a mmap. Oddly, it was *slower* in benchmarks. */ req->mmap_entry_var = find_mmap(data_fd, &statbuf); if (req->mmap_entry_var == NULL) { req->buffer_end = 0; if (errno == ENOENT) send_r_not_found(req); else if (errno == EACCES) send_r_forbidden(req); else send_r_bad_request(req); close(data_fd); return 0; } req->data_mem = req->mmap_entry_var->mmap; close(data_fd); /* close data file */ if ((long) req->data_mem == -1) { boa_perror(req, "mmap"); return 0; } send_r_request_ok(req); /* All's well */ bytes = BUFFER_SIZE - req->buffer_end; /* bytes is now how much the buffer can hold * after the headers */ if (bytes > 0) { if (bytes > req->filesize) bytes = req->filesize; if (sigsetjmp(env, 1) == 0) { handle_sigbus = 1; memcpy(req->buffer + req->buffer_end, req->data_mem, bytes); handle_sigbus = 0; /* OK, SIGBUS **after** this point is very bad! */ } else { /* sigbus! */ log_error_doc(req); reset_output_buffer(req); send_r_error(req); fprintf(stderr, "%sGot SIGBUS in memcpy!\n", get_commonlog_time()); return 0; } req->buffer_end += bytes; req->filepos += bytes; if (req->filesize == req->filepos) { req_flush(req); req->status = DONE; } } /* We lose statbuf here, so make sure response has been sent */ return 1;}/* * Name: process_get * Description: Writes a chunk of data to the socket. * * Return values: * -1: request blocked, move to blocked queue * 0: EOF or error, close it down * 1: successful write, recycle in ready queue */int process_get(request * req){ int bytes_written; volatile int bytes_to_write; bytes_to_write = req->filesize - req->filepos; if (bytes_to_write > SOCKETBUF_SIZE) bytes_to_write = SOCKETBUF_SIZE; if (sigsetjmp(env, 1) == 0) { handle_sigbus = 1; bytes_written = write(req->fd, req->data_mem + req->filepos, bytes_to_write); handle_sigbus = 0; /* OK, SIGBUS **after** this point is very bad! */ } else { /* sigbus! */ log_error_doc(req); /* sending an error here is inappropriate * if we are here, the file is mmapped, and thus, * a content-length has been sent. If we send fewer bytes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -