1
0
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:
Ken Coar
2000-09-13 01:58:15 +00:00
parent 023faddf07
commit 5d50a3e277
6 changed files with 279 additions and 68 deletions

View File

@@ -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;

View 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.
*/

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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);
}
}