void log_error_doc(request * req) { int errno_save = errno; char *escaped_pathname; if (virtualhost) { fprintf(stderr, "%s ", req->local_ip_addr); } else if (vhost_root) { fprintf(stderr, "%s ", (req->host ? req->host : "(null)")); } escaped_pathname = escape_pathname(req->pathname); print_remote_ip (req, stderr); if (vhost_root) { fprintf(stderr, " - - %srequest [%s] \"%s\" (\"%s\"): ", get_commonlog_time(), (req->header_host ? req->header_host : "(null)"), (req->logline ? req->logline : "(null)"), (escaped_pathname ? escaped_pathname : "(null)")); } else { fprintf(stderr, " - - %srequest \"%s\" (\"%s\"): ", get_commonlog_time(), (req->logline ? req->logline : "(null)"), (escaped_pathname ? escaped_pathname : "(null)")); } free(escaped_pathname); errno = errno_save; }
void log_error_doc(request * req) { int errno_save = errno; if (virtualhost) { fprintf(stderr, "%s ", req->local_ip_addr); } else if (vhost_root) { fprintf(stderr, "%s ", (req->host ? req->host : "(null)")); } if (vhost_root) { fprintf(stderr, "%s - - %srequest [%s] \"%s\" (\"%s\"): ", req->remote_ip_addr, get_commonlog_time(), (req->header_host ? req->header_host : "(null)"), (req->logline ? req->logline : "(null)"), (req->pathname ? req->pathname : "(null)")); } else { fprintf(stderr, "%s - - %srequest \"%s\" (\"%s\"): ", req->remote_ip_addr, get_commonlog_time(), (req->logline ? req->logline : "(null)"), (req->pathname ? req->pathname : "(null)")); } errno = errno_save; }
void log_access(request * req) { if (!access_log_name) return; if (virtualhost) { printf("%s ", req->local_ip_addr); } else if (vhost_root) { printf("%s ", (req->host ? req->host : "(null)")); } if(req->logline==0 || (req->logline!=0 && strstr(req->logline, "SetStatus")!=0)) {//by steve printf("%s - - %s\"%s\" %d %ld \"%s\" \"%s\"\n", req->remote_ip_addr, get_commonlog_time(), req->logline ? req->logline : "-", req->response_status, req->bytes_written, (req->header_referer ? req->header_referer : "-"), (req->header_user_agent ? req->header_user_agent : "-")); } else printf("-"); }
void log_error_mesg(const char *file, int line, const char *mesg) { int errno_save = errno; fprintf(stderr, "%s%s:%d - ", get_commonlog_time(), file, line); errno = errno_save; perror(mesg); errno = errno_save; }
void log_error_mesg_fatal(const char *file, int line, const char *func, const char *mesg) { int errno_save = errno; fprintf(stderr, "%s%s:%d (%s) - ", get_commonlog_time(), file, line, func); errno = errno_save; perror(mesg); exit(EXIT_FAILURE); }
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 * the client knows there has been a problem. * We run the risk of accidentally sending the right number * of bytes (or a few too many) and the client * won't be the wiser. */ req->status = DEAD; fprintf(stderr, "%sGot SIGBUS in write(2)!\n", get_commonlog_time()); return 0; } if (bytes_written < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return -1; /* request blocked at the pipe level, but keep going */ else { if (errno != EPIPE) { log_error_doc(req); /* Can generate lots of log entries, */ perror("write"); /* OK to disable if your logs get too big */ } req->status = DEAD; return 0; } } req->filepos += bytes_written; if (req->filepos == req->filesize) { /* EOF */ return 0; } else return 1; /* more to do */ }
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; } else { 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 * the client knows there has been a problem. * We run the risk of accidentally sending the right number * of bytes (or a few too many) and the client * won't be the wiser. */ req->status = DEAD; fprintf(stderr, "%sGot SIGBUS in write(2)!\n", get_commonlog_time()); return 0; } if (bytes_written < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return -1; else { if (errno != EPIPE) { log_error_doc(req); perror("write"); } req->status = DEAD; return 0; } } req->filepos += bytes_written; if (req->filepos == req->filesize) { return 0; } else return 1; }
void log_access(request * req) { if (!access_log_name) return; if (virtualhost) { printf("%s ", req->local_ip_addr); } else if (vhost_root) { printf("%s ", (req->host ? req->host : "(null)")); } print_remote_ip (req, stdout); printf(" - - %s\"%s\" %d %zu \"%s\" \"%s\"\n", get_commonlog_time(), req->logline ? req->logline : "-", req->response_status, req->bytes_written, (req->header_referer ? req->header_referer : "-"), (req->header_user_agent ? req->header_user_agent : "-")); }
void log_error(const char *mesg) { fprintf(stderr, "%s%s", get_commonlog_time(), mesg); }
void log_error_time(void) { int errno_save = errno; fputs(get_commonlog_time(), stderr); errno = errno_save; }
int process_get(request * req) { off_t bytes_written; volatile off_t bytes_to_write; if (req->method == M_HEAD) { return complete_response(req); } bytes_to_write = (req->ranges->stop - req->ranges->start) + 1; if (bytes_to_write > system_bufsize) bytes_to_write = system_bufsize; if (setjmp(env) == 0) { handle_sigbus = 1; bytes_written = write(req->fd, req->data_mem + req->ranges->start, bytes_to_write); handle_sigbus = 0; /* OK, SIGBUS **after** this point is very bad! */ } else { /* sigbus! */ req->status = DEAD; log_error_doc(req); fprintf(stderr, "%sGot SIGBUS in write(2)!\n", get_commonlog_time()); /* 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 * the client knows there has been a problem. * We run the risk of accidentally sending the right number * of bytes (or a few too many) and the client * won't be the wiser. */ return 0; } if (bytes_written < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return -1; /* request blocked at the pipe level, but keep going */ else { #ifdef QUIET_DISCONNECT if (errno != EPIPE) { #else if (1) { #endif log_error_doc(req); /* Can generate lots of log entries, */ perror("write"); /* OK to disable if your logs get too big */ } req->status = DEAD; return 0; } } req->bytes_written += bytes_written; req->ranges->start += bytes_written; if ((req->ranges->stop + 1 - req->ranges->start) == 0) { return complete_response(req); } return 1; /* more to do */ } /* * Name: get_dir * Description: Called from process_get if the request is a directory. * statbuf must describe directory on input, since we may need its * device, inode, and mtime. * statbuf is updated, since we may need to check mtimes of a cache. * returns: * -1 error * 0 cgi (either gunzip or auto-generated) * >0 file descriptor of file */ int get_dir(request * req, struct stat *statbuf) { char pathname_with_index[MAX_PATH_LENGTH]; int data_fd; if (directory_index) { /* look for index.html first?? */ unsigned int l1, l2; l1 = strlen(req->pathname); l2 = strlen(directory_index); #ifdef GUNZIP if (l1 + l2 + 3 + 1 > sizeof(pathname_with_index)) { /* for .gz */ #else if (l1 + l2 + 1 > sizeof(pathname_with_index)) { #endif errno = ENOMEM; boa_perror(req, "pathname_with_index not large enough for pathname + index"); return -1; } memcpy(pathname_with_index, req->pathname, l1); /* doesn't copy NUL */ memcpy(pathname_with_index + l1, directory_index, l2 + 1); /* does */ data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE); if (data_fd != -1) { /* user's index file */ /* We have to assume that directory_index will fit, because * if it doesn't, well, that's a huge configuration problem. * this is only the 'index.html' pathname for mime type */ memcpy(req->request_uri, directory_index, l2 + 1); /* for mimetype */ fstat(data_fd, statbuf); return data_fd; } if (errno == EACCES) { send_r_forbidden(req); return -1; } else if (errno != ENOENT) { /* if there is an error *other* than EACCES or ENOENT */ send_r_not_found(req); return -1; } #ifdef GUNZIP /* if we are here, trying index.html didn't work * try index.html.gz */ strcat(pathname_with_index, ".gz"); data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE); if (data_fd != -1) { /* user's index file */ close(data_fd); req->response_status = R_REQUEST_OK; SQUASH_KA(req); if (req->pathname) free(req->pathname); req->pathname = strdup(pathname_with_index); if (!req->pathname) { boa_perror(req, "strdup of pathname_with_index for .gz files " __FILE__ ":" STR(__LINE__)); return 0; } if (req->http_version != HTTP09) { req_write(req, http_ver_string(req->http_version)); req_write(req, " 200 OK-GUNZIP" CRLF); print_http_headers(req); print_last_modified(req); req_write(req, "Content-Type: "); req_write(req, get_mime_type(directory_index)); req_write(req, CRLF CRLF); req_flush(req); } if (req->method == M_HEAD) return 0; return init_cgi(req); } #endif } /* only here if index.html, index.html.gz don't exist */ if (dirmaker != NULL) { /* don't look for index.html... maybe automake? */ req->response_status = R_REQUEST_OK; SQUASH_KA(req); /* the indexer should take care of all headers */ if (req->http_version != HTTP09) { req_write(req, http_ver_string(req->http_version)); req_write(req, " 200 OK" CRLF); print_http_headers(req); print_last_modified(req); req_write(req, "Content-Type: text/html" CRLF CRLF); req_flush(req); } if (req->method == M_HEAD) return 0; return init_cgi(req); /* in this case, 0 means success */ } else if (cachedir) { return get_cachedir_file(req, statbuf); } else { /* neither index.html nor autogenerate are allowed */ send_r_forbidden(req); return -1; /* nothing worked */ } } static int get_cachedir_file(request * req, struct stat *statbuf) { char pathname_with_index[MAX_PATH_LENGTH]; int data_fd; time_t real_dir_mtime; real_dir_mtime = statbuf->st_mtime; /* the sizeof() doesn't need a -1 because snprintf will * include the NUL when calculating if the size is enough */ snprintf(pathname_with_index, sizeof(pathname_with_index), "%s/dir.%d." PRINTF_OFF_T_ARG, cachedir, (int) statbuf->st_dev, statbuf->st_ino); data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE); if (data_fd != -1) { /* index cache */ fstat(data_fd, statbuf); if (statbuf->st_mtime > real_dir_mtime) { statbuf->st_mtime = real_dir_mtime; /* lie */ strcpy(req->request_uri, directory_index); /* for mimetype */ return data_fd; } close(data_fd); unlink(pathname_with_index); /* cache is stale, delete it */ } if (index_directory(req, pathname_with_index) == -1) return -1; data_fd = open(pathname_with_index, O_RDONLY|O_LARGEFILE); /* Last chance */ if (data_fd != -1) { strcpy(req->request_uri, directory_index); /* for mimetype */ fstat(data_fd, statbuf); statbuf->st_mtime = real_dir_mtime; /* lie */ return data_fd; } boa_perror(req, "re-opening dircache"); return -1; /* Nothing worked. */ }
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; #ifdef SERVER_SSL if(req->ssl == NULL){ #endif /*SERVER_SSL*/ bytes_written = write(req->fd, req->data_mem + req->filepos, bytes_to_write); #ifdef SERVER_SSL }else{ bytes_written = SSL_write(req->ssl, req->data_mem + req->filepos, bytes_to_write); #if 0 printf("SSL_write\n"); #endif /*0*/ } #endif /*SERVER_SSL*/ 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 * the client knows there has been a problem. * We run the risk of accidentally sending the right number * of bytes (or a few too many) and the client * won't be the wiser. */ req->status = DEAD; fprintf(stderr, "%sGot SIGBUS in write(2)!\n", get_commonlog_time()); return 0; } if (bytes_written < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return -1; /* request blocked at the pipe level, but keep going */ else { if (errno != EPIPE) { log_error_doc(req); /* Can generate lots of log entries, */ perror("write"); /* OK to disable if your logs get too big */ } req->status = DEAD; return 0; } } req->filepos += bytes_written; req->busy_flag = BUSY_FLAG_AUDIO|BUSY_FLAG_VIDEO; if (req->filepos == req->filesize) { /* EOF */ #ifdef DAVINCI_IPCAM if (req->http_stream == URI_STREAM_MJPEG) { #if 1 #if 0 while (audio_get(req) > 0); if (req->audio_length >= AUDIO_SEND_SIZE) { audio_send(req); return 1; } #else if (audio_get(req, FMT_MJPEG) > 0) return 1; #endif #else req->busy_flag &= ~BUSY_FLAG_AUDIO; #endif if (req->serial_lock) { GetAVData(AV_OP_UNLOCK_MJPEG, req->serial_lock, NULL); req->serial_lock = 0; } GetAVData(AV_OP_GET_MJPEG_SERIAL, -1, &req->av_data); if (req->av_data.serial < req->serial_book) { req->busy_flag &= ~BUSY_FLAG_VIDEO; return 1; } GetAVData(AV_OP_LOCK_MJPEG, req->av_data.serial, &req->av_data ); req->data_mem = req->av_data.ptr; req->filesize = req->av_data.size+16; req->filepos = 0; req->serial_lock = req->av_data.serial; req->serial_book = req->av_data.serial+1; reset_output_buffer(req); req_write(req, "\r\n"); print_mjpeg_headers(req); return 1; } if (req->http_stream == URI_STREAM_MPEG4 || req->http_stream == URI_STREAM_AVC) { int ret; #if 1 #if 0 while (audio_get(req) > 0); if (req->audio_length > AUDIO_SEND_SIZE) { req->busy_flag |= BUSY_FLAG_AUDIO; audio_send(req); return 1; } #else if (audio_get(req, FMT_MPEG4) > 0) return 1; #endif #else req->busy_flag &= ~BUSY_FLAG_AUDIO; #endif ret = GetAVData(AV_OP_LOCK_MP4, req->serial_book, &req->av_data); if (ret == RET_SUCCESS) { GetAVData(AV_OP_UNLOCK_MP4, req->serial_lock, NULL); req->data_mem = req->av_data.ptr; req->filesize = req->av_data.size+16; req->filepos = 0; req->serial_lock = req->av_data.serial; req->serial_book = req->av_data.serial+1; reset_output_buffer(req); req_write(req, "\r\n"); if (req->http_stream == URI_STREAM_AVC) { print_avc_headers(req); } else { print_mpeg4_headers(req); } return 1; } else if (ret == RET_NO_VALID_DATA) { req->busy_flag &= ~BUSY_FLAG_VIDEO; return 1; } else { GetAVData(AV_OP_GET_MPEG4_SERIAL, -1, &req->av_data ); req->serial_book = req->av_data.serial; dbg("lock error ret=%d\n", ret); return 1; } } if (req->http_stream == URI_STREAM_MPEG4CIF || req->http_stream == URI_STREAM_AVCCIF) { int ret; #if 1 #if 0 while (audio_get(req) > 0); if (req->audio_length > AUDIO_SEND_SIZE) { audio_send(req); return 1; } #else if (audio_get(req, FMT_MPEG4_EXT) > 0) return 1; #endif #else req->busy_flag &= ~BUSY_FLAG_AUDIO; #endif ret = GetAVData(AV_OP_LOCK_MP4_CIF, req->serial_book, &req->av_data); if (ret == RET_SUCCESS) { GetAVData(AV_OP_UNLOCK_MP4_CIF, req->serial_lock, NULL); req->data_mem = req->av_data.ptr; req->filesize = req->av_data.size+16; req->filepos = 0; req->serial_lock = req->av_data.serial; req->serial_book = req->av_data.serial+1; reset_output_buffer(req); req_write(req, "\r\n"); if (req->http_stream == URI_STREAM_AVCCIF) { print_avc_headers(req); } else { print_mpeg4_headers(req); } return 1; } else if (ret == RET_NO_VALID_DATA) { req->busy_flag &= ~BUSY_FLAG_VIDEO; return 1; } else { GetAVData(AV_OP_GET_MPEG4_CIF_SERIAL, -1, &req->av_data ); req->serial_book = req->av_data.serial; dbg("lock error ret=%d\n", ret); return 1; } } #endif // DAVINCI_IPCAM return 0; } else return 1; /* more to do */ }
int init_get(request * req) { int data_fd, saved_errno, dynamic=0; 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... */ } #ifdef DAVINCI_IPCAM if (req->http_uri && (req->http_uri->uri_flag & URI_FLAG_NEED_PARSE)) dynamic = 1; #endif if (req->if_modified_since && !dynamic && !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; } #ifdef DAVINCI_IPCAM if (dynamic) { char *addr = (char *)malloc(req->filesize + 1025); if (addr) { req->mem_flag |= MFLAG_IS_MEMORY; req->mmap_ptr = req->data_mem; req->mmap_size = req->filesize; memcpy(addr+1024, req->data_mem, req->filesize); addr[req->filesize+1024] = '\0'; req->data_mem = addr; req->filesize = html_argument_parse(req->authority, addr+1024, req->data_mem); send_request_ok_no_cache(req); /* All's well */ return 1; } } #endif // DAVINCI_IPCAM 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; }
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; #ifdef GUNZIP if (data_fd == -1 && errno == ENOENT) { 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)) { close(data_fd); 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); if (data_fd == -1) return 0; else if (data_fd <= 1) return data_fd; } 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); 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) { send_r_request_ok(req); 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); if ((long) req->data_mem == -1) { boa_perror(req, "mmap"); return 0; } send_r_request_ok(req); 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; } else { 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; } } return 1; }