📄 mod_dav.c
字号:
*range_end = apr_atoi64(dash + 1); if (*range_end < *range_start || (slash[1] != '*' && apr_atoi64(slash + 1) <= *range_end)) { /* invalid range. ignore it (per S14.16 of RFC2616) */ return 0; } /* we now have a valid range */ return 1;}/* handle the GET method */static int dav_method_get(request_rec *r){ dav_resource *resource; dav_error *err; /* This method should only be called when the resource is not * visible to Apache. We will fetch the resource from the repository, * then create a subrequest for Apache to handle. */ err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, &resource); if (err != NULL) return dav_handle_err(r, err, NULL); if (!resource->exists) { /* Apache will supply a default error for this. */ return HTTP_NOT_FOUND; } /* 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; } /* 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); } return DONE;}/* validate resource/locks on POST, then pass to the default handler */static int dav_method_post(request_rec *r){ dav_resource *resource; dav_error *err; /* Ask repository module to resolve the resource */ err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, &resource); if (err != NULL) return dav_handle_err(r, err, NULL); /* Note: depth == 0. Implies no need for a multistatus response. */ if ((err = dav_validate_request(r, resource, 0, NULL, NULL, DAV_VALIDATE_RESOURCE, NULL)) != NULL) { /* ### add a higher-level description? */ return dav_handle_err(r, err, NULL); } return DECLINED;}/* handle the PUT method */static int dav_method_put(request_rec *r){ dav_resource *resource; int resource_state; dav_auto_version_info av_info; const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); const char *body; dav_error *err; dav_error *err2; dav_stream_mode mode; dav_stream *stream; dav_response *multi_response; int has_range; apr_off_t range_start; apr_off_t range_end; /* Ask repository module to resolve the resource */ err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, &resource); if (err != NULL) return dav_handle_err(r, err, NULL); /* If not a file or collection resource, PUT not allowed */ if (resource->type != DAV_RESOURCE_TYPE_REGULAR && resource->type != DAV_RESOURCE_TYPE_WORKING) { body = apr_psprintf(r->pool, "Cannot create resource %s with PUT.", ap_escape_html(r->pool, r->uri)); return dav_error_response(r, HTTP_CONFLICT, body); } /* Cannot PUT a collection */ if (resource->collection) { return dav_error_response(r, HTTP_CONFLICT, "Cannot PUT to a collection."); } resource_state = dav_get_resource_state(r, resource); /* * Note: depth == 0 normally requires no multistatus response. However, * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI * other than the Request-URI, thereby requiring a multistatus. * * If the resource does not exist (DAV_RESOURCE_NULL), then we must * check the resource *and* its parent. If the resource exists or is * a locknull resource, then we check only the resource. */ if ((err = dav_validate_request(r, resource, 0, NULL, &multi_response, resource_state == DAV_RESOURCE_NULL ? DAV_VALIDATE_PARENT : DAV_VALIDATE_RESOURCE, NULL)) != NULL) { /* ### add a higher-level description? */ return dav_handle_err(r, err, multi_response); } /* make sure the resource can be modified (if versioning repository) */ if ((err = dav_auto_checkout(r, resource, 0 /* not parent_only */, &av_info)) != NULL) { /* ### add a higher-level description? */ return dav_handle_err(r, err, NULL); } /* truncate and rewrite the file unless we see a Content-Range */ mode = DAV_MODE_WRITE_TRUNC; has_range = dav_parse_range(r, &range_start, &range_end); if (has_range) { mode = DAV_MODE_WRITE_SEEKABLE; } /* Create the new file in the repository */ if ((err = (*resource->hooks->open_stream)(resource, mode, &stream)) != NULL) { /* ### assuming FORBIDDEN is probably not quite right... */ err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0, apr_psprintf(r->pool, "Unable to PUT new contents for %s.", ap_escape_html(r->pool, r->uri)), err); } if (err == NULL && has_range) { /* a range was provided. seek to the start */ err = (*resource->hooks->seek_stream)(stream, range_start); } if (err == NULL) { apr_bucket_brigade *bb; apr_bucket *b; int seen_eos = 0; bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); do { apr_status_t rc; rc = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, DAV_READ_BLOCKSIZE); if (rc != APR_SUCCESS) { err = dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not get next bucket brigade"); break; } for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(b)) { seen_eos = 1; break; } if (APR_BUCKET_IS_METADATA(b)) { continue; } rc = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); if (rc != APR_SUCCESS) { err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, "An error occurred while reading " "the request body."); break; } if (err == NULL) { /* write whatever we read, until we see an error */ err = (*resource->hooks->write_stream)(stream, data, len); } } apr_brigade_cleanup(bb); } while (!seen_eos); apr_brigade_destroy(bb); err2 = (*resource->hooks->close_stream)(stream, err == NULL /* commit */); if (err2 != NULL && err == NULL) { /* no error during the write, but we hit one at close. use it. */ err = err2; } } /* * Ensure that we think the resource exists now. * ### eek. if an error occurred during the write and we did not commit, * ### then the resource might NOT exist (e.g. dav_fs_repos.c) */ if (err == NULL) { resource->exists = 1; } /* restore modifiability of resources back to what they were */ err2 = dav_auto_checkin(r, resource, err != NULL /* undo if error */, 0 /*unlock*/, &av_info); /* check for errors now */ if (err != NULL) { return dav_handle_err(r, err, NULL); } if (err2 != NULL) { /* just log a warning */ err2 = dav_push_error(r->pool, err2->status, 0, "The PUT was successful, but there " "was a problem automatically checking in " "the resource or its parent collection.", err2); dav_log_err(r, err2, APLOG_WARNING); } /* ### place the Content-Type and Content-Language into the propdb */ if (locks_hooks != NULL) { dav_lockdb *lockdb; if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { /* The file creation was successful, but the locking failed. */ err = dav_push_error(r->pool, err->status, 0, "The file was PUT successfully, but there " "was a problem opening the lock database " "which prevents inheriting locks from the " "parent resources.", err); return dav_handle_err(r, err, NULL); } /* notify lock system that we have created/replaced a resource */ err = dav_notify_created(r, lockdb, resource, resource_state, 0); (*locks_hooks->close_lockdb)(lockdb); if (err != NULL) { /* The file creation was successful, but the locking failed. */ err = dav_push_error(r->pool, err->status, 0, "The file was PUT successfully, but there " "was a problem updating its lock " "information.", err); return dav_handle_err(r, err, NULL); } } /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */ /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS);}/* Use POOL to temporarily construct a dav_response object (from WRES STATUS, and PROPSTATS) and stream it via WRES's ctx->brigade. */static void dav_stream_response(dav_walk_resource *wres, int status, dav_get_props_result *propstats, apr_pool_t *pool){ dav_response resp = { 0 }; dav_walker_ctx *ctx = wres->walk_ctx; resp.href = wres->resource->uri; resp.status = status; if (propstats) { resp.propresult = *propstats; } dav_send_one_response(&resp, ctx->bb, ctx->r->output_filters, pool);}/* ### move this to dav_util? */DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres, int status, dav_get_props_result *propstats){ dav_response *resp; /* just drop some data into an dav_response */ resp = apr_pcalloc(wres->pool, sizeof(*resp)); resp->href = apr_pstrdup(wres->pool, wres->resource->uri); resp->status = status; if (propstats) { resp->propresult = *propstats; } resp->next = wres->response; wres->response = resp;}/* handle the DELETE method */static int dav_method_delete(request_rec *r){ dav_resource *resource; dav_auto_version_info av_info; dav_error *err; dav_error *err2; dav_response *multi_response; int result; int depth; /* We don't use the request body right now, so torch it. */ if ((result = ap_discard_request_body(r)) != OK) { return result; } /* Ask repository module to resolve the resource */ err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, &resource); if (err != NULL) return dav_handle_err(r, err, NULL); if (!resource->exists) { /* Apache will supply a default error for this. */ return HTTP_NOT_FOUND; } /* 2518 says that depth must be infinity only for collections. * For non-collections, depth is ignored, unless it is an illegal value (1). */ depth = dav_get_depth(r, DAV_INFINITY); if (resource->collection && depth != DAV_INFINITY) { /* This supplies additional information for the default message. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Depth must be \"infinity\" for DELETE of a collection."); return HTTP_BAD_REQUEST; } if (!resource->collection && depth == 1) { /* This supplies additional information for the default message. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Depth of \"1\" is not allowed for DELETE."); return HTTP_BAD_REQUEST; } /* ** If any resources fail the lock/If: conditions, then we must fail ** the delete. Each of the failing resources will be listed within ** a DAV:multistatus body, wrapped into a 424 response. ** ** Note that a failure on the resource itself does not generate a ** multistatus response -- only internal members/collections. */ if ((err = dav_validate_request(r, resource, depth, NULL, &multi_response, DAV_VALIDATE_PARENT | DAV_VALIDATE_USE_424, NULL)) != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -