diff options
Diffstat (limited to 'common/buffer.c')
-rw-r--r-- | common/buffer.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/common/buffer.c b/common/buffer.c new file mode 100644 index 0000000..28cab24 --- /dev/null +++ b/common/buffer.c @@ -0,0 +1,429 @@ + +#include "usuals.h" +#include "httpauthd.h" + +#include <syslog.h> + +/* ----------------------------------------------------------------------- + * Memory Buffer + */ + +/* + * LEGEND: + * _al: allocated + * _dt: data + * _rp: read/write point + * _pp: parse/begin point + */ + +void buffer_bump(ha_buffer_t* buf, int count) +{ + if(ha_buferr(buf)) + return; + + if(buf->_rp + count >= buf->_dt + buf->_al) + { + char* old = buf->_dt; + int alloc = buf->_al; + int diff; + + while((buf->_al + count) > alloc) + alloc *= 2; + + buf->_dt = (char*)reallocf(buf->_dt, alloc * sizeof(char)); + if(!buf->_dt) + { + buf->_al = 0; + buf->_rp = buf->_pp = NULL; + ha_messagex(LOG_CRIT, "out of memory"); + return; + } + + buf->_al = alloc; + + diff = buf->_dt - old; + buf->_rp += diff; + buf->_pp += diff; + } +} + +void ha_bufreset(ha_buffer_t* buf) +{ + if(!buf->_dt || buf->_al == 0) + { + buf->_dt = (char*)reallocf(buf->_dt, 256 * sizeof(char)); + if(!buf->_dt) + { + buf->_al = 0; + buf->_rp = buf->_pp = NULL; + ha_messagex(LOG_CRIT, "out of memory"); + return; + } + + buf->_al = 256; + } + + buf->_rp = buf->_dt; + buf->_pp = buf->_dt; +} + +void ha_bufinit(ha_buffer_t* buf) +{ + memset(buf, 0, sizeof(*buf)); + ha_bufreset(buf); +} + +void ha_buffree(ha_buffer_t* buf) +{ + if(buf->_dt) + free(buf->_dt); + + buf->_al = 0; + buf->_rp = buf->_pp = NULL; +} + +int ha_readline(int fd, ha_buffer_t* buf) +{ + int l; + + if(ha_buferr(buf)) + return 0; + + for(;;) + { + buffer_bump(buf, 1); + l = read(fd, (void*)buf->_rp, sizeof(char)); + + /* We got a character */ + if(l == 1) + { + /* Skip junky CRLFs */ + if(*(buf->_rp) == '\r') + { + *(buf->_rp) = ' '; + continue; + } + + /* End of line */ + else if(*(buf->_rp) == '\n') + { + buf->_rp++; + break; + } + + /* All other characters */ + else + { + buf->_rp++; + } + } + + /* If it's the end of file then return that */ + else if(l == 0) + return 0; + + /* Transient errors */ + else if(l == -1 && (errno == EINTR || errno == EAGAIN)) + continue; + + /* Fatal errors */ + else if(l == -1) + { + ha_message(LOG_ERR, "couldn't read data"); + return 0; + } + } + + return 1; +} + +char* ha_parseword(ha_buffer_t* buf, const char* delims) +{ + char* word = NULL; + + if(ha_buferr(buf)) + return NULL; + + /* Knock out any previous delims */ + while(buf->_pp < buf->_rp && strchr(delims, *(buf->_pp))) + buf->_pp++; + + /* If at end of buffer or end of line return null */ + if(buf->_pp == buf->_rp || *(buf->_pp) == '\n') + return NULL; + + /* We do this before we stash away a pointer */ + buffer_bump(buf, 1); + + word = buf->_pp; + + while(!strchr(delims, *(buf->_pp))) + { + buf->_pp++; + + /* At the end of the buffer */ + if(buf->_pp == buf->_rp) + { + *(buf->_rp) = 0; + buf->_rp++; + break; + } + + /* At the end of a line */ + else if(*(buf->_pp) == '\n') + break; + } + + /* Now null terminate what we found */ + *(buf->_pp) = 0; + buf->_pp++; + + /* We don't return empty strings */ + if(word[0] == 0) + return NULL; + + return word; +} + +char* ha_parseline(ha_buffer_t* buf, int trim) +{ + char* t; + char* line = NULL; + + if(ha_buferr(buf)) + return NULL; + + if(trim) + { + /* Knock out any previous whitespace */ + while(buf->_pp < buf->_rp && isblank(*(buf->_pp))) + buf->_pp++; + } + + if(buf->_pp == buf->_rp) + return NULL; + + /* We do this before we stash away a pointer */ + buffer_bump(buf, 1); + + line = buf->_pp; + + t = (char*)memchr(buf->_pp, '\n', ha_buflen(buf)); + if(t == NULL) + { + t = (buf->_rp); + buf->_rp++; + } + + *t = 0; + buf->_pp = t + 1; + + if(trim) + { + while(t > line && isspace(*(--t))) + *t = 0; + } + + /* We don't return empty strings */ + if(line[0] == 0) + return NULL; + + return line; +} + +void ha_bufnext(ha_buffer_t* buf) +{ + buffer_bump(buf, 1); + + if(!ha_buferr(buf)) + { + buf->_rp++; + buf->_pp = buf->_rp; + *(buf->_rp) = 0; + } +} + +void ha_bufcat(ha_buffer_t* buf, ...) +{ + const char* str; + va_list ap; + + va_start(ap, buf); + + while((str = va_arg(ap, char*)) != NULL) + { + int len = strlen(str); + + buffer_bump(buf, len); + + if(ha_buferr(buf)) + return; + + /* _rpoint points to teh null */ + strcpy(buf->_rp, str); + buf->_rp += len; + } +} + +void* ha_bufmalloc(ha_buffer_t* buf, size_t sz) +{ + void* ret; + + ha_bufnext(buf); + buffer_bump(buf, sz); + buf->_rp += sz; + + if(ha_buferr(buf)) + return NULL; + + ret = (void*)ha_bufdata(buf); + ha_bufnext(buf); + + return ret; +} + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +static const char BASE64C[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char PAD64C = '='; + +void ha_bufenc64(ha_buffer_t* buf, const char* src, int len) +{ + unsigned char input[3]; + unsigned char output[4]; + size_t i; + + if(len == -1) + len = strlen(src); + + while(2 < len) + { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + len -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + buffer_bump(buf, 5); + + if(ha_buferr(buf)) + return; + + *(buf->_rp++) = BASE64C[output[0]]; + *(buf->_rp++) = BASE64C[output[1]]; + *(buf->_rp++) = BASE64C[output[2]]; + *(buf->_rp++) = BASE64C[output[3]]; + } + + /* Now we worry about padding. */ + if(0 != len) + { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for(i = 0; i < len; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + buffer_bump(buf, 5); + + if(ha_buferr(buf)) + return; + + *(buf->_rp++) = BASE64C[output[0]]; + *(buf->_rp++) = BASE64C[output[1]]; + if(len == 1) + *(buf->_rp++) = PAD64C; + else + *(buf->_rp++) = BASE64C[output[2]]; + *(buf->_rp++) = PAD64C; + } + + *(buf->_rp++) = '\0'; +} + +void ha_bufdec64(ha_buffer_t* buf, const char* src) +{ + int state; + int ch; + char* pos; + + state = 0; + + while((ch = *src++) != '\0') + { + if(isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if(ch == PAD64C) + break; + + pos = strchr(BASE64C, ch); + if(pos == 0) /* A non-base64 character. */ + break; + + buffer_bump(buf, 3); + + if(ha_buferr(buf)) + return; + + switch(state) + { + case 0: + *(buf->_rp++) = (pos - BASE64C) << 2; + state = 1; + break; + + case 1: + *(buf->_rp++) |= (pos - BASE64C) >> 4; + *(buf->_rp) = ((pos - BASE64C) & 0x0f) << 4; + state = 2; + break; + + case 2: + *(buf->_rp++) |= (pos - BASE64C) >> 2; + *(buf->_rp) = ((pos - BASE64C) & 0x03) << 6; + state = 3; + break; + + case 3: + *(buf->_rp++) |= (pos - BASE64C); + state = 0; + break; + }; + + /* TODO: Validate ending and return error if invalid somehow */ + } + + *(buf->_rp++) = '\0'; +} |