"Fossies" - the Fresh Open Source Software Archive

Member "haproxy-2.0.8/src/chunk.c" (23 Oct 2019, 7820 Bytes) of package /linux/misc/haproxy-2.0.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "chunk.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Chunk management functions.
    3  *
    4  * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
    5  *
    6  * This program is free software; you can redistribute it and/or
    7  * modify it under the terms of the GNU General Public License
    8  * as published by the Free Software Foundation; either version
    9  * 2 of the License, or (at your option) any later version.
   10  *
   11  */
   12 
   13 #include <ctype.h>
   14 #include <stdarg.h>
   15 #include <stdio.h>
   16 #include <string.h>
   17 
   18 #include <common/config.h>
   19 #include <common/chunk.h>
   20 #include <common/standard.h>
   21 
   22 #include <types/global.h>
   23 
   24 /* trash chunks used for various conversions */
   25 static THREAD_LOCAL struct buffer *trash_chunk;
   26 static THREAD_LOCAL struct buffer trash_chunk1;
   27 static THREAD_LOCAL struct buffer trash_chunk2;
   28 
   29 /* trash buffers used for various conversions */
   30 static int trash_size;
   31 static THREAD_LOCAL char *trash_buf1;
   32 static THREAD_LOCAL char *trash_buf2;
   33 
   34 /* the trash pool for reentrant allocations */
   35 struct pool_head *pool_head_trash = NULL;
   36 
   37 /* this is used to drain data, and as a temporary buffer for sprintf()... */
   38 THREAD_LOCAL struct buffer trash = { };
   39 
   40 /*
   41 * Returns a pre-allocated and initialized trash chunk that can be used for any
   42 * type of conversion. Two chunks and their respective buffers are alternatively
   43 * returned so that it is always possible to iterate data transformations without
   44 * losing the data being transformed. The blocks are initialized to the size of
   45 * a standard buffer, so they should be enough for everything. For convenience,
   46 * a zero is always emitted at the beginning of the string so that it may be
   47 * used as an empty string as well.
   48 */
   49 struct buffer *get_trash_chunk(void)
   50 {
   51     char *trash_buf;
   52 
   53     if (trash_chunk == &trash_chunk1) {
   54         trash_chunk = &trash_chunk2;
   55         trash_buf = trash_buf2;
   56     }
   57     else {
   58         trash_chunk = &trash_chunk1;
   59         trash_buf = trash_buf1;
   60     }
   61     *trash_buf = 0;
   62     chunk_init(trash_chunk, trash_buf, trash_size);
   63     return trash_chunk;
   64 }
   65 
   66 /* (re)allocates the trash buffers. Returns 0 in case of failure. It is
   67  * possible to call this function multiple times if the trash size changes.
   68  */
   69 static int alloc_trash_buffers(int bufsize)
   70 {
   71     chunk_init(&trash, my_realloc2(trash.area, bufsize), bufsize);
   72     trash_size = bufsize;
   73     trash_buf1 = (char *)my_realloc2(trash_buf1, bufsize);
   74     trash_buf2 = (char *)my_realloc2(trash_buf2, bufsize);
   75     return trash.area && trash_buf1 && trash_buf2;
   76 }
   77 
   78 static int alloc_trash_buffers_per_thread()
   79 {
   80     return alloc_trash_buffers(global.tune.bufsize);
   81 }
   82 
   83 static void free_trash_buffers_per_thread()
   84 {
   85     chunk_destroy(&trash);
   86     free(trash_buf2);
   87     free(trash_buf1);
   88     trash_buf2 = NULL;
   89     trash_buf1 = NULL;
   90 }
   91 
   92 /* Initialize the trash buffers. It returns 0 if an error occurred. */
   93 int init_trash_buffers(int first)
   94 {
   95     pool_destroy(pool_head_trash);
   96     pool_head_trash = create_pool("trash",
   97                       sizeof(struct buffer) + global.tune.bufsize,
   98                       MEM_F_EXACT);
   99     if (!pool_head_trash || !alloc_trash_buffers(global.tune.bufsize))
  100         return 0;
  101     return 1;
  102 }
  103 
  104 /*
  105  * Allocate a trash chunk from the reentrant pool. The buffer starts at the
  106  * end of the chunk. This chunk must be freed using free_trash_chunk(). This
  107  * call may fail and the caller is responsible for checking that the returned
  108  * pointer is not NULL.
  109  */
  110 struct buffer *alloc_trash_chunk(void)
  111 {
  112     struct buffer *chunk;
  113 
  114     chunk = pool_alloc(pool_head_trash);
  115     if (chunk) {
  116         char *buf = (char *)chunk + sizeof(struct buffer);
  117         *buf = 0;
  118         chunk_init(chunk, buf,
  119                pool_head_trash->size - sizeof(struct buffer));
  120     }
  121     return chunk;
  122 }
  123 
  124 /*
  125  * Does an snprintf() at the beginning of chunk <chk>, respecting the limit of
  126  * at most chk->size chars. If the chk->len is over, nothing is added. Returns
  127  * the new chunk size, or < 0 in case of failure.
  128  */
  129 int chunk_printf(struct buffer *chk, const char *fmt, ...)
  130 {
  131     va_list argp;
  132     int ret;
  133 
  134     if (!chk->area || !chk->size)
  135         return 0;
  136 
  137     va_start(argp, fmt);
  138     ret = vsnprintf(chk->area, chk->size, fmt, argp);
  139     va_end(argp);
  140 
  141     if (ret >= chk->size)
  142         return -1;
  143 
  144     chk->data = ret;
  145     return chk->data;
  146 }
  147 
  148 /*
  149  * Does an snprintf() at the end of chunk <chk>, respecting the limit of
  150  * at most chk->size chars. If the chk->len is over, nothing is added. Returns
  151  * the new chunk size.
  152  */
  153 int chunk_appendf(struct buffer *chk, const char *fmt, ...)
  154 {
  155     va_list argp;
  156     int ret;
  157 
  158     if (!chk->area || !chk->size)
  159         return 0;
  160 
  161     va_start(argp, fmt);
  162     ret = vsnprintf(chk->area + chk->data, chk->size - chk->data, fmt,
  163             argp);
  164     if (ret >= chk->size - chk->data)
  165         /* do not copy anything in case of truncation */
  166         chk->area[chk->data] = 0;
  167     else
  168         chk->data += ret;
  169     va_end(argp);
  170     return chk->data;
  171 }
  172 
  173 /*
  174  * Encode chunk <src> into chunk <dst>, respecting the limit of at most
  175  * chk->size chars. Replace non-printable or special chracters with "&#%d;".
  176  * If the chk->len is over, nothing is added. Returns the new chunk size.
  177  */
  178 int chunk_htmlencode(struct buffer *dst, struct buffer *src)
  179 {
  180     int i, l;
  181     int olen, free;
  182     char c;
  183 
  184     olen = dst->data;
  185 
  186     for (i = 0; i < src->data; i++) {
  187         free = dst->size - dst->data;
  188 
  189         if (!free) {
  190             dst->data = olen;
  191             return dst->data;
  192         }
  193 
  194         c = src->area[i];
  195 
  196         if (!isascii(c) || !isprint((unsigned char)c) || c == '&' || c == '"' || c == '\'' || c == '<' || c == '>') {
  197             l = snprintf(dst->area + dst->data, free, "&#%u;",
  198                      (unsigned char)c);
  199 
  200             if (free < l) {
  201                 dst->data = olen;
  202                 return dst->data;
  203             }
  204 
  205             dst->data += l;
  206         } else {
  207             dst->area[dst->data] = c;
  208             dst->data++;
  209         }
  210     }
  211 
  212     return dst->data;
  213 }
  214 
  215 /*
  216  * Encode chunk <src> into chunk <dst>, respecting the limit of at most
  217  * chk->size chars. Replace non-printable or char passed in qc with "<%02X>".
  218  * If the chk->len is over, nothing is added. Returns the new chunk size.
  219  */
  220 int chunk_asciiencode(struct buffer *dst, struct buffer *src, char qc)
  221 {
  222     int i, l;
  223     int olen, free;
  224     char c;
  225 
  226     olen = dst->data;
  227 
  228     for (i = 0; i < src->data; i++) {
  229         free = dst->size - dst->data;
  230 
  231         if (!free) {
  232             dst->data = olen;
  233             return dst->data;
  234         }
  235 
  236         c = src->area[i];
  237 
  238         if (!isascii(c) || !isprint((unsigned char)c) || c == '<' || c == '>' || c == qc) {
  239             l = snprintf(dst->area + dst->data, free, "<%02X>",
  240                      (unsigned char)c);
  241 
  242             if (free < l) {
  243                 dst->data = olen;
  244                 return dst->data;
  245             }
  246 
  247             dst->data += l;
  248         } else {
  249             dst->area[dst->data] = c;
  250             dst->data++;
  251         }
  252     }
  253 
  254     return dst->data;
  255 }
  256 
  257 /* Compares the string in chunk <chk> with the string in <str> which must be
  258  * zero-terminated. Return is the same as with strcmp(). Neither is allowed
  259  * to be null.
  260  */
  261 int chunk_strcmp(const struct buffer *chk, const char *str)
  262 {
  263     const char *s1 = chk->area;
  264     int len = chk->data;
  265     int diff = 0;
  266 
  267     do {
  268         if (--len < 0) {
  269             diff = (unsigned char)0 - (unsigned char)*str;
  270             break;
  271         }
  272         diff = (unsigned char)*(s1++) - (unsigned char)*(str++);
  273     } while (!diff);
  274     return diff;
  275 }
  276 
  277 /* Case-insensitively compares the string in chunk <chk> with the string in
  278  * <str> which must be zero-terminated. Return is the same as with strcmp().
  279  * Neither is allowed to be null.
  280  */
  281 int chunk_strcasecmp(const struct buffer *chk, const char *str)
  282 {
  283     const char *s1 = chk->area;
  284     int len = chk->data;
  285     int diff = 0;
  286 
  287     do {
  288         if (--len < 0) {
  289             diff = (unsigned char)0 - (unsigned char)*str;
  290             break;
  291         }
  292         diff = (unsigned char)*s1 - (unsigned char)*str;
  293         if (unlikely(diff)) {
  294             unsigned int l = (unsigned char)*s1;
  295             unsigned int r = (unsigned char)*str;
  296 
  297             l -= 'a';
  298             r -= 'a';
  299 
  300             if (likely(l <= (unsigned char)'z' - 'a'))
  301                 l -= 'a' - 'A';
  302             if (likely(r <= (unsigned char)'z' - 'a'))
  303                 r -= 'a' - 'A';
  304             diff = l - r;
  305         }
  306         s1++; str++;
  307     } while (!diff);
  308     return diff;
  309 }
  310 
  311 REGISTER_PER_THREAD_ALLOC(alloc_trash_buffers_per_thread);
  312 REGISTER_PER_THREAD_FREE(free_trash_buffers_per_thread);
  313 
  314 /*
  315  * Local variables:
  316  *  c-indent-level: 8
  317  *  c-basic-offset: 8
  318  * End:
  319  */