From: Greg Stein Date: Mon, 14 Jan 2002 13:43:24 +0000 (+0000) Subject: Revamp how mod_dav asks its provider to generate a GET response. X-Git-Tag: 2.0.31~199 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a065e197e4d662fb8d9270055ee0bdbc40b24802;p=apache Revamp how mod_dav asks its provider to generate a GET response. * eliminate the get_pathname and free_file vtable functions. add the deliver() function to have the provider deliver the content straight into a filter [stack]. * eliminate readable streams -- they are now obsolete. this gets rid of the read_stream vtable function and DAV_MODE_READ* * implement a deliver() function for the FS provider. this simply constructs a bucket and EOS and shoves them into the filter. note that this is debug code only, so the "large file" issue handled by the core's default handler doesn't count here. * allow the provider to handle GET for any resource type and for collections. this moves the checks into the provider. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@92848 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 50f408d131..8ea05944c6 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -75,7 +75,6 @@ /* to assist in debugging mod_dav's GET handling */ #define DEBUG_GET_HANDLER 0 -#define DEBUG_PATHNAME_STYLE 0 #define DAV_FS_COPY_BLOCKSIZE 16384 /* copy 16k at a time */ @@ -804,8 +803,6 @@ static dav_error * dav_fs_open_stream(const dav_resource *resource, apr_int32_t flags; switch (mode) { - case DAV_MODE_READ: - case DAV_MODE_READ_SEEKABLE: default: flags = APR_READ | APR_BINARY; break; @@ -850,18 +847,6 @@ static dav_error * dav_fs_close_stream(dav_stream *stream, int commit) return NULL; } -static dav_error * dav_fs_read_stream(dav_stream *stream, - void *buf, apr_size_t *bufsize) -{ - if (apr_file_read(stream->f, buf, bufsize) != APR_SUCCESS) { - /* ### use something besides 500? */ - return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "An error occurred while reading from a " - "resource."); - } - return NULL; -} - static dav_error * dav_fs_write_stream(dav_stream *stream, const void *buf, apr_size_t bufsize) { @@ -895,11 +880,16 @@ static dav_error * dav_fs_seek_stream(dav_stream *stream, apr_off_t abs_pos) return NULL; } + +#if DEBUG_GET_HANDLER + +/* only define set_headers() and deliver() for debug purposes */ + + static dav_error * dav_fs_set_headers(request_rec *r, const dav_resource *resource) { /* ### this function isn't really used since we have a get_pathname */ -#if DEBUG_GET_HANDLER if (!resource->exists) return NULL; @@ -919,25 +909,60 @@ static dav_error * dav_fs_set_headers(request_rec *r, /* ### how to set the content type? */ /* ### until this is resolved, the Content-Type header is busted */ -#endif - return NULL; } -#if DEBUG_PATHNAME_STYLE -static const char * dav_fs_get_pathname( - const dav_resource *resource, - void **free_handle_p) +static dav_error * dav_fs_deliver(const dav_resource *resource, + ap_filter_t *output) { - return resource->info->pathname; -} -#endif + apr_pool_t *pool = resource->pool; + apr_bucket_brigade *bb; + apr_file_t *fd; + apr_status_t status; + apr_bucket *bkt; -static void dav_fs_free_file(void *free_handle) -{ - /* nothing to free ... */ + /* Check resource type */ + if (resource->type != DAV_RESOURCE_TYPE_REGULAR + && resource->type != DAV_RESOURCE_TYPE_VERSION + && resource->type != DAV_RESOURCE_TYPE_WORKING) { + return dav_new_error(pool, HTTP_CONFLICT, 0, + "Cannot GET this type of resource."); + } + if (resource->collection) { + return dav_new_error(pool, HTTP_CONFLICT, 0, + "There is no default response to GET for a " + "collection."); + } + + if ((status = apr_file_open(&fd, resource->info->pathname, + APR_READ | APR_BINARY, 0, + pool)) != APR_SUCCESS) { + return dav_new_error(pool, HTTP_FORBIDDEN, 0, + "File permissions deny server access."); + } + + bb = apr_brigade_create(pool); + + /* ### 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); + APR_BRIGADE_INSERT_TAIL(bb, bkt); + + bkt = apr_bucket_eos_create(); + APR_BRIGADE_INSERT_TAIL(bb, bkt); + + if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { + return dav_new_error(pool, HTTP_FORBIDDEN, 0, + "Could not write contents to filter."); + } + + return NULL; } +#endif /* DEBUG_GET_HANDLER */ + + static dav_error * dav_fs_create_collection(dav_resource *resource) { dav_resource_private *ctx = resource->info; @@ -1714,16 +1739,15 @@ static const dav_hooks_repository dav_hooks_repository_fs = dav_fs_is_parent_resource, dav_fs_open_stream, dav_fs_close_stream, - dav_fs_read_stream, dav_fs_write_stream, dav_fs_seek_stream, +#if DEBUG_GET_HANDLER dav_fs_set_headers, -#if DEBUG_PATHNAME_STYLE - dav_fs_get_pathname, + dav_fs_deliver, #else - 0, + NULL, + NULL, #endif - dav_fs_free_file, dav_fs_create_collection, dav_fs_copy_resource, dav_fs_move_resource, diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index f049f87959..2b522bb892 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -756,7 +756,6 @@ static int dav_parse_range(request_rec *r, static int dav_method_get(request_rec *r) { dav_resource *resource; - int result; dav_error *err; /* This method should only be called when the resource is not @@ -772,122 +771,28 @@ static int dav_method_get(request_rec *r) return HTTP_NOT_FOUND; } - /* Check resource type */ - if (resource->type != DAV_RESOURCE_TYPE_REGULAR && - resource->type != DAV_RESOURCE_TYPE_VERSION && - resource->type != DAV_RESOURCE_TYPE_WORKING) - { - return dav_error_response(r, HTTP_CONFLICT, - "Cannot GET this type of resource."); - } - - /* Cannot handle GET of a collection from a repository */ - if (resource->collection) { - return dav_error_response(r, HTTP_CONFLICT, - "No default response to GET for a " - "collection."); + /* set up the HTTP headers for the response */ + if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) { + err = dav_push_error(r->pool, err->status, 0, + "Unable to set up HTTP headers.", + err); + return dav_handle_err(r, err, NULL); } - /* - ** We can use two different approaches for a GET. - ** - ** 1) get_pathname will return a pathname to a file which should be - ** sent to the client. If the repository provides this, then we - ** use it. - ** - ** This is the best alternative since it allows us to do a sub- - ** request on the file, which gives the Apache framework a chance - ** to deal with negotiation, MIME types, or whatever. - ** - ** 2) open_stream and read_stream. - */ - if (resource->hooks->get_pathname != NULL) { - const char *pathname; - void *fhandle; - request_rec *new_req; - - /* Ask repository for copy of file */ - pathname = (*resource->hooks->get_pathname)(resource, &fhandle); - if (pathname == NULL) { - return HTTP_NOT_FOUND; - } - - /* Create a sub-request with the new filename - * The new_req filename is canonicalized by ap_sub_req_lookup_file() - */ - new_req = ap_sub_req_lookup_file(pathname, r, NULL); - if (new_req == NULL) { - (*resource->hooks->free_file)(fhandle); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* This may be a HEAD request */ - new_req->header_only = r->header_only; - - /* ### this enables header generation */ - new_req->assbackwards = 0; - - /* Run the sub-request */ - result = ap_run_sub_req(new_req); - ap_destroy_sub_req(new_req); - - /* Free resources */ - (*resource->hooks->free_file)(fhandle); - - return result; + if (r->header_only) { + return DONE; } - else { - dav_stream *stream; - void *buffer; - /* set up the HTTP headers for the response */ - if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) { - err = dav_push_error(r->pool, err->status, 0, - "Unable to set up HTTP headers.", - err); - return dav_handle_err(r, err, NULL); - } - - if (r->header_only) { - return DONE; - } - - if ((err = (*resource->hooks->open_stream)(resource, DAV_MODE_READ, - &stream)) != NULL) { - /* ### assuming FORBIDDEN is probably not quite right... */ - err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0, - apr_psprintf(r->pool, - "Unable to GET contents for %s.", - ap_escape_html(r->pool, r->uri)), - err); - return dav_handle_err(r, err, NULL); - } - - buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE); - while (1) { - apr_size_t amt = DAV_READ_BLOCKSIZE; - - if ((err = (*resource->hooks->read_stream)(stream, buffer, - &amt)) != NULL) { - break; - } - if (amt == 0) { - /* no more content */ - break; - } - if (ap_rwrite(buffer, amt, r) < 0) { - /* ### what to do with this error? */ - break; - } - } - - if (err != NULL) - return dav_handle_err(r, err, NULL); - - return DONE; + /* okay... time to deliver the content */ + if ((err = (*resource->hooks->deliver)(resource, + r->output_filters)) != NULL) { + err = dav_push_error(r->pool, err->status, 0, + "Unable to deliver content.", + err); + return dav_handle_err(r, err, NULL); } - /* NOTREACHED */ + return DONE; } /* validate resource on POST, then pass it off to the default handler */ diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h index f9e8dbebc6..2d47ca9224 100644 --- a/modules/dav/main/mod_dav.h +++ b/modules/dav/main/mod_dav.h @@ -1672,13 +1672,15 @@ DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres, ** ** Note that the structure is opaque -- it is private to the repository ** that created the stream in the repository's "open" function. +** +** ### THIS STUFF IS GOING AWAY ... GET/read requests are handled by +** ### having the provider jam stuff straight into the filter stack. +** ### this is only left for handling PUT/write requests. */ typedef struct dav_stream dav_stream; typedef enum { - DAV_MODE_READ, /* open for reading */ - DAV_MODE_READ_SEEKABLE, /* open for random access reading */ DAV_MODE_WRITE_TRUNC, /* truncate and open for writing */ DAV_MODE_WRITE_SEEKABLE /* open for writing; random access */ } dav_stream_mode; @@ -1788,19 +1790,6 @@ struct dav_hooks_repository */ dav_error * (*close_stream)(dav_stream *stream, int commit); - /* - ** Read data from the stream. - ** - ** The size of the buffer is passed in *bufsize, and the amount read - ** is returned in *bufsize. - ** - ** *bufsize should be set to zero when the end of file is reached. - ** As a corollary, this function should always read at least one byte - ** on each call, until the EOF condition is met. - */ - dav_error * (*read_stream)(dav_stream *stream, - void *buf, apr_size_t *bufsize); - /* ** Write data to the stream. ** @@ -1824,30 +1813,29 @@ struct dav_hooks_repository ** is used to provide the repository with a way to set the headers ** in the response. ** - ** It may be NULL if get_pathname is provided. + ** This function may be called without a following deliver(), to + ** handle a HEAD request. + ** + ** This may be NULL if handle_get is FALSE. */ dav_error * (*set_headers)(request_rec *r, const dav_resource *resource); - /* Get a pathname for the file represented by the resource descriptor. - * A provider may need to create a temporary copy of the file, if it is - * not directly accessible in a filesystem. free_handle_p will be set by - * the provider to point to information needed to clean up any temporary - * storage used. - * - * Returns NULL if the file could not be made accessible. - */ - const char * (*get_pathname)( - const dav_resource *resource, - void **free_handle_p - ); - - /* Free any temporary storage associated with a file made accessible by - * get_pathname(). - */ - void (*free_file)( - void *free_handle - ); + /* + ** The provider should deliver the resource into the specified filter. + ** Basically, this is the response to the GET method. + ** + ** Note that this is called for all resources, including collections. + ** The provider should determine what has content to deliver or not. + ** + ** set_headers will be called prior to this function, allowing the + ** provider to set the appropriate response headers. + ** + ** This may be NULL if handle_get is FALSE. + ** ### maybe toss handle_get and just use this function as the marker + */ + dav_error * (*deliver)(const dav_resource *resource, + ap_filter_t *output); /* Create a collection resource. The resource must not already exist. *