Coverage Report

Created: 2026-08-31 07:13

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