diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core.c | 1 | ||||
-rw-r--r-- | src/core.h | 4 | ||||
-rw-r--r-- | src/handler.c | 74 |
3 files changed, 74 insertions, 5 deletions
@@ -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)); @@ -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; } |