📄 mod_dav.c
字号:
else { dav_stream_mode mode; dav_stream *stream; dav_error *err; void *buffer; int has_range; apr_off_t range_start; apr_off_t range_end; /* 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); } /* use plain READ mode unless we see a Content-Range */ mode = DAV_MODE_READ; /* process the Content-Range header (if present) */ has_range = dav_parse_range(r, &range_start, &range_end); if (has_range) { /* use a read mode which is seekable */ mode = DAV_MODE_READ_SEEKABLE; /* prep the output */ r->status = HTTP_PARTIAL_CONTENT; apr_table_setn(r->headers_out, "Content-Range", apr_psprintf(r->pool, "bytes %" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/*", range_start, range_end)); ap_set_content_length(r, range_end - range_start + 1); } if (r->header_only) { return DONE; } 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 GET contents for %s.", ap_escape_html(r->pool, r->uri)), err); return dav_handle_err(r, err, NULL); } if (has_range && (err = (*resource->hooks->seek_stream)(stream, range_start)) != NULL) { err = dav_push_error(r->pool, err->status, 0, "Could not seek to beginning of the " "specified Content-Range.", err); return dav_handle_err(r, err, NULL); } buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE); while (1) { apr_size_t amt; if (!has_range) amt = DAV_READ_BLOCKSIZE; else if ((range_end - range_start + 1) > DAV_READ_BLOCKSIZE) amt = DAV_READ_BLOCKSIZE; else { /* note: range_end - range_start is an ssize_t */ amt = (apr_size_t)(range_end - range_start + 1); } 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 (has_range) { range_start += amt; if (range_start > range_end) break; } } if (err != NULL) return dav_handle_err(r, err, NULL); /* ** ### range_start should equal range_end+1. if it doesn't, then ** ### we did not send enough data to the client. the client will ** ### hang (and timeout) waiting for the data. ** ** ### what to do? abort the connection? */ return DONE; } /* NOTREACHED */}/* validate resource on POST, then pass it off 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; int result; dav_stream_mode mode; dav_stream *stream; dav_response *multi_response; int has_range; apr_off_t range_start; apr_off_t range_end; if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != 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 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_ensure_resource_writable(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) { if (ap_should_client_block(r)) { char *buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE); long len; /* ** Once we start reading the request, then we must read the ** whole darn thing. ap_discard_request_body() won't do anything ** for a partially-read request. */ while ((len = ap_get_client_block(r, buffer, DAV_READ_BLOCKSIZE)) > 0) { if (err == NULL) { /* write whatever we read, until we see an error */ err = (*resource->hooks->write_stream)(stream, buffer, len); } } /* ** ### what happens if we read more/less than the amount ** ### specified in the Content-Range? eek... */ if (len == -1) { /* ** Error reading request body. This has precedence over ** prior errors. */ err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, "An error occurred while reading the " "request body."); } } 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_revert_resource_writability(r, resource, err != NULL /* undo if error */, &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, err->status, 0, "The PUT was successful, but there " "was a problem reverting the writability of " "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);}/* ### 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 | APLOG_NOERRNO, 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 | APLOG_NOERRNO, 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. **
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -