summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortiptorrent development team <tiptorrent@soleta.eu>2021-09-23 22:05:20 +0200
committertiptorrent development team <tiptorrent@soleta.eu>2021-09-29 15:49:11 +0200
commit324fdcfd583dbd95ce479712be57c6ca93c29fbb (patch)
tree472f5b4c00587ed8cd49d8987c806100ab5acb1b
parente39f7f8e3c940cb6e6fd23e99f03017bb5865114 (diff)
runtime split original file into chunks
No need to split the original file on the server side.
-rw-r--r--src/core.c1
-rw-r--r--src/core.h4
-rw-r--r--src/handler.c74
3 files changed, 74 insertions, 5 deletions
diff --git a/src/core.c b/src/core.c
index ff471cc..8caabec 100644
--- a/src/core.c
+++ b/src/core.c
@@ -471,6 +471,7 @@ void tip_server_accept_cb(struct ev_loop *loop, struct ev_io *io, int events)
}
memcpy(&cli->addr, &client_addr, sizeof(client_addr));
cli->fd = -1;
+ cli->chunk = -1;
syslog(LOG_ERR, "accepting client connection from %s:%hu",
inet_ntoa(cli->addr.sin_addr), htons(cli->addr.sin_port));
diff --git a/src/core.h b/src/core.h
index 36fb205..0a82d2e 100644
--- a/src/core.h
+++ b/src/core.h
@@ -6,6 +6,8 @@
#include <stdbool.h>
#include <netinet/in.h>
+#define MAX_CHUNKS 4
+
#define TIP_MSG_REQUEST_MAXLEN 131072
extern const char *root;
@@ -48,7 +50,9 @@ struct tip_client {
enum tip_http_method method;
const char *uri;
const char *path;
+ uint32_t chunk;
off_t size;
+ off_t left;
int fd;
off_t offset;
diff --git a/src/handler.c b/src/handler.c
index 54c2c1b..f3ce8ec 100644
--- a/src/handler.c
+++ b/src/handler.c
@@ -59,6 +59,7 @@ int tip_client_state_process_payload(struct tip_client *cli)
char _uri[32], *uri = _uri;
char allow_redirect_str[5];
char path[PATH_MAX + 1];
+ char *chunk = NULL;
struct stat st;
int err;
@@ -93,14 +94,37 @@ int tip_client_state_process_payload(struct tip_client *cli)
if (!sanitize(uri))
return tip_client_method_not_found(cli);
+ /* skip initial / */
+ uri++;
+
+ switch (cli->method) {
+ case TIP_METHOD_GET:
+ case TIP_METHOD_POST:
+ /* get chunk number from file extension, e.g. FILE.0 */
+ chunk = strchr(uri, '.');
+ if (chunk) {
+ *chunk = '\0';
+ chunk++;
+ cli->chunk = atoi(chunk);
+ if (cli->chunk >= MAX_CHUNKS)
+ return tip_client_file_not_found(cli);
+ }
+ break;
+ case TIP_METHOD_HEAD:
+ break;
+ }
+
snprintf(path, PATH_MAX, "%s/%s", root, uri);
err = stat(path, &st);
if (err < 0)
return tip_client_file_not_found(cli);
- /* skip initial / */
- uri++;
+ /* restore the original uri that was mangled. */
+ if (chunk) {
+ chunk--;
+ *chunk = '.';
+ }
cli->uri = strdup(uri);
cli->path = strdup(path);
@@ -139,6 +163,8 @@ int tip_client_state_process_payload(struct tip_client *cli)
int tip_client_state_process_payload_reply(struct tip_client *cli)
{
+ uint64_t chunk_size;
+ off_t chunk_offset;
char buf[1024];
int fd;
@@ -156,8 +182,35 @@ int tip_client_state_process_payload_reply(struct tip_client *cli)
if (fd < 0)
return tip_client_file_not_found(cli);
- if (cli->method == TIP_METHOD_POST)
+ switch (cli->method) {
+ case TIP_METHOD_GET:
+ if (cli->chunk < 0)
+ break;
+
+ chunk_size = cli->size / MAX_CHUNKS;
+ if (cli->size % MAX_CHUNKS) {
+ if (cli->chunk < MAX_CHUNKS - 1) {
+ chunk_size++;
+ chunk_offset = chunk_size * cli->chunk;
+ } else {
+ chunk_offset = chunk_size * cli->chunk;
+ chunk_offset += MAX_CHUNKS - 1;
+ chunk_size--;
+ }
+ } else {
+ chunk_offset = chunk_size * cli->chunk;
+ }
+ cli->size = chunk_size;
+ cli->offset = chunk_offset;
+ break;
+ case TIP_METHOD_POST:
cli->size = 0;
+ break;
+ case TIP_METHOD_HEAD:
+ break;
+ }
+
+ cli->left = cli->size;
snprintf(buf, sizeof(buf),
"HTTP/1.1 200 OK\r\nContent-Length: %lu\r\n\r\n",
@@ -181,10 +234,21 @@ int tip_client_state_process_payload_reply(struct tip_client *cli)
int tip_client_state_process_payload_bulk(struct tip_client *cli)
{
- if (sendfile(tip_client_socket(cli), cli->fd, &cli->offset, BLOCK) < 0)
+ uint32_t bytes;
+ int ret;
+
+ if (cli->left < BLOCK)
+ bytes = cli->left;
+ else
+ bytes = BLOCK;
+
+ ret = sendfile(tip_client_socket(cli), cli->fd, &cli->offset, bytes);
+ if (ret < 0)
return -1;
- if (cli->offset >= cli->size) {
+ cli->left -= ret;
+
+ if (cli->left <= 0) {
cli->state = TIP_CLIENT_CLOSE_WAIT;
return 1;
}