void
http_Setup(struct http *hp, void *space, unsigned len)
{
- char *sp = space;
assert(len > 0);
memset(hp, 0, sizeof *hp);
hp->magic = HTTP_MAGIC;
- hp->s = sp;
- hp->t = sp;
- hp->v = sp;
- hp->f = sp;
- hp->e = sp + len;
+ WS_Init(hp->ws, space, len);
hp->nhd = HTTP_HDR_FIRST;
}
http_GetTail(struct http *hp, unsigned len, char **b, char **e)
{
- if (hp->t >= hp->v)
+ if (hp->pl_s >= hp->pl_e)
return (0);
if (len == 0)
- len = hp->v - hp->t;
+ len = hp->pl_e - hp->pl_e;
- if (hp->t + len > hp->v)
- len = hp->v - hp->t;
+ if (hp->pl_s + len > hp->pl_e)
+ len = hp->pl_e - hp->pl_s;
if (len == 0)
return (0);
- *b = hp->t;
- *e = hp->t + len;
- hp->t += len;
- assert(hp->t <= hp->v);
+ *b = hp->pl_s;
+ *e = hp->pl_s + len;
+ hp->pl_s += len;
+ assert(hp->pl_s <= hp->pl_e);
return (1);
}
char *b = p;
u = 0;
- if (hp->t < hp->v) {
- u = hp->v - hp->t;
+ if (hp->pl_s < hp->pl_e) {
+ u = hp->pl_e - hp->pl_s;
if (u > len)
u = len;
- memcpy(b, hp->t, u);
- hp->t += u;
+ memcpy(b, hp->pl_s, u);
+ hp->pl_s += u;
b += u;
len -= u;
}
+ hp->pl_s = hp->pl_e = NULL;
if (len > 0) {
i = read(fd, b, len);
if (i < 0)
hp->nhd = HTTP_HDR_FIRST;
hp->conds = 0;
r = NULL; /* For FlexeLint */
- assert(p < hp->v); /* http_header_complete() guarantees this */
- for (; p < hp->v; p = r) {
+ assert(p < hp->rx_e); /* http_header_complete() guarantees this */
+ for (; p < hp->rx_e; p = r) {
/* XXX: handle continuation lines */
q = strchr(p, '\n');
assert(q != NULL);
WSLR(w, http2shmlog(hp, HTTP_T_LostHeader), fd, p, q);
}
}
- assert(hp->t <= hp->v);
- assert(hp->t == r);
return (0);
}
char *p;
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- AN(hp->t);
- assert(hp->s < hp->t);
- assert(hp->t <= hp->v);
+ /* Assert a NUL at rx_e */
+ assert(hp->rx_s < hp->rx_e);
hp->logtag = HTTP_Rx;
- for (p = hp->s ; isspace(*p); p++)
+ for (p = hp->rx_s ; isspace(*p); p++)
continue;
/* First, the request type (GET/HEAD etc) */
while (isspace(*p) && *p != '\n')
p++;
if (*p == '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
+ WSLR(w, SLT_HttpGarbage, fd, hp->rx_s, hp->rx_e);
return (400);
}
hp->hd[HTTP_HDR_URL].b = p;
hp->hd[HTTP_HDR_URL].e = p;
WSLH(w, HTTP_T_URL, fd, hp, HTTP_HDR_URL);
if (*p == '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
+ WSLR(w, SLT_HttpGarbage, fd, hp->rx_s, hp->rx_e);
return (400);
}
*p++ = '\0';
while (isspace(*p) && *p != '\n')
p++;
if (*p == '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
+ WSLR(w, SLT_HttpGarbage, fd, hp->rx_s, hp->rx_e);
return (400);
}
hp->hd[HTTP_HDR_PROTO].b = p;
while (isspace(*p) && *p != '\n')
p++;
if (*p != '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
+ WSLR(w, SLT_HttpGarbage, fd, hp->rx_s, hp->rx_e);
return (400);
}
*p++ = '\0';
char *p, *q;
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- AN(hp->t);
- assert(hp->s < hp->t);
- assert(hp->t <= hp->v);
+ /* Assert a NUL at rx_e */
+ assert(hp->rx_s < hp->rx_e);
hp->logtag = HTTP_Rx;
- for (p = hp->s ; isspace(*p); p++)
+ for (p = hp->rx_s ; isspace(*p); p++)
continue;
if (memcmp(p, "HTTP/1.", 7)) {
- WSLR(w, SLT_HttpGarbage, fd, hp->s, hp->v);
+ WSLR(w, SLT_HttpGarbage, fd, hp->rx_s, hp->rx_e);
return (400);
}
/* First, protocol */
return (http_dissect_hdrs(w, hp, fd, p));
}
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * Return nonzero if we have a complete HTTP request.
+ */
static int
http_header_complete(struct http *hp)
char *p;
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- assert(hp->v <= hp->e);
- assert(*hp->v == '\0');
+ assert(*hp->rx_e == '\0');
/* Skip any leading white space */
- for (p = hp->s ; p < hp->v && isspace(*p); p++)
+ for (p = hp->rx_s ; p < hp->rx_e && isspace(*p); p++)
continue;
- if (p >= hp->v) {
- hp->v = hp->s;
+ if (p >= hp->rx_e) {
+ hp->rx_e = hp->rx_s;
return (0);
}
while (1) {
/* XXX: we could save location of all linebreaks for later */
p = strchr(p, '\n');
if (p == NULL)
- return (0);
+ return (0); /* XXX: Could cache p */
p++;
if (*p == '\r')
p++;
- if (*p != '\n')
- continue;
- break;
+ if (*p == '\n')
+ break;
}
- if (++p > hp->v)
- return (0);
- hp->t = p;
- assert(hp->t > hp->s);
- assert(hp->t <= hp->v);
- hp->f = hp->v;
+ p++;
+ WS_ReleaseP(hp->ws, hp->rx_e);
+ if (p != hp->rx_e) {
+ hp->pl_s = p;
+ hp->pl_e = hp->rx_e;
+ hp->rx_e = p;
+ }
+ /* XXX: Check this stuff... */
return (1);
}
unsigned l;
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- assert(hp->v <= hp->e);
- assert(hp->t <= hp->v);
- if (hp->t > hp->s && hp->t < hp->v) {
- l = hp->v - hp->t;
- memmove(hp->s, hp->t, l);
- hp->v = hp->s + l;
- hp->t = hp->s;
- *hp->v = '\0';
- } else {
- hp->v = hp->s;
- hp->t = hp->s;
+ WS_Assert(hp->ws);
+ WS_Reset(hp->ws);
+ WS_Reserve(hp->ws, 0);
+ hp->rx_s = hp->ws->f;
+ hp->rx_e = hp->rx_s;
+ if (hp->pl_s != NULL) {
+ assert(hp->pl_s < hp->pl_e);
+ l = hp->pl_e - hp->pl_s;
+ memmove(hp->rx_s, hp->pl_s, l);
+ hp->rx_e = hp->rx_s + l;
+ hp->pl_s = hp->pl_e = NULL;
}
+ *hp->rx_e = '\0';
}
int
http_RecvPrepAgain(struct http *hp)
{
http_RecvPrep(hp);
- if (hp->v == hp->s)
+ if (hp->rx_s == hp->rx_e)
return (0);
return (http_header_complete(hp));
}
unsigned l;
int i;
- l = (hp->e - hp->s) / 2;
- if (l < hp->v - hp->s)
- l = 0;
- else
- l -= hp->v - hp->s;
+ l = (hp->ws->e - hp->rx_e) - 1;
if (l <= 1) {
VSL(SLT_HttpError, fd, "Received too much");
- VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
- hp->t = NULL;
+ VSLR(SLT_HttpGarbage, fd, hp->rx_s, hp->rx_e);
+ hp->rx_s = hp->rx_e = NULL;
+ WS_Release(hp->ws, 0);
return (1);
}
errno = 0;
- i = read(fd, hp->v, l - 1);
+ i = read(fd, hp->rx_e, l - 1);
if (i > 0) {
- hp->v += i;
- *hp->v = '\0';
+ hp->rx_e += i;
+ *hp->rx_e = '\0';
if (http_header_complete(hp))
return(0);
return (-1);
}
- if (hp->v != hp->s) {
+ if (hp->rx_e != hp->rx_s) {
VSL(SLT_HttpError, fd,
"Received (only) %d bytes, errno %d",
- hp->v - hp->s, errno);
- VSLR(SLT_Debug, fd, hp->s, hp->v);
+ hp->rx_e - hp->rx_s, errno);
+ VSLR(SLT_Debug, fd, hp->rx_s, hp->rx_e);
} else if (errno == 0)
VSL(SLT_HttpError, fd, "Received nothing");
else
- VSL(SLT_HttpError, fd,
- "Received errno %d", errno);
- hp->t = NULL;
+ VSL(SLT_HttpError, fd, "Received errno %d", errno);
+ hp->rx_s = hp->rx_e = NULL;
+ WS_Release(hp->ws, 0);
return(2);
}
http_CopyHttp(struct http *to, struct http *fm)
{
unsigned u, l;
+ char *p;
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
AN(fm->hd[u].e);
l += (fm->hd[u].e - fm->hd[u].b) + 1;
}
- to->s = malloc(l);
- XXXAN(to->s);
- to->e = to->s + l;
- to->f = to->s;
+ p = malloc(l);
+ XXXAN(p);
+ WS_Init(to->ws, p, l);
+ WS_Reserve(to->ws, 0);
for (u = 0; u < fm->nhd; u++) {
if (fm->hd[u].b == NULL)
continue;
assert(*fm->hd[u].e == '\0');
l = fm->hd[u].e - fm->hd[u].b;
assert(l == strlen(fm->hd[u].b));
- memcpy(to->f, fm->hd[u].b, l);
- to->hd[u].b = to->f;
- to->hd[u].e = to->f + l;
+ memcpy(p, fm->hd[u].b, l);
+ to->hd[u].b = p;
+ to->hd[u].e = p + l;
*to->hd[u].e = '\0';
- to->f += l + 1;
+ p += l + 1;
}
+ /* XXX: Leave to->ws reserved for now */
to->nhd = fm->nhd;
}
{
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
- to->f = to->v;
+ /* XXX ??? to->f = to->v; Not sure this is valid */
to->nhd = HTTP_HDR_FIRST;
memset(to->hd, 0, sizeof to->hd);
}
/*--------------------------------------------------------------------*/
-void
-http_PutProtocol(struct worker *w, int fd, struct http *to, const char *protocol)
+static void
+http_PutField(struct http *to, int field, const char *string)
{
+ char *e, *p;
int l;
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
- l = strlcpy(to->f, protocol, to->e - to->f);
- xxxassert(to->f + l < to->e);
- to->hd[HTTP_HDR_PROTO].b = to->f;
- to->hd[HTTP_HDR_PROTO].e = to->f + l;
- to->f += l + 1;
+ e = strchr(string, '\0');
+ l = (e - string);
+ p = WS_Alloc(to->ws, l + 1);
+ memcpy(p, string, l + 1);
+ to->hd[field].b = p;
+ to->hd[field].e = p + l;
+}
+
+void
+http_PutProtocol(struct worker *w, int fd, struct http *to, const char *protocol)
+{
+
+ http_PutField(to, HTTP_HDR_PROTO, protocol);
WSLH(w, HTTP_T_Protocol, fd, to, HTTP_HDR_PROTO);
}
void
http_PutStatus(struct worker *w, int fd, struct http *to, int status)
{
- int l;
+ char stat[4];
- CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
- assert(status >= 100 && status <= 999);
- l = snprintf(to->f, to->e - to->f, "%d", status);
- xxxassert(to->f + l < to->e);
- to->hd[HTTP_HDR_STATUS].b = to->f;
- to->hd[HTTP_HDR_STATUS].e = to->f + l;
- to->f += l + 1;
+ assert(status >= 0 && status <= 999);
+ sprintf(stat, "%d", status);
+ http_PutField(to, HTTP_HDR_STATUS, stat);
WSLH(w, HTTP_T_Status, fd, to, HTTP_HDR_STATUS);
}
void
http_PutResponse(struct worker *w, int fd, struct http *to, const char *response)
{
- int l;
- CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
- l = strlcpy(to->f, response, to->e - to->f);
- xxxassert(to->f + l < to->e);
- to->hd[HTTP_HDR_RESPONSE].b = to->f;
- to->hd[HTTP_HDR_RESPONSE].e = to->f + l;
- to->f += l + 1;
+ http_PutField(to, HTTP_HDR_RESPONSE, response);
WSLH(w, HTTP_T_Response, fd, to, HTTP_HDR_RESPONSE);
}
unsigned l, n;
CHECK_OBJ_NOTNULL(to, HTTP_MAGIC);
- l = to->e - to->f;
+ l = WS_Reserve(to->ws, 0);
va_start(ap, fmt);
- n = vsnprintf(to->f, l, fmt, ap);
+ n = vsnprintf(to->ws->f, l, fmt, ap);
va_end(ap);
- if (n >= l || to->nhd >= HTTP_HDR_MAX) {
+ if (n + 1 >= l || to->nhd >= HTTP_HDR_MAX) {
VSL_stats->losthdr++;
- WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", to->f);
+ WSL(w, http2shmlog(to, HTTP_T_LostHeader), fd, "%s", to->ws->f);
+ WS_Release(to->ws, 0);
} else {
- assert(to->f < to->e);
- to->hd[to->nhd].b = to->f;
- to->hd[to->nhd].e = to->f + n;
- to->f += n + 1;
+ to->hd[to->nhd].b = to->ws->f;
+ to->hd[to->nhd].e = to->ws->f + n;
+ WS_Release(to->ws, n + 1);
WSLH(w, HTTP_T_Header, fd, to, to->nhd);
to->nhd++;
}
--- /dev/null
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "heritage.h"
+#include "shmlog.h"
+#include "vcl.h"
+#include "cli_priv.h"
+#include "cache.h"
+
+void
+WS_Assert(struct ws *ws)
+{
+
+ assert(ws != NULL);
+ assert(ws->s != NULL);
+ assert(ws->e != NULL);
+ assert(ws->s < ws->e);
+ assert(ws->f >= ws->s);
+ assert(ws->f <= ws->e);
+ if (ws->r) {
+ assert(ws->r > ws->s);
+ assert(ws->r <= ws->e);
+ }
+}
+
+void
+WS_Init(struct ws *ws, void *space, unsigned len)
+{
+
+ assert(space != NULL);
+ memset(ws, 0, sizeof *ws);
+ ws->s = space;
+ ws->e = ws->s + len;
+ ws->f = ws->s;
+ WS_Assert(ws);
+}
+
+void
+WS_Reset(struct ws *ws)
+{
+
+ WS_Assert(ws);
+ assert(ws->r == NULL);
+ ws->f = ws->s;
+}
+
+char *
+WS_Alloc(struct ws *ws, unsigned bytes)
+{
+ char *r;
+
+ WS_Assert(ws);
+ assert(ws->r == NULL);
+ xxxassert(ws->f + bytes <= ws->e);
+ r = ws->f;
+ ws->f += bytes;
+ return (r);
+}
+
+unsigned
+WS_Reserve(struct ws *ws, unsigned bytes)
+{
+ WS_Assert(ws);
+ assert(ws->r == NULL);
+ if (bytes == 0)
+ bytes = ws->e - ws->f;
+ xxxassert(ws->f + bytes <= ws->e);
+ ws->r = ws->f + bytes;
+ return (ws->r - ws->f);
+}
+
+void
+WS_Release(struct ws *ws, unsigned bytes)
+{
+ WS_Assert(ws);
+ assert(ws->r != NULL);
+ assert(ws->f + bytes <= ws->r);
+ ws->f += bytes;
+ ws->r = NULL;
+}
+
+void
+WS_ReleaseP(struct ws *ws, char *ptr)
+{
+ WS_Assert(ws);
+ assert(ws->r != NULL);
+ assert(ptr >= ws->f);
+ assert(ptr <= ws->r);
+ ws->f = ptr;
+ ws->r = NULL;
+}
+
+void
+WS_Return(struct ws *ws, char *s, char *e)
+{
+
+ WS_Assert(ws);
+ if (e == ws->f)
+ ws->f = s;
+}