int MultipartFormPeek(MultipartFormRef const form, MultipartEvent *const type, uv_buf_t *const buf) { if(!form) return UV_EINVAL; if(!type) return UV_EINVAL; if(!buf) return UV_EINVAL; uv_buf_t raw[1]; HTTPEvent t; int rc; ssize_t len; for(;;) { if(MultipartNothing != form->type) break; rc = HTTPConnectionPeek(form->conn, &t, raw); if(rc < 0) return rc; if(HTTPMessageEnd == t) { *raw = uv_buf_init(NULL, 0); t = HTTPBody; } if(HTTPBody != t) { assertf(0, "Multipart unexpected HTTP event: %d\n", t); return UV_UNKNOWN; } len = multipart_parser_execute(form->parser, raw->base, raw->len); if(len < 0) { alogf("Multipart parse error\n"); return -1; } HTTPConnectionPop(form->conn, len); } assertf(MultipartNothing != form->type, "MultipartFormPeek must return an event"); *type = form->type; *buf = *form->out; return 0; }
ssize_t HTTPConnectionReadRequest(HTTPConnectionRef const conn, HTTPMethod *const method, str_t *const out, size_t const max) { if(!conn) return UV_EINVAL; if(!max) return UV_EINVAL; uv_buf_t buf[1]; int rc; HTTPEvent type; size_t len = 0; for(;;) { // Use unref because we shouldn't block the server // on a request that may never arrive. uv_unref((uv_handle_t *)conn->stream); rc = HTTPConnectionPeek(conn, &type, buf); uv_ref((uv_handle_t *)conn->stream); if(rc < 0) return rc; if(HTTPHeaderField == type || HTTPHeadersComplete == type) break; HTTPConnectionPop(conn, buf->len); if(HTTPMessageBegin == type) continue; if(HTTPURL != type) { assertf(0, "Unexpected HTTP event %d", type); return UV_UNKNOWN; } if(len+buf->len+1 > max) return UV_EMSGSIZE; memcpy(out+len, buf->base, buf->len); len += buf->len; out[len] = '\0'; } *method = conn->parser->method; return (ssize_t)len; }
int HTTPHeadersLoad(HTTPHeadersRef const h, HTTPConnectionRef const conn) { if(!h) return 0; if(!conn) return UV_EINVAL; uv_buf_t buf[1]; HTTPEvent type; str_t field[FIELD_MAX]; str_t value[VALUE_MAX]; int rc; for(;;) { rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPHeadersComplete == type) { HTTPConnectionPop(conn, buf->len); break; } ssize_t const flen = HTTPConnectionReadHeaderField(conn, field, sizeof(field)); ssize_t const vlen = HTTPConnectionReadHeaderValue(conn, value, sizeof(value)); if(UV_EMSGSIZE == flen) continue; if(flen < 0) return flen; if(vlen < 0) return vlen; if(h->count >= HEADERS_MAX) return UV_EMSGSIZE; if(h->offset+flen+1 > FIELDS_SIZE) return UV_EMSGSIZE; if(h->total+vlen > TOTAL_MAX) return UV_EMSGSIZE; if(!flen) continue; // We could use strlcpy() here, but it doesn't buy us much... memcpy(h->fields + h->offset, field, flen+1); h->offset += flen+1; h->values[h->count] = strndup(value, vlen); h->count++; h->total += vlen+1; } return 0; }
int HTTPConnectionReadBody(HTTPConnectionRef const conn, uv_buf_t *const buf) { if(!conn) return UV_EINVAL; HTTPEvent type; int rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPBody != type && HTTPMessageEnd != type) { assertf(0, "Unexpected HTTP event %d", type); return UV_UNKNOWN; } HTTPConnectionPop(conn, buf->len); return 0; }
int HTTPConnectionReadResponseStatus(HTTPConnectionRef const conn) { if(!conn) return UV_EINVAL; uv_buf_t buf[1]; int rc; HTTPEvent type; for(;;) { rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPHeaderField == type || HTTPHeadersComplete == type) break; if(HTTPMessageBegin != type) { assertf(0, "Unexpected HTTP event %d", type); return UV_UNKNOWN; } HTTPConnectionPop(conn, buf->len); } return conn->parser->status_code; }
int HTTPConnectionReadBodyLine(HTTPConnectionRef const conn, str_t out[], size_t const max) { if(!conn) return UV_EINVAL; if(!max) return UV_EINVAL; uv_buf_t buf[1]; int rc; size_t i; HTTPEvent type; out[0] = '\0'; for(;;) { rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPMessageEnd == type) { if(out[0]) return 0; HTTPConnectionPop(conn, buf->len); return UV_EOF; } if(HTTPBody != type) { assertf(0, "Unexpected HTTP event %d", type); return UV_UNKNOWN; } for(i = 0; i < buf->len; ++i) { if('\r' == buf->base[i]) break; if('\n' == buf->base[i]) break; } append_buf_to_string(out, max, buf->base, i); HTTPConnectionPop(conn, i); if(i < buf->len) break; } rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPMessageEnd == type) { if(out[0]) return 0; HTTPConnectionPop(conn, i); return UV_EOF; } if(HTTPBody != type) return UV_UNKNOWN; if('\r' == buf->base[0]) HTTPConnectionPop(conn, 1); rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPMessageEnd == type) { if(out[0]) return 0; HTTPConnectionPop(conn, i); return UV_EOF; } if(HTTPBody != type) return UV_UNKNOWN; if('\n' == buf->base[0]) HTTPConnectionPop(conn, 1); return 0; }
int HTTPConnectionDrainMessage(HTTPConnectionRef const conn) { if(!conn) return 0; if(HTTPStreamEOF & conn->flags) return UV_EOF; if(!(HTTPMessageIncomplete & conn->flags)) return 0; uv_buf_t buf[1]; int rc; HTTPEvent type; for(;;) { rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPMessageBegin == type) { assertf(0, "HTTPConnectionDrainMessage shouldn't start a new message"); return UV_UNKNOWN; } HTTPConnectionPop(conn, buf->len); if(HTTPMessageEnd == type) break; } return 0; }
ssize_t HTTPConnectionReadHeaderValue(HTTPConnectionRef const conn, str_t out[], size_t const max) { if(!conn) return UV_EINVAL; uv_buf_t buf[1]; int rc; HTTPEvent type; size_t len = 0; if(max > 0) out[0] = '\0'; for(;;) { rc = HTTPConnectionPeek(conn, &type, buf); if(rc < 0) return rc; if(HTTPHeaderField == type) break; if(HTTPHeadersComplete == type) break; HTTPConnectionPop(conn, buf->len); if(HTTPHeaderValue != type) { assertf(0, "Unexpected HTTP event %d", type); return UV_UNKNOWN; } if(len+buf->len+1 > max) return UV_EMSGSIZE; memcpy(out+len, buf->base, buf->len); len += buf->len; out[len] = '\0'; } return (ssize_t)len; }