APU_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb, apr_file_t *f, apr_off_t start, apr_off_t length, apr_pool_t *p) { apr_bucket *e; if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) { e = apr_bucket_file_create(f, start, (apr_size_t)length, p, bb->bucket_alloc); } else { /* Several buckets are needed. */ e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p, bb->bucket_alloc); while (length > MAX_BUCKET_SIZE) { apr_bucket *ce; apr_bucket_copy(e, &ce); APR_BRIGADE_INSERT_TAIL(bb, ce); e->start += MAX_BUCKET_SIZE; length -= MAX_BUCKET_SIZE; } e->length = (apr_size_t)length; /* Resize just the last bucket */ } APR_BRIGADE_INSERT_TAIL(bb, e); return e; }
static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb) { apr_bucket *e; disk_cache_object_t *dobj = (disk_cache_object_t*) h->cache_obj->vobj; e = apr_bucket_file_create(dobj->fd, 0, (apr_size_t) dobj->file_size, p, bb->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, e); e = apr_bucket_eos_create(bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); return APR_SUCCESS; }
static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb) { apr_bucket *b; mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj; if (mobj->type == CACHE_TYPE_FILE) { /* CACHE_TYPE_FILE */ apr_file_t *file; apr_os_file_put(&file, &mobj->fd, mobj->flags, p); b = apr_bucket_file_create(file, 0, mobj->m_len, p, bb->bucket_alloc); } else { /* CACHE_TYPE_HEAP */ b = apr_bucket_immortal_create(mobj->m, mobj->m_len, bb->bucket_alloc); } APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return APR_SUCCESS; }
static int asis_handler(request_rec *r) { conn_rec *c = r->connection; apr_file_t *f = NULL; apr_status_t rv; const char *location; if(strcmp(r->handler,ASIS_MAGIC_TYPE) && strcmp(r->handler,"send-as-is")) return DECLINED; r->allowed |= (AP_METHOD_BIT << M_GET); if (r->method_number != M_GET) return DECLINED; if (r->finfo.filetype == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "File does not exist: %s", r->filename); return HTTP_NOT_FOUND; } if ((rv = apr_file_open(&f, r->filename, APR_READ, APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "file permissions deny server access: %s", r->filename); return HTTP_FORBIDDEN; } ap_scan_script_header_err(r, f, NULL); location = apr_table_get(r->headers_out, "Location"); if (location && location[0] == '/' && ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) { apr_file_close(f); /* Internal redirect -- fake-up a pseudo-request */ r->status = HTTP_OK; /* This redirect needs to be a GET no matter what the original * method was. */ r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; ap_internal_redirect_handler(location, r); return OK; } if (!r->header_only) { apr_bucket_brigade *bb; apr_bucket *b; apr_off_t pos = 0; rv = apr_file_seek(f, APR_CUR, &pos); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_asis: failed to find end-of-headers position " "for %s", r->filename); apr_file_close(f); return HTTP_INTERNAL_SERVER_ERROR; } bb = apr_brigade_create(r->pool, c->bucket_alloc); #if APR_HAS_LARGE_FILES if (r->finfo.size - pos > AP_MAX_SENDFILE) { /* APR_HAS_LARGE_FILES issue; must split into mutiple buckets, * no greater than MAX(apr_size_t), and more granular than that * in case the brigade code/filters attempt to read it directly. */ apr_off_t fsize = r->finfo.size - pos; b = apr_bucket_file_create(f, pos, AP_MAX_SENDFILE, r->pool, c->bucket_alloc); while (fsize > AP_MAX_SENDFILE) { APR_BRIGADE_INSERT_TAIL(bb, b); apr_bucket_copy(b, &b); b->start += AP_MAX_SENDFILE; fsize -= AP_MAX_SENDFILE; } b->length = (apr_size_t)fsize; /* Resize just the last bucket */ } else #endif b = apr_bucket_file_create(f, pos, (apr_size_t) (r->finfo.size - pos), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(r->output_filters, bb); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_asis: ap_pass_brigade failed for file %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } } else { apr_file_close(f); } return OK; }
int trell_send_reply_static_file( trell_sconf_t* sconf, request_rec* r, trell_dispatch_info_t* dinfo ) { apr_status_t rv; char* path = NULL; if( dinfo->m_component == TRELL_COMPONENT_JOB ) { path = apr_pstrcat( r->pool, sconf->m_job_www_root, "/", dinfo->m_requestname, NULL ); } if( path == NULL ) { ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, r, "Empty file." ); } apr_finfo_t finfo; rv = apr_stat( &finfo, path, APR_FINFO_SIZE, r->pool); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "Failed to stat static file." ); return HTTP_NOT_FOUND; } ap_set_content_length( r, finfo.size ); // guess content type size_t l = strlen( path ); if( (l>5) && (strcmp(&path[l-5], ".html") == 0 ) ) { ap_set_content_type( r, "text/html" ); } else if( (l>3) && (strcmp(&path[l-3], ".js") == 0 ) ) { ap_set_content_type( r, "text/javascript" ); } else if( (l>4) && (strcmp(&path[l-4], ".css" ) == 0 ) ) { ap_set_content_type( r, "text/css" ); } else if( (l>4) && (strcmp(&path[l-4], ".gif" ) == 0 ) ) { ap_set_content_type( r, "image/gif" ); } else if( (l>4) && (strcmp(&path[l-4], ".png" ) == 0 ) ) { ap_set_content_type( r, "image/png" ); } apr_file_t* fd; rv = apr_file_open( &fd, path, APR_READ | APR_SENDFILE_ENABLED, APR_OS_DEFAULT, r->pool ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "Failed to open static file." ); return HTTP_NOT_FOUND; } apr_bucket_brigade* bb = apr_brigade_create( r->pool, r->connection->bucket_alloc ); APR_BRIGADE_INSERT_TAIL( bb, apr_bucket_file_create( fd, 0, finfo.size, r->pool, r->connection->bucket_alloc ) ); APR_BRIGADE_INSERT_TAIL( bb, apr_bucket_eos_create( bb->bucket_alloc ) ); rv = ap_pass_brigade( r->output_filters, bb ); if( rv != APR_SUCCESS ) { apr_file_close( fd ); ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "Output error" ); return HTTP_INTERNAL_SERVER_ERROR; } else { apr_file_close( fd ); return OK; } }
static apr_status_t ap_xsendfile_output_filter(ap_filter_t *f, apr_bucket_brigade *in) { request_rec *r = f->r, *sr = NULL; xsendfile_conf_t *dconf = (xsendfile_conf_t *)ap_get_module_config(r->per_dir_config, &xsendfile_module), *sconf = (xsendfile_conf_t *)ap_get_module_config(r->server->module_config, &xsendfile_module), *conf = xsendfile_config_merge(r->pool, sconf, dconf); core_dir_config *coreconf = (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); apr_status_t rv; apr_bucket *e; apr_file_t *fd = NULL; apr_finfo_t finfo; const char *file = NULL; char *translated = NULL; int errcode; #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: output_filter for %s", r->the_request); #endif /* should we proceed with this request? * sub-requests suck * furthermore default-handled requests suck, as they actually shouldn't be able to set headers */ if ( r->status != HTTP_OK || r->main || (r->handler && strcmp(r->handler, "default-handler") == 0) /* those table-keys are lower-case, right? */ ) { #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: not met [%d]", r->status); #endif ap_remove_output_filter(f); return ap_pass_brigade(f->next, in); } /* alright, look for x-sendfile */ file = apr_table_get(r->headers_out, AP_XSENDFILE_HEADER); apr_table_unset(r->headers_out, AP_XSENDFILE_HEADER); /* cgi/fastcgi will put the stuff into err_headers_out */ if (!file || !*file) { file = apr_table_get(r->err_headers_out, AP_XSENDFILE_HEADER); apr_table_unset(r->err_headers_out, AP_XSENDFILE_HEADER); } /* nothing there :p */ if (!file || !*file) { #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: nothing found"); #endif ap_remove_output_filter(f); return ap_pass_brigade(f->next, in); } /* drop *everything* might be pretty expensive to generate content first that goes straight to the bitbucket, but actually the scripts that might set this flag won't output too much anyway */ while (!APR_BRIGADE_EMPTY(in)) { e = APR_BRIGADE_FIRST(in); apr_bucket_delete(e); } r->eos_sent = 0; rv = ap_xsendfile_get_filepath(r, conf, file, &translated); if (rv != OK) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "xsendfile: unable to find file: %s", file ); ap_remove_output_filter(f); ap_die(HTTP_NOT_FOUND, r); return HTTP_NOT_FOUND; } #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: found %s", translated); #endif /* ry open the file */ if ((rv = apr_file_open( &fd, translated, APR_READ | APR_BINARY #if APR_HAS_SENDFILE | (coreconf->enable_sendfile == ENABLE_SENDFILE_ON ? APR_SENDFILE_ENABLED : 0) #endif , 0, r->pool )) != APR_SUCCESS) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "xsendfile: cannot open file: %s", translated ); ap_remove_output_filter(f); ap_die(HTTP_NOT_FOUND, r); return HTTP_NOT_FOUND; } #if APR_HAS_SENDFILE && defined(_DEBUG) if (coreconf->enable_sendfile != ENABLE_SENDFILE_ON) { ap_log_error( APLOG_MARK, APLOG_WARNING, 0, r->server, "xsendfile: sendfile configured, but not active %d", coreconf->enable_sendfile ); } #endif /* stat (for etag/cache/content-length stuff) */ if ((rv = apr_file_info_get(&finfo, APR_FINFO_NORM, fd)) != APR_SUCCESS) { ap_log_rerror( APLOG_MARK, APLOG_ERR, rv, r, "xsendfile: unable to stat file: %s", translated ); apr_file_close(fd); ap_remove_output_filter(f); ap_die(HTTP_FORBIDDEN, r); return HTTP_FORBIDDEN; } /* no inclusion of directories! we're serving files! */ if (finfo.filetype != APR_REG) { ap_log_rerror( APLOG_MARK, APLOG_ERR, APR_EBADPATH, r, "xsendfile: not a file %s", translated ); apr_file_close(fd); ap_remove_output_filter(f); ap_die(HTTP_NOT_FOUND, r); return HTTP_NOT_FOUND; } /* need to cheat here a bit as etag generator will use those ;) and we want local_copy and cache */ r->finfo.inode = finfo.inode; r->finfo.size = finfo.size; /* caching? why not :p */ r->no_cache = r->no_local_copy = 0; /* some script (f?cgi) place stuff in err_headers_out */ if ( conf->ignoreLM == XSENDFILE_ENABLED || ( !apr_table_get(r->headers_out, "last-modified") && !apr_table_get(r->headers_out, "last-modified") ) ) { apr_table_unset(r->err_headers_out, "last-modified"); ap_update_mtime(r, finfo.mtime); ap_set_last_modified(r); } if ( conf->ignoreETag == XSENDFILE_ENABLED || ( !apr_table_get(r->headers_out, "etag") && !apr_table_get(r->err_headers_out, "etag") ) ) { apr_table_unset(r->err_headers_out, "etag"); ap_set_etag(r); } apr_table_unset(r->err_headers_out, "content-length"); ap_set_content_length(r, finfo.size); /* as we dropped all the content this field is not valid anymore! */ apr_table_unset(r->headers_out, "Content-Encoding"); apr_table_unset(r->err_headers_out, "Content-Encoding"); /* cache or something? */ if ((errcode = ap_meets_conditions(r)) != OK) { #ifdef _DEBUG ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: met condition %d for %s", errcode, file ); #endif apr_file_close(fd); r->status = errcode; } else { /* For platforms where the size of the file may be larger than * that which can be stored in a single bucket (where the * length field is an apr_size_t), split it into several * buckets: */ if (sizeof(apr_off_t) > sizeof(apr_size_t) && finfo.size > AP_MAX_SENDFILE) { apr_off_t fsize = finfo.size; e = apr_bucket_file_create(fd, 0, AP_MAX_SENDFILE, r->pool, in->bucket_alloc); while (fsize > AP_MAX_SENDFILE) { apr_bucket *ce; apr_bucket_copy(e, &ce); APR_BRIGADE_INSERT_TAIL(in, ce); e->start += AP_MAX_SENDFILE; fsize -= AP_MAX_SENDFILE; } e->length = (apr_size_t)fsize; /* Resize just the last bucket */ } else { e = apr_bucket_file_create(fd, 0, (apr_size_t)finfo.size, r->pool, in->bucket_alloc); } #if APR_HAS_MMAP if (coreconf->enable_mmap == ENABLE_MMAP_ON) { apr_bucket_file_enable_mmap(e, 0); } #if defined(_DEBUG) else { ap_log_error( APLOG_MARK, APLOG_WARNING, 0, r->server, "xsendfile: mmap configured, but not active %d", coreconf->enable_mmap ); } #endif /* _DEBUG */ #endif /* APR_HAS_MMAP */ APR_BRIGADE_INSERT_TAIL(in, e); } e = apr_bucket_eos_create(in->bucket_alloc); APR_BRIGADE_INSERT_TAIL(in, e); /* remove ourselves from the filter chain */ ap_remove_output_filter(f); #ifdef _DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "xsendfile: sending %d bytes", (int)finfo.size); #endif /* send the data up the stack */ return ap_pass_brigade(f->next, in); }
static dav_error * dav_rawx_deliver(const dav_resource *resource, ap_filter_t *output) { dav_rawx_server_conf *conf; apr_pool_t *pool; apr_bucket_brigade *bb = NULL; apr_status_t status; apr_bucket *bkt = NULL; dav_resource_private *ctx; dav_error *e = NULL; apr_finfo_t info; DAV_XDEBUG_RES(resource, 0, "%s(%s)", __FUNCTION__, resource_get_pathname(resource)); pool = resource->pool; conf = resource_get_server_config(resource); /* Check resource type */ if (DAV_RESOURCE_TYPE_REGULAR != resource->type) { e = server_create_and_stat_error(conf, pool, HTTP_CONFLICT, 0, "Cannot GET this type of resource."); goto end_deliver; } if (resource->collection) { e = server_create_and_stat_error(conf, pool, HTTP_CONFLICT, 0, "No GET on collections"); goto end_deliver; } ctx = resource->info; if (ctx->update_only) { /* Check if it is not a busy file. We accept reads during * compression but not attr updates. */ char *pending_file = apr_pstrcat(pool, resource_get_pathname(resource), ".pending", NULL); status = apr_stat(&info, pending_file, APR_FINFO_ATIME, pool); if (status == APR_SUCCESS) { e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, "File in pending mode."); goto end_deliver; } GError *error_local = NULL; /* UPDATE chunk attributes and go on */ const char *path = resource_get_pathname(resource); FILE *f = NULL; f = fopen(path, "r"); /* Try to open the file but forbids a creation */ if (!set_rawx_info_to_fd(fileno(f), &error_local, &(ctx->chunk))) { fclose(f); e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, apr_pstrdup(pool, gerror_get_message(error_local))); g_clear_error(&error_local); goto end_deliver; } fclose(f); } else { bb = apr_brigade_create(pool, output->c->bucket_alloc); if (!ctx->compression){ apr_file_t *fd = NULL; /* Try to open the file but forbids a creation */ status = apr_file_open(&fd, resource_get_pathname(resource), APR_READ|APR_BINARY|APR_BUFFERED, 0, pool); if (APR_SUCCESS != status) { e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, "File permissions deny server access."); goto end_deliver; } /* FIXME this does not handle large files. but this is test code anyway */ bkt = apr_bucket_file_create(fd, 0, (apr_size_t)resource->info->finfo.size, pool, output->c->bucket_alloc); } else { DAV_DEBUG_RES(resource, 0, "Building a compressed resource bucket"); gint i64; i64 = g_ascii_strtoll(ctx->cp_chunk.uncompressed_size, NULL, 10); /* creation of compression specific bucket */ bkt = apr_pcalloc(pool, sizeof(struct apr_bucket)); bkt->type = &chunk_bucket_type; bkt->length = i64; bkt->start = 0; bkt->data = ctx; bkt->free = chunk_bucket_free_noop; bkt->list = output->c->bucket_alloc; } APR_BRIGADE_INSERT_TAIL(bb, bkt); /* as soon as the chunk has been sent, end of stream!*/ bkt = apr_bucket_eos_create(output->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bkt); if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS){ e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, "Could not write contents to filter."); /* close file */ if (ctx->cp_chunk.fd) { fclose(ctx->cp_chunk.fd); } goto end_deliver; } if (ctx->cp_chunk.buf){ g_free(ctx->cp_chunk.buf); ctx->cp_chunk.buf = NULL; } if (ctx->cp_chunk.uncompressed_size){ g_free(ctx->cp_chunk.uncompressed_size); ctx->cp_chunk.uncompressed_size = NULL; } /* close file */ if (ctx->cp_chunk.fd) { fclose(ctx->cp_chunk.fd); } server_inc_stat(conf, RAWX_STATNAME_REP_2XX, 0); server_add_stat(conf, RAWX_STATNAME_REP_BWRITTEN, resource->info->finfo.size, 0); } end_deliver: if (bb) { apr_brigade_destroy(bb); bb = NULL; } /* Now we pass here even if an error occured, for process request duration */ server_inc_request_stat(resource_get_server_config(resource), RAWX_STATNAME_REQ_CHUNKGET, request_get_duration(resource->info->request)); return e; }