diff --git a/docs/README.md b/docs/README.md index c1ab71ab..5cf22551 100644 --- a/docs/README.md +++ b/docs/README.md @@ -603,21 +603,20 @@ Free memory pointed by `io->buf` and set to NULL. Both `size` and `len` are set to 0. -### mg\_iobuf\_append() +### mg\_iobuf\_add() ```c -size_t mg_iobuf_append(struct mg_iobuf *io, const void *data, size_t data_size, size_t granularity); +size_t mg_iobuf_add(struct mg_iobuf *io, size_t offset, const void *buf, size_t len, size_t granularity); ``` -Append `data` bytes of size `data_size` to the end of the buffer. The buffer -is expanded if `data_size` is greater than `io->size - io->len`. If that -happens, the `io->buf` can change. The resulting `io->size` is always -set to the `granularity` byte boundary. Example: +Insert data buffer `buf`, `len` at offset `offset`. The iobuf gets +is expanded if required. The resulting `io->size` is always +aligned to the `granularity` byte boundary. Example: ```c struct mg_iobuf io; -mg_iobuf_init(&io, 0); // Empty buffer -mg_iobuf_append(&io, "hi", 2, 1024); // io->len is 2, io->size is 1024 +mg_iobuf_init(&io, 0); // Empty buffer +mg_iobuf_add(&io, 0, "hi", 2, 512); // io->len is 2, io->size is 512 ``` ### mg\_iobuf\_del() diff --git a/mongoose.c b/mongoose.c index e3bbc6f0..ee990d01 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1762,8 +1762,8 @@ int mg_iobuf_init(struct mg_iobuf *io, size_t size) { return mg_iobuf_resize(io, size); } -size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len, - size_t chunk_size) { +size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, + size_t len, size_t chunk_size) { size_t new_size = io->len + len; if (new_size > io->size) { new_size += chunk_size; // Make sure that io->size @@ -1771,7 +1771,9 @@ size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len, mg_iobuf_resize(io, new_size); // Attempt to realloc if (new_size != io->size) len = 0; // Realloc failure, append nothing } - if (buf != NULL) memmove(io->buf + io->len, buf, len); + if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs); + if (buf != NULL) memmove(io->buf + ofs, buf, len); + if (ofs > io->len) io->len += ofs - io->len; io->len += len; return len; } @@ -2935,7 +2937,7 @@ static long mg_sock_send(struct mg_connection *c, const void *buf, size_t len) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) { return c->is_udp ? mg_sock_send(c, buf, len) > 0 - : mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE); + : mg_iobuf_add(&c->send, c->send.len, buf, len, MG_IO_SIZE); } static void mg_set_non_blocking_mode(SOCKET fd) { @@ -3434,7 +3436,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); if (depth < MG_MAX_SSI_DEPTH && (data = mg_ssi(tmp, root, depth + 1)) != NULL) { - mg_iobuf_append(&b, data, strlen(data), align); + mg_iobuf_add(&b, b.len, data, strlen(data), align); free(data); } else { LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg)); @@ -3444,7 +3446,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { snprintf(tmp, sizeof(tmp), "%s%s", root, arg); if (depth < MG_MAX_SSI_DEPTH && (data = mg_ssi(tmp, root, depth + 1)) != NULL) { - mg_iobuf_append(&b, data, strlen(data), align); + mg_iobuf_add(&b, b.len, data, strlen(data), align); free(data); } else { LOG(LL_ERROR, ("%s: virtual=%s error or too deep", path, arg)); @@ -3452,13 +3454,13 @@ static char *mg_ssi(const char *path, const char *root, int depth) { } else { // Unknown SSI tag LOG(LL_INFO, ("Unknown SSI tag: %.*s", (int) len, buf)); - mg_iobuf_append(&b, buf, len, align); + mg_iobuf_add(&b, b.len, buf, len, align); } intag = 0; len = 0; } else if (ch == '<') { intag = 1; - if (len > 0) mg_iobuf_append(&b, buf, len, align); + if (len > 0) mg_iobuf_add(&b, b.len, buf, len, align); len = 0; buf[len++] = (char) (ch & 0xff); } else if (intag) { @@ -3472,13 +3474,13 @@ static char *mg_ssi(const char *path, const char *root, int depth) { } else { buf[len++] = (char) (ch & 0xff); if (len >= sizeof(buf)) { - mg_iobuf_append(&b, buf, len, align); + mg_iobuf_add(&b, b.len, buf, len, align); len = 0; } } } - if (len > 0) mg_iobuf_append(&b, buf, len, align); - if (b.len > 0) mg_iobuf_append(&b, "", 1, align); // nul-terminate + if (len > 0) mg_iobuf_add(&b, b.len, buf, len, align); + if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1, align); // nul-terminate fclose(fp); } (void) depth; @@ -4749,11 +4751,11 @@ size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) { size_t header_len = mkhdr(len, op, c->is_client, header); // NOTE: order of operations is important! - mg_iobuf_append(&c->send, NULL, header_len, MG_IO_SIZE); // Add header space - p = &c->send.buf[c->send.len - len]; // p points to data - memmove(p, p - header_len, len); // Shift data - memcpy(p - header_len, header, header_len); // Prepend header - mg_ws_mask(c, len); // Mask data + mg_iobuf_add(&c->send, c->send.len, NULL, header_len, MG_IO_SIZE); + p = &c->send.buf[c->send.len - len]; // p points to data + memmove(p, p - header_len, len); // Shift data + memcpy(p - header_len, header, header_len); // Prepend header + mg_ws_mask(c, len); // Mask data return c->send.len; } diff --git a/mongoose.h b/mongoose.h index 16efc5d4..11199337 100644 --- a/mongoose.h +++ b/mongoose.h @@ -628,14 +628,15 @@ const char *mg_url_uri(const char *url); #include struct mg_iobuf { - unsigned char *buf; - size_t size, len; + unsigned char *buf; // Data + size_t size; // Total size available + size_t len; // Current number of bytes }; int mg_iobuf_init(struct mg_iobuf *, size_t); int mg_iobuf_resize(struct mg_iobuf *, size_t); void mg_iobuf_free(struct mg_iobuf *); -size_t mg_iobuf_append(struct mg_iobuf *, const void *, size_t, size_t); +size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t, size_t); size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); int mg_base64_update(unsigned char p, char *to, int len); diff --git a/src/iobuf.c b/src/iobuf.c index c1550676..4856e2bb 100644 --- a/src/iobuf.c +++ b/src/iobuf.c @@ -42,8 +42,8 @@ int mg_iobuf_init(struct mg_iobuf *io, size_t size) { return mg_iobuf_resize(io, size); } -size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len, - size_t chunk_size) { +size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, + size_t len, size_t chunk_size) { size_t new_size = io->len + len; if (new_size > io->size) { new_size += chunk_size; // Make sure that io->size @@ -51,7 +51,9 @@ size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len, mg_iobuf_resize(io, new_size); // Attempt to realloc if (new_size != io->size) len = 0; // Realloc failure, append nothing } - if (buf != NULL) memmove(io->buf + io->len, buf, len); + if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs); + if (buf != NULL) memmove(io->buf + ofs, buf, len); + if (ofs > io->len) io->len += ofs - io->len; io->len += len; return len; } diff --git a/src/iobuf.h b/src/iobuf.h index 19b76517..c456e3be 100644 --- a/src/iobuf.h +++ b/src/iobuf.h @@ -3,12 +3,13 @@ #include struct mg_iobuf { - unsigned char *buf; - size_t size, len; + unsigned char *buf; // Data + size_t size; // Total size available + size_t len; // Current number of bytes }; int mg_iobuf_init(struct mg_iobuf *, size_t); int mg_iobuf_resize(struct mg_iobuf *, size_t); void mg_iobuf_free(struct mg_iobuf *); -size_t mg_iobuf_append(struct mg_iobuf *, const void *, size_t, size_t); +size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t, size_t); size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); diff --git a/src/sock.c b/src/sock.c index eca28937..f72bd5b6 100644 --- a/src/sock.c +++ b/src/sock.c @@ -107,7 +107,7 @@ static long mg_sock_send(struct mg_connection *c, const void *buf, size_t len) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) { return c->is_udp ? mg_sock_send(c, buf, len) > 0 - : mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE); + : mg_iobuf_add(&c->send, c->send.len, buf, len, MG_IO_SIZE); } static void mg_set_non_blocking_mode(SOCKET fd) { diff --git a/src/ssi.c b/src/ssi.c index 93182829..5bf16f22 100644 --- a/src/ssi.c +++ b/src/ssi.c @@ -24,7 +24,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); if (depth < MG_MAX_SSI_DEPTH && (data = mg_ssi(tmp, root, depth + 1)) != NULL) { - mg_iobuf_append(&b, data, strlen(data), align); + mg_iobuf_add(&b, b.len, data, strlen(data), align); free(data); } else { LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg)); @@ -34,7 +34,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { snprintf(tmp, sizeof(tmp), "%s%s", root, arg); if (depth < MG_MAX_SSI_DEPTH && (data = mg_ssi(tmp, root, depth + 1)) != NULL) { - mg_iobuf_append(&b, data, strlen(data), align); + mg_iobuf_add(&b, b.len, data, strlen(data), align); free(data); } else { LOG(LL_ERROR, ("%s: virtual=%s error or too deep", path, arg)); @@ -42,13 +42,13 @@ static char *mg_ssi(const char *path, const char *root, int depth) { } else { // Unknown SSI tag LOG(LL_INFO, ("Unknown SSI tag: %.*s", (int) len, buf)); - mg_iobuf_append(&b, buf, len, align); + mg_iobuf_add(&b, b.len, buf, len, align); } intag = 0; len = 0; } else if (ch == '<') { intag = 1; - if (len > 0) mg_iobuf_append(&b, buf, len, align); + if (len > 0) mg_iobuf_add(&b, b.len, buf, len, align); len = 0; buf[len++] = (char) (ch & 0xff); } else if (intag) { @@ -62,13 +62,13 @@ static char *mg_ssi(const char *path, const char *root, int depth) { } else { buf[len++] = (char) (ch & 0xff); if (len >= sizeof(buf)) { - mg_iobuf_append(&b, buf, len, align); + mg_iobuf_add(&b, b.len, buf, len, align); len = 0; } } } - if (len > 0) mg_iobuf_append(&b, buf, len, align); - if (b.len > 0) mg_iobuf_append(&b, "", 1, align); // nul-terminate + if (len > 0) mg_iobuf_add(&b, b.len, buf, len, align); + if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1, align); // nul-terminate fclose(fp); } (void) depth; diff --git a/src/ws.c b/src/ws.c index 54f71f7d..e6c5db14 100644 --- a/src/ws.c +++ b/src/ws.c @@ -269,11 +269,11 @@ size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) { size_t header_len = mkhdr(len, op, c->is_client, header); // NOTE: order of operations is important! - mg_iobuf_append(&c->send, NULL, header_len, MG_IO_SIZE); // Add header space - p = &c->send.buf[c->send.len - len]; // p points to data - memmove(p, p - header_len, len); // Shift data - memcpy(p - header_len, header, header_len); // Prepend header - mg_ws_mask(c, len); // Mask data + mg_iobuf_add(&c->send, c->send.len, NULL, header_len, MG_IO_SIZE); + p = &c->send.buf[c->send.len - len]; // p points to data + memmove(p, p - header_len, len); // Shift data + memcpy(p - header_len, header, header_len); // Prepend header + mg_ws_mask(c, len); // Mask data return c->send.len; } diff --git a/test/unit_test.c b/test/unit_test.c index 003101e1..f3f8c2b9 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -208,12 +208,22 @@ static void test_iobuf(void) { ASSERT(io.buf == NULL && io.size == 0 && io.len == 0); mg_iobuf_resize(&io, 1); ASSERT(io.buf != NULL && io.size == 1 && io.len == 0); - mg_iobuf_append(&io, "hi", 2, 10); - ASSERT(io.buf != NULL && io.size == 10 && io.len == 2); - ASSERT(memcmp(io.buf, "hi", 2) == 0); - mg_iobuf_append(&io, "!", 1, 10); - ASSERT(io.buf != NULL && io.size == 10 && io.len == 3); - ASSERT(memcmp(io.buf, "hi!", 3) == 0); + ASSERT(memcmp(io.buf, "\x00", 1) == 0); + mg_iobuf_add(&io, 3, "hi", 2, 10); + ASSERT(io.buf != NULL && io.size == 10 && io.len == 5); + ASSERT(memcmp(io.buf, "\x00\x00\x00hi", 5) == 0); + mg_iobuf_add(&io, io.len, "!", 1, 10); + ASSERT(io.buf != NULL && io.size == 10 && io.len == 6); + ASSERT(memcmp(io.buf, "\x00\x00\x00hi!", 6) == 0); + mg_iobuf_add(&io, 0, "x", 1, 10); + ASSERT(memcmp(io.buf, "x\x00\x00\x00hi!", 7) == 0); + ASSERT(io.buf != NULL && io.size == 10 && io.len == 7); + mg_iobuf_del(&io, 1, 3); + ASSERT(io.buf != NULL && io.size == 10 && io.len == 4); + ASSERT(memcmp(io.buf, "xhi!", 3) == 0); + mg_iobuf_del(&io, 10, 100); + ASSERT(io.buf != NULL && io.size == 10 && io.len == 4); + ASSERT(memcmp(io.buf, "xhi!", 3) == 0); free(io.buf); }