mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-20 21:53:12 +00:00
Improve HTTP server generated content logic
Support generated content with an unspecified Content-Length. Generator functions return 1 if there is more content to come, and 0 if they have just produced the last piece of content.
This commit is contained in:
parent
051eca4775
commit
d337542067
@ -1642,16 +1642,22 @@ static void http_request_receive(struct http_request *r)
|
|||||||
*/
|
*/
|
||||||
static void http_request_send_response(struct http_request *r)
|
static void http_request_send_response(struct http_request *r)
|
||||||
{
|
{
|
||||||
|
if (r->response_length != CONTENT_LENGTH_UNKNOWN)
|
||||||
assert(r->response_sent <= r->response_length);
|
assert(r->response_sent <= r->response_length);
|
||||||
while (r->response_sent < r->response_length) {
|
int g = 1;
|
||||||
|
while (g) {
|
||||||
|
if (r->response_length != CONTENT_LENGTH_UNKNOWN && r->response_sent == r->response_length)
|
||||||
|
break;
|
||||||
assert(r->response_buffer_sent <= r->response_buffer_length);
|
assert(r->response_buffer_sent <= r->response_buffer_length);
|
||||||
if (r->response_buffer_sent == r->response_buffer_length) {
|
if (r->response_buffer_sent == r->response_buffer_length) {
|
||||||
|
g = 0;
|
||||||
if (r->response.content_generator) {
|
if (r->response.content_generator) {
|
||||||
// Content generator must fill or partly fill response_buffer and set response_buffer_sent
|
// Content generator must fill or partly fill response_buffer and set response_buffer_sent
|
||||||
// and response_buffer_length. May also malloc() a bigger buffer and set response_buffer to
|
// and response_buffer_length. May also malloc() a bigger buffer and set response_buffer to
|
||||||
// point to it.
|
// point to it.
|
||||||
r->response_buffer_sent = r->response_buffer_length = 0;
|
r->response_buffer_sent = r->response_buffer_length = 0;
|
||||||
if (r->response.content_generator(r) == -1) {
|
g = r->response.content_generator(r);
|
||||||
|
if (g == -1) {
|
||||||
if (r->debug_flag && *r->debug_flag)
|
if (r->debug_flag && *r->debug_flag)
|
||||||
DEBUG("Content generation error, closing connection");
|
DEBUG("Content generation error, closing connection");
|
||||||
http_request_finalise(r);
|
http_request_finalise(r);
|
||||||
@ -1659,12 +1665,17 @@ static void http_request_send_response(struct http_request *r)
|
|||||||
}
|
}
|
||||||
assert(r->response_buffer_sent <= r->response_buffer_length);
|
assert(r->response_buffer_sent <= r->response_buffer_length);
|
||||||
if (r->response_buffer_sent == r->response_buffer_length) {
|
if (r->response_buffer_sent == r->response_buffer_length) {
|
||||||
|
if (g == 0)
|
||||||
|
break;
|
||||||
|
if (r->response_length != CONTENT_LENGTH_UNKNOWN)
|
||||||
WHYF("HTTP response generator produced no content at offset %"PRIhttp_size_t"/%"PRIhttp_size_t" (%"PRIhttp_size_t" bytes remaining)",
|
WHYF("HTTP response generator produced no content at offset %"PRIhttp_size_t"/%"PRIhttp_size_t" (%"PRIhttp_size_t" bytes remaining)",
|
||||||
r->response_sent, r->response_length, r->response_length - r->response_sent);
|
r->response_sent, r->response_length, r->response_length - r->response_sent);
|
||||||
|
else
|
||||||
|
WHYF("HTTP response generator produced no content at offset %"PRIhttp_size_t"", r->response_sent);
|
||||||
http_request_finalise(r);
|
http_request_finalise(r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (r->response_length != CONTENT_LENGTH_UNKNOWN) {
|
||||||
WHYF("HTTP response is short of total length (%"PRIhttp_size_t") by %"PRIhttp_size_t" bytes",
|
WHYF("HTTP response is short of total length (%"PRIhttp_size_t") by %"PRIhttp_size_t" bytes",
|
||||||
r->response_length, r->response_length - r->response_sent);
|
r->response_length, r->response_length - r->response_sent);
|
||||||
http_request_finalise(r);
|
http_request_finalise(r);
|
||||||
@ -1900,6 +1911,7 @@ static int _render_response(struct http_request *r)
|
|||||||
hr.header.resource_length
|
hr.header.resource_length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (hr.header.content_length != CONTENT_LENGTH_UNKNOWN)
|
||||||
strbuf_sprintf(sb, "Content-Length: %"PRIhttp_size_t"\r\n", hr.header.content_length);
|
strbuf_sprintf(sb, "Content-Length: %"PRIhttp_size_t"\r\n", hr.header.content_length);
|
||||||
const char *scheme = NULL;
|
const char *scheme = NULL;
|
||||||
switch (hr.header.www_authenticate.scheme) {
|
switch (hr.header.www_authenticate.scheme) {
|
||||||
@ -1913,17 +1925,23 @@ static int _render_response(struct http_request *r)
|
|||||||
strbuf_puts(sb, "\r\n");
|
strbuf_puts(sb, "\r\n");
|
||||||
}
|
}
|
||||||
strbuf_puts(sb, "\r\n");
|
strbuf_puts(sb, "\r\n");
|
||||||
if (strbuf_overrun(sb))
|
if (hr.header.content_length != CONTENT_LENGTH_UNKNOWN)
|
||||||
return 0;
|
r->response_length = strbuf_count(sb) + hr.header.content_length;
|
||||||
r->response_length = strbuf_len(sb) + hr.header.content_length;
|
else
|
||||||
|
r->response_length = CONTENT_LENGTH_UNKNOWN;
|
||||||
if (hr.content) {
|
if (hr.content) {
|
||||||
if (r->response_buffer_size < r->response_length)
|
assert(r->response_length != CONTENT_LENGTH_UNKNOWN);
|
||||||
return 0;
|
r->response_buffer_need = r->response_length + 1;
|
||||||
bcopy(hr.content, strbuf_end(sb), hr.header.content_length);
|
|
||||||
r->response_buffer_length = r->response_length;
|
|
||||||
} else {
|
} else {
|
||||||
r->response_buffer_length = strbuf_len(sb);
|
assert(hr.content_generator);
|
||||||
|
r->response_buffer_need = strbuf_count(sb) + 1;
|
||||||
}
|
}
|
||||||
|
if (r->response_buffer_size < r->response_buffer_need)
|
||||||
|
return 0;
|
||||||
|
assert(!strbuf_overrun(sb));
|
||||||
|
if (hr.content)
|
||||||
|
bcopy(hr.content, strbuf_end(sb), hr.header.content_length);
|
||||||
|
r->response_buffer_length = r->response_buffer_need;
|
||||||
r->response_buffer_sent = 0;
|
r->response_buffer_sent = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1942,9 +1960,9 @@ static void http_request_render_response(struct http_request *r)
|
|||||||
// rendered headers, so after this step, whether or not the buffer was overrun, we know the total
|
// rendered headers, so after this step, whether or not the buffer was overrun, we know the total
|
||||||
// length of the response.
|
// length of the response.
|
||||||
if (!_render_response(r)) {
|
if (!_render_response(r)) {
|
||||||
// If the response did not fit into the existing buffer, then allocate a large buffer from the
|
// If the static response did not fit into the existing buffer, then allocate a large buffer
|
||||||
// heap and try rendering again.
|
// from the heap and try rendering again.
|
||||||
if (http_request_set_response_bufsize(r, r->response_length + 1) == -1)
|
if (http_request_set_response_bufsize(r, r->response_buffer_need) == -1)
|
||||||
WHY("Cannot render HTTP response, out of memory");
|
WHY("Cannot render HTTP response, out of memory");
|
||||||
else if (!_render_response(r))
|
else if (!_render_response(r))
|
||||||
FATAL("Re-render of HTTP response overflowed buffer");
|
FATAL("Re-render of HTTP response overflowed buffer");
|
||||||
|
@ -192,6 +192,7 @@ struct http_request {
|
|||||||
http_size_t response_length; // total response bytes (header + content)
|
http_size_t response_length; // total response bytes (header + content)
|
||||||
http_size_t response_sent; // for counting up to response_length
|
http_size_t response_sent; // for counting up to response_length
|
||||||
char *response_buffer;
|
char *response_buffer;
|
||||||
|
size_t response_buffer_need;
|
||||||
size_t response_buffer_size;
|
size_t response_buffer_size;
|
||||||
size_t response_buffer_length;
|
size_t response_buffer_length;
|
||||||
size_t response_buffer_sent;
|
size_t response_buffer_sent;
|
||||||
|
@ -443,7 +443,7 @@ static int rhizome_file_content(struct http_request *hr)
|
|||||||
return -1;
|
return -1;
|
||||||
assert((size_t) len <= r->http.response_buffer_size);
|
assert((size_t) len <= r->http.response_buffer_size);
|
||||||
r->http.response_buffer_length += (size_t) len;
|
r->http.response_buffer_length += (size_t) len;
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rhizome_file_page(rhizome_http_request *r, const char *remainder)
|
static int rhizome_file_page(rhizome_http_request *r, const char *remainder)
|
||||||
|
Loading…
Reference in New Issue
Block a user