~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/metadata/mod_version.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
 
2
 * contributor license agreements.  See the NOTICE file distributed with
 
3
 * this work for additional information regarding copyright ownership.
 
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
5
 * (the "License"); you may not use this file except in compliance with
 
6
 * the License.  You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/*
 
18
 * mod_version.c
 
19
 * Allow conditional configuration depending on the httpd version
 
20
 *
 
21
 * Andr� Malo (nd/perlig.de), January 2004
 
22
 *
 
23
 * Some stuff coded here is heavily based on the core <IfModule>
 
24
 * containers.
 
25
 *
 
26
 * The module makes the following confgurations possible:
 
27
 *
 
28
 * <IfVersion op major.minor.patch>
 
29
 *     # conditional config here ...
 
30
 *</IfVersion>
 
31
 *
 
32
 * where "op" is one of:
 
33
 * = / ==       equal
 
34
 * >            greater than
 
35
 * >=           greater or equal
 
36
 * <            less than
 
37
 * <=           less or equal
 
38
 *
 
39
 * If minor version and patch level are omitted they are assumed to be 0.
 
40
 *
 
41
 * Alternatively you can match the whole version (including some vendor-added
 
42
 * string of the CORE version, see ap_release.h) against a regular expression:
 
43
 *
 
44
 * <IfVersion op regex>
 
45
 *     # conditional config here ...
 
46
 *</IfVersion>
 
47
 *
 
48
 * where "op" is one of:
 
49
 * = / ==       match; regex must be surrounded by slashes
 
50
 * ~            match; regex MAY NOT be surrounded by slashes
 
51
 *
 
52
 * Note that all operators may be preceeded by an exclamation mark
 
53
 * (without spaces) in order to reverse their meaning.
 
54
 *
 
55
 */
 
56
 
 
57
#include "apr.h"
 
58
#include "apr_strings.h"
 
59
#include "apr_lib.h"
 
60
 
 
61
#include "httpd.h"
 
62
#include "http_config.h"
 
63
#include "http_log.h"
 
64
 
 
65
 
 
66
/* module structure */
 
67
module AP_MODULE_DECLARE_DATA version_module;
 
68
 
 
69
/* queried httpd version */
 
70
static ap_version_t httpd_version;
 
71
 
 
72
 
 
73
/*
 
74
 * compare the supplied version with the core one
 
75
 */
 
76
static int compare_version(char *version_string, const char **error)
 
77
{
 
78
    char *p = version_string, *ep;
 
79
    int version[3] = {0, 0, 0};
 
80
    int c = 0;
 
81
 
 
82
    *error = "Version appears to be invalid. It must have the format "
 
83
             "major[.minor[.patch]] where major, minor and patch are "
 
84
             "numbers.";
 
85
 
 
86
    if (!apr_isdigit(*p)) {
 
87
        return 0;
 
88
    }
 
89
 
 
90
    /* parse supplied version */
 
91
    ep = version_string + strlen(version_string);
 
92
    while (p <= ep && c < 3) {
 
93
        if (*p == '.') {
 
94
            *p = '\0';
 
95
        }
 
96
 
 
97
        if (!*p) {
 
98
            version[c++] = atoi(version_string);
 
99
            version_string = ++p;
 
100
            continue;
 
101
        }
 
102
 
 
103
        if (!apr_isdigit(*p)) {
 
104
            break;
 
105
        }
 
106
 
 
107
        ++p;
 
108
    }
 
109
 
 
110
    if (p < ep) { /* syntax error */
 
111
        return 0;
 
112
    }
 
113
 
 
114
    *error = NULL;
 
115
 
 
116
    if      (httpd_version.major > version[0]) {
 
117
        return 1;
 
118
    }
 
119
    else if (httpd_version.major < version[0]) {
 
120
        return -1;
 
121
    }
 
122
    else if (httpd_version.minor > version[1]) {
 
123
        return 1;
 
124
    }
 
125
    else if (httpd_version.minor < version[1]) {
 
126
        return -1;
 
127
    }
 
128
    else if (httpd_version.patch > version[2]) {
 
129
        return 1;
 
130
    }
 
131
    else if (httpd_version.patch < version[2]) {
 
132
        return -1;
 
133
    }
 
134
 
 
135
    /* seems to be the same */
 
136
    return 0;
 
137
}
 
138
 
 
139
/*
 
140
 * match version against a regular expression
 
141
 */
 
142
static int match_version(apr_pool_t *pool, char *version_string,
 
143
                         const char **error)
 
144
{
 
145
    ap_regex_t *compiled;
 
146
    const char *to_match;
 
147
    int rc;
 
148
 
 
149
    compiled = ap_pregcomp(pool, version_string, AP_REG_EXTENDED);
 
150
    if (!compiled) {
 
151
        *error = "Unable to compile regular expression";
 
152
        return 0;
 
153
    }
 
154
 
 
155
    *error = NULL;
 
156
 
 
157
    to_match = apr_psprintf(pool, "%d.%d.%d%s",
 
158
                            httpd_version.major,
 
159
                            httpd_version.minor,
 
160
                            httpd_version.patch,
 
161
                            httpd_version.add_string);
 
162
 
 
163
    rc = !ap_regexec(compiled, to_match, 0, NULL, 0);
 
164
 
 
165
    ap_pregfree(pool, compiled);
 
166
    return rc;
 
167
}
 
168
 
 
169
/*
 
170
 * Implements the <IfVersion> container
 
171
 */
 
172
static const char *start_ifversion(cmd_parms *cmd, void *mconfig,
 
173
                                   const char *arg1, const char *arg2,
 
174
                                   const char *arg3)
 
175
{
 
176
    const char *endp;
 
177
    int reverse = 0, done = 0, match = 0, compare;
 
178
    const char *p, *error;
 
179
    char c;
 
180
 
 
181
    /* supplying one argument is possible, we assume an equality check then */
 
182
    if (!arg2) {
 
183
        arg2 = arg1;
 
184
        arg1 = "=";
 
185
    }
 
186
 
 
187
    /* surrounding quotes without operator */
 
188
    if (!arg3 && *arg2 == '>' && !arg2[1]) {
 
189
        arg3 = ">";
 
190
        arg2 = arg1;
 
191
        arg1 = "=";
 
192
    }
 
193
 
 
194
    /* the third argument makes version surrounding quotes plus operator
 
195
     * possible.
 
196
     */
 
197
    endp = arg2 + strlen(arg2);
 
198
    if (   endp == arg2
 
199
        || (!(arg3 && *arg3 == '>' && !arg3[1]) && *--endp != '>')) {
 
200
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
 
201
                           "> directive missing closing '>'", NULL);
 
202
    }
 
203
 
 
204
    p = arg1;
 
205
    if (*p == '!') {
 
206
        reverse = 1;
 
207
        if (p[1]) {
 
208
            ++p;
 
209
        }
 
210
    }
 
211
 
 
212
    c = *p++;
 
213
    if (!*p || (*p == '=' && !p[1] && c != '~')) {
 
214
        if (!httpd_version.major) {
 
215
            ap_get_server_revision(&httpd_version);
 
216
        }
 
217
 
 
218
        done = 1;
 
219
        switch (c) {
 
220
        case '=':
 
221
            /* normal comparison */
 
222
            if (*arg2 != '/') {
 
223
                compare = compare_version(apr_pstrmemdup(cmd->pool, arg2,
 
224
                                                         endp-arg2),
 
225
                                          &error);
 
226
                if (error) {
 
227
                    return error;
 
228
                }
 
229
 
 
230
                match = !compare;
 
231
                break;
 
232
            }
 
233
 
 
234
            /* regexp otherwise */
 
235
            if (endp == ++arg2 || *--endp != '/') {
 
236
                return "Missing delimiting / of regular expression.";
 
237
            }
 
238
 
 
239
        case '~':
 
240
            /* regular expression */
 
241
            match = match_version(cmd->pool, apr_pstrmemdup(cmd->pool, arg2,
 
242
                                                            endp-arg2),
 
243
                                  &error);
 
244
            if (error) {
 
245
                return error;
 
246
            }
 
247
            break;
 
248
 
 
249
        case '<':
 
250
            compare = compare_version(apr_pstrmemdup(cmd->pool, arg2,
 
251
                                                     endp-arg2),
 
252
                                      &error);
 
253
            if (error) {
 
254
                return error;
 
255
            }
 
256
 
 
257
            match = ((-1 == compare) || (*p && !compare));
 
258
            break;
 
259
 
 
260
        case '>':
 
261
            compare = compare_version(apr_pstrmemdup(cmd->pool, arg2,
 
262
                                                     endp-arg2),
 
263
                                      &error);
 
264
            if (error) {
 
265
                return error;
 
266
            }
 
267
 
 
268
            match = ((1 == compare) || (*p && !compare));
 
269
            break;
 
270
 
 
271
        default:
 
272
            done = 0;
 
273
            break;
 
274
        }
 
275
    }
 
276
 
 
277
    if (!done) {
 
278
        return apr_pstrcat(cmd->pool, "unrecognized operator '", arg1, "'",
 
279
                           NULL);
 
280
    }
 
281
 
 
282
    if ((!reverse && match) || (reverse && !match)) {
 
283
        ap_directive_t *parent = NULL;
 
284
        ap_directive_t *current = NULL;
 
285
        const char *retval;
 
286
 
 
287
        retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
 
288
                                      &current, &parent, "<IfVersion");
 
289
        *(ap_directive_t **)mconfig = current;
 
290
        return retval;
 
291
    }
 
292
 
 
293
    *(ap_directive_t **)mconfig = NULL;
 
294
    return ap_soak_end_container(cmd, "<IfVersion");
 
295
}
 
296
 
 
297
static const command_rec version_cmds[] = {
 
298
    AP_INIT_TAKE123("<IfVersion", start_ifversion, NULL, EXEC_ON_READ | OR_ALL,
 
299
                    "a comparison operator, a version (and a delimiter)"),
 
300
    { NULL }
 
301
};
 
302
 
 
303
module AP_MODULE_DECLARE_DATA version_module =
 
304
{
 
305
    STANDARD20_MODULE_STUFF,
 
306
    NULL,             /* dir config creater */
 
307
    NULL,             /* dir merger --- default is to override */
 
308
    NULL,             /* server config */
 
309
    NULL,             /* merge server configs */
 
310
    version_cmds,     /* command apr_table_t */
 
311
    NULL,             /* register hooks */
 
312
};