diff options
Diffstat (limited to 'src/handler.c')
-rw-r--r-- | src/handler.c | 74 |
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; } |