📄 util.c
字号:
** The check of parent should be done when it is necessary to verify that** the parent collection will accept a new member (ie current resource** state is null).**** Return OK on successful validation.** On error, return appropriate HTTP_* code, and log error. If a multi-stat** error is necessary, response will point to it, else NULL.*/DAV_DECLARE(dav_error *) dav_validate_request(request_rec *r, dav_resource *resource, int depth, dav_locktoken *locktoken, dav_response **response, int flags, dav_lockdb *lockdb){ dav_error *err; int result; dav_if_header *if_header; int lock_db_opened_locally = 0; const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); const dav_hooks_repository *repos_hooks = resource->hooks; dav_buffer work_buf = { 0 }; dav_response *new_response; int resource_state; const char *etag; int set_etag = 0;#if DAV_DEBUG if (depth && response == NULL) { /* ** ### bleck. we can't return errors for other URIs unless we have ** ### a "response" ptr. */ return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DESIGN ERROR: dav_validate_request called " "with depth>0, but no response ptr."); }#endif if (response != NULL) *response = NULL; /* Set the ETag header required by dav_meets_conditions() */ etag = apr_table_get(r->headers_out, "ETag"); if (!etag) { etag = (*resource->hooks->getetag)(resource); if (etag && *etag) { apr_table_set(r->headers_out, "ETag", etag); set_etag = 1; } } /* Do the standard checks for conditional requests using * If-..-Since, If-Match etc */ resource_state = dav_get_resource_state(r, resource); result = dav_meets_conditions(r, resource_state); if (set_etag) { /* * If we have set an ETag to headers out above for * dav_meets_conditions() revert this here as we do not want to set * the ETag in responses to requests with methods where this might not * be desired. */ apr_table_unset(r->headers_out, "ETag"); } if (result != OK) { return dav_new_error(r->pool, result, 0, NULL); } /* always parse (and later process) the If: header */ if ((err = dav_process_if_header(r, &if_header)) != NULL) { /* ### maybe add higher-level description */ return err; } /* If a locktoken was specified, create a dummy if_header with which * to validate resources. In the interim, figure out why DAV uses * locktokens in an if-header without a Lock-Token header to refresh * locks, but a Lock-Token header without an if-header to remove them. */ if (locktoken != NULL) { dav_if_header *ifhdr_new; ifhdr_new = apr_pcalloc(r->pool, sizeof(*ifhdr_new)); ifhdr_new->uri = resource->uri; ifhdr_new->uri_len = strlen(resource->uri); ifhdr_new->dummy_header = 1; ifhdr_new->state = apr_pcalloc(r->pool, sizeof(*ifhdr_new->state)); ifhdr_new->state->type = dav_if_opaquelock; ifhdr_new->state->condition = DAV_IF_COND_NORMAL; ifhdr_new->state->locktoken = locktoken; ifhdr_new->next = if_header; if_header = ifhdr_new; } /* ** If necessary, open the lock database (read-only, lazily); ** the validation process may need to retrieve or update lock info. ** Otherwise, assume provided lockdb is valid and opened rw. */ if (lockdb == NULL) { if (locks_hooks != NULL) { if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) { /* ### maybe insert higher-level comment */ return err; } lock_db_opened_locally = 1; } } /* (1) Validate the specified resource, at the specified depth */ if (resource->exists && depth > 0) { dav_walker_ctx ctx = { { 0 } }; dav_response *multi_status; ctx.w.walk_type = DAV_WALKTYPE_NORMAL; ctx.w.func = dav_validate_walker; ctx.w.walk_ctx = &ctx; ctx.w.pool = r->pool; ctx.w.root = resource; ctx.if_header = if_header; ctx.r = r; ctx.flags = flags; if (lockdb != NULL) { ctx.w.lockdb = lockdb; ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL; } err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status); if (err == NULL) { *response = multi_status;; } /* else: implies a 5xx status code occurred. */ } else { err = dav_validate_resource_state(r->pool, resource, lockdb, if_header, flags, &work_buf, r); } /* (2) Validate the parent resource if requested */ if (err == NULL && (flags & DAV_VALIDATE_PARENT)) { dav_resource *parent_resource; err = (*repos_hooks->get_parent_resource)(resource, &parent_resource); if (err == NULL && parent_resource == NULL) { err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0, "Cannot access parent of repository root."); } else if (err == NULL) { err = dav_validate_resource_state(r->pool, parent_resource, lockdb, if_header, flags | DAV_VALIDATE_IS_PARENT, &work_buf, r); /* ** This error occurred on the parent resource. This implies that ** we have to create a multistatus response (to report the error ** against a URI other than the Request-URI). "Convert" this error ** into a multistatus response. */ if (err != NULL) { new_response = apr_pcalloc(r->pool, sizeof(*new_response)); new_response->href = parent_resource->uri; new_response->status = err->status; new_response->desc = "A validation error has occurred on the parent resource, " "preventing the operation on the resource specified by " "the Request-URI."; if (err->desc != NULL) { new_response->desc = apr_pstrcat(r->pool, new_response->desc, " The error was: ", err->desc, NULL); } /* assert: DAV_VALIDATE_PARENT implies response != NULL */ new_response->next = *response; *response = new_response; err = NULL; } } } if (lock_db_opened_locally) (*locks_hooks->close_lockdb)(lockdb); /* ** If we don't have a (serious) error, and we have multistatus responses, ** then we need to construct an "error". This error will be the overall ** status returned, and the multistatus responses will go into its body. ** ** For certain methods, the overall error will be a 424. The default is ** to construct a standard 207 response. */ if (err == NULL && response != NULL && *response != NULL) { apr_text *propstat = NULL; if ((flags & DAV_VALIDATE_USE_424) != 0) { /* manufacture a 424 error to hold the multistatus response(s) */ return dav_new_error(r->pool, HTTP_FAILED_DEPENDENCY, 0, "An error occurred on another resource, " "preventing the requested operation on " "this resource."); } /* ** Whatever caused the error, the Request-URI should have a 424 ** associated with it since we cannot complete the method. ** ** For a LOCK operation, insert an empty DAV:lockdiscovery property. ** For other methods, return a simple 424. */ if ((flags & DAV_VALIDATE_ADD_LD) != 0) { propstat = apr_pcalloc(r->pool, sizeof(*propstat)); propstat->text = "<D:propstat>" DEBUG_CR "<D:prop><D:lockdiscovery/></D:prop>" DEBUG_CR "<D:status>HTTP/1.1 424 Failed Dependency</D:status>" DEBUG_CR "</D:propstat>" DEBUG_CR; } /* create the 424 response */ new_response = apr_pcalloc(r->pool, sizeof(*new_response)); new_response->href = resource->uri; new_response->status = HTTP_FAILED_DEPENDENCY; new_response->propresult.propstats = propstat; new_response->desc = "An error occurred on another resource, preventing the " "requested operation on this resource."; new_response->next = *response; *response = new_response; /* manufacture a 207 error for the multistatus response(s) */ return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0, "Error(s) occurred on resources during the " "validation process."); } return err;}/* dav_get_locktoken_list: * * Sets ltl to a locktoken_list of all positive locktokens in header, * else NULL if no If-header, or no positive locktokens. */DAV_DECLARE(dav_error *) dav_get_locktoken_list(request_rec *r, dav_locktoken_list **ltl){ dav_error *err; dav_if_header *if_header; dav_if_state_list *if_state; dav_locktoken_list *lock_token = NULL; *ltl = NULL; if ((err = dav_process_if_header(r, &if_header)) != NULL) { /* ### add a higher-level description? */ return err; } while (if_header != NULL) { if_state = if_header->state; /* Begining of the if_state linked list */ while (if_state != NULL) { if (if_state->condition == DAV_IF_COND_NORMAL && if_state->type == dav_if_opaquelock) { lock_token = apr_pcalloc(r->pool, sizeof(dav_locktoken_list)); lock_token->locktoken = if_state->locktoken; lock_token->next = *ltl; *ltl = lock_token; } if_state = if_state->next; } if_header = if_header->next; } if (*ltl == NULL) { /* No nodes added */ return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_ABSENT, "No locktokens were specified in the \"If:\" " "header, so the refresh could not be performed."); } return NULL;}#if 0 /* not needed right now... */static const char *strip_white(const char *s, apr_pool_t *pool){ apr_size_t idx; /* trim leading whitespace */ while (apr_isspace(*s)) /* assume: return false for '\0' */ ++s; /* trim trailing whitespace */ idx = strlen(s) - 1; if (apr_isspace(s[idx])) { char *s2 = apr_pstrdup(pool, s); while (apr_isspace(s2[idx]) && idx > 0) --idx; s2[idx + 1] = '\0'; return s2; } return s;}#endif#define DAV_LABEL_HDR "Label"/* dav_add_vary_header * * If there were any headers in the request which require a Vary header * in the response, add it. */DAV_DECLARE(void) dav_add_vary_header(request_rec *in_req, request_rec *out_req, const dav_resource *resource){ const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req); /* ### this is probably all wrong... I think there is a function in ### the Apache API to add things to the Vary header. need to check */ /* Only versioning headers require a Vary response header, * so only do this check if there is a versioning provider */ if (vsn_hooks != NULL) { const char *target = apr_table_get(in_req->headers_in, DAV_LABEL_HDR); const char *vary = apr_table_get(out_req->headers_out, "Vary"); /* If Target-Selector specified, add it to the Vary header */ if (target != NULL) { if (vary == NULL) vary = DAV_LABEL_HDR; else vary = apr_pstrcat(out_req->pool, vary, "," DAV_LABEL_HDR, NULL); apr_table_setn(out_req->headers_out, "Vary", vary); } }}/* dav_can_auto_checkout * * Determine whether auto-checkout is enabled for a resource. * r - the request_rec * resource - the resource * auto_version - the value of the auto_versionable hook for the resource * lockdb - pointer to lock database (opened if necessary) * a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -