Skip to content

Commit c50920d

Browse files
committed
Merge branch 'release/0.1beta'
2 parents 4fd85ec + 21f23d2 commit c50920d

File tree

3 files changed

+164
-18
lines changed

3 files changed

+164
-18
lines changed

LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2010 Evan Kaufman
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

README.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,22 @@ I wrote this mostly for fun and because it's been a while since I dabbled in the
2525
Licensing
2626
--
2727
This software is released as open source under the MIT license:
28-
http://www.opensource.org/licenses/mit-license.php
28+
http://www.opensource.org/licenses/mit-license.php
29+
30+
31+
Usage Example
32+
--
33+
This is an example configuration that would insert an `X-Fortune` header to every successful request.
34+
# if mod_header is enabled...
35+
<IfModule mod_header.c>
36+
# load and configure mod_fortune (default path but custom max length)
37+
LoadModule fortune_module modules/mod_fortune.so
38+
39+
<IfModule mod_fortune.c>
40+
FortuneMaxLength 1000
41+
#FortuneProgram /usr/games/fortune
42+
</IfModule>
43+
44+
# set X-Fortune header for successful response, if env variable exists
45+
Header onsuccess set X-Fortune %{FORTUNE_COOKIE}e env=FORTUNE_COOKIE
46+
</IfModule>

mod_fortune.c

+126-17
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,27 @@
2323
/*
2424
* Include the core server components.
2525
*/
26+
27+
#include <unistd.h>
28+
29+
#include "apr_lib.h"
30+
2631
#include "httpd.h"
2732
#include "http_config.h"
33+
#include "http_log.h"
34+
35+
/*
36+
* This module
37+
*/
38+
module AP_MODULE_DECLARE_DATA fortune_module;
39+
40+
/*
41+
* This modules per-server configuration structure.
42+
*/
43+
typedef struct {
44+
const char *maxlen;
45+
const char *binloc;
46+
} modfortune_config;
2847

2948
/*
3049
* Remove trailing newline(s) from pipe output
@@ -42,23 +61,44 @@ static char* mod_fortune_chomp_output(char* str)
4261
*/
4362
static int mod_fortune_method_handler (request_rec *r)
4463
{
45-
// assuming short fortune to be 160 chars (plus null char)
46-
char fortune_output[161];
47-
FILE *fortune_pipe;
64+
// Get the module configuration
65+
modfortune_config* svr = ap_get_module_config(r->server->module_config, &fortune_module);
4866

49-
// invoke "fortune -s" in a subshell
50-
char fortune_cmd[] = "/usr/games/fortune -s";
51-
fortune_pipe = popen(fortune_cmd, "r");
52-
// if opening pipe fails, write a message to stderr
53-
if (fortune_pipe == NULL) {
54-
fprintf(stderr,"apache2_mod_fortune: Failed to open a pipe to '%s'.\n", fortune_cmd);
67+
// short circuit early if binloc isnt executable
68+
if (access(svr->binloc, X_OK) < 0) {
69+
// presumably binloc is the default value, and that binary simply doesnt exist or isnt executable
70+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_fortune: Failed to find or execute %s", svr->binloc);
5571
}
56-
// otherwise funnel pipe's output into cstring and set as environment variable
5772
else {
58-
// TODO: fgets cuts off @ first newline...need to keep reading until EOF
59-
fgets(fortune_output, sizeof(fortune_output)-1, fortune_pipe);
60-
pclose(fortune_pipe);
61-
apr_table_set(r->subprocess_env, "FORTUNE_COOKIE", mod_fortune_chomp_output(fortune_output) );
73+
// estimate size of fortune output from config directive (short circuit if maxlen is not positive int)
74+
int maxlen = atoi(svr->maxlen);
75+
char *fortune_output = (char *) malloc((maxlen + 1) * sizeof(char));
76+
strcpy(fortune_output, "");
77+
78+
// dynamically allocate fortune_cmd based on size of its pieces (from config directives)
79+
char *fortune_cmd = (char *) malloc((strlen(svr->binloc) + strlen(svr->maxlen) + 10) * sizeof(char));
80+
sprintf(fortune_cmd, "%s -n %s -s", svr->binloc, svr->maxlen);
81+
82+
// invoke in a subshell
83+
FILE *fortune_pipe;
84+
fortune_pipe = popen(fortune_cmd, "r");
85+
86+
// if opening pipe fails, log a warning
87+
if (fortune_pipe == NULL) {
88+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_fortune: Failed to open pipe to %s", fortune_cmd);
89+
}
90+
// otherwise funnel pipe's output into cstring and set as environment variable
91+
else {
92+
int fortune_size = fread(fortune_output, sizeof(char), maxlen, fortune_pipe);
93+
fortune_output[ fortune_size ] = '\0';
94+
pclose(fortune_pipe);
95+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "mod_fortune: Retrieved fortune of %d chars", (int)strlen(fortune_output));
96+
apr_table_set(r->subprocess_env, "FORTUNE_COOKIE", mod_fortune_chomp_output(fortune_output) );
97+
}
98+
99+
// deallocate dynamic cstrings we no longer need
100+
free(fortune_output);
101+
free(fortune_cmd);
62102
}
63103

64104
// Return DECLINED so that the Apache core will keep looking for
@@ -67,6 +107,75 @@ static int mod_fortune_method_handler (request_rec *r)
67107
return DECLINED;
68108
}
69109

110+
/*
111+
* Set the max length of fortunes to retrieve
112+
*/
113+
static const char * set_modfortune_maxlen(cmd_parms *parms, void *dummy, const char *arg)
114+
{
115+
if (!apr_isdigit(arg[0]))
116+
return "FortuneMaxLength: length must be numeric";
117+
118+
if (atoi((char *)arg) < 1)
119+
return "FortuneMaxLength: must be at least one character long";
120+
121+
modfortune_config* svr = ap_get_module_config(parms->server->module_config, &fortune_module);
122+
svr->maxlen = (char *) arg;
123+
124+
return NULL;
125+
}
126+
127+
/*
128+
* Set the location of the executable fortune binary
129+
*/
130+
static const char * set_modfortune_binloc(cmd_parms *parms, void *dummy, const char *arg)
131+
{
132+
char *binloc = (char *) arg;
133+
134+
if (access(binloc, F_OK) < 0)
135+
return "FortuneProgram: file must exist";
136+
137+
if (access(binloc, X_OK) < 0)
138+
return "FortuneProgram: file must be executable";
139+
140+
modfortune_config* svr = ap_get_module_config(parms->server->module_config, &fortune_module);
141+
svr->binloc = binloc;
142+
143+
return NULL;
144+
}
145+
146+
/**
147+
* A declaration of the configuration directives that are supported by this module.
148+
*/
149+
static const command_rec mod_fortune_cmds[] =
150+
{
151+
AP_INIT_TAKE1(
152+
"FortuneMaxLength",
153+
set_modfortune_maxlen,
154+
NULL,
155+
OR_ALL,//RSRC_CONF,
156+
"FortuneMaxLength <integer> -- the maximum length in characters of fortune to retrieve."
157+
),
158+
AP_INIT_TAKE1(
159+
"FortuneProgram",
160+
set_modfortune_binloc,
161+
NULL,
162+
OR_ALL,//RSRC_CONF,
163+
"FortuneProgram <string> -- the location of the executable fortune binary."
164+
),
165+
{NULL}
166+
};
167+
168+
/**
169+
* Creates the per-server configuration records.
170+
*/
171+
static void* create_modfortune_config(apr_pool_t* pool, server_rec* s) {
172+
modfortune_config* svr = apr_pcalloc(pool, sizeof(modfortune_config));
173+
/* Set up the default values for fields of svr */
174+
svr->maxlen = "160";
175+
svr->binloc = "/usr/games/fortune";
176+
return svr ;
177+
}
178+
70179
/*
71180
* This function is a callback and it declares what other functions
72181
* should be called for request processing and configuration requests.
@@ -85,9 +194,9 @@ module AP_MODULE_DECLARE_DATA fortune_module =
85194
STANDARD20_MODULE_STUFF,
86195
NULL,
87196
NULL,
197+
create_modfortune_config, /* Create config rec for host */
88198
NULL,
89-
NULL,
90-
NULL,
91-
mod_fortune_register_hooks, /* callback for registering hooks */
199+
mod_fortune_cmds, /* Configuration directives */
200+
mod_fortune_register_hooks, /* Hook into APR API */
92201
};
93202

0 commit comments

Comments
 (0)