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;
}
Пример #4
0
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;
}