Coverage Report

Created: 2026-09-25 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}