| 1374 | } |
| 1375 | |
| 1376 | Status GcsFileSystem::GetChildrenBounded(const string& dirname, |
| 1377 | uint64 max_results, |
| 1378 | std::vector<string>* result, |
| 1379 | bool recursive, |
| 1380 | bool include_self_directory_marker) { |
| 1381 | if (!result) { |
| 1382 | return errors::InvalidArgument("'result' cannot be null"); |
| 1383 | } |
| 1384 | string bucket, object_prefix; |
| 1385 | TF_RETURN_IF_ERROR( |
| 1386 | ParseGcsPath(MaybeAppendSlash(dirname), true, &bucket, &object_prefix)); |
| 1387 | |
| 1388 | string nextPageToken; |
| 1389 | uint64 retrieved_results = 0; |
| 1390 | while (true) { // A loop over multiple result pages. |
| 1391 | std::vector<char> output_buffer; |
| 1392 | std::unique_ptr<HttpRequest> request; |
| 1393 | TF_RETURN_IF_ERROR(CreateHttpRequest(&request)); |
| 1394 | auto uri = strings::StrCat(kGcsUriBase, "b/", bucket, "/o"); |
| 1395 | if (recursive) { |
| 1396 | uri = strings::StrCat(uri, "?fields=items%2Fname%2CnextPageToken"); |
| 1397 | } else { |
| 1398 | // Set "/" as a delimiter to ask GCS to treat subfolders as children |
| 1399 | // and return them in "prefixes". |
| 1400 | uri = strings::StrCat(uri, |
| 1401 | "?fields=items%2Fname%2Cprefixes%2CnextPageToken"); |
| 1402 | uri = strings::StrCat(uri, "&delimiter=%2F"); |
| 1403 | } |
| 1404 | if (!object_prefix.empty()) { |
| 1405 | uri = strings::StrCat(uri, |
| 1406 | "&prefix=", request->EscapeString(object_prefix)); |
| 1407 | } |
| 1408 | if (!nextPageToken.empty()) { |
| 1409 | uri = strings::StrCat( |
| 1410 | uri, "&pageToken=", request->EscapeString(nextPageToken)); |
| 1411 | } |
| 1412 | if (max_results - retrieved_results < kGetChildrenDefaultPageSize) { |
| 1413 | uri = |
| 1414 | strings::StrCat(uri, "&maxResults=", max_results - retrieved_results); |
| 1415 | } |
| 1416 | request->SetUri(uri); |
| 1417 | request->SetResultBuffer(&output_buffer); |
| 1418 | request->SetTimeouts(timeouts_.connect, timeouts_.idle, timeouts_.metadata); |
| 1419 | |
| 1420 | TF_RETURN_WITH_CONTEXT_IF_ERROR(request->Send(), " when reading ", dirname); |
| 1421 | Json::Value root; |
| 1422 | TF_RETURN_IF_ERROR(ParseJson(output_buffer, &root)); |
| 1423 | const auto items = root.get("items", Json::Value::null); |
| 1424 | if (!items.isNull()) { |
| 1425 | if (!items.isArray()) { |
| 1426 | return errors::Internal( |
| 1427 | "Expected an array 'items' in the GCS response."); |
| 1428 | } |
| 1429 | for (size_t i = 0; i < items.size(); i++) { |
| 1430 | const auto item = items.get(i, Json::Value::null); |
| 1431 | if (!item.isObject()) { |
| 1432 | return errors::Internal( |
| 1433 | "Unexpected JSON format: 'items' should be a list of objects."); |
nothing calls this directly
no test coverage detected