Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
    }
}
Esempio n. 6
0
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;
}