| 1671 | } |
| 1672 | |
| 1673 | ACTOR Future<std::string> uploadPart_impl(Reference<S3BlobStoreEndpoint> bstore, |
| 1674 | std::string bucket, |
| 1675 | std::string object, |
| 1676 | std::string uploadID, |
| 1677 | unsigned int partNumber, |
| 1678 | UnsentPacketQueue* pContent, |
| 1679 | int contentLen, |
| 1680 | std::string contentMD5) { |
| 1681 | wait(bstore->requestRateWrite->getAllowance(1)); |
| 1682 | wait(bstore->concurrentUploads.take()); |
| 1683 | state FlowLock::Releaser uploadReleaser(bstore->concurrentUploads, 1); |
| 1684 | |
| 1685 | std::string resource = constructResourcePath(bstore, bucket, object); |
| 1686 | resource += format("?partNumber=%d&uploadId=%s", partNumber, uploadID.c_str()); |
| 1687 | HTTP::Headers headers; |
| 1688 | // Send MD5 sum for content so blobstore can verify it |
| 1689 | headers["Content-MD5"] = contentMD5; |
| 1690 | state Reference<HTTP::Response> r = |
| 1691 | wait(bstore->doRequest("PUT", resource, headers, pContent, contentLen, { 200 })); |
| 1692 | // TODO: In the event that the client times out just before the request completes (so the client is unaware) then |
| 1693 | // the next retry will see error 400. That could be detected and handled gracefully by retrieving the etag for the |
| 1694 | // successful request. |
| 1695 | |
| 1696 | // For uploads, Blobstore returns an MD5 sum of uploaded content so check it. |
| 1697 | if (!r->verifyMD5(false, contentMD5)) |
| 1698 | throw checksum_failed(); |
| 1699 | |
| 1700 | // No etag -> bad response. |
| 1701 | std::string etag = r->headers["ETag"]; |
| 1702 | if (etag.empty()) |
| 1703 | throw http_bad_response(); |
| 1704 | |
| 1705 | return etag; |
| 1706 | } |
| 1707 | |
| 1708 | Future<std::string> S3BlobStoreEndpoint::uploadPart(std::string const& bucket, |
| 1709 | std::string const& object, |
nothing calls this directly
no test coverage detected