summaryrefslogtreecommitdiffstats
path: root/src/handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/handler.c')
-rw-r--r--src/handler.c74
1 files changed, 69 insertions, 5 deletions
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;
}