23
23
/*
24
24
* Include the core server components.
25
25
*/
26
+
27
+ #include <unistd.h>
28
+
29
+ #include "apr_lib.h"
30
+
26
31
#include "httpd.h"
27
32
#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 ;
28
47
29
48
/*
30
49
* Remove trailing newline(s) from pipe output
@@ -42,23 +61,44 @@ static char* mod_fortune_chomp_output(char* str)
42
61
*/
43
62
static int mod_fortune_method_handler (request_rec * r )
44
63
{
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 );
48
66
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 );
55
71
}
56
- // otherwise funnel pipe's output into cstring and set as environment variable
57
72
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 );
62
102
}
63
103
64
104
// Return DECLINED so that the Apache core will keep looking for
@@ -67,6 +107,75 @@ static int mod_fortune_method_handler (request_rec *r)
67
107
return DECLINED ;
68
108
}
69
109
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
+
70
179
/*
71
180
* This function is a callback and it declares what other functions
72
181
* should be called for request processing and configuration requests.
@@ -85,9 +194,9 @@ module AP_MODULE_DECLARE_DATA fortune_module =
85
194
STANDARD20_MODULE_STUFF ,
86
195
NULL ,
87
196
NULL ,
197
+ create_modfortune_config , /* Create config rec for host */
88
198
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 */
92
201
};
93
202
0 commit comments