~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr-util/xlate/xlate.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * 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 "apu.h"
 
18
#include "apu_config.h"
 
19
#include "apr_lib.h"
 
20
#include "apr_strings.h"
 
21
#include "apr_portable.h"
 
22
#include "apr_xlate.h"
 
23
 
 
24
/* If no implementation is available, don't generate code here since
 
25
 * apr_xlate.h emitted macros which return APR_ENOTIMPL.
 
26
 */
 
27
 
 
28
#if APR_HAS_XLATE
 
29
 
 
30
#ifdef HAVE_STDDEF_H
 
31
#include <stddef.h> /* for NULL */
 
32
#endif
 
33
#if APR_HAVE_STRING_H
 
34
#include <string.h>
 
35
#endif
 
36
#if APR_HAVE_STRINGS_H
 
37
#include <strings.h>
 
38
#endif
 
39
#ifdef HAVE_ICONV_H
 
40
#include <iconv.h>
 
41
#endif
 
42
#if APU_HAVE_APR_ICONV
 
43
#include <apr_iconv.h>
 
44
#endif
 
45
 
 
46
#if defined(APU_ICONV_INBUF_CONST) || APU_HAVE_APR_ICONV
 
47
#define ICONV_INBUF_TYPE const char **
 
48
#else
 
49
#define ICONV_INBUF_TYPE char **
 
50
#endif
 
51
 
 
52
#ifndef min
 
53
#define min(x,y) ((x) <= (y) ? (x) : (y))
 
54
#endif
 
55
 
 
56
struct apr_xlate_t {
 
57
    apr_pool_t *pool;
 
58
    char *frompage;
 
59
    char *topage;
 
60
    char *sbcs_table;
 
61
#if APU_HAVE_ICONV
 
62
    iconv_t ich;
 
63
#elif APU_HAVE_APR_ICONV
 
64
    apr_iconv_t ich;
 
65
#endif
 
66
};
 
67
 
 
68
 
 
69
static const char *handle_special_names(const char *page, apr_pool_t *pool)
 
70
{
 
71
    if (page == APR_DEFAULT_CHARSET) {
 
72
        return apr_os_default_encoding(pool);
 
73
    }
 
74
    else if (page == APR_LOCALE_CHARSET) {
 
75
        return apr_os_locale_encoding(pool);
 
76
    }
 
77
    else {
 
78
        return page;
 
79
    }
 
80
}
 
81
 
 
82
static apr_status_t apr_xlate_cleanup(void *convset)
 
83
{
 
84
    apr_xlate_t *old = convset;
 
85
 
 
86
#if APU_HAVE_APR_ICONV
 
87
    if (old->ich != (apr_iconv_t)-1) {
 
88
        return apr_iconv_close(old->ich, old->pool);
 
89
    }
 
90
 
 
91
#elif APU_HAVE_ICONV
 
92
    if (old->ich != (iconv_t)-1) {
 
93
        if (iconv_close(old->ich)) {
 
94
            int rv = errno;
 
95
 
 
96
            /* Sometimes, iconv is not good about setting errno. */
 
97
            return rv ? rv : APR_EINVAL;
 
98
        }
 
99
    }
 
100
#endif
 
101
 
 
102
    return APR_SUCCESS;
 
103
}
 
104
 
 
105
#if APU_HAVE_ICONV
 
106
static void check_sbcs(apr_xlate_t *convset)
 
107
{
 
108
    char inbuf[256], outbuf[256];
 
109
    char *inbufptr = inbuf;
 
110
    char *outbufptr = outbuf;
 
111
    apr_size_t inbytes_left, outbytes_left;
 
112
    int i;
 
113
    apr_size_t translated;
 
114
 
 
115
    for (i = 0; i < sizeof(inbuf); i++) {
 
116
        inbuf[i] = i;
 
117
    }
 
118
 
 
119
    inbytes_left = outbytes_left = sizeof(inbuf);
 
120
    translated = iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr,
 
121
                       &inbytes_left, &outbufptr, &outbytes_left);
 
122
 
 
123
    if (translated != (apr_size_t)-1
 
124
        && inbytes_left == 0
 
125
        && outbytes_left == 0) {
 
126
        /* hurray... this is simple translation; save the table,
 
127
         * close the iconv descriptor
 
128
         */
 
129
 
 
130
        convset->sbcs_table = apr_palloc(convset->pool, sizeof(outbuf));
 
131
        memcpy(convset->sbcs_table, outbuf, sizeof(outbuf));
 
132
        iconv_close(convset->ich);
 
133
        convset->ich = (iconv_t)-1;
 
134
 
 
135
        /* TODO: add the table to the cache */
 
136
    }
 
137
    else {
 
138
        /* reset the iconv descriptor, since it's now in an undefined
 
139
         * state. */
 
140
        iconv_close(convset->ich);
 
141
        convset->ich = iconv_open(convset->topage, convset->frompage);
 
142
    }
 
143
}
 
144
#elif APU_HAVE_APR_ICONV
 
145
static void check_sbcs(apr_xlate_t *convset)
 
146
{
 
147
    char inbuf[256], outbuf[256];
 
148
    char *inbufptr = inbuf;
 
149
    char *outbufptr = outbuf;
 
150
    apr_size_t inbytes_left, outbytes_left;
 
151
    int i;
 
152
    apr_size_t translated;
 
153
    apr_status_t rv;
 
154
 
 
155
    for (i = 0; i < sizeof(inbuf); i++) {
 
156
        inbuf[i] = i;
 
157
    }
 
158
 
 
159
    inbytes_left = outbytes_left = sizeof(inbuf);
 
160
    rv = apr_iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr,
 
161
                   &inbytes_left, &outbufptr, &outbytes_left,
 
162
                   &translated);
 
163
 
 
164
    if ((rv == APR_SUCCESS)
 
165
        && (translated != (apr_size_t)-1)
 
166
        && inbytes_left == 0
 
167
        && outbytes_left == 0) {
 
168
        /* hurray... this is simple translation; save the table,
 
169
         * close the iconv descriptor
 
170
         */
 
171
 
 
172
        convset->sbcs_table = apr_palloc(convset->pool, sizeof(outbuf));
 
173
        memcpy(convset->sbcs_table, outbuf, sizeof(outbuf));
 
174
        apr_iconv_close(convset->ich, convset->pool);
 
175
        convset->ich = (apr_iconv_t)-1;
 
176
 
 
177
        /* TODO: add the table to the cache */
 
178
    }
 
179
    else {
 
180
        /* reset the iconv descriptor, since it's now in an undefined
 
181
         * state. */
 
182
        apr_iconv_close(convset->ich, convset->pool);
 
183
        rv = apr_iconv_open(convset->topage, convset->frompage, 
 
184
                            convset->pool, &convset->ich);
 
185
    }
 
186
}
 
187
#endif /* APU_HAVE_APR_ICONV */
 
188
 
 
189
static void make_identity_table(apr_xlate_t *convset)
 
190
{
 
191
  int i;
 
192
 
 
193
  convset->sbcs_table = apr_palloc(convset->pool, 256);
 
194
  for (i = 0; i < 256; i++)
 
195
      convset->sbcs_table[i] = i;
 
196
}
 
197
 
 
198
APU_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset,
 
199
                                         const char *topage,
 
200
                                         const char *frompage,
 
201
                                         apr_pool_t *pool)
 
202
{
 
203
    apr_status_t rv;
 
204
    apr_xlate_t *new;
 
205
    int found = 0;
 
206
 
 
207
    *convset = NULL;
 
208
 
 
209
    topage = handle_special_names(topage, pool);
 
210
    frompage = handle_special_names(frompage, pool);
 
211
 
 
212
    new = (apr_xlate_t *)apr_pcalloc(pool, sizeof(apr_xlate_t));
 
213
    if (!new) {
 
214
        return APR_ENOMEM;
 
215
    }
 
216
 
 
217
    new->pool = pool;
 
218
    new->topage = apr_pstrdup(pool, topage);
 
219
    new->frompage = apr_pstrdup(pool, frompage);
 
220
    if (!new->topage || !new->frompage) {
 
221
        return APR_ENOMEM;
 
222
    }
 
223
 
 
224
#ifdef TODO
 
225
    /* search cache of codepage pairs; we may be able to avoid the
 
226
     * expensive iconv_open()
 
227
     */
 
228
 
 
229
    set found to non-zero if found in the cache
 
230
#endif
 
231
 
 
232
    if ((! found) && (strcmp(topage, frompage) == 0)) {
 
233
        /* to and from are the same */
 
234
        found = 1;
 
235
        make_identity_table(new);
 
236
    }
 
237
 
 
238
#if APU_HAVE_APR_ICONV
 
239
    if (!found) {
 
240
        rv = apr_iconv_open(topage, frompage, pool, &new->ich);
 
241
        if (rv != APR_SUCCESS) {
 
242
            return rv;
 
243
        }
 
244
        found = 1;
 
245
        check_sbcs(new);
 
246
    } else
 
247
        new->ich = (apr_iconv_t)-1;
 
248
 
 
249
#elif APU_HAVE_ICONV
 
250
    if (!found) {
 
251
        new->ich = iconv_open(topage, frompage);
 
252
        if (new->ich == (iconv_t)-1) {
 
253
            int rv = errno;
 
254
            /* Sometimes, iconv is not good about setting errno. */
 
255
            return rv ? rv : APR_EINVAL;
 
256
        }
 
257
        found = 1;
 
258
        check_sbcs(new);
 
259
    } else
 
260
        new->ich = (iconv_t)-1;
 
261
#endif /* APU_HAVE_ICONV */
 
262
 
 
263
    if (found) {
 
264
        *convset = new;
 
265
        apr_pool_cleanup_register(pool, (void *)new, apr_xlate_cleanup,
 
266
                            apr_pool_cleanup_null);
 
267
        rv = APR_SUCCESS;
 
268
    }
 
269
    else {
 
270
        rv = APR_EINVAL; /* iconv() would return EINVAL if it
 
271
                                couldn't handle the pair */
 
272
    }
 
273
 
 
274
    return rv;
 
275
}
 
276
 
 
277
APU_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff)
 
278
{
 
279
    *onoff = convset->sbcs_table != NULL;
 
280
    return APR_SUCCESS;
 
281
}
 
282
 
 
283
APU_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset,
 
284
                                                const char *inbuf,
 
285
                                                apr_size_t *inbytes_left,
 
286
                                                char *outbuf,
 
287
                                                apr_size_t *outbytes_left)
 
288
{
 
289
    apr_status_t status = APR_SUCCESS;
 
290
 
 
291
#if APU_HAVE_APR_ICONV
 
292
    if (convset->ich != (apr_iconv_t)-1) {
 
293
        const char *inbufptr = inbuf;
 
294
        apr_size_t translated;
 
295
        char *outbufptr = outbuf;
 
296
        status = apr_iconv(convset->ich, &inbufptr, inbytes_left,
 
297
                           &outbufptr, outbytes_left, &translated);
 
298
 
 
299
        /* If everything went fine but we ran out of buffer, don't
 
300
         * report it as an error.  Caller needs to look at the two
 
301
         * bytes-left values anyway.
 
302
         *
 
303
         * There are three expected cases where rc is -1.  In each of
 
304
         * these cases, *inbytes_left != 0.
 
305
         * a) the non-error condition where we ran out of output
 
306
         *    buffer
 
307
         * b) the non-error condition where we ran out of input (i.e.,
 
308
         *    the last input character is incomplete)
 
309
         * c) the error condition where the input is invalid
 
310
         */
 
311
        switch (status) {
 
312
 
 
313
            case E2BIG:  /* out of space on output */
 
314
                status = 0; /* change table lookup code below if you
 
315
                               make this an error */
 
316
                break;
 
317
 
 
318
            case EINVAL: /* input character not complete (yet) */
 
319
                status = APR_INCOMPLETE;
 
320
                break;
 
321
 
 
322
            case EILSEQ: /* bad input byte */
 
323
                status = APR_EINVAL;
 
324
                break;
 
325
 
 
326
             /* Sometimes, iconv is not good about setting errno. */
 
327
            case 0:
 
328
                if (*inbytes_left)
 
329
                    status = APR_INCOMPLETE;
 
330
                break;
 
331
 
 
332
            default:
 
333
                break;
 
334
        }
 
335
    }
 
336
    else
 
337
 
 
338
#elif APU_HAVE_ICONV
 
339
    if (convset->ich != (iconv_t)-1) {
 
340
        const char *inbufptr = inbuf;
 
341
        char *outbufptr = outbuf;
 
342
        apr_size_t translated;
 
343
        translated = iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr,
 
344
                           inbytes_left, &outbufptr, outbytes_left);
 
345
 
 
346
        /* If everything went fine but we ran out of buffer, don't
 
347
         * report it as an error.  Caller needs to look at the two
 
348
         * bytes-left values anyway.
 
349
         *
 
350
         * There are three expected cases where rc is -1.  In each of
 
351
         * these cases, *inbytes_left != 0.
 
352
         * a) the non-error condition where we ran out of output
 
353
         *    buffer
 
354
         * b) the non-error condition where we ran out of input (i.e.,
 
355
         *    the last input character is incomplete)
 
356
         * c) the error condition where the input is invalid
 
357
         */
 
358
        if (translated == (apr_size_t)-1) {
 
359
            int rv = errno;
 
360
            switch (rv) {
 
361
 
 
362
            case E2BIG:  /* out of space on output */
 
363
                status = 0; /* change table lookup code below if you
 
364
                               make this an error */
 
365
                break;
 
366
 
 
367
            case EINVAL: /* input character not complete (yet) */
 
368
                status = APR_INCOMPLETE;
 
369
                break;
 
370
 
 
371
            case EILSEQ: /* bad input byte */
 
372
                status = APR_EINVAL;
 
373
                break;
 
374
 
 
375
             /* Sometimes, iconv is not good about setting errno. */
 
376
            case 0:
 
377
                status = APR_INCOMPLETE;
 
378
                break;
 
379
 
 
380
            default:
 
381
                status = rv;
 
382
                break;
 
383
            }
 
384
        }
 
385
    }
 
386
    else
 
387
#endif
 
388
 
 
389
    if (inbuf) {
 
390
        int to_convert = min(*inbytes_left, *outbytes_left);
 
391
        int converted = to_convert;
 
392
        char *table = convset->sbcs_table;
 
393
 
 
394
        while (to_convert) {
 
395
            *outbuf = table[(unsigned char)*inbuf];
 
396
            ++outbuf;
 
397
            ++inbuf;
 
398
            --to_convert;
 
399
        }
 
400
        *inbytes_left -= converted;
 
401
        *outbytes_left -= converted;
 
402
    }
 
403
 
 
404
    return status;
 
405
}
 
406
 
 
407
APU_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset,
 
408
                                             unsigned char inchar)
 
409
{
 
410
    if (convset->sbcs_table) {
 
411
        return convset->sbcs_table[inchar];
 
412
    }
 
413
    else {
 
414
        return -1;
 
415
    }
 
416
}
 
417
 
 
418
APU_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset)
 
419
{
 
420
    return apr_pool_cleanup_run(convset->pool, convset, apr_xlate_cleanup);
 
421
}
 
422
 
 
423
#else /* !APR_HAS_XLATE */
 
424
 
 
425
APU_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset,
 
426
                                         const char *topage,
 
427
                                         const char *frompage,
 
428
                                         apr_pool_t *pool)
 
429
{
 
430
    return APR_ENOTIMPL;
 
431
}
 
432
 
 
433
APU_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff)
 
434
{
 
435
    return APR_ENOTIMPL;
 
436
}
 
437
 
 
438
APU_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset,
 
439
                                             unsigned char inchar)
 
440
{
 
441
    return (-1);
 
442
}
 
443
 
 
444
APU_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset,
 
445
                                                const char *inbuf,
 
446
                                                apr_size_t *inbytes_left,
 
447
                                                char *outbuf,
 
448
                                                apr_size_t *outbytes_left)
 
449
{
 
450
    return APR_ENOTIMPL;
 
451
}
 
452
 
 
453
APU_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset)
 
454
{
 
455
    return APR_ENOTIMPL;
 
456
}
 
457
 
 
458
#endif /* APR_HAS_XLATE */