/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements . See the NOTICE file distributed with
* this work for additional information regarding copyright ownership .
* The ASF licenses this file to You under the Apache License , Version 2 . 0
* ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
/*
* mod_version . c
* Allow conditional configuration depending on the httpd version
*
* Andr é Malo ( nd / perlig . de ) , January 2004
*
* Some stuff coded here is heavily based on the core < IfModule >
* containers .
*
* The module makes the following confgurations possible :
*
* < IfVersion op major . minor . patch >
* # conditional config here . . .
* < / IfVersion >
*
* where " op " is one of :
* = / = = equal
* > greater than
* > = greater or equal
* < less than
* < = less or equal
*
* If minor version and patch level are omitted they are assumed to be 0 .
*
* Alternatively you can match the whole version ( including some vendor - added
* string of the CORE version , see ap_release . h ) against a regular expression :
*
* < IfVersion op regex >
* # conditional config here . . .
* < / IfVersion >
*
* where " op " is one of :
* = / = = match ; regex must be surrounded by slashes
* ~ match ; regex MAY NOT be surrounded by slashes
*
* Note that all operators may be preceded by an exclamation mark
* ( without spaces ) in order to reverse their meaning .
*
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
/* module structure */
module AP_MODULE_DECLARE_DATA version_module;
/* queried httpd version */
static ap_version_t httpd_version;
/*
* compare the supplied version with the core one
*/
static int compare_version(char *version_string, const char **error)
{
char *p = version_string, *ep;
int version[3 ] = {0 , 0 , 0 };
int c = 0 ;
*error = "Version appears to be invalid. It must have the format "
"major[.minor[.patch]] where major, minor and patch are "
"numbers." ;
if (!apr_isdigit(*p)) {
return 0 ;
}
/* parse supplied version */
ep = version_string + strlen(version_string);
while (p <= ep && c < 3 ) {
if (*p == '.' ) {
*p = '\0' ;
}
if (!*p) {
version[c++] = atoi(version_string);
version_string = ++p;
continue ;
}
if (!apr_isdigit(*p)) {
break ;
}
++p;
}
if (p < ep) { /* syntax error */
return 0 ;
}
*error = NULL;
if (httpd_version.major > version[0 ]) {
return 1 ;
}
else if (httpd_version.major < version[0 ]) {
return -1 ;
}
else if (httpd_version.minor > version[1 ]) {
return 1 ;
}
else if (httpd_version.minor < version[1 ]) {
return -1 ;
}
else if (httpd_version.patch > version[2 ]) {
return 1 ;
}
else if (httpd_version.patch < version[2 ]) {
return -1 ;
}
/* seems to be the same */
return 0 ;
}
/*
* match version against a regular expression
*/
static int match_version(apr_pool_t *pool, char *version_string,
const char **error)
{
ap_regex_t *compiled;
const char *to_match;
int rc;
compiled = ap_pregcomp(pool, version_string, AP_REG_EXTENDED);
if (!compiled) {
*error = "Unable to compile regular expression" ;
return 0 ;
}
*error = NULL;
to_match = apr_psprintf(pool, "%d.%d.%d%s" ,
httpd_version.major,
httpd_version.minor,
httpd_version.patch,
httpd_version.add_string);
rc = !ap_regexec(compiled, to_match, 0 , NULL, 0 );
ap_pregfree(pool, compiled);
return rc;
}
/*
* Implements the < IfVersion > container
*/
static const char *start_ifversion(cmd_parms *cmd, void *mconfig,
const char *arg1, const char *arg2,
const char *arg3)
{
const char *endp;
int reverse = 0 , done = 0 , match = 0 , compare;
const char *p, *error;
char c;
/* supplying one argument is possible, we assume an equality check then */
if (!arg2) {
arg2 = arg1;
arg1 = "=" ;
}
/* surrounding quotes without operator */
if (!arg3 && *arg2 == '>' && !arg2[1 ]) {
arg3 = ">" ;
arg2 = arg1;
arg1 = "=" ;
}
/* the third argument makes version surrounding quotes plus operator
* possible .
*/
endp = arg2 + strlen(arg2);
if ( endp == arg2
|| (!(arg3 && *arg3 == '>' && !arg3[1 ]) && *--endp != '>' )) {
return apr_pstrcat(cmd->pool, cmd->cmd->name,
"> directive missing closing '>'" , NULL);
}
p = arg1;
if (*p == '!' ) {
reverse = 1 ;
if (p[1 ]) {
++p;
}
}
c = *p++;
if (!*p || (*p == '=' && !p[1 ] && c != '~' )) {
if (!httpd_version.major) {
ap_get_server_revision(&httpd_version);
}
done = 1 ;
switch (c) {
case '=' :
/* normal comparison */
if (*arg2 != '/' ) {
compare = compare_version(apr_pstrmemdup(cmd->temp_pool, arg2,
endp-arg2),
&error);
if (error) {
return error;
}
match = !compare;
break ;
}
/* regexp otherwise */
if (endp == ++arg2 || *--endp != '/' ) {
return "Missing delimiting / of regular expression." ;
}
case '~' :
/* regular expression */
match = match_version(cmd->temp_pool,
apr_pstrmemdup(cmd->temp_pool, arg2,
endp-arg2),
&error);
if (error) {
return error;
}
break ;
case '<' :
compare = compare_version(apr_pstrmemdup(cmd->temp_pool, arg2,
endp-arg2),
&error);
if (error) {
return error;
}
match = ((-1 == compare) || (*p && !compare));
break ;
case '>' :
compare = compare_version(apr_pstrmemdup(cmd->temp_pool, arg2,
endp-arg2),
&error);
if (error) {
return error;
}
match = ((1 == compare) || (*p && !compare));
break ;
default :
done = 0 ;
break ;
}
}
if (!done) {
return apr_pstrcat(cmd->pool, "unrecognized operator '" , arg1, "'" ,
NULL);
}
if ((!reverse && match) || (reverse && !match)) {
ap_directive_t *parent = NULL;
ap_directive_t *current = NULL;
const char *retval;
retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
¤t, &parent, "<IfVersion" );
*(ap_directive_t **)mconfig = current;
return retval;
}
*(ap_directive_t **)mconfig = NULL;
return ap_soak_end_container(cmd, "<IfVersion" );
}
static const command_rec version_cmds[] = {
AP_INIT_TAKE123("<IfVersion" , start_ifversion, NULL, EXEC_ON_READ | OR_ALL,
"a comparison operator, a version (and a delimiter)" ),
{ NULL }
};
AP_DECLARE_MODULE(version) =
{
STANDARD20_MODULE_STUFF,
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server configs */
version_cmds, /* command apr_table_t */
NULL, /* register hooks */
};
Messung V0.5 in Prozent C=93 H=99 G=95
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland