#define HTTP_MAGIC 0x6428b5c9
struct ws *ws;
- txt rx; /* Received Request */
- txt pl; /* Pipelined bytes */
unsigned char conds; /* If-* headers present */
enum httpwhence logtag;
unsigned magic;
#define HTTP_CONN_MAGIC 0x3e19edd1
- struct http *http;
+ int fd;
struct ws *ws;
txt rxbuf;
txt pipeline;
struct http *http;
struct ws ws[1];
+ struct http_conn htc[1];
+
/* Timestamps, all on TIM_real() timescale */
double t_open;
double t_req;
const char *http_GetReq(const struct http *hp);
const char *http_GetProto(const struct http *hp);
int http_HdrIs(const struct http *hp, const char *hdr, const char *val);
-int http_GetTail(struct http *hp, unsigned len, char **b, char **e);
-int http_Read(struct http *hp, int fd, void *b, unsigned len);
-void http_RecvPrep(struct http *hp);
-int http_RecvPrepAgain(struct http *hp);
-int http_RecvSome(int fd, struct http *hp);
-int http_RecvHead(struct http *hp, int fd);
-int http_DissectRequest(struct worker *w, struct http *sp, int fd);
-int http_DissectResponse(struct worker *w, struct http *sp, int fd);
+int http_DissectRequest(struct sess *sp);
+int http_DissectResponse(struct worker *w, struct http_conn *htc, struct http *sp);
const char *http_DoConnection(struct http *hp);
void http_CopyHome(struct worker *w, int fd, struct http *hp);
void http_Unset(struct http *hp, const char *hdr);
+/* cache_httpconn.c */
+void HTC_Init(struct http_conn *htc, struct ws *ws, int fd);
+int HTC_Reinit(struct http_conn *htc);
+int HTC_Rx(struct http_conn *htc);
+int HTC_Read(struct http_conn *htc, void *d, unsigned len);
#define HTTPH(a, b, c, d, e, f, g) extern char b[];
#include "http_headers.h"
sp->id = i;
sp->t_open = TIM_real();
- http_RecvPrep(sp->http);
+ HTC_Init(sp->htc, sp->ws, sp->fd);
sp->step = STP_FIRST;
WRK_QueueSession(sp);
}
{
int i;
- i = http_RecvSome(sp->fd, sp->http);
- if (i < 1)
- return (i);
+ i = HTC_Rx(sp->htc);
+ /* XXX: fix retval */
+ if (i == 0)
+ return (-1);
if (i == 1)
- vca_close_session(sp, "overflow");
- else if (i == 2)
- vca_close_session(sp, "no request");
+ return (0);
+ vca_close_session(sp, "err/poll");
return (1);
}
assert(sp->xid == 0);
- do
- i = http_RecvSome(sp->fd, sp->http);
- while (i == -1);
- if (i == 0) {
+ do
+ i = HTC_Rx(sp->htc);
+ while (i == 0);
+ if (i == 1) {
sp->step = STP_RECV;
- return (0);
- }
- if (i == 1)
+ } else {
vca_close_session(sp, "overflow");
- else if (i == 2)
- vca_close_session(sp, "no request");
- else
- INCOMPL();
- sp->step = STP_DONE;
+ sp->step = STP_DONE;
+ }
return (0);
}
cnt_done(struct sess *sp)
{
double dh, dp, da;
+ int i;
AZ(sp->obj);
AZ(sp->bereq);
return (1);
}
- if (http_RecvPrepAgain(sp->http)) {
+ i = HTC_Reinit(sp->htc);
+ if (i == 1) {
VSL_stats->sess_pipeline++;
sp->step = STP_RECV;
return (0);
}
- if (sp->http->pl.b < sp->http->pl.e) {
+ if (Tlen(sp->htc->rxbuf)) {
VSL_stats->sess_readahead++;
sp->step = STP_AGAIN;
return (0);
sp->wrk->acct.sess++;
SES_RefSrcAddr(sp);
do
- i = http_RecvSome(sp->fd, sp->http);
- while (i == -1);
- if (i == 0) {
+ i = HTC_Rx(sp->htc);
+ while (i == 0);
+ if (i == 1) {
sp->step = STP_RECV;
return (0);
}
- if (i == 1)
+ if (i == -1)
vca_close_session(sp, "blast");
else if (i == 2)
vca_close_session(sp, "silent");
sp->vcl = sp->wrk->vcl;
sp->wrk->vcl = NULL;
- done = http_DissectRequest(sp->wrk, sp->http, sp->fd);
+ done = http_DissectRequest(sp);
if (done != 0) {
RES_Error(sp, done, NULL); /* XXX: STP_ERROR ? */
sp->step = STP_DONE;
/*--------------------------------------------------------------------*/
static int
-fetch_straight(struct sess *sp, int fd, struct http *hp, const char *b)
+fetch_straight(struct sess *sp, struct http_conn *htc, const char *b)
{
int i;
unsigned char *p;
sp->obj->len = cl;
p = st->ptr;
- i = fcntl(fd, F_GETFL); /* XXX ? */
+ i = fcntl(htc->fd, F_GETFL); /* XXX ? */
i &= ~O_NONBLOCK;
- i = fcntl(fd, F_SETFL, i);
+ i = fcntl(htc->fd, F_SETFL, i);
while (cl > 0) {
- i = http_Read(hp, fd, p, cl);
+ i = HTC_Read(htc, p, cl);
if (i <= 0)
return (-1);
p += i;
/* XXX: Cleanup. It must be possible somehow :-( */
static int
-fetch_chunked(struct sess *sp, int fd, struct http *hp)
+fetch_chunked(struct sess *sp, struct http_conn *htc)
{
int i;
char *q;
* deal more complex than reading a single character
* at a time.
*/
- i = http_Read(hp, fd, bp, 1);
+ i = HTC_Read(htc, bp, 1);
if (i <= 0)
return (-1);
bp += i;
/* Pick up the rest of this chunk */
while (v > 0) {
- i = http_Read(hp, fd, st->ptr + st->len, v);
+ i = HTC_Read(htc, st->ptr + st->len, v);
if (i <= 0)
return (-1);
st->len += i;
#include <errno.h>
static int
-fetch_eof(struct sess *sp, int fd, struct http *hp)
+fetch_eof(struct sess *sp, struct http_conn *htc)
{
int i;
unsigned char *p;
struct storage *st;
unsigned v;
- i = fcntl(fd, F_GETFL); /* XXX ? */
+ i = fcntl(htc->fd, F_GETFL); /* XXX ? */
i &= ~O_NONBLOCK;
- i = fcntl(fd, F_SETFL, i);
+ i = fcntl(htc->fd, F_SETFL, i);
p = NULL;
v = 0;
}
AN(p);
AN(st);
- i = http_Read(hp, fd, p, v);
+ i = HTC_Read(htc, p, v);
if (i < 0)
return (-1);
if (i == 0)
struct bereq *bereq;
int mklen, is_head;
unsigned len;
+ struct http_conn htc[1];
+ int i;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
- CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
- if (http_RecvHead(hp, vc->fd)) {
- /* XXX: cleanup */
- return (1);
- }
- if (http_DissectResponse(sp->wrk, hp, vc->fd)) {
+ HTC_Init(htc, bereq->ws, vc->fd);
+ do
+ i = HTC_Rx(htc);
+ while (i == 0);
+
+ if (http_DissectResponse(sp->wrk, htc, hp)) {
/* XXX: cleanup */
return (1);
}
CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
/* Filter into object */
hp2 = &sp->obj->http;
- len = Tlen(hp->rx);
- len += 256; /* margin for content-length etc */
+ len = Tlen(htc->rxbuf);
+ len += 256; /* XXX: margin for content-length etc */
CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
b = malloc(len);
if (is_head) {
/* nothing */
} else if (http_GetHdr(hp, H_Content_Length, &b)) {
- cls = fetch_straight(sp, vc->fd, hp, b);
+ cls = fetch_straight(sp, htc, b);
mklen = 1;
} else if (http_HdrIs(hp, H_Transfer_Encoding, "chunked")) {
- cls = fetch_chunked(sp, vc->fd, hp);
+ cls = fetch_chunked(sp, htc);
mklen = 1;
} else if (http_GetHdr(hp, H_Transfer_Encoding, &b)) {
/* XXX: AUGH! */
} else if (strcmp(http_GetProto(hp), "HTTP/1.1")) {
switch (http_GetStatus(hp)) {
case 200:
- cls = fetch_eof(sp, vc->fd, hp);
+ cls = fetch_eof(sp, htc);
mklen = 1;
break;
default:
*/
static int
-http_dissect_hdrs(struct worker *w, struct http *hp, int fd, char *p)
+http_dissect_hdrs(struct worker *w, struct http *hp, int fd, char *p, txt t)
{
char *q, *r;
hp->nhd = HTTP_HDR_FIRST;
hp->conds = 0;
r = NULL; /* For FlexeLint */
- assert(p < hp->rx.e); /* http_header_complete() guarantees this */
- for (; p < hp->rx.e; p = r) {
+ assert(p < t.e); /* http_header_complete() guarantees this */
+ for (; p < t.e; p = r) {
/* XXX: handle continuation lines */
q = strchr(p, '\n');
assert(q != NULL);
/*--------------------------------------------------------------------*/
int
-http_DissectRequest(struct worker *w, struct http *hp, int fd)
+http_DissectRequest(struct sess *sp)
{
char *p;
+ struct http_conn *htc;
+ struct http *hp;
+ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+ htc = sp->htc;
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+ hp = sp->http;
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+
/* Assert a NUL at rx.e */
- Tcheck(hp->rx);
+ Tcheck(htc->rxbuf);
hp->logtag = HTTP_Rx;
- for (p = hp->rx.b ; isspace(*p); p++)
+ for (p = htc->rxbuf.b ; isspace(*p); p++)
continue;
/* First, the request type (GET/HEAD etc) */
for (; isalpha(*p); p++)
;
hp->hd[HTTP_HDR_REQ].e = p;
- WSLH(w, HTTP_T_Request, fd, hp, HTTP_HDR_REQ);
+ WSLH(sp->wrk, HTTP_T_Request, sp->fd, hp, HTTP_HDR_REQ);
*p++ = '\0';
/* Next find the URI */
while (isspace(*p) && *p != '\n')
p++;
if (*p == '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->rx);
+ WSLR(sp->wrk, SLT_HttpGarbage, sp->fd, htc->rxbuf);
return (400);
}
hp->hd[HTTP_HDR_URL].b = p;
while (!isspace(*p))
p++;
hp->hd[HTTP_HDR_URL].e = p;
- WSLH(w, HTTP_T_URL, fd, hp, HTTP_HDR_URL);
+ WSLH(sp->wrk, HTTP_T_URL, sp->fd, hp, HTTP_HDR_URL);
if (*p == '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->rx);
+ WSLR(sp->wrk, SLT_HttpGarbage, sp->fd, htc->rxbuf);
return (400);
}
*p++ = '\0';
while (isspace(*p) && *p != '\n')
p++;
if (*p == '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->rx);
+ WSLR(sp->wrk, SLT_HttpGarbage, sp->fd, htc->rxbuf);
return (400);
}
hp->hd[HTTP_HDR_PROTO].b = p;
while (!isspace(*p))
p++;
hp->hd[HTTP_HDR_PROTO].e = p;
- WSLH(w, HTTP_T_Protocol, fd, hp, HTTP_HDR_PROTO);
+ WSLH(sp->wrk, HTTP_T_Protocol, sp->fd, hp, HTTP_HDR_PROTO);
if (*p != '\n')
*p++ = '\0';
while (isspace(*p) && *p != '\n')
p++;
if (*p != '\n') {
- WSLR(w, SLT_HttpGarbage, fd, hp->rx);
+ WSLR(sp->wrk, SLT_HttpGarbage, sp->fd, htc->rxbuf);
return (400);
}
*p++ = '\0';
- return (http_dissect_hdrs(w, hp, fd, p));
+ return (http_dissect_hdrs(sp->wrk, hp, sp->fd, p, htc->rxbuf));
}
/*--------------------------------------------------------------------*/
int
-http_DissectResponse(struct worker *w, struct http *hp, int fd)
+http_DissectResponse(struct worker *w, struct http_conn *htc, struct http *hp)
{
char *p, *q;
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- /* Assert a NUL at rx.e */
- Tcheck(hp->rx);
+ /* Assert a NUL at rx.e (?) */
+ Tcheck(htc->rxbuf);
hp->logtag = HTTP_Rx;
- for (p = hp->rx.b ; isspace(*p); p++)
+ for (p = htc->rxbuf.b ; isspace(*p); p++)
continue;
if (memcmp(p, "HTTP/1.", 7)) {
- WSLR(w, SLT_HttpGarbage, fd, hp->rx);
+ WSLR(w, SLT_HttpGarbage, htc->fd, htc->rxbuf);
return (400);
}
/* First, protocol */
while (!isspace(*p))
p++;
hp->hd[HTTP_HDR_PROTO].e = p;
- WSLH(w, HTTP_T_Protocol, fd, hp, HTTP_HDR_PROTO);
+ WSLH(w, HTTP_T_Protocol, htc->fd, hp, HTTP_HDR_PROTO);
*p++ = '\0';
/* Next find the status */
while (!isspace(*p))
p++;
hp->hd[HTTP_HDR_STATUS].e = p;
- WSLH(w, HTTP_T_Status, fd, hp, HTTP_HDR_STATUS);
+ WSLH(w, HTTP_T_Status, htc->fd, hp, HTTP_HDR_STATUS);
*p++ = '\0';
/* Next find the response */
continue;
*q = '\0';
hp->hd[HTTP_HDR_RESPONSE].e = q;
- WSLH(w, HTTP_T_Response, fd, hp, HTTP_HDR_RESPONSE);
+ WSLH(w, HTTP_T_Response, htc->fd, hp, HTTP_HDR_RESPONSE);
p++;
- return (http_dissect_hdrs(w, hp, fd, p));
+ return (http_dissect_hdrs(w, hp, htc->fd, p, htc->rxbuf));
}
+
/*--------------------------------------------------------------------*/
void
* HTTP protocol requests
*/
+#include <stdio.h>
+#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include "cache.h"
/*--------------------------------------------------------------------
- * Check if we have a complete HTTP request or response yet between the
- * two pointers given.
+ * Check if we have a complete HTTP request or response yet
*
* Return values:
* -1 No, and you can nuke the (white-space) content.
*/
static int
-http_header_complete(const char *b, const char *e)
+htc_header_complete(txt *t)
{
const char *p;
- AN(b);
- AN(e);
- assert(b <= e);
- assert(*e == '\0');
+ Tcheck(*t);
+ assert(*t->e == '\0');
/* Skip any leading white space */
- for (p = b ; isspace(*p); p++)
+ for (p = t->b ; isspace(*p); p++)
continue;
- if (*p == '\0')
- return (-1);
+ if (*p == '\0') {
+ t->e = t->b;
+ return (0);
+ }
while (1) {
p = strchr(p, '\n');
if (p == NULL)
break;
}
p++;
- return (p - b);
+ return (p - t->b);
}
/*--------------------------------------------------------------------*/
void
-http_RecvPrep(struct http *hp)
+HTC_Init(struct http_conn *htc, struct ws *ws, int fd)
{
- unsigned l;
- CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- WS_Assert(hp->ws);
- WS_Reset(hp->ws);
- WS_Reserve(hp->ws, 0);
- hp->rx.b = hp->ws->f;
- hp->rx.e = hp->rx.b;
- if (hp->pl.b != NULL) {
- l = Tlen(hp->pl);
- memmove(hp->rx.b, hp->pl.b, l);
- hp->rx.e = hp->rx.b + l;
- hp->pl.b = hp->pl.e = NULL;
- }
- *hp->rx.e = '\0';
+ htc->magic = HTTP_CONN_MAGIC;
+ htc->ws = ws;
+ htc->fd = fd;
+ WS_Reset(htc->ws);
+ WS_Reserve(htc->ws, (htc->ws->e - htc->ws->s) / 2);
+ htc->rxbuf.b = ws->f;
+ htc->rxbuf.e = ws->f;
+ htc->pipeline.b = NULL;
+ htc->pipeline.e = NULL;
}
+/*--------------------------------------------------------------------
+ * Start over, and recycle any pipelined input.
+ * The WS_Reset is safe, even though the pipelined input is stored in
+ * the ws somewhere, because WS_Reset only fiddles pointers.
+ */
+
int
-http_RecvPrepAgain(struct http *hp)
+HTC_Reinit(struct http_conn *htc)
{
+ unsigned l;
int i;
- http_RecvPrep(hp);
- if (hp->rx.b == hp->rx.e)
- return (0);
- i = http_header_complete(hp->rx.b, hp->rx.e);
- if (i == -1)
- hp->rx.e = hp->rx.b;
- if (i <= 0)
- return (0);
- WS_ReleaseP(hp->ws, hp->rx.e);
- if (hp->rx.e != hp->rx.b + i) {
- hp->pl.b = hp->rx.b + i;
- hp->pl.e = hp->rx.e;
- hp->rx.e = hp->pl.b;
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+ WS_Reset(htc->ws);
+ WS_Reserve(htc->ws, (htc->ws->e - htc->ws->s) / 2);
+ htc->rxbuf.b = htc->ws->f;
+ htc->rxbuf.e = htc->ws->f;
+ if (htc->pipeline.b != NULL) {
+ l = Tlen(htc->pipeline);
+ memmove(htc->rxbuf.b, htc->pipeline.b, l);
+ htc->rxbuf.e += l;
+ htc->pipeline.b = NULL;
+ htc->pipeline.e = NULL;
}
+ *htc->rxbuf.e = '\0';
+ i = htc_header_complete(&htc->rxbuf);
return (i);
}
/*--------------------------------------------------------------------*/
int
-http_RecvSome(int fd, struct http *hp)
+HTC_Rx(struct http_conn *htc)
{
- unsigned l;
int i;
- l = pdiff(hp->rx.e, hp->ws->e) - 1;
- l /= 2; /* Don't fill all of workspace with read-ahead */
- if (l <= 1) {
- VSL(SLT_HttpError, fd, "Received too much");
- VSLR(SLT_HttpGarbage, fd, hp->rx);
- hp->rx.b = hp->rx.e = NULL;
- WS_Release(hp->ws, 0);
- return (1);
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+ i = (htc->ws->r - htc->rxbuf.e) - 1; /* space for NUL */
+ assert(i > 0);
+ i = read(htc->fd, htc->rxbuf.e, i);
+ if (i < 0) {
+ WS_ReleaseP(htc->ws, htc->rxbuf.b);
+ return (-1);
}
- errno = 0;
- i = read(fd, hp->rx.e, l - 1);
- if (i > 0) {
- hp->rx.e += i;
- *hp->rx.e = '\0';
- i = http_header_complete(hp->rx.b, hp->rx.e);
- if (i == -1)
- hp->rx.e = hp->rx.b;
- if (i == 0)
- return (-1);
- WS_ReleaseP(hp->ws, hp->rx.e);
- if (hp->rx.e != hp->rx.b + i) {
- hp->pl.b = hp->rx.b + i;
- hp->pl.e = hp->rx.e;
- hp->rx.e = hp->pl.b;
- }
+ htc->rxbuf.e += i;
+ *htc->rxbuf.e = '\0';
+ i = htc_header_complete(&htc->rxbuf);
+ if (i == 0)
return (0);
+ WS_ReleaseP(htc->ws, htc->rxbuf.e);
+ if (htc->rxbuf.b + i < htc->rxbuf.e) {
+ htc->pipeline.b = htc->rxbuf.b + i;
+ htc->pipeline.e = htc->rxbuf.e;
+ htc->rxbuf.e = htc->pipeline.b;
}
-
- if (hp->rx.e != hp->rx.b) {
- VSL(SLT_HttpError, fd,
- "Received (only) %d bytes, errno %d",
- hp->rx.e - hp->rx.b, errno);
- VSLR(SLT_Debug, fd, hp->rx);
- } else if (errno == 0)
- VSL(SLT_HttpError, fd, "Received nothing");
- else
- VSL(SLT_HttpError, fd, "Received errno %d", errno);
- hp->rx.b = hp->rx.e = NULL;
- WS_Release(hp->ws, 0);
- return(2);
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-http_RecvHead(struct http *hp, int fd)
-{
- int i;
-
- CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
- http_RecvPrep(hp);
- do
- i = http_RecvSome(fd, hp);
- while (i == -1);
- return (i);
-}
-
-/*--------------------------------------------------------------------*/
-
-int
-http_GetTail(struct http *hp, unsigned len, char **b, char **e)
-{
-
- if (hp->pl.b >= hp->pl.e)
- return (0);
-
- if (len == 0)
- len = Tlen(hp->pl);
-
- if (hp->pl.b + len > hp->pl.e)
- len = Tlen(hp->pl);
- if (len == 0)
- return (0);
- *b = hp->pl.b;
- *e = hp->pl.b + len;
- hp->pl.b += len;
- Tcheck(hp->pl);
return (1);
}
-/*--------------------------------------------------------------------*/
-/* Read from fd, but soak up any tail first */
-
int
-http_Read(struct http *hp, int fd, void *p, unsigned len)
+HTC_Read(struct http_conn *htc, void *d, unsigned len)
{
+ unsigned l;
+ unsigned char *p;
int i;
- unsigned u;
- char *b = p;
-
- u = 0;
- if (hp->pl.b < hp->pl.e) {
- u = Tlen(hp->pl);
- if (u > len)
- u = len;
- memcpy(b, hp->pl.b, u);
- hp->pl.b += u;
- b += u;
- len -= u;
- }
- if (hp->pl.e == hp->pl.b)
- hp->pl.b = hp->pl.e = NULL;
- if (len > 0) {
- i = read(fd, b, len);
- if (i < 0) /* XXX i == 0 ?? */
- return (i);
- u += i;
+
+ l = 0;
+ p = d;
+ CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+ if (htc->pipeline.b) {
+ l = Tlen(htc->pipeline);
+ if (l > len)
+ l = len;
+ memcpy(p, htc->pipeline.b, l);
+ p += l;
+ len -= l;
+ htc->pipeline.b += l;
+ if (htc->pipeline.b == htc->pipeline.e)
+ htc->pipeline.b = htc->pipeline.e = NULL;
}
- return (u);
+ if (len == 0)
+ return (l);
+ i = read(htc->fd, p, len);
+ if (i < 0)
+ return (i);
+ return (i + l);
}
-
PipeSession(struct sess *sp)
{
struct vbe_conn *vc;
- char *b, *e;
struct worker *w;
struct bereq *bereq;
struct pollfd fds[2];
WRK_Reset(w, &vc->fd);
http_Write(w, bereq->http, 0);
- if (http_GetTail(sp->http, 0, &b, &e) && b != e)
- WRK_Write(w, b, e - b);
+ if (sp->htc->pipeline.b != NULL)
+ WRK_Write(w, sp->htc->pipeline.b, Tlen(sp->htc->pipeline));
if (WRK_Flush(w)) {
vca_close_session(sp, "pipe");