static inline void conn_refcnt_dec(struct connection *c) { c->refcnt--; if (0 == c->refcnt) { struct http_request *r, *first, *next; if (NULL != c->pending_reqs) { first = r = c->pending_reqs; do { next = r->next; /* FIXME: don't do this if the request * has been made external to this * component. */ if (!(r->flags & HTTP_REQ_PROCESSED)) { http_free_request(r); } r = next; } while (first != r); } free(c); } }
static int connection_get_reply(struct connection *c, char *resp, int resp_sz) { struct http_request *r; int used = 0; /* * Currently, this doesn't do anything interesting. In the * future it will call the content provider and get the * (ready) response. */ r = c->pending_reqs; if (NULL == r) return 0; while (r) { struct http_request *next; struct cos_array *arr = NULL; char *local_resp; int *more = NULL; int local_more, consumed, ret, local_resp_sz; assert(r->c == c); if (r->flags & HTTP_REQ_PENDING) break; assert(r->flags & HTTP_REQ_PROCESSED); assert(r->content_id >= 0); /* Previously saved response? */ if (NULL != r->resp.resp) { local_resp = r->resp.resp; local_resp_sz = r->resp.resp_len; local_more = r->resp.more; } else { /* Make the request to the content * component */ more = cos_argreg_alloc(sizeof(int)); assert(more); arr = cos_argreg_alloc(sizeof(struct cos_array) + resp_sz - used); assert(arr); arr->sz = resp_sz - used; if ((ret = content_retrieve(cos_spd_id(), r->content_id, arr, more))) { cos_argreg_free(arr); cos_argreg_free(more); if (0 > ret) { BUG(); /* FIXME send an error message. */ } printc("https get reply returning %d.\n", ret); return ret; } local_more = *more; local_resp_sz = arr->sz; local_resp = arr->mem; } /* still more date, but not available now... */ if (local_resp_sz == 0) { cos_argreg_free(arr); cos_argreg_free(more); break; } /* If the header and data couldn't fit into the * provided buffer, then we need to save the response, * so that we can send it out later... */ if (http_get_header(resp+used, resp_sz-used, local_resp_sz, &consumed)) { if (NULL == r->resp.resp) { char *save; save = malloc(local_resp_sz); assert(save); assert(arr); memcpy(save, arr->mem, local_resp_sz); cos_argreg_free(arr); r->resp.more = *more; cos_argreg_free(more); r->resp.resp = save; r->resp.resp_len = local_resp_sz; } if (0 == used) { printc("https: could not allocate either header or response of sz %d:%s\n", local_resp_sz, local_resp); if (arr) cos_argreg_free(arr); if (more) cos_argreg_free(more); return -ENOMEM; } break; } memcpy(resp+used+consumed, local_resp, local_resp_sz); if (arr) cos_argreg_free(arr); if (more) cos_argreg_free(more); more = NULL; arr = NULL; used += local_resp_sz + consumed; next = r->next; /* bookkeeping */ http_req_cnt++; http_free_request(r); r = c->pending_reqs; assert(r == next || NULL == r); } return used; }
/* * This is annoying, but the caller needs to know the buffer size of * the request that we are using. In most cases, the passed in buffer * is what we use, so it isn't an issue, but if we malloc our own * buffer (see the HTTP_REQ_PENDING case), then the total buffer size * can grow. Thus the buff_sz argument. */ static struct http_request *connection_handle_request(struct connection *c, char *buff, int amnt, int *buff_sz) { struct http_request *r, *last; *buff_sz = amnt; r = http_new_request(c, buff, amnt); if (NULL == r) return NULL; last = r->prev; /* * If a previous request required more data to parse correctly * (was pending), then we need to combine its buffer with the * current one and try to parse again. */ if (last != r && last->flags & HTTP_REQ_PENDING) { char *new_buff; int new_len; if (last->prev != last && last->prev->flags & HTTP_REQ_PENDING) { http_free_request(r); return NULL; } new_len = amnt + last->req_len; new_buff = malloc(new_len + 1); if (NULL == new_buff) { printc("malloc fail 1\n"); fflush(stdout); http_free_request(r); return NULL; } memcpy(new_buff, last->req, last->req_len); memcpy(new_buff + last->req_len, buff, amnt); buff = new_buff; *buff_sz = amnt = new_len; new_buff[new_len] = '\0'; http_free_request(last); if (r->flags & HTTP_REQ_MALLOC) free(r->req); r->req_len = new_len; r->req = new_buff; r->flags |= HTTP_REQ_MALLOC; } /* * Process the list of requests first, then go through and * actually make the requests. */ if (http_parse_request(r)) { char *save_buff; /* parse error?! Parsing broke somewhere _in_ the * message, so we need to report this as an error */ if (r->req_len != amnt) { /* FIXME: kill connection */ http_free_request(r); return NULL; } assert(r->req_len == amnt && r->req == buff); /* * If we failed because we simply don't have a whole * message (more data is pending), then store it away * appropriately. */ save_buff = malloc(amnt + 1); if (NULL == save_buff) { printc("malloc fail 2\n"); fflush(stdout); /* FIXME: kill connection */ http_free_request(r); return NULL; } memcpy(save_buff, buff, amnt); save_buff[amnt] = '\0'; if (r->flags & HTTP_REQ_MALLOC) free(r->req); r->req = save_buff; r->flags |= (HTTP_REQ_PENDING | HTTP_REQ_MALLOC); } return r; }
static int connection_get_reply(struct connection *c, char *resp, int resp_sz) { struct http_request *r; int used = 0; /* * Currently, this doesn't do anything interesting. In the * future it will call the content provider and get the * (ready) response. */ r = c->pending_reqs; if (NULL == r) return 0; while (r) { struct http_request *next; char *local_resp; cbuf_t cb; int consumed, ret, local_resp_sz; assert(r->c == c); if (r->flags & HTTP_REQ_PENDING) break; assert(r->flags & HTTP_REQ_PROCESSED); assert(r->content_id >= 0); /* Previously saved response? */ if (NULL != r->resp.resp) { local_resp = r->resp.resp; local_resp_sz = r->resp.resp_len; } else { int sz; /* Make the request to the content * component */ sz = resp_sz - used; local_resp = cbuf_alloc(sz, &cb); if (!local_resp) BUG(); ret = server_tread(cos_spd_id(), r->content_id, cb, sz); if (ret < 0) { cbuf_free(local_resp); printc("https get reply returning %d.\n", ret); return ret; } local_resp_sz = ret; } /* no more data */ if (local_resp_sz == 0) { cbuf_free(local_resp); break; } /* If the header and data couldn't fit into the * provided buffer, then we need to save the response, * so that we can send it out later... */ if (http_get_header(resp+used, resp_sz-used, local_resp_sz, &consumed)) { if (NULL == r->resp.resp) { char *save; save = malloc(local_resp_sz); assert(save); assert(local_resp); memcpy(save, local_resp, local_resp_sz); cbuf_free(local_resp); local_resp = NULL; r->resp.resp = save; r->resp.resp_len = local_resp_sz; } if (0 == used) { printc("https: could not allocate either header or response of sz %d:%s\n", local_resp_sz, local_resp); if (local_resp) cbuf_free(local_resp); return -ENOMEM; } break; } memcpy(resp+used+consumed, local_resp, local_resp_sz); assert(local_resp); cbuf_free(local_resp); local_resp = NULL; used += local_resp_sz + consumed; next = r->next; /* bookkeeping */ http_req_cnt++; http_free_request(r); r = c->pending_reqs; assert(r == next || NULL == r); } return used; }