#include "chain.hpp"
CPoolPTS<buf_t> buf_pool;
void buf_t::debug() {
log(io, "%p: %zu/%zu -> %p", this, off, len, next);
}
buf_t* chain_t::pop_head() {
assert(head);
buf_t* node = head;
if (head == tail) {
head = NULL;
tail = NULL;
} else {
head = head->next;
}
--bufs;
node->next = NULL;
return node;
}
bool chain_t::add_data(chain_t* c) {
if (!c->head) {
return false;
}
c->head->rewind(); // only for first buf
if (!tail) {
assert(!bufs && !head);
head = c->head;
tail = c->tail;
bufs = c->bufs;
} else if (tail->has_space()) {
return false; // should not happen in our scenario
} else {
tail->next = c->head;
tail = c->tail;
bufs += c->bufs;
}
is_initial_data = false; // not sure about that
c->head = NULL;
c->tail = NULL;
c->bufs = 0;
return true;
}
void chain_t::add_data(const char* buf, size_t len) {
char* b;
size_t l;
while (len) {
buf_t* nbuf = NULL;
if (!get_space(b, l)) {
nbuf = buf_pool.pop();
nbuf->get_space(b, l);
}
l = MIN(l, len);
memcpy(b, buf, l);
len -= l;
buf += l;
if (nbuf) {
nbuf->add_data(l);
add_data(nbuf);
} else {
add_data(l);
}
}
}
/*void chain_t::prepend(chain_t* c) {
if (!c->head) {
return;
} else {
assert(c->bufs && c->tail);
}
bufs += c->bufs;
c->tail->next = head;
head = c->head;
is_initial_data = c->is_initial_data;
c->head = NULL;
c->tail = NULL;
c->bufs = 0;
c->is_initial_data = true;
}*/
void chain_t::prepend(buf_t* b) {
assert(is_initial_data);
if (!b->has_data()) {
buf_pool.push(b);
return;
}
if (!tail) {
b->next = NULL;
head = b;
tail = b;
} else {
assert(false); // TODO: have to review is_done() checks if we need this
b->next = head;
head = b;
}
++bufs;
}
tristate_t chain_t::startswith(const char* s, size_t sl) const {
if (!is_initial_data) return TRI_FALSE; // cannot know (anymore)
if (!head || !head->has_data()) return TRI_NONE; // cannot know (yet)
const char* b;
size_t bl;
head->get_data(b, bl);
assert(b == (const char*)head); // as buf is first member and its the initial data
if (strncmp(b, s, MIN(bl, sl)) != 0) return TRI_FALSE; // cannot be
if (bl < sl) return TRI_NONE; // cannot know (yet)
return TRI_TRUE; // can be sure now
}
tristate_t chain_t::is_http_req() const {
return startswith("GET /", cstrlen("GET /"));
}
tristate_t chain_t::is_http_resp() const {
return startswith("HTTP/1", cstrlen("HTTP/1"));
}
void chain_t::debug() {
log(io, "chain %p (%p->%p #%zu):", this, head, tail, bufs);
buf_t* node = head;
while (node) {
node->debug();
node = node->next;
}
}