Coverage Report

Created: 2026-09-06 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httpd/srclib/apr/hooks/apr_hooks.c
Line
Count
Source
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <assert.h>
18
#include <stdio.h>
19
#include <stdlib.h>
20
21
#include "apr_pools.h"
22
#include "apr_tables.h"
23
#include "apr.h"
24
#include "apr_hooks.h"
25
#include "apr_hash.h"
26
#include "apr_optional_hooks.h"
27
#include "apr_optional.h"
28
#define APR_WANT_MEMFUNC
29
#define APR_WANT_STRFUNC
30
#include "apr_want.h"
31
32
#if 0
33
#define apr_palloc(pool,size)   malloc(size)
34
#endif
35
36
APR_DECLARE_DATA apr_pool_t *apr_hook_global_pool = NULL;
37
APR_DECLARE_DATA int apr_hook_debug_enabled = 0;
38
APR_DECLARE_DATA const char *apr_hook_debug_current = NULL;
39
40
/** @deprecated @see apr_hook_global_pool */
41
APR_DECLARE_DATA apr_pool_t *apr_global_hook_pool = NULL;
42
43
/** @deprecated @see apr_hook_debug_enabled */
44
APR_DECLARE_DATA int apr_debug_module_hooks = 0;
45
46
/** @deprecated @see apr_hook_debug_current */
47
APR_DECLARE_DATA const char *apr_current_hooking_module = NULL;
48
49
/* NB: This must echo the LINK_##name structure */
50
typedef struct
51
{
52
    void (*dummy)(void *);
53
    const char *szName;
54
    const char * const *aszPredecessors;
55
    const char * const *aszSuccessors;
56
    int nOrder;
57
} TSortData;
58
59
typedef struct tsort_
60
{
61
    void *pData;
62
    int nPredecessors;
63
    struct tsort_ **ppPredecessors;
64
    struct tsort_ *pNext;
65
} TSort;
66
67
static int crude_order(const void *a_,const void *b_)
68
0
{
69
0
    const TSortData *a=a_;
70
0
    const TSortData *b=b_;
71
72
0
    return a->nOrder-b->nOrder;
73
0
}
74
75
static TSort *prepare(apr_pool_t *p,TSortData *pItems,int nItems)
76
0
{
77
0
    TSort *pData=apr_palloc(p,nItems*sizeof *pData);
78
0
    int n;
79
80
0
    qsort(pItems,nItems,sizeof *pItems,crude_order);
81
0
    for(n=0 ; n < nItems ; ++n) {
82
0
        pData[n].nPredecessors=0;
83
0
        pData[n].ppPredecessors=apr_pcalloc(p,nItems*sizeof *pData[n].ppPredecessors);
84
0
        pData[n].pNext=NULL;
85
0
        pData[n].pData=&pItems[n];
86
0
    }
87
88
0
    for(n=0 ; n < nItems ; ++n) {
89
0
        int i,k;
90
91
0
        for(i=0 ; pItems[n].aszPredecessors && pItems[n].aszPredecessors[i] ; ++i)
92
0
            for(k=0 ; k < nItems ; ++k)
93
0
                if(!strcmp(pItems[k].szName,pItems[n].aszPredecessors[i])) {
94
0
                    int l;
95
96
0
                    for(l=0 ; l < pData[n].nPredecessors ; ++l)
97
0
                        if(pData[n].ppPredecessors[l] == &pData[k])
98
0
                            goto got_it;
99
0
                    pData[n].ppPredecessors[pData[n].nPredecessors]=&pData[k];
100
0
                    ++pData[n].nPredecessors;
101
0
                got_it:
102
0
                    break;
103
0
                }
104
0
        for(i=0 ; pItems[n].aszSuccessors && pItems[n].aszSuccessors[i] ; ++i)
105
0
            for(k=0 ; k < nItems ; ++k)
106
0
                if(!strcmp(pItems[k].szName,pItems[n].aszSuccessors[i])) {
107
0
                    int l;
108
109
0
                    for(l=0 ; l < pData[k].nPredecessors ; ++l)
110
0
                        if(pData[k].ppPredecessors[l] == &pData[n])
111
0
                            goto got_it2;
112
0
                    pData[k].ppPredecessors[pData[k].nPredecessors]=&pData[n];
113
0
                    ++pData[k].nPredecessors;
114
0
                got_it2:
115
0
                    break;
116
0
                }
117
0
    }
118
119
0
    return pData;
120
0
}
121
122
/* Topologically sort, dragging out-of-order items to the front. Note that
123
   this tends to preserve things that want to be near the front better, and
124
   changing that behaviour might compromise some of Apache's behaviour (in
125
   particular, mod_log_forensic might otherwise get pushed to the end, and
126
   core.c's log open function used to end up at the end when pushing items
127
   to the back was the methedology). Also note that the algorithm could
128
   go back to its original simplicity by sorting from the back instead of
129
   the front.
130
*/
131
static TSort *tsort(TSort *pData,int nItems)
132
0
{
133
0
    int nTotal;
134
0
    TSort *pHead=NULL;
135
0
    TSort *pTail=NULL;
136
137
0
    for(nTotal=0 ; nTotal < nItems ; ++nTotal) {
138
0
        int n,i,k;
139
140
0
        for(n=0 ; ; ++n) {
141
0
            if(n == nItems)
142
0
                assert(0);      /* we have a loop... */
143
0
            if(!pData[n].pNext) {
144
0
                if(pData[n].nPredecessors) {
145
0
                    for(k=0 ; ; ++k) {
146
0
                        assert(k < nItems);
147
0
                        if(pData[n].ppPredecessors[k])
148
0
                            break;
149
0
                    }
150
0
                    for(i=0 ; ; ++i) {
151
0
                        assert(i < nItems);
152
0
                        if(&pData[i] == pData[n].ppPredecessors[k]) {
153
0
                            n=i-1;
154
0
                            break;
155
0
                        }
156
0
                    }
157
0
                } else
158
0
                    break;
159
0
            }
160
0
        }
161
0
        if(pTail)
162
0
            pTail->pNext=&pData[n];
163
0
        else
164
0
            pHead=&pData[n];
165
0
        pTail=&pData[n];
166
0
        pTail->pNext=pTail;     /* fudge it so it looks linked */
167
0
        for(i=0 ; i < nItems ; ++i)
168
0
            for(k=0 ; k < nItems ; ++k)
169
0
                if(pData[i].ppPredecessors[k] == &pData[n]) {
170
0
                    --pData[i].nPredecessors;
171
0
                    pData[i].ppPredecessors[k]=NULL;
172
0
                    break;
173
0
                }
174
0
    }
175
0
    if(pTail)
176
0
        pTail->pNext=NULL;  /* unfudge the tail */
177
0
    return pHead;
178
0
}
179
180
static apr_array_header_t *sort_hook(apr_array_header_t *pHooks,
181
                                     const char *szName)
182
0
{
183
0
    apr_pool_t *p;
184
0
    TSort *pSort;
185
0
    apr_array_header_t *pNew;
186
0
    int n;
187
188
0
    apr_pool_create(&p, apr_hook_global_pool);
189
0
    pSort=prepare(p,(TSortData *)pHooks->elts,pHooks->nelts);
190
0
    pSort=tsort(pSort,pHooks->nelts);
191
0
    pNew=apr_array_make(apr_hook_global_pool,pHooks->nelts,sizeof(TSortData));
192
0
    if(apr_hook_debug_enabled)
193
0
        printf("Sorting %s:",szName);
194
0
    for(n=0 ; pSort ; pSort=pSort->pNext,++n) {
195
0
        TSortData *pHook;
196
0
        assert(n < pHooks->nelts);
197
0
        pHook=apr_array_push(pNew);
198
0
        memcpy(pHook,pSort->pData,sizeof *pHook);
199
0
        if(apr_hook_debug_enabled)
200
0
            printf(" %s",pHook->szName);
201
0
    }
202
0
    if(apr_hook_debug_enabled)
203
0
        fputc('\n',stdout);
204
205
    /* destroy the pool - the sorted hooks were already copied */
206
0
    apr_pool_destroy(p);
207
208
0
    return pNew;
209
0
}
210
211
static apr_array_header_t *s_aHooksToSort;
212
213
typedef struct
214
{
215
    const char *szHookName;
216
    apr_array_header_t **paHooks;
217
} HookSortEntry;
218
219
APR_DECLARE(void) apr_hook_sort_register(const char *szHookName,
220
                                        apr_array_header_t **paHooks)
221
2
{
222
2
    HookSortEntry *pEntry;
223
224
2
    if(!s_aHooksToSort)
225
2
        s_aHooksToSort=apr_array_make(apr_hook_global_pool,1,sizeof(HookSortEntry));
226
2
    pEntry=apr_array_push(s_aHooksToSort);
227
2
    pEntry->szHookName=szHookName;
228
2
    pEntry->paHooks=paHooks;
229
2
}
230
231
APR_DECLARE(void) apr_hook_sort_all(void)
232
0
{
233
0
    int n;
234
235
0
    if (!s_aHooksToSort) {
236
0
        s_aHooksToSort = apr_array_make(apr_hook_global_pool, 1, sizeof(HookSortEntry));
237
0
    }
238
239
0
    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
240
0
        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
241
0
        *pEntry->paHooks=sort_hook(*pEntry->paHooks,pEntry->szHookName);
242
0
    }
243
0
}
244
245
static apr_hash_t *s_phOptionalHooks;
246
static apr_hash_t *s_phOptionalFunctions;
247
248
APR_DECLARE(void) apr_hook_deregister_all(void)
249
0
{
250
0
    int n;
251
252
0
    if (!s_aHooksToSort) {
253
0
        return;
254
0
    }
255
256
0
    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
257
0
        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
258
0
        *pEntry->paHooks=NULL;
259
0
    }
260
0
    s_aHooksToSort=NULL;
261
0
    s_phOptionalHooks=NULL;
262
0
    s_phOptionalFunctions=NULL;
263
0
}
264
265
APR_DECLARE(void) apr_hook_debug_show(const char *szName,
266
                                      const char * const *aszPre,
267
                                      const char * const *aszSucc)
268
0
{
269
0
    int nFirst;
270
271
0
    printf("  Hooked %s",szName);
272
0
    if(aszPre) {
273
0
        fputs(" pre(",stdout);
274
0
        nFirst=1;
275
0
        while(*aszPre) {
276
0
            if(!nFirst)
277
0
                fputc(',',stdout);
278
0
            nFirst=0;
279
0
            fputs(*aszPre,stdout);
280
0
            ++aszPre;
281
0
        }
282
0
        fputc(')',stdout);
283
0
    }
284
0
    if(aszSucc) {
285
0
        fputs(" succ(",stdout);
286
0
        nFirst=1;
287
0
        while(*aszSucc) {
288
0
            if(!nFirst)
289
0
                fputc(',',stdout);
290
0
            nFirst=0;
291
0
            fputs(*aszSucc,stdout);
292
0
            ++aszSucc;
293
0
        }
294
0
        fputc(')',stdout);
295
0
    }
296
0
    fputc('\n',stdout);
297
0
}
298
299
/* Optional hook support */
300
301
APR_DECLARE_EXTERNAL_HOOK(apr,APR,void,_optional,(void))
302
303
APR_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName)
304
0
{
305
0
    apr_array_header_t **ppArray;
306
307
0
    if(!s_phOptionalHooks)
308
0
        return NULL;
309
0
    ppArray=apr_hash_get(s_phOptionalHooks,szName,strlen(szName));
310
0
    if(!ppArray)
311
0
        return NULL;
312
0
    return *ppArray;
313
0
}
314
315
APR_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
316
                                        const char * const *aszPre,
317
                                        const char * const *aszSucc,int nOrder)
318
0
{
319
0
    apr_array_header_t *pArray=apr_optional_hook_get(szName);
320
0
    apr_LINK__optional_t *pHook;
321
322
0
    if(!pArray) {
323
0
        apr_array_header_t **ppArray;
324
325
0
        pArray=apr_array_make(apr_hook_global_pool,1,
326
0
                              sizeof(apr_LINK__optional_t));
327
0
        if(!s_phOptionalHooks)
328
0
            s_phOptionalHooks=apr_hash_make(apr_hook_global_pool);
329
0
        ppArray=apr_palloc(apr_hook_global_pool,sizeof *ppArray);
330
0
        *ppArray=pArray;
331
0
        apr_hash_set(s_phOptionalHooks,szName,strlen(szName),ppArray);
332
0
        apr_hook_sort_register(szName,ppArray);
333
0
    }
334
0
    pHook=apr_array_push(pArray);
335
0
    pHook->pFunc=pfn;
336
0
    pHook->aszPredecessors=aszPre;
337
0
    pHook->aszSuccessors=aszSucc;
338
0
    pHook->nOrder=nOrder;
339
0
    pHook->szName=apr_hook_debug_current;
340
0
    if(apr_hook_debug_enabled)
341
0
        apr_hook_debug_show(szName,aszPre,aszSucc);
342
0
}
343
344
/* optional function support */
345
346
APR_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
347
0
{
348
0
    if(!s_phOptionalFunctions)
349
0
        return NULL;
350
0
    return (void(*)(void))apr_hash_get(s_phOptionalFunctions,szName,strlen(szName));
351
0
}
352
353
/* Deprecated */
354
APR_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
355
                                                  apr_opt_fn_t *pfn)
356
0
{
357
0
    if(!s_phOptionalFunctions)
358
0
        s_phOptionalFunctions=apr_hash_make(apr_hook_global_pool);
359
0
    apr_hash_set(s_phOptionalFunctions,szName,strlen(szName),(void *)pfn);
360
0
}
361
362
#if 0
363
void main()
364
{
365
    const char *aszAPre[]={"b","c",NULL};
366
    const char *aszBPost[]={"a",NULL};
367
    const char *aszCPost[]={"b",NULL};
368
    TSortData t1[]=
369
    {
370
        { "a",aszAPre,NULL },
371
        { "b",NULL,aszBPost },
372
        { "c",NULL,aszCPost }
373
    };
374
    TSort *pResult;
375
376
    pResult=prepare(t1,3);
377
    pResult=tsort(pResult,3);
378
379
    for( ; pResult ; pResult=pResult->pNext)
380
        printf("%s\n",pResult->pData->szName);
381
}
382
#endif