From 7e062f55b4f694371af0eea0616e6b985290f1d3 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Stefan=20B=C3=BChler?= <stbuehler@web.de>
Date: Fri, 15 Feb 2008 16:40:35 +0100
Subject: [PATCH] Fix mod_compress bug (#1027)
---
src/mod_compress.c | 90 +++++++++++++++++++++++++++------------------------
1 files changed, 48 insertions(+), 42 deletions(-)
diff --git a/src/mod_compress.c b/src/mod_compress.c
index 0acf1f3..b90e655 100644
|
a
|
b
|
|
| 104 | 104 | return HANDLER_GO_ON; |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | | void mkdir_recursive(const char *dir) { |
| 108 | | |
| 109 | | char dir_copy[256]; |
| 110 | | char *p = dir_copy; |
| | 107 | // 0 on success, -1 for error |
| | 108 | int mkdir_recursive(char *dir) { |
| | 109 | char *p = dir; |
| 111 | 110 | |
| 112 | 111 | if (!dir || !dir[0]) |
| 113 | | return; |
| | 112 | return 0; |
| | 113 | |
| | 114 | while ((p = strchr(p + 1, '/')) != NULL) { |
| 114 | 115 | |
| 115 | | strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0])); |
| | 116 | *p = '\0'; |
| | 117 | if ((mkdir(dir, 0700) != 0) && (errno != EEXIST)) { |
| | 118 | *p = '/'; |
| | 119 | return -1; |
| | 120 | } |
| | 121 | |
| | 122 | *p++ = '/'; |
| | 123 | if (!*p) return 0; // Ignore trailing slash |
| | 124 | } |
| | 125 | |
| | 126 | return (mkdir(dir, 0700) != 0) && (errno != EEXIST) ? -1 : 0; |
| | 127 | } |
| | 128 | |
| | 129 | // 0 on success, -1 for error |
| | 130 | int mkdir_for_file(char *filename) { |
| | 131 | char *p = filename; |
| | 132 | |
| | 133 | if (!filename || !filename[0]) |
| | 134 | return -1; |
| 116 | 135 | |
| 117 | 136 | while ((p = strchr(p + 1, '/')) != NULL) { |
| 118 | 137 | |
| 119 | 138 | *p = '\0'; |
| 120 | | if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST)) |
| 121 | | return; |
| | 139 | if ((mkdir(filename, 0700) != 0) && (errno != EEXIST)) { |
| | 140 | ERROR("creating cache-directory \"%s\" failed: %s", filename, strerror(errno)); |
| | 141 | *p = '/'; |
| | 142 | return -1; |
| | 143 | } |
| 122 | 144 | |
| 123 | 145 | *p++ = '/'; |
| | 146 | if (!*p) { |
| | 147 | ERROR("unexpected trailing slash for filename \"%s\"", filename); |
| | 148 | return -1; |
| | 149 | } |
| 124 | 150 | } |
| 125 | 151 | |
| 126 | | mkdir(dir, 0700); |
| | 152 | return 0; |
| 127 | 153 | } |
| 128 | 154 | |
| 129 | 155 | SETDEFAULTS_FUNC(mod_compress_setdefaults) { |
| … |
… |
|
| 161 | 187 | struct stat st; |
| 162 | 188 | if (0 != stat(s->compress_cache_dir->ptr, &st)) { |
| 163 | 189 | |
| 164 | | log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create", |
| 165 | | s->compress_cache_dir, strerror(errno)); |
| | 190 | ERROR("can't stat compress.cache-dir (%s), attempting to create '%s'", strerror(errno),SAFE_BUF_STR(s->compress_cache_dir)); |
| 166 | 191 | mkdir_recursive(s->compress_cache_dir->ptr); |
| 167 | 192 | |
| 168 | 193 | if (0 != stat(s->compress_cache_dir->ptr, &st)) { |
| 169 | | |
| 170 | | log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed", |
| 171 | | s->compress_cache_dir, strerror(errno)); |
| 172 | | |
| | 194 | ERROR("can't stat compress.cache-dir (%s), failed to create '%s'", strerror(errno),SAFE_BUF_STR(s->compress_cache_dir)); |
| 173 | 195 | return HANDLER_ERROR; |
| 174 | 196 | } |
| 175 | 197 | } |
| … |
… |
|
| 377 | 399 | PATHNAME_APPEND_SLASH(p->ofn); |
| 378 | 400 | |
| 379 | 401 | if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) { |
| 380 | | size_t offset = p->ofn->used - 1; |
| 381 | | char *dir, *nextdir; |
| 382 | | |
| 383 | 402 | buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1); |
| 384 | | |
| 385 | 403 | buffer_copy_string_buffer(p->b, p->ofn); |
| 386 | | |
| 387 | | /* mkdir -p ... */ |
| 388 | | for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) { |
| 389 | | *nextdir = '\0'; |
| 390 | | |
| 391 | | if (-1 == mkdir(p->b->ptr, 0700)) { |
| 392 | | if (errno != EEXIST) { |
| 393 | | log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno)); |
| 394 | | |
| 395 | | return -1; |
| 396 | | } |
| 397 | | } |
| 398 | | |
| 399 | | *nextdir = '/'; |
| 400 | | } |
| 401 | 404 | } else { |
| 402 | 405 | buffer_append_string_buffer(p->ofn, con->uri.path); |
| 403 | 406 | } |
| … |
… |
|
| 422 | 425 | |
| 423 | 426 | if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) { |
| 424 | 427 | /* file exists */ |
| 425 | | if (con->conf.log_request_handling) TRACE("file exists in the cache (%s), sending it", BUF_STR(p->ofn)); |
| | 428 | if (con->conf.log_request_handling) TRACE("file exists in the cache (%s), sending it", SAFE_BUF_STR(p->ofn)); |
| 426 | 429 | |
| 427 | 430 | chunkqueue_reset(con->send); |
| 428 | 431 | chunkqueue_append_file(con->send, p->ofn, 0, compressed_sce->st.st_size); |
| … |
… |
|
| 431 | 434 | return 0; |
| 432 | 435 | } |
| 433 | 436 | |
| | 437 | if (-1 == mkdir_for_file(p->ofn->ptr)) |
| | 438 | return -1; // error message in mkdir_for_file |
| | 439 | |
| 434 | 440 | if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) { |
| 435 | 441 | if (errno == EEXIST) { |
| 436 | 442 | /* cache-entry exists */ |
| … |
… |
|
| 643 | 649 | max_fsize = p->conf.compress_max_filesize; |
| 644 | 650 | |
| 645 | 651 | if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { |
| 646 | | if (con->conf.log_request_handling) TRACE("file '%s' not found", BUF_STR(con->physical.path)); |
| | 652 | if (con->conf.log_request_handling) TRACE("file '%s' not found", SAFE_BUF_STR(con->physical.path)); |
| 647 | 653 | return HANDLER_GO_ON; |
| 648 | 654 | } |
| 649 | 655 | |
| 650 | 656 | /* don't compress files that are too large as we need to much time to handle them */ |
| 651 | 657 | if (max_fsize && (sce->st.st_size >> 10) > max_fsize) { |
| 652 | 658 | if (con->conf.log_request_handling) TRACE("file '%s' is too large: %ju", |
| 653 | | BUF_STR(con->physical.path), |
| | 659 | SAFE_BUF_STR(con->physical.path), |
| 654 | 660 | (intmax_t) sce->st.st_size); |
| 655 | 661 | |
| 656 | 662 | return HANDLER_GO_ON; |
| … |
… |
|
| 659 | 665 | /* compressing the file might lead to larger files instead */ |
| 660 | 666 | if (sce->st.st_size < 128) { |
| 661 | 667 | if (con->conf.log_request_handling) TRACE("file '%s' is too small: %ju", |
| 662 | | BUF_STR(con->physical.path), |
| | 668 | SAFE_BUF_STR(con->physical.path), |
| 663 | 669 | (intmax_t) sce->st.st_size); |
| 664 | 670 | |
| 665 | 671 | return HANDLER_GO_ON; |
| … |
… |
|
| 669 | 675 | content_type = 0; |
| 670 | 676 | { |
| 671 | 677 | char *c; |
| 672 | | if ( (c == strchr(BUF_STR(sce->content_type), ';')) != 0) { |
| | 678 | if ( (c = strchr(BUF_STR(sce->content_type), ';')) != 0) { |
| 673 | 679 | content_type = buffer_init(); |
| 674 | 680 | buffer_copy_string_len(content_type, BUF_STR(sce->content_type), c - BUF_STR(sce->content_type)); |
| 675 | 681 | } |
| … |
… |
|
| 678 | 684 | data_string *compress_ds = (data_string *)p->conf.compress->data[m]; |
| 679 | 685 | |
| 680 | 686 | if (!compress_ds) { |
| 681 | | ERROR("evil: %s .. %s", BUF_STR(con->physical.path), BUF_STR(con->uri.path)); |
| | 687 | ERROR("evil: %s .. %s", SAFE_BUF_STR(con->physical.path), SAFE_BUF_STR(con->uri.path)); |
| 682 | 688 | |
| 683 | 689 | return HANDLER_GO_ON; |
| 684 | 690 | } |
| … |
… |
|
| 757 | 763 | /* perhaps we don't even have to compress the file as the browser still has the |
| 758 | 764 | * current version */ |
| 759 | 765 | if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) { |
| 760 | | if (con->conf.log_request_handling) TRACE("%s is still the same, caching", BUF_STR(con->physical.path)); |
| | 766 | if (con->conf.log_request_handling) TRACE("%s is still the same, caching", SAFE_BUF_STR(con->physical.path)); |
| 761 | 767 | return HANDLER_FINISHED; |
| 762 | 768 | } |
| 763 | 769 | |
| … |
… |
|
| 789 | 795 | CONST_STR_LEN("Content-Type"), |
| 790 | 796 | CONST_BUF_LEN(sce->content_type)); |
| 791 | 797 | |
| 792 | | if (con->conf.log_request_handling) TRACE("looks like %s could be compressed", BUF_STR(con->physical.path)); |
| | 798 | if (con->conf.log_request_handling) TRACE("looks like %s could be compressed", SAFE_BUF_STR(con->physical.path)); |
| 793 | 799 | return HANDLER_FINISHED; |
| 794 | 800 | } |
| 795 | 801 | |