Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

mod_asis.c

Go to the documentation of this file.
00001 /* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "apr_strings.h"
00018 #include "ap_config.h"
00019 #include "httpd.h"
00020 #include "http_config.h"
00021 #include "http_protocol.h"
00022 #include "http_log.h"
00023 #include "util_script.h"
00024 #include "http_main.h"
00025 #include "http_request.h"
00026 
00027 #include "mod_core.h"
00028 
00029 #define ASIS_MAGIC_TYPE "httpd/send-as-is"
00030 
00031 static int asis_handler(request_rec *r)
00032 {
00033     conn_rec *c = r->connection;
00034     apr_file_t *f = NULL;
00035     apr_status_t rv;
00036     const char *location;
00037 
00038     if(strcmp(r->handler,ASIS_MAGIC_TYPE) && strcmp(r->handler,"send-as-is"))
00039         return DECLINED;
00040 
00041     r->allowed |= (AP_METHOD_BIT << M_GET);
00042     if (r->method_number != M_GET)
00043         return DECLINED;
00044     if (r->finfo.filetype == 0) {
00045         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00046                     "File does not exist: %s", r->filename);
00047         return HTTP_NOT_FOUND;
00048     }
00049 
00050     if ((rv = apr_file_open(&f, r->filename, APR_READ, 
00051                 APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) {
00052         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
00053                     "file permissions deny server access: %s", r->filename);
00054         return HTTP_FORBIDDEN;
00055     }
00056 
00057     ap_scan_script_header_err(r, f, NULL);
00058     location = apr_table_get(r->headers_out, "Location");
00059 
00060     if (location && location[0] == '/' &&
00061         ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
00062 
00063         apr_file_close(f);
00064 
00065         /* Internal redirect -- fake-up a pseudo-request */
00066         r->status = HTTP_OK;
00067 
00068         /* This redirect needs to be a GET no matter what the original
00069          * method was.
00070          */
00071         r->method = apr_pstrdup(r->pool, "GET");
00072         r->method_number = M_GET;
00073 
00074         ap_internal_redirect_handler(location, r);
00075         return OK;
00076     }
00077 
00078     if (!r->header_only) {
00079         apr_bucket_brigade *bb;
00080         apr_bucket *b;
00081         apr_off_t pos = 0;
00082 
00083         rv = apr_file_seek(f, APR_CUR, &pos);
00084         if (rv != APR_SUCCESS) {
00085             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
00086                           "mod_asis: failed to find end-of-headers position "
00087                           "for %s", r->filename);
00088             apr_file_close(f);
00089             return HTTP_INTERNAL_SERVER_ERROR;
00090         }
00091 
00092         bb = apr_brigade_create(r->pool, c->bucket_alloc);
00093 #if APR_HAS_LARGE_FILES
00094         if (r->finfo.size - pos > AP_MAX_SENDFILE) {
00095             /* APR_HAS_LARGE_FILES issue; must split into mutiple buckets, 
00096              * no greater than MAX(apr_size_t), and more granular than that
00097              * in case the brigade code/filters attempt to read it directly.
00098              */
00099             apr_off_t fsize = r->finfo.size - pos;
00100             b = apr_bucket_file_create(f, pos, AP_MAX_SENDFILE,
00101                                        r->pool, c->bucket_alloc);
00102             while (fsize > AP_MAX_SENDFILE) {
00103                 APR_BRIGADE_INSERT_TAIL(bb, b);
00104                 apr_bucket_copy(b, &b);
00105                 b->start += AP_MAX_SENDFILE;
00106                 fsize -= AP_MAX_SENDFILE;
00107             }
00108             b->length = (apr_size_t)fsize; /* Resize just the last bucket */
00109         }
00110         else
00111 #endif
00112         b = apr_bucket_file_create(f, pos, (apr_size_t) (r->finfo.size - pos),
00113                                    r->pool, c->bucket_alloc);
00114         APR_BRIGADE_INSERT_TAIL(bb, b);
00115         b = apr_bucket_eos_create(c->bucket_alloc);
00116         APR_BRIGADE_INSERT_TAIL(bb, b);
00117         rv = ap_pass_brigade(r->output_filters, bb);
00118         if (rv != APR_SUCCESS) {
00119             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
00120                           "mod_asis: ap_pass_brigade failed for file %s", r->filename);
00121             return HTTP_INTERNAL_SERVER_ERROR;
00122         }
00123     }
00124     else {
00125         apr_file_close(f);
00126     }
00127 
00128     return OK;
00129 }
00130 
00131 static void register_hooks(apr_pool_t *p)
00132 {
00133     ap_hook_handler(asis_handler,NULL,NULL,APR_HOOK_MIDDLE);
00134 }
00135 
00136 module AP_MODULE_DECLARE_DATA asis_module =
00137 {
00138     STANDARD20_MODULE_STUFF,
00139     NULL,                       /* create per-directory config structure */
00140     NULL,                       /* merge per-directory config structures */
00141     NULL,                       /* create per-server config structure */
00142     NULL,                       /* merge per-server config structures */
00143     NULL,                       /* command apr_table_t */
00144     register_hooks              /* register hooks */
00145 };