Refactor the sucker

parent 7d5f638d
...@@ -1079,23 +1079,65 @@ tus_file_new(VRT_CTX, struct VPFX(tus_server) *srv, enum tus_f_type type, ...@@ -1079,23 +1079,65 @@ tus_file_new(VRT_CTX, struct VPFX(tus_server) *srv, enum tus_f_type type,
return (NULL); return (NULL);
} }
struct tus_suck { /* ------------------------------------------------------------
unsigned magic; * things all suckers have in common
#define TUS_SUCK_MAGIC 0x10550c55 */
struct tus_suck_common {
VRT_CTX; VRT_CTX;
VCL_BYTES max; VCL_BYTES max;
int fd;
ssize_t *upload_offset; ssize_t *upload_offset;
struct tus_chksum *chksum; struct tus_chksum *chksum;
}; };
struct tus_suck_fd {
unsigned magic;
#define TUS_SUCK_FD_MAGIC 0x10550c55
int fd;
struct tus_suck_common sc;
};
typedef int suck_truncate_f(void *, off_t);
struct tus_suck {
union {
struct tus_suck_fd fd;
} priv;
objiterate_f *func;
suck_truncate_f *trunc;
};
static int
tus_suck_finish(struct tus_suck_common *sc,
ssize_t written, const void *ptr, ssize_t len)
{
if (written > 0) {
*sc->upload_offset += written;
if (*sc->upload_offset > sc->max) {
errno = EFBIG;
return (-1);
}
}
if (written != len)
return (-1);
if (sc->chksum)
tus_chksum_update(sc->ctx, sc->chksum, ptr, len);
return (0);
}
/* ------------------------------------------------------------
* suck to an fd (data is not mmaped)
*/
static int v_matchproto_(objiterate_f) static int v_matchproto_(objiterate_f)
tus_suck_f(void *priv, unsigned flush, const void *ptr, ssize_t len) tus_suck_fd_f(void *priv, unsigned flush, const void *ptr, ssize_t len)
{ {
struct tus_suck *suck; struct tus_suck_fd *suck_fd;
ssize_t l;
CAST_OBJ_NOTNULL(suck, priv, TUS_SUCK_MAGIC); CAST_OBJ_NOTNULL(suck_fd, priv, TUS_SUCK_FD_MAGIC);
// we could use writev(), but unclear if it is worth it // we could use writev(), but unclear if it is worth it
(void) flush; (void) flush;
...@@ -1105,29 +1147,58 @@ tus_suck_f(void *priv, unsigned flush, const void *ptr, ssize_t len) ...@@ -1105,29 +1147,58 @@ tus_suck_f(void *priv, unsigned flush, const void *ptr, ssize_t len)
assert(len > 0); assert(len > 0);
l = write(suck->fd, ptr, len); return (tus_suck_finish(&suck_fd->sc, write(suck_fd->fd, ptr, len),
ptr, len));
}
if (l > 0) { static int
*suck->upload_offset += l; tus_suck_fd_truncate_f(void *priv, off_t length)
if (*suck->upload_offset > suck->max) { {
errno = EFBIG; struct tus_suck_fd *suck_fd;
return (-1);
}
}
if (l != len) CAST_OBJ_NOTNULL(suck_fd, priv, TUS_SUCK_FD_MAGIC);
return (-1);
if (suck->chksum) return (ftruncate(suck_fd->fd, length));
tus_chksum_update(suck->ctx, suck->chksum, ptr, len); }
return (0); static inline struct tus_suck_common *
tus_suck_fd_init(struct tus_suck *suck, struct tus_file_core *fcore)
{
suck->priv.fd.magic = TUS_SUCK_FD_MAGIC;
suck->priv.fd.fd = tus_file_open(fcore);
assert(suck->priv.fd.fd >= 0);
suck->func = tus_suck_fd_f;
suck->trunc = tus_suck_fd_truncate_f;
return (&suck->priv.fd.sc);
}
/* ------------------------------------------------------------
* suck to mmapped
*/
/* ------------------------------------------------------------
* top level sucking
*/
static inline void
tus_suck_trunc(struct tus_suck *suck, off_t length)
{
if (suck->trunc == NULL)
return;
AZ(suck->trunc(&suck->priv, length));
}
static inline struct tus_suck_common *
tus_suck_init(struct tus_suck *suck, struct tus_file_core *fcore)
{
return (tus_suck_fd_init(suck, fcore));
} }
unsigned unsigned
tus_body_to_file(VRT_CTX, struct tus_file_core *fcore) tus_body_to_file(VRT_CTX, struct tus_file_core *fcore)
{ {
struct tus_suck suck; struct tus_suck suck;
struct tus_suck_common *sc;
const char *hdr; const char *hdr;
ssize_t offset_saved, written; ssize_t offset_saved, written;
struct tus_file_disk *fdisk; struct tus_file_disk *fdisk;
...@@ -1139,47 +1210,48 @@ tus_body_to_file(VRT_CTX, struct tus_file_core *fcore) ...@@ -1139,47 +1210,48 @@ tus_body_to_file(VRT_CTX, struct tus_file_core *fcore)
fdisk = fcore->disk; fdisk = fcore->disk;
CHECK_OBJ_NOTNULL(fdisk, VMOD_TUS_FILE_DISK_MAGIC); CHECK_OBJ_NOTNULL(fdisk, VMOD_TUS_FILE_DISK_MAGIC);
INIT_OBJ(&suck, TUS_SUCK_MAGIC); memset(&suck, 0, sizeof suck);
sc = tus_suck_init(&suck, fcore);
AN(sc);
offset_saved = fcore->disk->upload_offset; offset_saved = fcore->disk->upload_offset;
suck.ctx = ctx; sc->ctx = ctx;
suck.max = tus_server_max(fcore->server); sc->max = tus_server_max(fcore->server);
if (fdisk->upload_length != -1 && if (fdisk->upload_length != -1 &&
fdisk->upload_length < suck.max) fdisk->upload_length < sc->max)
suck.max = fdisk->upload_length; sc->max = fdisk->upload_length;
suck.fd = tus_file_open(fcore); sc->upload_offset = &fdisk->upload_offset;
assert(suck.fd >= 0);
suck.upload_offset = &fdisk->upload_offset;
if (http_GetHdr(ctx->http_req, hdr_chksum, &hdr)) { if (http_GetHdr(ctx->http_req, hdr_chksum, &hdr)) {
suck.chksum = tus_chksum_hdr(ctx, hdr); sc->chksum = tus_chksum_hdr(ctx, hdr);
if (suck.chksum == NULL) if (sc->chksum == NULL)
return (400); return (400);
} }
written = VRB_Iterate(ctx->req->wrk, ctx->vsl, ctx->req, written = VRB_Iterate(ctx->req->wrk, ctx->vsl, ctx->req,
tus_suck_f, &suck); suck.func, &suck.priv);
if (written < 0 && errno == EFBIG) { if (written < 0 && errno == EFBIG) {
fdisk->upload_offset = fdisk->upload_length = suck.max; fdisk->upload_offset = fdisk->upload_length = sc->max;
AZ(ftruncate(fcore->fd, header_size + suck.max)); tus_suck_trunc(&suck, header_size + sc->max);
return (413); return (413);
} }
if (suck.chksum == NULL) { if (sc->chksum == NULL) {
if (written >= 0) if (written >= 0)
return (204); return (204);
else else
return (408); // Timeout return (408); // Timeout
} }
if (tus_chksum_equal(ctx, suck.chksum)) if (tus_chksum_equal(ctx, sc->chksum))
return (204); return (204);
fcore->disk->upload_offset = offset_saved; fcore->disk->upload_offset = offset_saved;
AZ(ftruncate(fcore->fd, header_size + offset_saved)); tus_suck_trunc(&suck, header_size + offset_saved);
return (460); return (460);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment