| 459 | } |
| 460 | |
| 461 | string S3InterfaceService::uploadPartOfData(S3VectorUInt8 &data, const S3Url &s3Url, |
| 462 | uint64_t partNumber, const string &uploadId) { |
| 463 | HTTPHeaders headers; |
| 464 | stringstream queryString; |
| 465 | |
| 466 | headers.Add(HOST, s3Url.getHostForCurl()); |
| 467 | |
| 468 | char contentSha256[SHA256_DIGEST_STRING_LENGTH]; // 65 |
| 469 | sha256_hex((const char *)data.data(), data.size(), contentSha256); |
| 470 | headers.Add(X_AMZ_CONTENT_SHA256, contentSha256); |
| 471 | |
| 472 | headers.Add(CONTENTTYPE, "text/plain"); |
| 473 | // headers.Add(CONTENTLENGTH, std::to_string((unsigned long long)data.size())); |
| 474 | |
| 475 | queryString << "partNumber=" << partNumber << "&uploadId=" << uploadId; |
| 476 | |
| 477 | SignRequestV4("PUT", &headers, s3Url.getRegion(), s3Url.getPathForCurl(), queryString.str(), |
| 478 | this->params.getCred()); |
| 479 | |
| 480 | stringstream urlWithQuery; |
| 481 | urlWithQuery << s3Url.getFullUrlForCurl() << "?partNumber=" << partNumber |
| 482 | << "&uploadId=" << uploadId; |
| 483 | |
| 484 | Response resp = this->putResponseWithRetries(urlWithQuery.str(), headers, data); |
| 485 | if (resp.getStatus() == RESPONSE_OK) { |
| 486 | string headers(resp.getRawHeaders().begin(), resp.getRawHeaders().end()); |
| 487 | string toSearch = "etag: "; |
| 488 | |
| 489 | auto res = |
| 490 | std::search(headers.begin(), headers.end(), toSearch.begin(), toSearch.end(), |
| 491 | [](char ch1, char ch2) { return std::tolower(ch1) == std::tolower(ch2); }); |
| 492 | |
| 493 | if (res == headers.end()) { |
| 494 | S3_DIE(S3RuntimeError, "Response does not contain etag in the header"); |
| 495 | } |
| 496 | |
| 497 | uint64_t etagStartPos = res - headers.begin() + toSearch.length(); |
| 498 | string etagToEnd = headers.substr(etagStartPos); |
| 499 | // RFC 2616 states "HTTP/1.1 defines the sequence CR LF as the end-of-line |
| 500 | // marker for all protocol elements except the entity-body" |
| 501 | uint64_t etagStrLen = etagToEnd.find("\r"); |
| 502 | |
| 503 | return etagToEnd.substr(0, etagStrLen); |
| 504 | } else if (resp.getStatus() == RESPONSE_ERROR) { |
| 505 | S3MessageParser s3msg(resp); |
| 506 | S3_DIE(S3LogicError, s3msg.getCode(), s3msg.getMessage()); |
| 507 | } else { |
| 508 | S3_DIE(S3RuntimeError, "unexpected response status"); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | bool S3InterfaceService::completeMultiPart(const S3Url &s3Url, const string &uploadId, |
| 513 | const vector<string> &etagArray) { |