char *test_IOBuf_read_operations() { char *data = NULL; int avail = 0; Connection *conn = fake_conn("/dev/zero", O_RDONLY); mu_assert(conn != NULL, "Failed to make fake /dev/zero connection."); IOBuf *buf = conn->iob; IOBuf_resize(buf, 31); mu_assert(buf->len == 31, "Wrong size after resize."); data = IOBuf_start(buf); avail = IOBuf_avail(buf); mu_assert(data != NULL, "Didn't get a data response on begin."); mu_assert(data == buf->buf, "Begin on fresh iobuf should be at the beginning."); mu_assert(avail == 0, "Should not have anything available yet."); data = IOBuf_read(buf, 10, &avail); mu_assert(data != NULL, "Should get something always."); mu_assert(data == IOBuf_start(buf), "First read should work from start."); mu_assert(data == buf->buf, "First read should be at start of internal buf."); mu_assert(avail == 10, "Should get 10 bytes."); // check compacting mu_assert(!IOBuf_compact_needed(buf, 10), "Should not need compacting for 10."); mu_assert(IOBuf_compact_needed(buf, 100), "SHOULD need compacting for 100."); mu_assert(IOBuf_read_commit(buf, 10) != -1, "Failed to commit."); data = IOBuf_start(buf); avail = IOBuf_avail(buf); mu_assert(data != NULL, "Didn't get a data response on begin."); mu_assert(data != buf->buf, "Later reads should not be at the start."); mu_assert(avail == 21, "Should have 21 bytes available in the buf already."); data = IOBuf_read(buf, 10, &avail); mu_assert(data != NULL, "Should get something always."); mu_assert(avail == 10, "Should get 10 bytes."); mu_assert(IOBuf_read_commit(buf, 10) != -1, "Finaly commit failed."); data = IOBuf_start(buf); avail = IOBuf_avail(buf); mu_assert(data != NULL, "Didn't get a data response on begin."); mu_assert(data != buf->buf, "Later reads should not be at the start."); mu_assert(avail == 11, "Should have 11 bytes available in the buf already."); // now test two reads, one that fits one that doesn't then commit // remember this doesn't *return* anything, just a pointer to the start data = IOBuf_read(buf, 5, &avail); mu_assert(data != NULL, "Should get something always."); mu_assert(avail == 5, "Should get 10 bytes."); // ok we didn't want 5 we want 20, so this will cause a compact data = IOBuf_read(buf, 20, &avail); mu_assert(data != NULL, "Should get something always."); mu_assert(avail == 20, "Should get 10 bytes."); mu_assert(IOBuf_read_commit(buf, 21) != -1, "Final commit failed."); debug("We've got %d avail after the last read.", buf->avail); mu_assert(buf->avail == 10, "Should have 11 still in the queue."); data = IOBuf_read_all(buf, 30, 1); mu_assert(data != NULL, "Failed to read all."); mu_assert(buf->avail == 1, "Should have 1 in the queue."); data = IOBuf_read_some(buf, &avail); mu_assert(data != NULL, "Failed to read some."); mu_assert(buf->avail == 31, "Should be full."); mu_assert(avail == 31, "And we should get the full amount."); fake_conn_close(conn); return NULL; }
int Upload_stream(Connection *conn, Handler *handler, int content_len) { char *data = NULL; int avail = 0; int offset = 0; int first_chunk = 1; int rc; hash_t *altheaders = NULL; bstring offsetstr; debug("max content length: %d, content_len: %d", MAX_CONTENT_LENGTH, content_len); IOBuf_resize(conn->iob, MAX_CONTENT_LENGTH); // give us a good buffer size while(content_len > 0) { if(first_chunk) { // read whatever's there data = IOBuf_read_some(conn->iob, &avail); } else if(conn->sendCredits > 0) { // read up to credits data = IOBuf_read(conn->iob, conn->sendCredits < content_len ? conn->sendCredits : content_len, &avail); conn->sendCredits -= avail; } else { // sleep until we have credits tasksleep(&conn->uploadRendez); continue; } check(!IOBuf_closed(conn->iob), "Closed while reading from IOBuf."); content_len -= avail; offsetstr = bformat("%d", offset); if(first_chunk) { Request_set(conn->req, &UPLOAD_STREAM, offsetstr, 1); if(content_len == 0) { Request_set(conn->req, &UPLOAD_STREAM_DONE, bfromcstr("1"), 1); } } else { altheaders = hash_create(2, (hash_comp_t)bstrcmp, bstr_hash_fun); add_to_hash(altheaders, &UPLOAD_STREAM, offsetstr); if(content_len == 0) { add_to_hash(altheaders, &UPLOAD_STREAM_DONE, bfromcstr("1")); } } rc = Connection_send_to_handler(conn, handler, data, avail, altheaders); check_debug(rc == 0, "Failed to deliver to the handler."); if(altheaders != NULL) { hash_free_nodes(altheaders); hash_destroy(altheaders); altheaders = NULL; } check(IOBuf_read_commit(conn->iob, avail) != -1, "Commit failed while streaming."); first_chunk = 0; offset += avail; } check(content_len == 0, "Failed to write everything to the large upload tmpfile."); return 0; error: return -1; }