Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/hooks/apr_hooks.c
Line
Count
Source (jump to first uncovered line)
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
#ifdef NETWARE
68
#include "apr_private.h"
69
#define get_apd                 APP_DATA* apd = (APP_DATA*)get_app_data(gLibId);
70
#define s_aHooksToSort          ((apr_array_header_t *)(apd->gs_aHooksToSort))
71
#define s_phOptionalHooks       ((apr_hash_t *)(apd->gs_phOptionalHooks))
72
#define s_phOptionalFunctions   ((apr_hash_t *)(apd->gs_phOptionalFunctions))
73
#endif
74
75
static int crude_order(const void *a_,const void *b_)
76
0
{
77
0
    const TSortData *a=a_;
78
0
    const TSortData *b=b_;
79
80
0
    return a->nOrder-b->nOrder;
81
0
}
82
83
static TSort *prepare(apr_pool_t *p,TSortData *pItems,int nItems)
84
0
{
85
0
    TSort *pData=apr_palloc(p,nItems*sizeof *pData);
86
0
    int n;
87
88
0
    qsort(pItems,nItems,sizeof *pItems,crude_order);
89
0
    for(n=0 ; n < nItems ; ++n) {
90
0
        pData[n].nPredecessors=0;
91
0
        pData[n].ppPredecessors=apr_pcalloc(p,nItems*sizeof *pData[n].ppPredecessors);
92
0
        pData[n].pNext=NULL;
93
0
        pData[n].pData=&pItems[n];
94
0
    }
95
96
0
    for(n=0 ; n < nItems ; ++n) {
97
0
        int i,k;
98
99
0
        for(i=0 ; pItems[n].aszPredecessors && pItems[n].aszPredecessors[i] ; ++i)
100
0
            for(k=0 ; k < nItems ; ++k)
101
0
                if(!strcmp(pItems[k].szName,pItems[n].aszPredecessors[i])) {
102
0
                    int l;
103
104
0
                    for(l=0 ; l < pData[n].nPredecessors ; ++l)
105
0
                        if(pData[n].ppPredecessors[l] == &pData[k])
106
0
                            goto got_it;
107
0
                    pData[n].ppPredecessors[pData[n].nPredecessors]=&pData[k];
108
0
                    ++pData[n].nPredecessors;
109
0
                got_it:
110
0
                    break;
111
0
                }
112
0
        for(i=0 ; pItems[n].aszSuccessors && pItems[n].aszSuccessors[i] ; ++i)
113
0
            for(k=0 ; k < nItems ; ++k)
114
0
                if(!strcmp(pItems[k].szName,pItems[n].aszSuccessors[i])) {
115
0
                    int l;
116
117
0
                    for(l=0 ; l < pData[k].nPredecessors ; ++l)
118
0
                        if(pData[k].ppPredecessors[l] == &pData[n])
119
0
                            goto got_it2;
120
0
                    pData[k].ppPredecessors[pData[k].nPredecessors]=&pData[n];
121
0
                    ++pData[k].nPredecessors;
122
0
                got_it2:
123
0
                    break;
124
0
                }
125
0
    }
126
127
0
    return pData;
128
0
}
129
130
/* Topologically sort, dragging out-of-order items to the front. Note that
131
   this tends to preserve things that want to be near the front better, and
132
   changing that behaviour might compromise some of Apache's behaviour (in
133
   particular, mod_log_forensic might otherwise get pushed to the end, and
134
   core.c's log open function used to end up at the end when pushing items
135
   to the back was the methedology). Also note that the algorithm could
136
   go back to its original simplicity by sorting from the back instead of
137
   the front.
138
*/
139
static TSort *tsort(TSort *pData,int nItems)
140
0
{
141
0
    int nTotal;
142
0
    TSort *pHead=NULL;
143
0
    TSort *pTail=NULL;
144
145
0
    for(nTotal=0 ; nTotal < nItems ; ++nTotal) {
146
0
        int n,i,k;
147
148
0
        for(n=0 ; ; ++n) {
149
0
            if(n == nItems)
150
0
                assert(0);      /* we have a loop... */
151
0
            if(!pData[n].pNext) {
152
0
                if(pData[n].nPredecessors) {
153
0
                    for(k=0 ; ; ++k) {
154
0
                        assert(k < nItems);
155
0
                        if(pData[n].ppPredecessors[k])
156
0
                            break;
157
0
                    }
158
0
                    for(i=0 ; ; ++i) {
159
0
                        assert(i < nItems);
160
0
                        if(&pData[i] == pData[n].ppPredecessors[k]) {
161
0
                            n=i-1;
162
0
                            break;
163
0
                        }
164
0
                    }
165
0
                } else
166
0
                    break;
167
0
            }
168
0
        }
169
0
        if(pTail)
170
0
            pTail->pNext=&pData[n];
171
0
        else
172
0
            pHead=&pData[n];
173
0
        pTail=&pData[n];
174
0
        pTail->pNext=pTail;     /* fudge it so it looks linked */
175
0
        for(i=0 ; i < nItems ; ++i)
176
0
            for(k=0 ; k < nItems ; ++k)
177
0
                if(pData[i].ppPredecessors[k] == &pData[n]) {
178
0
                    --pData[i].nPredecessors;
179
0
                    pData[i].ppPredecessors[k]=NULL;
180
0
                    break;
181
0
                }
182
0
    }
183
0
    if(pTail)
184
0
        pTail->pNext=NULL;  /* unfudge the tail */
185
0
    return pHead;
186
0
}
187
188
static apr_array_header_t *sort_hook(apr_array_header_t *pHooks,
189
                                     const char *szName)
190
0
{
191
0
    apr_pool_t *p;
192
0
    TSort *pSort;
193
0
    apr_array_header_t *pNew;
194
0
    int n;
195
196
0
    apr_pool_create(&p, apr_hook_global_pool);
197
0
    pSort=prepare(p,(TSortData *)pHooks->elts,pHooks->nelts);
198
0
    pSort=tsort(pSort,pHooks->nelts);
199
0
    pNew=apr_array_make(apr_hook_global_pool,pHooks->nelts,sizeof(TSortData));
200
0
    if(apr_hook_debug_enabled)
201
0
        printf("Sorting %s:",szName);
202
0
    for(n=0 ; pSort ; pSort=pSort->pNext,++n) {
203
0
        TSortData *pHook;
204
0
        assert(n < pHooks->nelts);
205
0
        pHook=apr_array_push(pNew);
206
0
        memcpy(pHook,pSort->pData,sizeof *pHook);
207
0
        if(apr_hook_debug_enabled)
208
0
            printf(" %s",pHook->szName);
209
0
    }
210
0
    if(apr_hook_debug_enabled)
211
0
        fputc('\n',stdout);
212
213
    /* destroy the pool - the sorted hooks were already copied */
214
0
    apr_pool_destroy(p);
215
216
0
    return pNew;
217
0
}
218
219
#ifndef NETWARE
220
static apr_array_header_t *s_aHooksToSort;
221
#endif
222
223
typedef struct
224
{
225
    const char *szHookName;
226
    apr_array_header_t **paHooks;
227
} HookSortEntry;
228
229
APR_DECLARE(void) apr_hook_sort_register(const char *szHookName,
230
                                        apr_array_header_t **paHooks)
231
2
{
232
#ifdef NETWARE
233
    get_apd
234
#endif
235
2
    HookSortEntry *pEntry;
236
237
2
    if(!s_aHooksToSort)
238
2
        s_aHooksToSort=apr_array_make(apr_hook_global_pool,1,sizeof(HookSortEntry));
239
2
    pEntry=apr_array_push(s_aHooksToSort);
240
2
    pEntry->szHookName=szHookName;
241
2
    pEntry->paHooks=paHooks;
242
2
}
243
244
APR_DECLARE(void) apr_hook_sort_all(void)
245
0
{
246
#ifdef NETWARE
247
    get_apd
248
#endif
249
0
    int n;
250
251
0
    if (!s_aHooksToSort) {
252
0
        s_aHooksToSort = apr_array_make(apr_hook_global_pool, 1, sizeof(HookSortEntry));
253
0
    }
254
255
0
    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
256
0
        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
257
0
        *pEntry->paHooks=sort_hook(*pEntry->paHooks,pEntry->szHookName);
258
0
    }
259
0
}
260
261
#ifndef NETWARE
262
static apr_hash_t *s_phOptionalHooks;
263
static apr_hash_t *s_phOptionalFunctions;
264
#endif
265
266
APR_DECLARE(void) apr_hook_deregister_all(void)
267
0
{
268
#ifdef NETWARE
269
    get_apd
270
#endif
271
0
    int n;
272
273
0
    if (!s_aHooksToSort) {
274
0
        return;
275
0
    }
276
277
0
    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
278
0
        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
279
0
        *pEntry->paHooks=NULL;
280
0
    }
281
0
    s_aHooksToSort=NULL;
282
0
    s_phOptionalHooks=NULL;
283
0
    s_phOptionalFunctions=NULL;
284
0
}
285
286
APR_DECLARE(void) apr_hook_debug_show(const char *szName,
287
                                      const char * const *aszPre,
288
                                      const char * const *aszSucc)
289
0
{
290
0
    int nFirst;
291
292
0
    printf("  Hooked %s",szName);
293
0
    if(aszPre) {
294
0
        fputs(" pre(",stdout);
295
0
        nFirst=1;
296
0
        while(*aszPre) {
297
0
            if(!nFirst)
298
0
                fputc(',',stdout);
299
0
            nFirst=0;
300
0
            fputs(*aszPre,stdout);
301
0
            ++aszPre;
302
0
        }
303
0
        fputc(')',stdout);
304
0
    }
305
0
    if(aszSucc) {
306
0
        fputs(" succ(",stdout);
307
0
        nFirst=1;
308
0
        while(*aszSucc) {
309
0
            if(!nFirst)
310
0
                fputc(',',stdout);
311
0
            nFirst=0;
312
0
            fputs(*aszSucc,stdout);
313
0
            ++aszSucc;
314
0
        }
315
0
        fputc(')',stdout);
316
0
    }
317
0
    fputc('\n',stdout);
318
0
}
319
320
/* Optional hook support */
321
322
APR_DECLARE_EXTERNAL_HOOK(apr,APR,void,_optional,(void))
323
324
APR_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName)
325
0
{
326
#ifdef NETWARE
327
    get_apd
328
#endif
329
0
    apr_array_header_t **ppArray;
330
331
0
    if(!s_phOptionalHooks)
332
0
        return NULL;
333
0
    ppArray=apr_hash_get(s_phOptionalHooks,szName,strlen(szName));
334
0
    if(!ppArray)
335
0
        return NULL;
336
0
    return *ppArray;
337
0
}
338
339
APR_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
340
                                        const char * const *aszPre,
341
                                        const char * const *aszSucc,int nOrder)
342
0
{
343
#ifdef NETWARE
344
    get_apd
345
#endif
346
0
    apr_array_header_t *pArray=apr_optional_hook_get(szName);
347
0
    apr_LINK__optional_t *pHook;
348
349
0
    if(!pArray) {
350
0
        apr_array_header_t **ppArray;
351
352
0
        pArray=apr_array_make(apr_hook_global_pool,1,
353
0
                              sizeof(apr_LINK__optional_t));
354
0
        if(!s_phOptionalHooks)
355
0
            s_phOptionalHooks=apr_hash_make(apr_hook_global_pool);
356
0
        ppArray=apr_palloc(apr_hook_global_pool,sizeof *ppArray);
357
0
        *ppArray=pArray;
358
0
        apr_hash_set(s_phOptionalHooks,szName,strlen(szName),ppArray);
359
0
        apr_hook_sort_register(szName,ppArray);
360
0
    }
361
0
    pHook=apr_array_push(pArray);
362
0
    pHook->pFunc=pfn;
363
0
    pHook->aszPredecessors=aszPre;
364
0
    pHook->aszSuccessors=aszSucc;
365
0
    pHook->nOrder=nOrder;
366
0
    pHook->szName=apr_hook_debug_current;
367
0
    if(apr_hook_debug_enabled)
368
0
        apr_hook_debug_show(szName,aszPre,aszSucc);
369
0
}
370
371
/* optional function support */
372
373
APR_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
374
0
{
375
#ifdef NETWARE
376
    get_apd
377
#endif
378
0
    if(!s_phOptionalFunctions)
379
0
        return NULL;
380
0
    return (void(*)(void))apr_hash_get(s_phOptionalFunctions,szName,strlen(szName));
381
0
}
382
383
/* Deprecated */
384
APR_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
385
                                                  apr_opt_fn_t *pfn)
386
0
{
387
#ifdef NETWARE
388
    get_apd
389
#endif
390
0
    if(!s_phOptionalFunctions)
391
0
        s_phOptionalFunctions=apr_hash_make(apr_hook_global_pool);
392
0
    apr_hash_set(s_phOptionalFunctions,szName,strlen(szName),(void *)pfn);
393
0
}
394
395
#if 0
396
void main()
397
{
398
    const char *aszAPre[]={"b","c",NULL};
399
    const char *aszBPost[]={"a",NULL};
400
    const char *aszCPost[]={"b",NULL};
401
    TSortData t1[]=
402
    {
403
        { "a",aszAPre,NULL },
404
        { "b",NULL,aszBPost },
405
        { "c",NULL,aszCPost }
406
    };
407
    TSort *pResult;
408
409
    pResult=prepare(t1,3);
410
    pResult=tsort(pResult,3);
411
412
    for( ; pResult ; pResult=pResult->pNext)
413
        printf("%s\n",pResult->pData->szName);
414
}
415
#endif