summaryrefslogtreecommitdiff
path: root/common/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/buffer.c')
-rw-r--r--common/buffer.c429
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';
+}