📄 mod_negotiation.c
字号:
else if (apr_isspace(c)) { /* Leading whitespace. POSSIBLE continuation line * Also, possibly blank --- if so, we ungetc() the final newline * so that we will pick up the blank line the next time 'round. */ while (c != '\n' && apr_isspace(c)) { if(apr_file_getc(&c, map) != APR_SUCCESS) break; } apr_file_ungetc(c, map); if (c == '\n') { return header_seen; /* Blank line */ } /* Continuation */ while ( cp < buf_end - 2 && (apr_file_getc(&c, map)) != APR_EOF && c != '\n') { *cp++ = c; } *cp++ = '\n'; *cp = '\0'; } else { /* Line beginning with something other than whitespace */ apr_file_ungetc(c, map); return header_seen; } } return header_seen;}static apr_off_t get_body(char *buffer, apr_size_t *len, const char *tag, apr_file_t *map){ char *endbody; int bodylen; int taglen; apr_off_t pos; taglen = strlen(tag); *len -= taglen; /* We are at the first character following a body:tag\n entry * Suck in the body, then backspace to the first char after the * closing tag entry. If we fail to read, find the tag or back * up then we have a hosed file, so give up already */ if (apr_file_read(map, buffer, len) != APR_SUCCESS) { return -1; } /* put a copy of the tag *after* the data read from the file * so that strstr() will find something with no reliance on * terminating '\0' */ memcpy(buffer + *len, tag, taglen); endbody = strstr(buffer, tag); if (endbody == buffer + *len) { return -1; } bodylen = endbody - buffer; endbody += taglen; /* Skip all the trailing cruft after the end tag to the next line */ while (*endbody) { if (*endbody == '\n') { ++endbody; break; } ++endbody; } pos = -(apr_off_t)(*len - (endbody - buffer)); if (apr_file_seek(map, APR_CUR, &pos) != APR_SUCCESS) { return -1; } /* Give the caller back the actual body's file offset and length */ *len = bodylen; return pos - (endbody - buffer);}/* Stripping out RFC822 comments */static void strip_paren_comments(char *hdr){ /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */ /* Nope, it isn't correct. Fails to handle backslash escape as well. */ while (*hdr) { if (*hdr == '"') { hdr = strchr(hdr, '"'); if (hdr == NULL) { return; } ++hdr; } else if (*hdr == '(') { while (*hdr && *hdr != ')') { *hdr++ = ' '; } if (*hdr) { *hdr++ = ' '; } } else { ++hdr; } }}/* Getting to a header body from the header */static char *lcase_header_name_return_body(char *header, request_rec *r){ char *cp = header; for ( ; *cp && *cp != ':' ; ++cp) { *cp = apr_tolower(*cp); } if (!*cp) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Syntax error in type map, no ':' in %s for header %s", r->filename, header); return NULL; } do { ++cp; } while (*cp && apr_isspace(*cp)); if (!*cp) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Syntax error in type map --- no header body: %s for %s", r->filename, header); return NULL; } return cp;}static int read_type_map(apr_file_t **map, negotiation_state *neg, request_rec *rr){ request_rec *r = neg->r; apr_file_t *map_ = NULL; apr_status_t status; char buffer[MAX_STRING_LEN]; enum header_state hstate; struct var_rec mime_info; int has_content; if (!map) map = &map_; /* We are not using multiviews */ neg->count_multiviews_variants = 0; if ((status = apr_file_open(map, rr->filename, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, neg->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, "cannot access type map file: %s", rr->filename); if (APR_STATUS_IS_ENOTDIR(status) || APR_STATUS_IS_ENOENT(status)) { return HTTP_NOT_FOUND; } else { return HTTP_FORBIDDEN; } } clean_var_rec(&mime_info); has_content = 0; do { hstate = get_header_line(buffer, MAX_STRING_LEN, *map); if (hstate == header_seen) { char *body1 = lcase_header_name_return_body(buffer, neg->r); const char *body; if (body1 == NULL) { return HTTP_INTERNAL_SERVER_ERROR; } strip_paren_comments(body1); body = body1; if (!strncmp(buffer, "uri:", 4)) { mime_info.file_name = ap_get_token(neg->pool, &body, 0); } else if (!strncmp(buffer, "content-type:", 13)) { struct accept_rec accept_info; get_entry(neg->pool, &accept_info, body); set_mime_fields(&mime_info, &accept_info); has_content = 1; } else if (!strncmp(buffer, "content-length:", 15)) { char *errp; apr_off_t number; if (apr_strtoff(&number, body, &errp, 10) || *errp || number < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Parse error in type map, Content-Length: " "'%s' in %s is invalid.", body, r->filename); break; } mime_info.bytes = number; has_content = 1; } else if (!strncmp(buffer, "content-language:", 17)) { mime_info.content_languages = do_languages_line(neg->pool, &body); has_content = 1; } else if (!strncmp(buffer, "content-encoding:", 17)) { mime_info.content_encoding = ap_get_token(neg->pool, &body, 0); has_content = 1; } else if (!strncmp(buffer, "description:", 12)) { char *desc = apr_pstrdup(neg->pool, body); char *cp; for (cp = desc; *cp; ++cp) { if (*cp=='\n') *cp=' '; } if (cp>desc) *(cp-1)=0; mime_info.description = desc; } else if (!strncmp(buffer, "body:", 5)) { char *tag = apr_pstrdup(neg->pool, body); char *eol = strchr(tag, '\0'); apr_size_t len = MAX_STRING_LEN; while (--eol >= tag && apr_isspace(*eol)) *eol = '\0'; if ((mime_info.body = get_body(buffer, &len, tag, *map)) < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Syntax error in type map, no end tag '%s'" "found in %s for Body: content.", tag, r->filename); break; } mime_info.bytes = len; mime_info.file_name = apr_filepath_name_get(rr->filename); } } else { if (*mime_info.file_name && has_content) { void *new_var = apr_array_push(neg->avail_vars); memcpy(new_var, (void *) &mime_info, sizeof(var_rec)); } clean_var_rec(&mime_info); has_content = 0; } } while (hstate != header_eof); if (map_) apr_file_close(map_); set_vlist_validator(r, rr); return OK;}/* Sort function used by read_types_multi. */static int variantsortf(var_rec *a, var_rec *b) { /* First key is the source quality, sort in descending order. */ /* XXX: note that we currently implement no method of setting the * source quality for multiviews variants, so we are always comparing * 1.0 to 1.0 for now */ if (a->source_quality < b->source_quality) return 1; if (a->source_quality > b->source_quality) return -1; /* Second key is the variant name */ return strcmp(a->file_name, b->file_name);}/***************************************************************** * * Same as read_type_map, except we use a filtered directory listing * as the map... */static int read_types_multi(negotiation_state *neg){ request_rec *r = neg->r; char *filp; int prefix_len; apr_dir_t *dirp; apr_finfo_t dirent; apr_status_t status; struct var_rec mime_info; struct accept_rec accept_info; void *new_var; int anymatch = 0; clean_var_rec(&mime_info); if (r->proxyreq || !r->filename || !ap_os_is_path_absolute(neg->pool, r->filename)) { return DECLINED; } /* Only absolute paths here */ if (!(filp = strrchr(r->filename, '/'))) { return DECLINED; } ++filp; prefix_len = strlen(filp); if ((status = apr_dir_open(&dirp, neg->dir_name, neg->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, "cannot read directory for multi: %s", neg->dir_name); return HTTP_FORBIDDEN; } while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) { apr_array_header_t *exception_list; request_rec *sub_req; /* Do we have a match? */#ifdef CASE_BLIND_FILESYSTEM if (strncasecmp(dirent.name, filp, prefix_len)) {#else if (strncmp(dirent.name, filp, prefix_len)) {#endif continue; } if (dirent.name[prefix_len] != '.') { continue; } /* Don't negotiate directories and other unusual files * Really shouldn't see anything but DIR/LNK/REG here, * and we aught to discover if the LNK was interesting. * * Of course, this only helps platforms that capture the * the filetype in apr_dir_read(), which most can once * they are optimized with some magic [it's known to the * dirent, not associated to the inode, on most FS's.] */ if ((dirent.valid & APR_FINFO_TYPE) && (dirent.filetype == APR_DIR)) continue; /* Ok, something's here. Maybe nothing useful. Remember that * we tried, if we completely fail, so we can reject the request! */ anymatch = 1; /* See if it's something which we have access to, and which * has a known type and encoding (as opposed to something * which we'll be slapping default_type on later). */ sub_req = ap_sub_req_lookup_dirent(&dirent, r, AP_SUBREQ_MERGE_ARGS, NULL); /* Double check, we still don't multi-resolve non-ordinary files */ if (sub_req->finfo.filetype != APR_REG) continue; /* If it has a handler, we'll pretend it's a CGI script, * since that's a good indication of the sort of thing it * might be doing. */ if (sub_req->handler && !sub_req->content_type) { ap_set_content_type(sub_req, CGI_MAGIC_TYPE); } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -