From: Robin Dong <sanbai at taobao.com> In swift spec, "Range: bytes=13-15" in http header means "read the three bytes of data after a 13-byte offset". We add this support by parsing http header and read specific bytes in range. We don't support multi-ranges at present. Signed-off-by: Robin Dong <sanbai at taobao.com> --- sheep/http/http.c | 30 ++++++++++++++++++++++++++++++ sheep/http/http.h | 1 + sheep/http/kv.c | 41 ++++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/sheep/http/http.c b/sheep/http/http.c index 165c818..16558b1 100644 --- a/sheep/http/http.c +++ b/sheep/http/http.c @@ -169,10 +169,40 @@ static int request_init_operation(struct http_request *req) req->uri = FCGX_GetParam("DOCUMENT_URI", env); if (!req->uri) return BAD_REQUEST; + p = FCGX_GetParam("HTTP_RANGE", env); + if (p && p[0] != '\0') { + const char prefix[] = "bytes="; + char *left, *right, num[64]; + left = strstr(p, prefix); + if (!p) + goto invalid_range; + right = strchr(left, '-'); + strncpy(num, left + sizeof(prefix) - 1, right - left); + req->range[0] = strtoll(num, &endp, 10); + if (num == endp) + goto invalid_range; + strcpy(num, right + 1); + /* + * In swift spec, the second number of RANGE should be included + * which means [num1, num2], but our common means for read and + * write data by 'offset' and 'len' is [num1, num2), so we + * should add 1 to num2. + */ + req->range[1] = strtoll(num, &endp, 10) + 1; + if (num == endp) + goto invalid_range; + if (req->range[1] <= req->range[0]) + goto invalid_range; + sd_debug("HTTP_RANGE: %lu %lu", req->range[0], req->range[1]); + } req->status = UNKNOWN; return OK; + +invalid_range: + sd_err("invalid range %s", p); + return BAD_REQUEST; } static int http_init_request(struct http_request *req) diff --git a/sheep/http/http.h b/sheep/http/http.h index 20246dc..7cf3916 100644 --- a/sheep/http/http.h +++ b/sheep/http/http.h @@ -48,6 +48,7 @@ struct http_request { enum http_opcode opcode; enum http_status status; uint64_t data_length; + uint64_t range[2]; }; struct http_driver { diff --git a/sheep/http/kv.c b/sheep/http/kv.c index 02d8e1b..8adfd45 100644 --- a/sheep/http/kv.c +++ b/sheep/http/kv.c @@ -857,23 +857,33 @@ static int onode_free_data(struct kv_onode *onode) return ret; } -static int onode_read_extents(struct kv_onode *onode, struct http_request *req) +static int onode_read_extents(struct kv_onode *onode, struct http_request *req, + uint64_t off, uint64_t len) { struct onode_extent *ext; - uint64_t size, total, total_size, offset, done = 0, i; + uint64_t size, total, total_size, offset, done = 0, i, ext_len; int ret; char *data_buf = NULL; data_buf = xmalloc(READ_WRITE_BUFFER); - total_size = onode->size; + total_size = len; for (i = 0; i < onode->nr_extent; i++) { ext = onode->o_extent + i; - total = min(ext->count * SD_DATA_OBJ_SIZE, total_size); - offset = ext->start * SD_DATA_OBJ_SIZE; + ext_len = ext->count * SD_DATA_OBJ_SIZE; + if (off >= ext_len) { + off -= ext_len; + continue; + } + total = min(ext_len - off, total_size); + offset = ext->start * SD_DATA_OBJ_SIZE + off; + off = 0; + done = 0; while (done < total) { size = MIN(total - done, READ_WRITE_BUFFER); ret = vdi_read_write(onode->data_vid, data_buf, size, offset, true); + sd_debug("vdi_read_write size: %"PRIx64", offset: %" + PRIx64, size, offset); if (ret != SD_RES_SUCCESS) { sd_err("Failed to read for vid %"PRIx32, onode->data_vid); @@ -951,11 +961,26 @@ out: static int onode_read_data(struct kv_onode *onode, struct http_request *req) { int ret; + uint64_t off = 0, len = onode->size; + + if (req->range[0] && req->range[1]) { + off = req->range[0]; + len = req->range[1] - off; + if (req->range[1] > onode->size) + len = onode->size - off; + if (off >= onode->size) + len = 0; + } + req->data_length = len; + http_response_header(req, OK); + + if (off >= onode->size) + return SD_RES_SUCCESS; if (!onode->inlined) - return onode_read_extents(onode, req); + return onode_read_extents(onode, req, off, len); - ret = http_request_write(req, onode->data, onode->size); + ret = http_request_write(req, onode->data + off, len); if (ret != onode->size) return SD_RES_SYSTEM_ERROR; @@ -1075,8 +1100,6 @@ int kv_read_object(struct http_request *req, const char *account, if (ret != SD_RES_SUCCESS) goto out; - req->data_length = onode->size; - http_response_header(req, OK); ret = onode_read_data(onode, req); if (ret != SD_RES_SUCCESS) sd_err("failed to read data for %s", name); -- 1.7.12.4 |