mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-17 10:00:45 +00:00
371 lines
11 KiB
C
371 lines
11 KiB
C
#include <uwsgi.h>
|
|
|
|
#ifdef UWSGI_ROUTING
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
|
|
struct uwsgi_router_file_conf {
|
|
|
|
char *filename;
|
|
size_t filename_len;
|
|
|
|
char *status;
|
|
size_t status_len;
|
|
|
|
char *content_type;
|
|
size_t content_type_len;
|
|
|
|
char *mime;
|
|
|
|
char *no_cl;
|
|
|
|
char *no_headers;
|
|
};
|
|
|
|
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
|
|
|
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
|
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
|
|
|
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
|
|
if (!ub) return UWSGI_ROUTE_BREAK;
|
|
|
|
uwsgi_file_serve(wsgi_req, ub->buf, ub->pos, NULL, 0, 1);
|
|
uwsgi_buffer_destroy(ub);
|
|
return UWSGI_ROUTE_BREAK;
|
|
}
|
|
|
|
int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
|
|
|
char buf[32768];
|
|
struct stat st;
|
|
int ret = UWSGI_ROUTE_BREAK;
|
|
size_t remains = 0;
|
|
|
|
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
|
|
|
|
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
|
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
|
|
|
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len);
|
|
if (!ub) return UWSGI_ROUTE_BREAK;
|
|
|
|
int fd = open(ub->buf, O_RDONLY);
|
|
if (fd < 0) {
|
|
if (ur->custom)
|
|
ret = UWSGI_ROUTE_NEXT;
|
|
goto end;
|
|
}
|
|
|
|
if (fstat(fd, &st)) {
|
|
goto end2;
|
|
}
|
|
|
|
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
|
if (!ub_s) goto end2;
|
|
|
|
// static file - don't update avg_rt after request
|
|
wsgi_req->do_not_account_avg_rt = 1;
|
|
|
|
if (urfc->no_headers) {
|
|
uwsgi_buffer_destroy(ub_s);
|
|
goto send;
|
|
}
|
|
|
|
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
|
uwsgi_buffer_destroy(ub_s);
|
|
goto end2;
|
|
}
|
|
uwsgi_buffer_destroy(ub_s);
|
|
if (!urfc->no_cl) {
|
|
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
|
|
}
|
|
if (urfc->mime) {
|
|
size_t mime_type_len = 0;
|
|
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
|
|
if (mime_type) {
|
|
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
|
|
}
|
|
else {
|
|
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
|
}
|
|
}
|
|
else {
|
|
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
|
}
|
|
|
|
send:
|
|
|
|
remains = st.st_size;
|
|
while(remains) {
|
|
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
|
|
if (rlen <= 0) goto end2;
|
|
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end2;
|
|
remains -= rlen;
|
|
}
|
|
|
|
end2:
|
|
close(fd);
|
|
end:
|
|
uwsgi_buffer_destroy(ub);
|
|
return ret;
|
|
}
|
|
|
|
int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
|
|
|
struct stat st;
|
|
int ret = UWSGI_ROUTE_BREAK;
|
|
|
|
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
|
|
|
|
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
|
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
|
|
|
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len);
|
|
if (!ub) return UWSGI_ROUTE_BREAK;
|
|
|
|
int fd = open(ub->buf, O_RDONLY);
|
|
if (fd < 0) {
|
|
if (ur->custom)
|
|
ret = UWSGI_ROUTE_NEXT;
|
|
goto end;
|
|
}
|
|
|
|
if (fstat(fd, &st)) {
|
|
goto end2;
|
|
}
|
|
|
|
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
|
if (!ub_s) goto end2;
|
|
|
|
// static file - don't update avg_rt after request
|
|
wsgi_req->do_not_account_avg_rt = 1;
|
|
|
|
if (urfc->no_headers) {
|
|
uwsgi_buffer_destroy(ub_s);
|
|
goto send;
|
|
}
|
|
|
|
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
|
uwsgi_buffer_destroy(ub_s);
|
|
goto end2;
|
|
}
|
|
uwsgi_buffer_destroy(ub_s);
|
|
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
|
|
if (urfc->mime) {
|
|
size_t mime_type_len = 0;
|
|
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
|
|
if (mime_type) {
|
|
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
|
|
}
|
|
else {
|
|
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
|
}
|
|
}
|
|
else {
|
|
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
|
}
|
|
|
|
send:
|
|
|
|
if (!wsgi_req->headers_sent) {
|
|
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
|
|
}
|
|
|
|
if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) {
|
|
wsgi_req->via = UWSGI_VIA_SENDFILE;
|
|
wsgi_req->response_size += st.st_size;
|
|
}
|
|
|
|
end2:
|
|
close(fd);
|
|
end:
|
|
uwsgi_buffer_destroy(ub);
|
|
return ret;
|
|
}
|
|
|
|
int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
|
|
|
struct stat st;
|
|
int ret = UWSGI_ROUTE_BREAK;
|
|
|
|
struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;
|
|
|
|
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
|
|
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
|
|
|
|
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len);
|
|
if (!ub) return UWSGI_ROUTE_BREAK;
|
|
|
|
int fd = open(ub->buf, O_RDONLY);
|
|
if (fd < 0) {
|
|
if (ur->custom)
|
|
ret = UWSGI_ROUTE_NEXT;
|
|
goto end;
|
|
}
|
|
|
|
if (fstat(fd, &st)) {
|
|
goto end2;
|
|
}
|
|
|
|
struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
|
|
if (!ub_s) goto end2;
|
|
|
|
// static file - don't update avg_rt after request
|
|
wsgi_req->do_not_account_avg_rt = 1;
|
|
|
|
if (urfc->no_headers) {
|
|
uwsgi_buffer_destroy(ub_s);
|
|
goto send;
|
|
}
|
|
|
|
if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
|
|
uwsgi_buffer_destroy(ub_s);
|
|
goto end2;
|
|
}
|
|
uwsgi_buffer_destroy(ub_s);
|
|
if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
|
|
if (urfc->mime) {
|
|
size_t mime_type_len = 0;
|
|
char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
|
|
if (mime_type) {
|
|
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
|
|
}
|
|
else {
|
|
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
|
}
|
|
}
|
|
else {
|
|
if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
|
|
}
|
|
|
|
send:
|
|
|
|
if (!wsgi_req->headers_sent) {
|
|
if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
|
|
}
|
|
|
|
if (wsgi_req->socket->can_offload) {
|
|
if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, st.st_size)) {
|
|
wsgi_req->via = UWSGI_VIA_OFFLOAD;
|
|
wsgi_req->response_size += st.st_size;
|
|
// the fd will be closed by the offload engine
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) {
|
|
wsgi_req->via = UWSGI_VIA_SENDFILE;
|
|
wsgi_req->response_size += st.st_size;
|
|
}
|
|
|
|
end2:
|
|
close(fd);
|
|
end:
|
|
uwsgi_buffer_destroy(ub);
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
static int uwsgi_router_static(struct uwsgi_route *ur, char *args) {
|
|
|
|
ur->func = uwsgi_routing_func_static;
|
|
ur->data = args;
|
|
ur->data_len = strlen(args);
|
|
return 0;
|
|
}
|
|
|
|
static int uwsgi_router_file(struct uwsgi_route *ur, char *args) {
|
|
ur->func = uwsgi_routing_func_file;
|
|
ur->data = args;
|
|
ur->data_len = strlen(args);
|
|
struct uwsgi_router_file_conf *urfc = uwsgi_calloc(sizeof(struct uwsgi_router_file_conf));
|
|
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
|
|
"filename", &urfc->filename,
|
|
"status", &urfc->status,
|
|
"content_type", &urfc->content_type,
|
|
"nocl", &urfc->no_cl,
|
|
"no_cl", &urfc->no_cl,
|
|
"no_content_length", &urfc->no_cl,
|
|
"mime", &urfc->mime,
|
|
"no_headers", &urfc->no_headers,
|
|
NULL)) {
|
|
uwsgi_log("invalid file route syntax: %s\n", args);
|
|
return -1;
|
|
}
|
|
|
|
if (!urfc->filename) {
|
|
uwsgi_log("you have to specifify a filename for the \"file\" router\n");
|
|
free(urfc);
|
|
return -1;
|
|
}
|
|
|
|
urfc->filename_len = strlen(urfc->filename);
|
|
if (!urfc->content_type) {
|
|
urfc->content_type = "text/html";
|
|
}
|
|
urfc->content_type_len = strlen(urfc->content_type);
|
|
|
|
if (!urfc->status) {
|
|
urfc->status = "200 OK";
|
|
}
|
|
urfc->status_len = strlen(urfc->status);
|
|
|
|
ur->data2 = urfc;
|
|
return 0;
|
|
}
|
|
|
|
static int uwsgi_router_file_next(struct uwsgi_route *ur, char *args) {
|
|
ur->custom = 1;
|
|
return uwsgi_router_file(ur, args);
|
|
}
|
|
|
|
static int uwsgi_router_sendfile(struct uwsgi_route *ur, char *args) {
|
|
int ret = uwsgi_router_file(ur, args);
|
|
ur->func = uwsgi_routing_func_sendfile;
|
|
return ret;
|
|
}
|
|
|
|
static int uwsgi_router_sendfile_next(struct uwsgi_route *ur, char *args) {
|
|
ur->custom = 1;
|
|
int ret = uwsgi_router_file(ur, args);
|
|
ur->func = uwsgi_routing_func_sendfile;
|
|
return ret;
|
|
}
|
|
|
|
static int uwsgi_router_fastfile(struct uwsgi_route *ur, char *args) {
|
|
int ret = uwsgi_router_file(ur, args);
|
|
ur->func = uwsgi_routing_func_fastfile;
|
|
return ret;
|
|
}
|
|
|
|
static int uwsgi_router_fastfile_next(struct uwsgi_route *ur, char *args) {
|
|
ur->custom = 1;
|
|
int ret = uwsgi_router_file(ur, args);
|
|
ur->func = uwsgi_routing_func_fastfile;
|
|
return ret;
|
|
}
|
|
|
|
static void router_static_register(void) {
|
|
|
|
uwsgi_register_router("static", uwsgi_router_static);
|
|
uwsgi_register_router("file", uwsgi_router_file);
|
|
uwsgi_register_router("file-next", uwsgi_router_file_next);
|
|
uwsgi_register_router("sendfile", uwsgi_router_sendfile);
|
|
uwsgi_register_router("sendfile-next", uwsgi_router_sendfile_next);
|
|
uwsgi_register_router("fastfile", uwsgi_router_fastfile);
|
|
uwsgi_register_router("fastfile-next", uwsgi_router_fastfile_next);
|
|
}
|
|
|
|
struct uwsgi_plugin router_static_plugin = {
|
|
|
|
.name = "router_static",
|
|
.on_load = router_static_register,
|
|
};
|
|
#else
|
|
struct uwsgi_plugin router_static_plugin = {
|
|
.name = "router_static",
|
|
};
|
|
#endif
|