mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
Start introducing the extension-method elements so we're not
bound to hard-coded names and a bitmask. We still use the bitmask for known methods, but we also have an array for extension method named. Wherever we used the M_* constants we need to use a routine that knows about the new structure instead. This is far from complete, but AFAIK this interim work doesn't break anything -- especially the compile. The rest of the work will be added in segments; this is just a checkpoint. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86210 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -287,6 +287,7 @@ struct cmd_parms_struct {
|
||||
/** Which methods are <Limit>ed */
|
||||
int limited;
|
||||
apr_array_header_t *limited_xmethods;
|
||||
ap_method_list_t *xlimited;
|
||||
|
||||
/** Config file structure. */
|
||||
configfile_t *config_file;
|
||||
|
||||
@@ -252,6 +252,69 @@ API_EXPORT(long) ap_send_fb_length(BUFF *f, request_rec *r, long length);
|
||||
API_EXPORT(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset,
|
||||
size_t length);
|
||||
|
||||
/**
|
||||
* Create a new method list with the specified number of preallocated
|
||||
* slots for extension methods.
|
||||
*
|
||||
* @param p Pointer to a pool in which the structure should be
|
||||
* allocated.
|
||||
* @param nelts Number of preallocated extension slots
|
||||
* @return Pointer to the newly created structure.
|
||||
* @deffunc ap_method_list_t ap_make_method_list(apr_pool_t *p, int nelts)
|
||||
*/
|
||||
API_EXPORT(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts);
|
||||
API_EXPORT(void) ap_copy_method_list(ap_method_list_t *dest,
|
||||
ap_method_list_t *src);
|
||||
API_EXPORT(void) ap_method_list_do(int (*comp) (void *urec, const char *mname,
|
||||
int mnum),
|
||||
void *rec,
|
||||
const ap_method_list_t *ml, ...);
|
||||
API_EXPORT(void) ap_method_list_vdo(int (*comp) (void *urec, const char *mname,
|
||||
int mnum),
|
||||
void *rec, const ap_method_list_t *ml,
|
||||
va_list vp);
|
||||
/**
|
||||
* Search for an HTTP method name in an ap_method_list_t structure, and
|
||||
* return true if found.
|
||||
*
|
||||
* @param method String containing the name of the method to check.
|
||||
* @param l Pointer to a method list, such as cmd->methods_limited.
|
||||
* @return 1 if method is in the list, otherwise 0
|
||||
* @deffunc int ap_method_in_list(const char *method, ap_method_list_t *l)
|
||||
*/
|
||||
API_EXPORT(int) ap_method_in_list(ap_method_list_t *l, const char *method);
|
||||
|
||||
/**
|
||||
* Add an HTTP method name to an ap_method_list_t structure if it isn't
|
||||
* already listed.
|
||||
*
|
||||
* @param method String containing the name of the method to check.
|
||||
* @param l Pointer to a method list, such as cmd->methods_limited.
|
||||
* @return None.
|
||||
* @deffunc void ap_method_in_list(ap_method_list_t *l, const char *method)
|
||||
*/
|
||||
API_EXPORT(void) ap_method_list_add(ap_method_list_t *l, const char *method);
|
||||
|
||||
/**
|
||||
* Remove an HTTP method name from an ap_method_list_t structure.
|
||||
*
|
||||
* @param l Pointer to a method list, such as cmd->methods_limited.
|
||||
* @param method String containing the name of the method to remove.
|
||||
* @return None.
|
||||
* @deffunc void ap_method_list_remove(ap_method_list_t *l, const char *method)
|
||||
*/
|
||||
API_EXPORT(void) ap_method_list_remove(ap_method_list_t *l,
|
||||
const char *method);
|
||||
|
||||
/**
|
||||
* Reset a method list to be completely empty.
|
||||
*
|
||||
* @param l Pointer to a method list, such as cmd->methods_limited.
|
||||
* @return None.
|
||||
* @deffunc void ap_clear_method_list(ap_method_list_t *l)
|
||||
*/
|
||||
API_EXPORT(void) ap_clear_method_list(ap_method_list_t *l);
|
||||
|
||||
/* Hmmm... could macrofy these for now, and maybe forever, though the
|
||||
* definitions of the macros would get a whole lot hairier.
|
||||
*/
|
||||
|
||||
@@ -484,6 +484,16 @@ API_EXPORT(const char *) ap_get_server_built(void);
|
||||
|
||||
#define METHODS 16
|
||||
|
||||
/*
|
||||
* Structure for handling HTTP methods. Methods known to the server are
|
||||
* accessed via a bitmask shortcut; extension methods are handled by
|
||||
* an array.
|
||||
*/
|
||||
typedef struct {
|
||||
int method_mask;
|
||||
apr_array_header_t *method_list;
|
||||
} ap_method_list_t;
|
||||
|
||||
#define CGI_MAGIC_TYPE "application/x-httpd-cgi"
|
||||
#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
|
||||
#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3"
|
||||
@@ -668,6 +678,7 @@ struct request_rec {
|
||||
*/
|
||||
int allowed; /* Allowed methods - for 405, OPTIONS, etc */
|
||||
apr_array_header_t *allowed_xmethods; /* Array of extension methods */
|
||||
ap_method_list_t *allowed_methods; /* List of allowed methods */
|
||||
|
||||
/** byte count in stream is for body */
|
||||
int sent_bodyct;
|
||||
|
||||
@@ -1497,9 +1497,7 @@ CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
limited |= (1 << methnum);
|
||||
}
|
||||
limited |= (1 << methnum);
|
||||
}
|
||||
|
||||
/* Killing two features with one function,
|
||||
|
||||
@@ -1181,6 +1181,8 @@ request_rec *ap_read_request(conn_rec *conn)
|
||||
r->user = NULL;
|
||||
r->ap_auth_type = NULL;
|
||||
|
||||
r->allowed_methods = ap_make_method_list(p, 2);
|
||||
|
||||
r->headers_in = apr_make_table(r->pool, 50);
|
||||
r->subprocess_env = apr_make_table(r->pool, 50);
|
||||
r->headers_out = apr_make_table(r->pool, 12);
|
||||
@@ -1645,40 +1647,210 @@ static void terminate_header(request_rec *r)
|
||||
(void) checked_bputs(CRLF, r); /* Send the terminating empty line */
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new method list with the specified number of preallocated
|
||||
* extension slots.
|
||||
*/
|
||||
API_EXPORT(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts)
|
||||
{
|
||||
ap_method_list_t *ml;
|
||||
|
||||
ml = (ap_method_list_t *) apr_palloc(p, sizeof(ap_method_list_t));
|
||||
ml->method_mask = 0;
|
||||
ml->method_list = apr_make_array(p, sizeof(char *), nelts);
|
||||
return ml;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a copy of a method list (primarily for subrequests that may
|
||||
* subsequently change it; don't want them changing the parent's, too!).
|
||||
*/
|
||||
API_EXPORT(void) ap_copy_method_list(ap_method_list_t *dest,
|
||||
ap_method_list_t *src)
|
||||
{
|
||||
int i;
|
||||
char **imethods;
|
||||
char **omethods;
|
||||
|
||||
dest->method_mask = src->method_mask;
|
||||
imethods = (char **) src->method_list->elts;
|
||||
for (i = 0; i < src->method_list->nelts; ++i) {
|
||||
omethods = (char **) apr_push_array(dest->method_list);
|
||||
*omethods = apr_pstrdup(dest->method_list->cont, imethods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke a callback routine for each method in the specified list.
|
||||
*/
|
||||
API_EXPORT(void) ap_method_list_do(int (*comp) (void *urec, const char *mname,
|
||||
int mnum),
|
||||
void *rec,
|
||||
const ap_method_list_t *ml, ...)
|
||||
{
|
||||
va_list vp;
|
||||
va_start(vp, ml);
|
||||
ap_method_list_vdo(comp, rec, ml, vp);
|
||||
va_end(vp);
|
||||
}
|
||||
|
||||
API_EXPORT(void) ap_method_list_vdo(int (*comp) (void *mrec,
|
||||
const char *mname,
|
||||
int mnum),
|
||||
void *rec, const ap_method_list_t *ml,
|
||||
va_list vp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the specified HTTP method is in the provided
|
||||
* method list.
|
||||
*/
|
||||
API_EXPORT(int) ap_method_in_list(ap_method_list_t *l, const char *method)
|
||||
{
|
||||
int methnum;
|
||||
int i;
|
||||
char **methods;
|
||||
|
||||
/*
|
||||
* If it's one of our known methods, use the shortcut and check the
|
||||
* bitmask.
|
||||
*/
|
||||
methnum = ap_method_number_of(method);
|
||||
if (methnum != M_INVALID) {
|
||||
return (l->method_mask & (1 << methnum));
|
||||
}
|
||||
/*
|
||||
* Otherwise, see if the method name is in the array or string names
|
||||
*/
|
||||
if ((l->method_list = NULL) || (l->method_list->nelts == 0)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < l->method_list->nelts; ++i) {
|
||||
if (strcmp(method, methods[i]) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the specified method to a method list (if it isn't already there).
|
||||
*/
|
||||
API_EXPORT(void) ap_method_list_add(ap_method_list_t *l, const char *method)
|
||||
{
|
||||
int methnum;
|
||||
int i;
|
||||
const char **xmethod;
|
||||
char **methods;
|
||||
|
||||
/*
|
||||
* If it's one of our known methods, use the shortcut and use the
|
||||
* bitmask.
|
||||
*/
|
||||
methnum = ap_method_number_of(method);
|
||||
l->method_mask |= (1 << methnum);
|
||||
if (methnum != M_INVALID) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Otherwise, see if the method name is in the array of string names.
|
||||
*/
|
||||
if (l->method_list->nelts != 0) {
|
||||
for (i = 0; i < l->method_list->nelts; ++i) {
|
||||
if (strcmp(method, methods[i]) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
xmethod = (const char **) apr_push_array(l->method_list);
|
||||
*xmethod = method;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the specified method from a method list.
|
||||
*/
|
||||
API_EXPORT(void) ap_method_list_remove(ap_method_list_t *l,
|
||||
const char *method)
|
||||
{
|
||||
int methnum;
|
||||
const char **xmethod;
|
||||
char **methods;
|
||||
|
||||
/*
|
||||
* If it's one of our known methods, use the shortcut and use the
|
||||
* bitmask.
|
||||
*/
|
||||
methnum = ap_method_number_of(method);
|
||||
l->method_mask |= ~(1 << methnum);
|
||||
if (methnum != M_INVALID) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Otherwise, see if the method name is in the array of string names.
|
||||
*/
|
||||
if (l->method_list->nelts != 0) {
|
||||
register int i, j, k;
|
||||
for (i = 0; i < l->method_list->nelts; ) {
|
||||
if (strcmp(method, methods[i]) == 0) {
|
||||
for (j = i, k = i + 1; k < l->method_list->nelts; ++j, ++k) {
|
||||
methods[j] = methods[k];
|
||||
}
|
||||
--l->method_list->nelts;
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset a method list to be completely empty.
|
||||
*/
|
||||
API_EXPORT(void) ap_clear_method_list(ap_method_list_t *l)
|
||||
{
|
||||
l->method_mask = 0;
|
||||
l->method_list->nelts = 0;
|
||||
}
|
||||
|
||||
/* Build the Allow field-value from the request handler method mask.
|
||||
* Note that we always allow TRACE, since it is handled below.
|
||||
*/
|
||||
static char *make_allow(request_rec *r)
|
||||
{
|
||||
char *list;
|
||||
int mask;
|
||||
|
||||
mask = r->allowed_methods->method_mask;
|
||||
list = apr_pstrcat(r->pool,
|
||||
(r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
|
||||
(r->allowed & (1 << M_POST)) ? ", POST" : "",
|
||||
(r->allowed & (1 << M_PUT)) ? ", PUT" : "",
|
||||
(r->allowed & (1 << M_DELETE)) ? ", DELETE" : "",
|
||||
(r->allowed & (1 << M_CONNECT)) ? ", CONNECT" : "",
|
||||
(r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
|
||||
(r->allowed & (1 << M_PATCH)) ? ", PATCH" : "",
|
||||
(r->allowed & (1 << M_PROPFIND)) ? ", PROPFIND" : "",
|
||||
(r->allowed & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
|
||||
(r->allowed & (1 << M_MKCOL)) ? ", MKCOL" : "",
|
||||
(r->allowed & (1 << M_COPY)) ? ", COPY" : "",
|
||||
(r->allowed & (1 << M_MOVE)) ? ", MOVE" : "",
|
||||
(r->allowed & (1 << M_LOCK)) ? ", LOCK" : "",
|
||||
(r->allowed & (1 << M_UNLOCK)) ? ", UNLOCK" : "",
|
||||
(mask & (1 << M_GET)) ? ", GET, HEAD" : "",
|
||||
(mask & (1 << M_POST)) ? ", POST" : "",
|
||||
(mask & (1 << M_PUT)) ? ", PUT" : "",
|
||||
(mask & (1 << M_DELETE)) ? ", DELETE" : "",
|
||||
(mask & (1 << M_CONNECT)) ? ", CONNECT" : "",
|
||||
(mask & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
|
||||
(mask & (1 << M_PATCH)) ? ", PATCH" : "",
|
||||
(mask & (1 << M_PROPFIND)) ? ", PROPFIND" : "",
|
||||
(mask & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
|
||||
(mask & (1 << M_MKCOL)) ? ", MKCOL" : "",
|
||||
(mask & (1 << M_COPY)) ? ", COPY" : "",
|
||||
(mask & (1 << M_MOVE)) ? ", MOVE" : "",
|
||||
(mask & (1 << M_LOCK)) ? ", LOCK" : "",
|
||||
(mask & (1 << M_UNLOCK)) ? ", UNLOCK" : "",
|
||||
", TRACE",
|
||||
NULL);
|
||||
if ((r->allowed & (1 << M_INVALID))
|
||||
&& (r->allowed_xmethods != NULL)
|
||||
&& (r->allowed_xmethods->nelts != 0)) {
|
||||
if ((mask & (1 << M_INVALID))
|
||||
&& (r->allowed_methods->method_list != NULL)
|
||||
&& (r->allowed_methods->method_list->nelts != 0)) {
|
||||
int i;
|
||||
char **xmethod = (char **) r->allowed_xmethods->elts;
|
||||
char **xmethod = (char **) r->allowed_methods->method_list->elts;
|
||||
|
||||
/*
|
||||
* Append all of the elements of r->allowed_xmethods
|
||||
* Append all of the elements of r->allowed_methods->method_list
|
||||
*/
|
||||
for (i = 0; i < r->allowed_xmethods->nelts; ++i) {
|
||||
for (i = 0; i < r->allowed_methods->method_list->nelts; ++i) {
|
||||
list = apr_pstrcat(r->pool, list, ", ", xmethod[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,6 +864,9 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_file(const char *new_file,
|
||||
rnew->htaccess = r->htaccess;
|
||||
rnew->chunked = r->chunked;
|
||||
|
||||
/* make a copy of the allowed-methods list */
|
||||
ap_copy_method_list(rnew->allowed_methods, r->allowed_methods);
|
||||
|
||||
/* start with the same set of output filters */
|
||||
rnew->filters = r->filters;
|
||||
|
||||
@@ -1321,10 +1324,11 @@ static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t)
|
||||
return new;
|
||||
}
|
||||
|
||||
static request_rec *internal_internal_redirect(const char *new_uri, request_rec *r)
|
||||
{
|
||||
static request_rec *internal_internal_redirect(const char *new_uri,
|
||||
request_rec *r) {
|
||||
int access_status;
|
||||
request_rec *new = (request_rec *) apr_pcalloc(r->pool, sizeof(request_rec));
|
||||
request_rec *new = (request_rec *) apr_pcalloc(r->pool,
|
||||
sizeof(request_rec));
|
||||
|
||||
new->connection = r->connection;
|
||||
new->server = r->server;
|
||||
@@ -1338,6 +1342,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, request_rec
|
||||
|
||||
new->method = r->method;
|
||||
new->method_number = r->method_number;
|
||||
new->allowed_methods = ap_make_method_list(new->pool, 2);
|
||||
ap_parse_uri(new, new_uri);
|
||||
new->request_config = ap_create_request_config(r->pool);
|
||||
new->per_dir_config = r->server->lookup_defaults;
|
||||
@@ -1365,6 +1370,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, request_rec
|
||||
new->err_headers_out = r->err_headers_out;
|
||||
new->subprocess_env = rename_original_env(r->pool, r->subprocess_env);
|
||||
new->notes = apr_make_table(r->pool, 5);
|
||||
new->allowed_methods = ap_make_method_list(new->pool, 2);
|
||||
|
||||
new->htaccess = r->htaccess;
|
||||
new->no_cache = r->no_cache;
|
||||
@@ -1445,51 +1451,11 @@ API_EXPORT(void) ap_allow_methods(request_rec *r, int reset, ...) {
|
||||
* well-known methods but any extensions as well.
|
||||
*/
|
||||
if (reset) {
|
||||
r->allowed = 0;
|
||||
if (r->allowed_xmethods != NULL) {
|
||||
r->allowed_xmethods->nelts = 0;
|
||||
}
|
||||
ap_clear_method_list(r->allowed_methods);
|
||||
}
|
||||
|
||||
va_start(methods, reset);
|
||||
while ((method = va_arg(methods, const char *)) != NULL) {
|
||||
/*
|
||||
* Look up our internal number for this particular method.
|
||||
* Even if it isn't one of the ones we know about, the return
|
||||
* value is used in the same way.
|
||||
*/
|
||||
mnum = ap_method_number_of(method);
|
||||
r->allowed |= (1 << mnum);
|
||||
/*
|
||||
* Now, if we don't know about it, we regard it as an
|
||||
* extension method. Add it to our array of such. This means
|
||||
* that anything that checks for M_INVALID needs to make an
|
||||
* additional check of this array if it *is* invalid.
|
||||
*/
|
||||
if (mnum == M_INVALID) {
|
||||
int i;
|
||||
int found;
|
||||
char **xmethods;
|
||||
|
||||
if (r->allowed_xmethods == NULL) {
|
||||
r->allowed_xmethods = apr_make_array(r->pool, 2,
|
||||
sizeof(char *));
|
||||
}
|
||||
/*
|
||||
* Don't add it to the array if it's already listed.
|
||||
*/
|
||||
xmethods = (char **) r->allowed_xmethods->elts;
|
||||
found = 0;
|
||||
for (i = 0; i < r->allowed_xmethods->nelts; ++i) {
|
||||
if (strcmp(method, xmethods[i]) == 0) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
xmethod = (const char **) apr_push_array(r->allowed_xmethods);
|
||||
*xmethod = method;
|
||||
}
|
||||
}
|
||||
ap_method_list_add(r->allowed_methods, method);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user