📄 mod_dav.c
字号:
** '<' or '>' characters, but who cares. */ return ap_xml_quote_string(p, e_uri, 0);}static void dav_send_multistatus(request_rec *r, int status, dav_response *first, apr_array_header_t *namespaces){ /* Set the correct status and Content-Type */ r->status = status; r->content_type = DAV_XML_CONTENT_TYPE; /* Send the headers and actual multistatus response now... */ ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:multistatus xmlns:D=\"DAV:\"", r); if (namespaces != NULL) { int i; for (i = namespaces->nelts; i--; ) { ap_rprintf(r, " xmlns:ns%d=\"%s\"", i, AP_XML_GET_URI_ITEM(namespaces, i)); } } /* ap_rputc('>', r); */ ap_rputs(">" DEBUG_CR, r); for (; first != NULL; first = first->next) { ap_text *t; if (first->propresult.xmlns == NULL) { ap_rputs("<D:response>", r); } else { ap_rputs("<D:response", r); for (t = first->propresult.xmlns; t; t = t->next) { ap_rputs(t->text, r); } ap_rputc('>', r); } ap_rputs(DEBUG_CR "<D:href>", r); ap_rputs(dav_xml_escape_uri(r->pool, first->href), r); ap_rputs("</D:href>" DEBUG_CR, r); if (first->propresult.propstats == NULL) { /* use the Status-Line text from Apache. Note, this will * default to 500 Internal Server Error if first->status * is not a known (or valid) status code. */ ap_rprintf(r, "<D:status>HTTP/1.1 %s</D:status>" DEBUG_CR, ap_get_status_line(first->status)); } else { /* assume this includes <propstat> and is quoted properly */ for (t = first->propresult.propstats; t; t = t->next) { ap_rputs(t->text, r); } } if (first->desc != NULL) { /* ** We supply the description, so we know it doesn't have to ** have any escaping/encoding applied to it. */ ap_rputs("<D:responsedescription>", r); ap_rputs(first->desc, r); ap_rputs("</D:responsedescription>" DEBUG_CR, r); } ap_rputs("</D:response>" DEBUG_CR, r); } ap_rputs("</D:multistatus>" DEBUG_CR, r);}/*** dav_log_err()**** Write error information to the log.*/static void dav_log_err(request_rec *r, dav_error *err, int level){ dav_error *errscan; /* Log the errors */ /* ### should have a directive to log the first or all */ for (errscan = err; errscan != NULL; errscan = errscan->prev) { if (errscan->desc == NULL) continue; if (errscan->save_errno != 0) { errno = errscan->save_errno; ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]", errscan->desc, errscan->status, errscan->error_id); } else { ap_log_rerror(APLOG_MARK, level | APLOG_NOERRNO, 0, r, "%s [%d, #%d]", errscan->desc, errscan->status, errscan->error_id); } }}/*** dav_handle_err()**** Handle the standard error processing. <err> must be non-NULL.**** <response> is set by the following:** - dav_validate_request()** - dav_add_lock()** - repos_hooks->remove_resource** - repos_hooks->move_resource** - repos_hooks->copy_resource*/static int dav_handle_err(request_rec *r, dav_error *err, dav_response *response){ /* log the errors */ dav_log_err(r, err, APLOG_ERR); if (response == NULL) { /* our error messages are safe; tell Apache this */ apr_table_setn(r->notes, "verbose-error-to", "*"); return err->status; } /* since we're returning DONE, ensure the request body is consumed. */ (void) ap_discard_request_body(r); /* send the multistatus and tell Apache the request/response is DONE. */ dav_send_multistatus(r, err->status, response, NULL); return DONE;}/* handy function for return values of methods that (may) create things */static int dav_created(request_rec *r, const char *locn, const char *what, int replaced){ const char *body; if (locn == NULL) { locn = r->uri; } /* did the target resource already exist? */ if (replaced) { /* Apache will supply a default message */ return HTTP_NO_CONTENT; } /* Per HTTP/1.1, S10.2.2: add a Location header to contain the * URI that was created. */ /* Convert locn to an absolute URI, and return in Location header */ apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r)); /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */ /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so * we must manufacture the entire response. */ body = apr_psprintf(r->pool, "%s %s has been created.", what, ap_escape_html(r->pool, locn)); return dav_error_response(r, HTTP_CREATED, body);}/* ### move to dav_util? */int dav_get_depth(request_rec *r, int def_depth){ const char *depth = apr_table_get(r->headers_in, "Depth"); if (depth == NULL) { return def_depth; } if (strcasecmp(depth, "infinity") == 0) { return DAV_INFINITY; } else if (strcmp(depth, "0") == 0) { return 0; } else if (strcmp(depth, "1") == 0) { return 1; } /* The caller will return an HTTP_BAD_REQUEST. This will augment the * default message that Apache provides. */ ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "An invalid Depth header was specified."); return -1;}static int dav_get_overwrite(request_rec *r){ const char *overwrite = apr_table_get(r->headers_in, "Overwrite"); if (overwrite == NULL) { return 1; /* default is "T" */ } if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') { return 0; } if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') { return 1; } /* The caller will return an HTTP_BAD_REQUEST. This will augment the * default message that Apache provides. */ ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "An invalid Overwrite header was specified."); return -1;}/* resolve a request URI to a resource descriptor. * * If label_allowed != 0, then allow the request target to be altered by * a Label: header. * * If use_checked_in is true, then the repository provider should return * the resource identified by the DAV:checked-in property of the resource * identified by the Request-URI. */static dav_error * dav_get_resource(request_rec *r, int label_allowed, int use_checked_in, dav_resource **res_p){ dav_dir_conf *conf; const char *label = NULL; dav_error *err; /* if the request target can be overridden, get any target selector */ if (label_allowed) { label = apr_table_get(r->headers_in, "label"); } conf = ap_get_module_config(r->per_dir_config, &dav_module); /* assert: conf->provider != NULL */ /* resolve the resource */ err = (*conf->provider->repos->get_resource)(r, conf->dir, label, use_checked_in, res_p); if (err != NULL) { err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not fetch resource information.", err); return err; } /* Note: this shouldn't happen, but just be sure... */ if (*res_p == NULL) { /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */ return dav_new_error(r->pool, HTTP_NOT_FOUND, 0, apr_psprintf(r->pool, "The provider did not define a " "resource for %s.", ap_escape_html(r->pool, r->uri))); } /* ### hmm. this doesn't feel like the right place or thing to do */ /* if there were any input headers requiring a Vary header in the response, * add it now */ dav_add_vary_header(r, r, *res_p); return NULL;}static dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb){ const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r); if (hooks == NULL) { *lockdb = NULL; return NULL; } /* open the thing lazily */ return (*hooks->open_lockdb)(r, ro, 0, lockdb);}static int dav_parse_range(request_rec *r, apr_off_t *range_start, apr_off_t *range_end){ const char *range_c; char *range; char *dash; char *slash; range_c = apr_table_get(r->headers_in, "content-range"); if (range_c == NULL) return 0; range = apr_pstrdup(r->pool, range_c); if (strncasecmp(range, "bytes ", 6) != 0 || (dash = ap_strchr(range, '-')) == NULL || (slash = ap_strchr(range, '/')) == NULL) { /* malformed header. ignore it (per S14.16 of RFC2616) */ return 0; } *dash = *slash = '\0'; /* ### atol may not be large enough for the apr_off_t */ *range_start = atol(range + 6); *range_end = atol(dash + 1); if (*range_end < *range_start || (slash[1] != '*' && atol(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; int result; 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; } /* 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."); } /* ** 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; } /* Convert to canonical filename, so Apache detects component * separators (on Windows, it only looks for '/', not '\') */ pathname = ap_os_case_canonical_filename(r->pool, pathname); /* Create a sub-request with the new filename */ 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -