mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-08-25 07:26:24 +00:00
139 lines
3.9 KiB
C
139 lines
3.9 KiB
C
#include <uwsgi.h>
|
|
|
|
#if defined(UWSGI_ROUTING)
|
|
|
|
/*
|
|
|
|
offload transformation
|
|
|
|
each chunk is buffered to the transformation custom buffer
|
|
|
|
if the buffer grows higher than the specified limit, the response will be buffered to disk
|
|
|
|
on final the memory (or the tmpfile) will be offloaded
|
|
|
|
even if we are talking about buffering, this is a streaming transformation
|
|
as we need to hold control on memory usage
|
|
|
|
"offload" MUST BE the last transformation in the chain. Hellish things will happen otherwise...
|
|
|
|
*/
|
|
|
|
static int transform_offload(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) {
|
|
|
|
if (ut->is_final) {
|
|
struct uwsgi_transformation *orig_ut = (struct uwsgi_transformation *) ut->data;
|
|
// sendfile offload
|
|
if (orig_ut->fd > -1) {
|
|
if (!uwsgi_offload_request_sendfile_do(wsgi_req, orig_ut->fd, orig_ut->len)) {
|
|
// the fd will be closed by the offload engine
|
|
orig_ut->fd = -1;
|
|
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
|
wsgi_req->response_size += orig_ut->len;
|
|
return 0;
|
|
}
|
|
// fallback to non-offloaded write
|
|
if (uwsgi_simple_sendfile(wsgi_req, orig_ut->fd, 0, orig_ut->len)) {
|
|
return -1;
|
|
}
|
|
wsgi_req->response_size += orig_ut->len;
|
|
return 0;
|
|
}
|
|
// memory offload
|
|
if (orig_ut->ub) {
|
|
if (!uwsgi_offload_request_memory_do(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) {
|
|
// memory will be freed by the offload engine
|
|
orig_ut->ub->buf = NULL;
|
|
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
|
wsgi_req->response_size += orig_ut->ub->pos;
|
|
return 0;
|
|
}
|
|
// fallback to non-offloaded write
|
|
if (uwsgi_simple_write(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) {
|
|
return -1;
|
|
}
|
|
wsgi_req->response_size += orig_ut->ub->pos;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// check if we need to start buffering to disk
|
|
if (ut->fd == -1 && ut->len + ut->chunk->pos > ut->custom64) {
|
|
ut->fd = uwsgi_tmpfd();
|
|
if (ut->fd < 0) return -1;
|
|
// save already buffered data
|
|
if (ut->ub) {
|
|
ssize_t wlen = write(ut->fd, ut->ub->buf, ut->ub->pos);
|
|
if (wlen != (ssize_t) ut->ub->pos) {
|
|
uwsgi_req_error("transform_offload/write()");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if fd > -1, append to file
|
|
if (ut->fd > -1) {
|
|
ssize_t wlen = write(ut->fd, ut->chunk->buf, ut->chunk->pos);
|
|
if (wlen != (ssize_t) ut->chunk->pos) {
|
|
uwsgi_req_error("transform_offload/write()");
|
|
return -1;
|
|
}
|
|
ut->len += wlen;
|
|
goto done;
|
|
}
|
|
|
|
// buffer to memory
|
|
if (!ut->ub) {
|
|
ut->ub = uwsgi_buffer_new(ut->chunk->pos);
|
|
}
|
|
|
|
// append the chunk to the custom buffer
|
|
if (uwsgi_buffer_append(ut->ub, ut->chunk->buf, ut->chunk->pos)) return -1;
|
|
ut->len += ut->chunk->pos;
|
|
done:
|
|
// reset the chunk !!!
|
|
ut->chunk->pos = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int uwsgi_routing_func_offload(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
|
if (!wsgi_req->socket->can_offload) {
|
|
uwsgi_log("unable to use the offload transformation without offload threads !!!\n");
|
|
return UWSGI_ROUTE_BREAK;
|
|
}
|
|
struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_offload, NULL);
|
|
ut->can_stream = 1;
|
|
ut->custom64 = ur->custom;
|
|
// add a "final" transformation to add the trailing chunk
|
|
ut = uwsgi_add_transformation(wsgi_req, transform_offload, ut);
|
|
ut->is_final = 1;
|
|
return UWSGI_ROUTE_NEXT;
|
|
}
|
|
|
|
static int uwsgi_router_offload(struct uwsgi_route *ur, char *args) {
|
|
ur->func = uwsgi_routing_func_offload;
|
|
if (args[0] == 0) {
|
|
// 1 MB limit
|
|
ur->custom = 1024 * 1024;
|
|
}
|
|
else {
|
|
ur->custom = strtoul(args, NULL, 10);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void router_offload_register(void) {
|
|
uwsgi_register_router("offload", uwsgi_router_offload);
|
|
}
|
|
|
|
struct uwsgi_plugin transformation_offload_plugin = {
|
|
.name = "transformation_offload",
|
|
.on_load = router_offload_register,
|
|
};
|
|
#else
|
|
struct uwsgi_plugin transformation_offload_plugin = {
|
|
.name = "transformation_offload",
|
|
};
|
|
#endif
|