Refactor the sucker

parent 7d5f638d
......@@ -1079,23 +1079,65 @@ tus_file_new(VRT_CTX, struct VPFX(tus_server) *srv, enum tus_f_type type,
return (NULL);
}
struct tus_suck {
unsigned magic;
#define TUS_SUCK_MAGIC 0x10550c55
/* ------------------------------------------------------------
* things all suckers have in common
*/
struct tus_suck_common {
VRT_CTX;
VCL_BYTES max;
int fd;
ssize_t *upload_offset;
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)
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;
ssize_t l;
struct tus_suck_fd *suck_fd;
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
(void) flush;
......@@ -1105,29 +1147,58 @@ tus_suck_f(void *priv, unsigned flush, const void *ptr, ssize_t len)
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) {
*suck->upload_offset += l;
if (*suck->upload_offset > suck->max) {
errno = EFBIG;
return (-1);
}
}
static int
tus_suck_fd_truncate_f(void *priv, off_t length)
{
struct tus_suck_fd *suck_fd;
if (l != len)
return (-1);
CAST_OBJ_NOTNULL(suck_fd, priv, TUS_SUCK_FD_MAGIC);
if (suck->chksum)
tus_chksum_update(suck->ctx, suck->chksum, ptr, len);
return (ftruncate(suck_fd->fd, length));
}
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
tus_body_to_file(VRT_CTX, struct tus_file_core *fcore)
{
struct tus_suck suck;
struct tus_suck_common *sc;
const char *hdr;
ssize_t offset_saved, written;
struct tus_file_disk *fdisk;
......@@ -1139,47 +1210,48 @@ tus_body_to_file(VRT_CTX, struct tus_file_core *fcore)
fdisk = fcore->disk;
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;
suck.ctx = ctx;
suck.max = tus_server_max(fcore->server);
sc->ctx = ctx;
sc->max = tus_server_max(fcore->server);
if (fdisk->upload_length != -1 &&
fdisk->upload_length < suck.max)
suck.max = fdisk->upload_length;
fdisk->upload_length < sc->max)
sc->max = fdisk->upload_length;
suck.fd = tus_file_open(fcore);
assert(suck.fd >= 0);
suck.upload_offset = &fdisk->upload_offset;
sc->upload_offset = &fdisk->upload_offset;
if (http_GetHdr(ctx->http_req, hdr_chksum, &hdr)) {
suck.chksum = tus_chksum_hdr(ctx, hdr);
if (suck.chksum == NULL)
sc->chksum = tus_chksum_hdr(ctx, hdr);
if (sc->chksum == NULL)
return (400);
}
written = VRB_Iterate(ctx->req->wrk, ctx->vsl, ctx->req,
tus_suck_f, &suck);
suck.func, &suck.priv);
if (written < 0 && errno == EFBIG) {
fdisk->upload_offset = fdisk->upload_length = suck.max;
AZ(ftruncate(fcore->fd, header_size + suck.max));
fdisk->upload_offset = fdisk->upload_length = sc->max;
tus_suck_trunc(&suck, header_size + sc->max);
return (413);
}
if (suck.chksum == NULL) {
if (sc->chksum == NULL) {
if (written >= 0)
return (204);
else
return (408); // Timeout
}
if (tus_chksum_equal(ctx, suck.chksum))
if (tus_chksum_equal(ctx, sc->chksum))
return (204);
fcore->disk->upload_offset = offset_saved;
AZ(ftruncate(fcore->fd, header_size + offset_saved));
tus_suck_trunc(&suck, header_size + offset_saved);
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