Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
(mime_dir_config *)ap_palloc (p, sizeof(mime_dir_config));<br />
</span>
<br />
new->forced_types = ap_overlay_tables (p, subdir->forced_types,<br />
<span class="indent">
parent_dir->forced_types);<br />
</span>
new->encoding_types = ap_overlay_tables (p, subdir->encoding_types,<br />
<span class="indent">
parent_dir->encoding_types);<br />
</span>
<br />
return new;<br />
</span>
}
</code></p></div>
<p>As a note -- if there is no per-directory merge function present, the
server will just use the subdirectory's configuration info, and ignore
the parent's. For some modules, that works just fine (<em>e.g.</em>, for
the includes module, whose per-directory configuration information
consists solely of the state of the <code>XBITHACK</code>), and for those
modules, you can just not declare one, and leave the corresponding
structure slot in the module itself <code>NULL</code>.</p>
<h3><a name="commands" id="commands">Command handling</a></h3>
<p>Now that we have these structures, we need to be able to figure out how
to fill them. That involves processing the actual <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code> and <code class="directive"><a href="../mod/mod_mime.html#addencoding">AddEncoding</a></code> commands. To find commands, the server looks in
the module's command table. That table contains information on how many
arguments the commands take, and in what formats, where it is permitted,
and so forth. That information is sufficient to allow the server to invoke
most command-handling functions with pre-parsed arguments. Without further
ado, let's look at the <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code>
command handler, which looks like this (the <code class="directive"><a href="../mod/mod_mime.html#addencoding">AddEncoding</a></code> command looks basically the same, and won't be
shown here):</p>
<div class="example"><p><code>
char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)<br />
{<br />
<span class="indent">
if (*ext == '.') ++ext;<br />
ap_table_set (m->forced_types, ext, ct);<br />
return NULL;<br />
</span>
}
</code></p></div>
<p>This command handler is unusually simple. As you can see, it takes
four arguments, two of which are pre-parsed arguments, the third being the
per-directory configuration structure for the module in question, and the
fourth being a pointer to a <code>cmd_parms</code> structure. That
structure contains a bunch of arguments which are frequently of use to
some, but not all, commands, including a resource pool (from which memory
can be allocated, and to which cleanups should be tied), and the (virtual)
server being configured, from which the module's per-server configuration
data can be obtained if required.</p>
<p>Another way in which this particular command handler is unusually
simple is that there are no error conditions which it can encounter. If
there were, it could return an error message instead of <code>NULL</code>;
this causes an error to be printed out on the server's
<code>stderr</code>, followed by a quick exit, if it is in the main config
files; for a <code>.htaccess</code> file, the syntax error is logged in
the server error log (along with an indication of where it came from), and
the request is bounced with a server error response (HTTP error status,
code 500).</p>
<p>The MIME module's command table has entries for these commands, which
look like this:</p>
<div class="example"><p><code>
command_rec mime_cmds[] = {<br />
<span class="indent">
{ "AddType", add_type, NULL, OR_FILEINFO, TAKE2,<br />
<span class="indent">"a mime type followed by a file extension" },<br /></span>
{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2,<br />
<span class="indent">
"an encoding (<em>e.g.</em>, gzip), followed by a file extension" },<br />
</span>
{ NULL }<br />
</span>
};
</code></p></div>
<p>The entries in these tables are:</p>
<ul>
<li>The name of the command</li>
<li>The function which handles it</li>
<li>a <code>(void *)</code> pointer, which is passed in the
<code>cmd_parms</code> structure to the command handler ---
this is useful in case many similar commands are handled by
the same function.</li>
<li>A bit mask indicating where the command may appear. There
are mask bits corresponding to each
<code>AllowOverride</code> option, and an additional mask
bit, <code>RSRC_CONF</code>, indicating that the command may
appear in the server's own config files, but <em>not</em> in
any <code>.htaccess</code> file.</li>
<li>A flag indicating how many arguments the command handler
wants pre-parsed, and how they should be passed in.
<code>TAKE2</code> indicates two pre-parsed arguments. Other
options are <code>TAKE1</code>, which indicates one
pre-parsed argument, <code>FLAG</code>, which indicates that
the argument should be <code>On</code> or <code>Off</code>,
and is passed in as a boolean flag, <code>RAW_ARGS</code>,
which causes the server to give the command the raw, unparsed
arguments (everything but the command name itself). There is
also <code>ITERATE</code>, which means that the handler looks
the same as <code>TAKE1</code>, but that if multiple
arguments are present, it should be called multiple times,
and finally <code>ITERATE2</code>, which indicates that the
command handler looks like a <code>TAKE2</code>, but if more
arguments are present, then it should be called multiple
times, holding the first argument constant.</li>
<li>Finally, we have a string which describes the arguments
that should be present. If the arguments in the actual config
file are not as required, this string will be used to help
give a more specific error message. (You can safely leave
this <code>NULL</code>).</li>
</ul>
<p>Finally, having set this all up, we have to use it. This is ultimately
done in the module's handlers, specifically for its file-typing handler,
which looks more or less like this; note that the per-directory
configuration structure is extracted from the <code>request_rec</code>'s
per-directory configuration vector by using the
<code>ap_get_module_config</code> function.</p>
<div class="example"><p><code>
int find_ct(request_rec *r)<br />
{<br />
<span class="indent">
int i;<br />
char *fn = ap_pstrdup (r->pool, r->filename);<br />
mime_dir_config *conf = (mime_dir_config *)<br />
<span class="indent">
ap_get_module_config(r->per_dir_config, &mime_module);<br />
</span>
char *type;<br />
<br />
if (S_ISDIR(r->finfo.st_mode)) {<br />
<span class="indent">
r->content_type = DIR_MAGIC_TYPE;<br />
return OK;<br />
</span>
}<br />
<br />
if((i=ap_rind(fn,'.')) < 0) return DECLINED;<br />
++i;<br />
<br />
if ((type = ap_table_get (conf->encoding_types, &fn[i])))<br />
{<br />
<span class="indent">
r->content_encoding = type;<br />
<br />
/* go back to previous extension to try to use it as a type */<br />
fn[i-1] = '\0';<br />
if((i=ap_rind(fn,'.')) < 0) return OK;<br />
++i;<br />
</span>
}<br />
<br />
if ((type = ap_table_get (conf->forced_types, &fn[i])))<br />
{<br />
<span class="indent">
r->content_type = type;<br />
</span>
}<br />
<br />
return OK;
</span>
}
</code></p></div>
<h3><a name="servconf" id="servconf">Side notes -- per-server configuration,
virtual servers, <em>etc</em>.</a></h3>
<p>The basic ideas behind per-server module configuration are basically
the same as those for per-directory configuration; there is a creation
function and a merge function, the latter being invoked where a virtual
server has partially overridden the base server configuration, and a
combined structure must be computed. (As with per-directory configuration,
the default if no merge function is specified, and a module is configured
in some virtual server, is that the base configuration is simply
ignored).</p>
<p>The only substantial difference is that when a command needs to
configure the per-server private module data, it needs to go to the
<code>cmd_parms</code> data to get at it. Here's an example, from the
alias module, which also indicates how a syntax error can be returned
(note that the per-directory configuration argument to the command
handler is declared as a dummy, since the module doesn't actually have
per-directory config data):</p>
<div class="example"><p><code>
char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)<br />
{<br />
<span class="indent">
server_rec *s = cmd->server;<br />
alias_server_conf *conf = (alias_server_conf *)<br />
<span class="indent">
ap_get_module_config(s->module_config,&alias_module);<br />
</span>
alias_entry *new = ap_push_array (conf->redirects);<br />
<br />
if (!ap_is_url (url)) return "Redirect to non-URL";<br />
<br />
new->fake = f; new->real = url;<br />
return NULL;<br />
</span>
}
</code></p></div>
</div></div>
<div class="bottomlang">
<p><span>Available Languages: </span><a href="../en/developer/API.html" title="English"> en </a></p>
</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our <a href="http://httpd.apache.org/lists.html">mailing lists</a>.</div>
<script type="text/javascript"><!--//--><![CDATA[//><!--
var comments_shortname = 'httpd';
var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/API.html';
(function(w, d) {
if (w.location.hostname.toLowerCase() == "httpd.apache.org") {
d.write('<div id="comments_thread"><\/div>');
var s = d.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier;
(d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
}
else {
d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>');
}
})(window, document);
//--><!]]></script></div><div id="footer">
<p class="apache">Copyright 2017 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!--
if (typeof(prettyPrint) !== 'undefined') {
prettyPrint();
}
//--><!]]></script>
</body></html>