/src/mod_auth_openidc/test/stub.c
Line | Count | Source |
1 | | #include "util/request_state.h" |
2 | | #include <apr_global_mutex.h> |
3 | | #include <apr_lib.h> |
4 | | #include <apr_strings.h> |
5 | | |
6 | | // clang-format off |
7 | | |
8 | | #include <httpd.h> |
9 | | #include <http_config.h> |
10 | | #include <http_core.h> |
11 | | #include <http_log.h> |
12 | | |
13 | | #ifdef WIN32 |
14 | | /* os/win32/os.h maps every exit() onto this server variable, so any test program that includes |
15 | | * the httpd headers references it; set, the real exit code passes through */ |
16 | | int ap_real_exit_code = 1; |
17 | | #endif |
18 | | |
19 | | // clang-format on |
20 | | |
21 | | /* NB: deliberately not "util.h": including it here pulls in <http_request.h>, whose AP_DECLARE_HOOK |
22 | | * declarations collide with the hand-rolled ap_hook_* shims below. These mirror the declarations in |
23 | | * util.h instead; the two must stay in step. */ |
24 | | typedef int (*oidc_test_hook_post_config_fn)(apr_pool_t *pool, apr_pool_t *p1, apr_pool_t *p2, server_rec *s); |
25 | | typedef void (*oidc_test_hook_child_init_fn)(apr_pool_t *p, server_rec *s); |
26 | | typedef void (*oidc_test_hook_insert_filter_fn)(request_rec *r); |
27 | | typedef apr_status_t (*oidc_test_input_filter_fn)(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, |
28 | | apr_read_type_e block, apr_off_t nbytes); |
29 | | |
30 | | static oidc_test_hook_insert_filter_fn _oidc_test_hook_insert_filter = NULL; |
31 | | static oidc_test_input_filter_fn _oidc_test_input_filter = NULL; |
32 | | static const char *_oidc_test_added_input_filter = NULL; |
33 | | static const char *_oidc_test_brigade_body = NULL; |
34 | | static apr_status_t _oidc_test_brigade_rc = APR_SUCCESS; |
35 | | static const char *_oidc_test_exec_line_output = NULL; |
36 | | |
37 | | #define ap_HOOK_check_user_id_t void |
38 | | |
39 | | AP_DECLARE(void) |
40 | | ap_hook_check_authn(ap_HOOK_check_user_id_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder, |
41 | 0 | int type) { |
42 | | // comment explaining why the method is empty |
43 | 0 | } |
44 | | |
45 | | /* the first authz provider the module registers, so its parse_require_line can be driven */ |
46 | | static const void *_oidc_test_authz_provider = NULL; |
47 | | |
48 | 0 | const void *oidc_test_authz_provider_get(void) { |
49 | 0 | return _oidc_test_authz_provider; |
50 | 0 | } |
51 | | |
52 | | AP_DECLARE(apr_status_t) |
53 | | ap_register_auth_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, |
54 | 0 | const char *provider_version, const void *provider, int type) { |
55 | 0 | if (_oidc_test_authz_provider == NULL) |
56 | 0 | _oidc_test_authz_provider = provider; |
57 | 0 | return 0; |
58 | 0 | } |
59 | | |
60 | 76 | AP_DECLARE(apr_status_t) ap_unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex) { |
61 | 76 | return 0; |
62 | 76 | } |
63 | | |
64 | | /* the AuthType reported to the module; default openid-connect, overridable per |
65 | | * test via oidc_test_set_auth_type() so the OAuth / mixed dispatch paths can be |
66 | | * exercised */ |
67 | | static const char *stub_auth_type = "openid-connect"; |
68 | | |
69 | 38 | void oidc_test_set_auth_type(const char *auth_type) { |
70 | 38 | stub_auth_type = (auth_type != NULL) ? auth_type : "openid-connect"; |
71 | 38 | } |
72 | | |
73 | 278 | AP_DECLARE(const char *) ap_auth_type(request_rec *r) { |
74 | 278 | return stub_auth_type; |
75 | 278 | } |
76 | | |
77 | 4.85k | AP_DECLARE(const char *) ap_auth_name(request_rec *r) { |
78 | 4.85k | return NULL; |
79 | 4.85k | } |
80 | | |
81 | 5.56k | AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz) { |
82 | | /* tests stash the POST body in r->args (and r->remaining tracks bytes left); copy |
83 | | * from there into the caller's buffer so oidc_util_read can drive the form parser */ |
84 | 5.56k | if (r->args == NULL || r->remaining == 0) |
85 | 0 | return 0; |
86 | | /* r->remaining is signed (apr_off_t) and is only ever positive here, but compare and |
87 | | * assign in one type so the narrowing is explicit rather than a signedness surprise */ |
88 | 5.56k | apr_size_t remaining = (apr_size_t)r->remaining; |
89 | 5.56k | apr_size_t off = strlen(r->args) - remaining; |
90 | 5.56k | apr_size_t n = (bufsiz < remaining) ? bufsiz : remaining; |
91 | 5.56k | memcpy(buffer, r->args + off, n); |
92 | 5.56k | r->remaining -= n; |
93 | 5.56k | return (long)n; |
94 | 5.56k | } |
95 | | |
96 | 315k | AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop) { |
97 | 315k | const char *pos = *line; |
98 | 315k | int len; |
99 | 315k | char *res; |
100 | | |
101 | 407M | while ((*pos != stop) && *pos) { |
102 | 407M | ++pos; |
103 | 407M | } |
104 | | |
105 | 315k | len = (int)(pos - *line); |
106 | 315k | res = apr_pstrmemdup(atrans, *line, len); |
107 | | |
108 | 315k | if (stop) { |
109 | 4.40M | while (*pos == stop) { |
110 | 4.08M | ++pos; |
111 | 4.08M | } |
112 | 315k | } |
113 | 315k | *line = pos; |
114 | | |
115 | 315k | return res; |
116 | 315k | } |
117 | | |
118 | 0 | static char *substring_conf(apr_pool_t *p, const char *start, int len, char quote) { |
119 | 0 | char *result = apr_palloc(p, len + 1); |
120 | 0 | char *resp = result; |
121 | 0 | int i; |
122 | |
|
123 | 0 | for (i = 0; i < len; ++i) { |
124 | 0 | if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) |
125 | 0 | *resp++ = start[++i]; |
126 | 0 | else |
127 | 0 | *resp++ = start[i]; |
128 | 0 | } |
129 | |
|
130 | 0 | *resp++ = '\0'; |
131 | | #if RESOLVE_ENV_PER_TOKEN |
132 | | return (char *)ap_resolve_env(p, result); |
133 | | #else |
134 | 0 | return result; |
135 | 0 | #endif |
136 | 0 | } |
137 | | |
138 | 0 | AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line) { |
139 | 0 | const char *str = *line, *strend; |
140 | 0 | char *res; |
141 | 0 | char quote; |
142 | |
|
143 | 0 | while (apr_isspace(*str)) |
144 | 0 | ++str; |
145 | |
|
146 | 0 | if (!*str) { |
147 | 0 | *line = str; |
148 | 0 | return ""; |
149 | 0 | } |
150 | | |
151 | 0 | if ((quote = *str) == '"' || quote == '\'') { |
152 | 0 | strend = str + 1; |
153 | 0 | while (*strend && *strend != quote) { |
154 | 0 | if (*strend == '\\' && strend[1] && (strend[1] == quote || strend[1] == '\\')) { |
155 | 0 | strend += 2; |
156 | 0 | } else { |
157 | 0 | ++strend; |
158 | 0 | } |
159 | 0 | } |
160 | 0 | res = substring_conf(p, str + 1, (int)(strend - str - 1), quote); |
161 | |
|
162 | 0 | if (*strend == quote) |
163 | 0 | ++strend; |
164 | 0 | } else { |
165 | 0 | strend = str; |
166 | 0 | while (*strend && !apr_isspace(*strend)) |
167 | 0 | ++strend; |
168 | |
|
169 | 0 | res = substring_conf(p, str, (int)(strend - str), 0); |
170 | 0 | } |
171 | |
|
172 | 0 | while (apr_isspace(*strend)) |
173 | 0 | ++strend; |
174 | 0 | *line = strend; |
175 | 0 | return res; |
176 | 0 | } |
177 | | |
178 | 54 | AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *p, const char **line, char stop) { |
179 | | /* match Apache semantics: return the word before `stop`, advance *line past |
180 | | * the separator (or to '\0' if `stop` is not present). The previous stub |
181 | | * silently returned "" and left *line untouched, which masked any callers |
182 | | * that relied on the advance — e.g. oidc_oauth_token_from_basic. */ |
183 | 54 | const char *pos = *line; |
184 | 1.87k | while (*pos && (*pos != stop)) |
185 | 1.82k | ++pos; |
186 | 54 | char *res = apr_pstrmemdup(p, *line, pos - *line); |
187 | 54 | *line = (*pos == stop) ? pos + 1 : pos; |
188 | 54 | return res; |
189 | 54 | } |
190 | | |
191 | 6.07M | AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line) { |
192 | 6.07M | const char *pos = *line; |
193 | 6.07M | int len; |
194 | 6.07M | char *res; |
195 | | |
196 | 117M | while (!apr_isspace(*pos) && *pos) { |
197 | 111M | ++pos; |
198 | 111M | } |
199 | | |
200 | 6.07M | len = (int)(pos - *line); |
201 | 6.07M | res = apr_pstrmemdup(atrans, *line, len); |
202 | | |
203 | 9.54M | while (apr_isspace(*pos)) { |
204 | 3.47M | ++pos; |
205 | 3.47M | } |
206 | | |
207 | 6.07M | *line = pos; |
208 | | |
209 | 6.07M | return res; |
210 | 6.07M | } |
211 | | |
212 | 0 | AP_DECLARE(int) ap_hook_check_user_id(request_rec *r) { |
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | 0 | AP_DECLARE(int) ap_hook_auth_checker(request_rec *r) { |
217 | 0 | return 0; |
218 | 0 | } |
219 | | |
220 | | AP_DECLARE(void) |
221 | 0 | ap_hook_fixups(int (*handler)(request_rec *r), const char *const *aszPre, const char *const *aszSucc, int nOrder) { |
222 | | // comment explaining why the method is empty |
223 | 0 | } |
224 | | |
225 | | AP_DECLARE(void) |
226 | | ap_hook_insert_filter(void (*insert_filter)(request_rec *r), const char *const *aszPre, const char *const *aszSucc, |
227 | 0 | int nOrder) { |
228 | 0 | _oidc_test_hook_insert_filter = insert_filter; |
229 | 0 | } |
230 | | |
231 | | /* |
232 | | * the hooks the module registers are recorded rather than discarded, so a test can drive the |
233 | | * server-lifetime entry points (post_config, child_init) the way httpd would; see test_config.c |
234 | | */ |
235 | | static oidc_test_hook_post_config_fn _oidc_test_hook_post_config = NULL; |
236 | | static oidc_test_hook_child_init_fn _oidc_test_hook_child_init = NULL; |
237 | | |
238 | 0 | oidc_test_hook_post_config_fn oidc_test_hook_post_config_get(void) { |
239 | 0 | return _oidc_test_hook_post_config; |
240 | 0 | } |
241 | | |
242 | 0 | oidc_test_hook_child_init_fn oidc_test_hook_child_init_get(void) { |
243 | 0 | return _oidc_test_hook_child_init; |
244 | 0 | } |
245 | | |
246 | | AP_DECLARE(void) |
247 | | ap_hook_post_config(int (*post_config)(apr_pool_t *pool, apr_pool_t *p1, apr_pool_t *p2, server_rec *s), |
248 | 0 | const char *const *aszPre, const char *const *aszSucc, int nOrder) { |
249 | 0 | _oidc_test_hook_post_config = post_config; |
250 | 0 | } |
251 | | |
252 | | AP_DECLARE(void) |
253 | | ap_hook_child_init(void (*child_init)(apr_pool_t *p, server_rec *s), const char *const *aszPre, |
254 | 0 | const char *const *aszSucc, int nOrder) { |
255 | 0 | _oidc_test_hook_child_init = child_init; |
256 | 0 | } |
257 | | |
258 | | AP_DECLARE(void) |
259 | 0 | ap_hook_handler(int (*handler)(request_rec *r), const char *const *aszPre, const char *const *aszSucc, int nOrder) { |
260 | | // comment explaining why the method is empty |
261 | 0 | } |
262 | | |
263 | 3.55k | AP_DECLARE(int) ap_is_initial_req(request_rec *r) { |
264 | | /* Match Apache: an initial request has neither main nor prev. */ |
265 | 3.55k | return (r->main == NULL) && (r->prev == NULL); |
266 | 3.55k | } |
267 | | |
268 | | AP_DECLARE(ap_expr_info_t *) |
269 | | ap_expr_parse_cmd_mi(const cmd_parms *cmd, const char *expr, unsigned int flags, const char **err, |
270 | 0 | ap_expr_lookup_fn_t *lookup_fn, int module_index) { |
271 | 0 | if (strcmp(expr, "#") == 0) { |
272 | 0 | *err = "error"; |
273 | 0 | return NULL; |
274 | 0 | } |
275 | 0 | ap_expr_info_t *rv = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t)); |
276 | | /* echo the expression through ap_expr_str_exec below so string-valued |
277 | | * expression directives behave like literal strings in the tests */ |
278 | 0 | rv->filename = apr_pstrdup(cmd->pool, expr); |
279 | 0 | rv->root_node = NULL; |
280 | 0 | return rv; |
281 | 0 | } |
282 | | |
283 | 0 | AP_DECLARE(const char *) ap_expr_str_exec(request_rec *r, const ap_expr_info_t *expr, const char **err) { |
284 | 0 | if (err) |
285 | 0 | *err = NULL; |
286 | 0 | return expr->filename; |
287 | 0 | } |
288 | | |
289 | | /* Return the primed first command-output line; an unprimed command fails with NULL. */ |
290 | 9 | AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p, const char *cmd, const char *const *argv) { |
291 | 9 | return (_oidc_test_exec_line_output == NULL) ? NULL : apr_pstrdup(p, _oidc_test_exec_line_output); |
292 | 9 | } |
293 | | |
294 | 0 | void oidc_test_exec_line_prime(const char *output) { |
295 | 0 | _oidc_test_exec_line_output = output; |
296 | 0 | } |
297 | | |
298 | | AP_DECLARE(void) |
299 | | ap_log_error_(const char *file, int line, int module_index, int level, apr_status_t status, const server_rec *s, |
300 | 0 | const char *fmt, ...) { |
301 | 0 | if (level < APLOG_DEBUG) { |
302 | 0 | fprintf(stderr, "%s:%d [%d] [%d] ", file, line, level, status); |
303 | 0 | va_list ap; |
304 | 0 | va_start(ap, fmt); |
305 | 0 | vfprintf(stderr, fmt, ap); |
306 | 0 | va_end(ap); |
307 | 0 | fprintf(stderr, "\n"); |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | | AP_DECLARE(void) |
312 | | ap_log_rerror_(const char *file, int line, int module_index, int level, apr_status_t status, const request_rec *r, |
313 | 1.99M | const char *fmt, ...) { |
314 | 1.99M | if (level < APLOG_DEBUG) { |
315 | 1.99M | fprintf(stderr, "%s:%d [%d] [%d] ", file, line, level, status); |
316 | 1.99M | va_list ap; |
317 | 1.99M | va_start(ap, fmt); |
318 | 1.99M | vfprintf(stderr, fmt, ap); |
319 | 1.99M | va_end(ap); |
320 | 1.99M | fprintf(stderr, "\n"); |
321 | 1.99M | } |
322 | 1.99M | } |
323 | | |
324 | 0 | AP_DECLARE(void) ap_note_auth_failure(request_rec *r) { |
325 | | // comment explaining why the method is empty |
326 | 0 | } |
327 | | |
328 | | /* capture the response body passed down the output filter chain in the request |
329 | | * state under "sent_body" so tests can assert on generated content; the test |
330 | | * fixture wires request->output_filters->r for this (see test/util.c) */ |
331 | | extern void oidc_request_state_set(request_rec *r, const char *key, const char *value); |
332 | | |
333 | 20 | AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket) { |
334 | 20 | char *buf = NULL; |
335 | 20 | apr_size_t len = 0; |
336 | 20 | if ((filter != NULL) && (filter->r != NULL) && |
337 | 20 | (apr_brigade_pflatten(bucket, &buf, &len, filter->r->pool) == APR_SUCCESS) && (len > 0)) |
338 | 20 | oidc_request_state_set(filter->r, "sent_body", apr_pstrmemdup(filter->r->pool, buf, len)); |
339 | 20 | return APR_SUCCESS; |
340 | 20 | } |
341 | | |
342 | 0 | AP_DECLARE(const apr_array_header_t *) ap_requires(request_rec *r) { |
343 | 0 | return NULL; |
344 | 0 | } |
345 | | |
346 | 74.0k | const char *ap_run_http_scheme(const request_rec *r) { |
347 | 74.0k | char *rv; |
348 | 74.0k | apr_pool_userdata_get((void **)&rv, "scheme", r->pool); |
349 | 74.0k | return (const char *)rv; |
350 | 74.0k | } |
351 | | |
352 | 20 | AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct) { |
353 | | // comment explaining why the method is empty |
354 | 20 | } |
355 | | |
356 | 0 | AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd, void *struct_ptr, int arg) { |
357 | 0 | return ""; |
358 | 0 | } |
359 | | |
360 | 0 | AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd, void *struct_ptr, const char *arg) { |
361 | 0 | return ""; |
362 | 0 | } |
363 | | |
364 | 0 | AP_DECLARE_NONSTD(const char *) ap_set_int_slot(cmd_parms *cmd, void *struct_ptr, const char *arg) { |
365 | 0 | return ""; |
366 | 0 | } |
367 | | |
368 | 6.33k | AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) { |
369 | 6.33k | return 0; |
370 | 6.33k | } |
371 | | |
372 | 6.33k | AP_DECLARE(int) ap_should_client_block(request_rec *r) { |
373 | 6.33k | return 1; |
374 | 6.33k | } |
375 | | |
376 | 156k | AP_DECLARE(int) ap_unescape_url(char *url) { |
377 | 156k | return 0; |
378 | 156k | } |
379 | | |
380 | 0 | AP_DECLARE(apr_status_t) unixd_set_global_mutex_perms(apr_global_mutex_t *gmutex) { |
381 | 0 | return APR_SUCCESS; |
382 | 0 | } |
383 | | |
384 | 4.93k | AP_DECLARE(const char *) ap_get_server_name(request_rec *r) { |
385 | 4.93k | return "www.example.com"; |
386 | 4.93k | } |
387 | | |
388 | 24 | AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file) { |
389 | | /* Apache's real implementation prepends ServerRoot to relative paths; in tests |
390 | | * we treat the path as already-absolute (or relative-to-cwd) and return it verbatim */ |
391 | 24 | if (file == NULL) |
392 | 1 | return NULL; |
393 | 23 | return apr_pstrdup(p, file); |
394 | 24 | } |
395 | | |
396 | 0 | AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c) { |
397 | 0 | _oidc_test_added_input_filter = name; |
398 | 0 | return NULL; |
399 | 0 | } |
400 | | |
401 | 0 | const char *oidc_test_added_input_filter_get(void) { |
402 | 0 | return _oidc_test_added_input_filter; |
403 | 0 | } |
404 | | |
405 | 0 | void oidc_test_added_input_filter_reset(void) { |
406 | 0 | _oidc_test_added_input_filter = NULL; |
407 | 0 | } |
408 | | |
409 | | AP_DECLARE(apr_status_t) |
410 | | ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, |
411 | 0 | apr_off_t readbytes) { |
412 | | /* Return the primed request body followed by EOS; unprimed calls return an empty brigade. */ |
413 | 0 | if (_oidc_test_brigade_body != NULL) { |
414 | 0 | apr_bucket_alloc_t *ba = bucket->bucket_alloc; |
415 | 0 | APR_BRIGADE_INSERT_TAIL( |
416 | 0 | bucket, apr_bucket_heap_create(_oidc_test_brigade_body, strlen(_oidc_test_brigade_body), NULL, ba)); |
417 | 0 | APR_BRIGADE_INSERT_TAIL(bucket, apr_bucket_eos_create(ba)); |
418 | 0 | _oidc_test_brigade_body = NULL; |
419 | 0 | } |
420 | 0 | return _oidc_test_brigade_rc; |
421 | 0 | } |
422 | | |
423 | 0 | void oidc_test_brigade_prime(const char *body, apr_status_t rc) { |
424 | 0 | _oidc_test_brigade_body = body; |
425 | 0 | _oidc_test_brigade_rc = rc; |
426 | 0 | } |
427 | | |
428 | | AP_DECLARE(ap_filter_rec_t *) |
429 | | ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_init_filter_func filter_init, |
430 | 0 | ap_filter_type ftype) { |
431 | 0 | _oidc_test_input_filter = filter_func; |
432 | 0 | return NULL; |
433 | 0 | } |
434 | | |
435 | 0 | oidc_test_input_filter_fn oidc_test_input_filter_get(void) { |
436 | 0 | return _oidc_test_input_filter; |
437 | 0 | } |
438 | | |
439 | 0 | oidc_test_hook_insert_filter_fn oidc_test_hook_insert_filter_get(void) { |
440 | 0 | return _oidc_test_hook_insert_filter; |
441 | 0 | } |
442 | | |
443 | 0 | AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s) { |
444 | 0 | return NULL; |
445 | 0 | } |
446 | | |
447 | 0 | AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) { |
448 | 0 | *result = 1; |
449 | 0 | return APR_SUCCESS; |
450 | 0 | } |
451 | | |
452 | | #if AP_MODULE_MAGIC_AT_LEAST(20080920, 2) |
453 | | AP_DECLARE(apr_status_t) |
454 | 0 | ap_timeout_parameter_parse(const char *timeout_parameter, apr_interval_time_t *timeout, const char *default_time_unit) { |
455 | 0 | char *endp; |
456 | 0 | const char *time_str; |
457 | 0 | apr_int64_t tout; |
458 | |
|
459 | 0 | tout = apr_strtoi64(timeout_parameter, &endp, 10); |
460 | 0 | if (!endp || !*endp) { |
461 | 0 | time_str = default_time_unit; |
462 | 0 | } else { |
463 | 0 | time_str = endp; |
464 | 0 | } |
465 | |
|
466 | 0 | switch (*time_str) { |
467 | | /* Time is in seconds */ |
468 | 0 | case 's': |
469 | 0 | *timeout = (apr_interval_time_t)apr_time_from_sec(tout); |
470 | 0 | break; |
471 | 0 | case 'h': |
472 | | /* Time is in hours */ |
473 | 0 | *timeout = (apr_interval_time_t)apr_time_from_sec(tout * 3600); |
474 | 0 | break; |
475 | 0 | case 'm': |
476 | 0 | switch (*(++time_str)) { |
477 | | /* Time is in milliseconds */ |
478 | 0 | case 's': |
479 | 0 | *timeout = (apr_interval_time_t)tout * 1000; |
480 | 0 | break; |
481 | | /* Time is in minutes */ |
482 | 0 | case 'i': |
483 | 0 | *timeout = (apr_interval_time_t)apr_time_from_sec(tout * 60); |
484 | 0 | break; |
485 | 0 | default: |
486 | 0 | return APR_EGENERAL; |
487 | 0 | } |
488 | 0 | break; |
489 | 0 | default: |
490 | 0 | return APR_EGENERAL; |
491 | 0 | } |
492 | 0 | return APR_SUCCESS; |
493 | 0 | } |
494 | | #endif |
495 | | |
496 | 0 | AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, const char **err) { |
497 | 0 | *err = "error"; |
498 | 0 | return 1; |
499 | 0 | } |