XRootD
XrdClHttp::TapeOperation Class Reference

#include <XrdClHttpTape.hh>

+ Collaboration diagram for XrdClHttp::TapeOperation:

Classes

struct  Impl
 

Public Member Functions

 TapeOperation (const std::string &url, const std::vector< std::string > &fileList, XrdCl::PrepareFlags::Flags flags)
 
 TapeOperation (const std::string &url, XrdCl::QueryCode::Code queryCode, const XrdCl::Buffer &arg)
 
 TapeOperation (const TapeOperation &)=delete
 
 ~TapeOperation ()
 
XrdCl::XRootDStatus Advance (CURL *curl, long statusCode, const std::string &body, TapeHttpRequest &request, std::string &response, bool &complete)
 
TapeOperation & operator= (const TapeOperation &)=delete
 
XrdCl::XRootDStatus Start (TapeHttpRequest &request)
 

Detailed Description

Definition at line 51 of file XrdClHttpTape.hh.

Constructor & Destructor Documentation

◆ TapeOperation() [1/3]

XrdClHttp::TapeOperation::TapeOperation ( const std::string &  url,
const std::vector< std::string > &  fileList,
XrdCl::PrepareFlags::Flags  flags 
)

Definition at line 829 of file XrdClHttpTape.cc.

832  :
833  pImpl(std::make_unique<Impl>())
834  {
835  pImpl->storageUrl = url;
836  pImpl->initialStatus = ValidateTapePrepareFlags(flags);
837  if(!pImpl->initialStatus.IsOK()) return;
838 
839  if(flags & XrdCl::PrepareFlags::Stage)
840  {
841  pImpl->kind = Impl::Kind::Stage;
842  pImpl->initialStatus = PrepareStageFiles(fileList, pImpl->stageFiles);
843  return;
844  }
845 
846  if(fileList.size() < 2)
847  {
848  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
849  "cancel and evict require a request id and at least one path");
850  return;
851  }
852 
853  pImpl->requestId = fileList.front();
854  if(!IsValidRequestId(pImpl->requestId))
855  {
856  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
857  "cancel and evict require a non-empty request id");
858  return;
859  }
860  pImpl->initialStatus = PathsFromInputs(
861  std::vector<std::string>(fileList.begin() + 1, fileList.end()),
862  pImpl->paths);
863  if(!pImpl->initialStatus.IsOK()) return;
864  pImpl->kind = (flags & XrdCl::PrepareFlags::Cancel)
865  ? Impl::Kind::StageCancel : Impl::Kind::Release;
866  }
const uint16_t errInvalidArgs
Definition: XrdClStatus.hh:58
@ Cancel
cancel staging request

References XrdCl::PrepareFlags::Cancel, XrdCl::errInvalidArgs, and XrdCl::PrepareFlags::Stage.

◆ TapeOperation() [2/3]

XrdClHttp::TapeOperation::TapeOperation ( const std::string &  url,
XrdCl::QueryCode::Code  queryCode,
const XrdCl::Buffer &  arg 
)

Definition at line 868 of file XrdClHttpTape.cc.

871  :
872  pImpl(std::make_unique<Impl>())
873  {
874  pImpl->storageUrl = url;
875  std::vector<std::string> args;
876  XrdCl::Utils::splitString(args, arg.ToString(), "\n");
877  if(queryCode == XrdCl::QueryCode::Prepare)
878  {
879  if(args.size() != 1 || !IsValidRequestId(args.front()))
880  {
881  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
882  "prepare query expects a single request id");
883  return;
884  }
885  pImpl->kind = Impl::Kind::StageStatus;
886  pImpl->requestId = args.front();
887  return;
888  }
889 
890  if(queryCode != XrdCl::QueryCode::Opaque)
891  {
892  pImpl->initialStatus = ErrorStatus(XrdCl::errNotSupported,
893  "unsupported HTTP query");
894  return;
895  }
896  if(args.empty() || args.front().find('\r') != std::string::npos)
897  {
898  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
899  "missing opaque query command");
900  return;
901  }
902 
903  if(args.front() == "tape.discover")
904  {
905  pImpl->kind = Impl::Kind::Discover;
906  return;
907  }
908  if(args.front() == "tape.stage_delete")
909  {
910  if(args.size() != 2 || !IsValidRequestId(args[1]))
911  {
912  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
913  "tape.stage_delete expects a request id");
914  return;
915  }
916  pImpl->kind = Impl::Kind::StageDelete;
917  pImpl->requestId = args[1];
918  return;
919  }
920  if(args.front() == "tape.archiveinfo")
921  {
922  if(args.size() < 2)
923  {
924  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
925  "tape.archiveinfo expects non-empty URLs");
926  return;
927  }
928  pImpl->urls.assign(args.begin() + 1, args.end());
929  for(const auto &archiveUrl : pImpl->urls)
930  {
931  if(archiveUrl.find('\r') != std::string::npos)
932  {
933  pImpl->initialStatus = ErrorStatus(XrdCl::errInvalidArgs,
934  "tape.archiveinfo expects non-empty URLs");
935  return;
936  }
937  }
938  pImpl->initialStatus = ValidateArchiveUrls(pImpl->urls, pImpl->paths);
939  if(pImpl->initialStatus.IsOK()) pImpl->kind = Impl::Kind::ArchiveInfo;
940  return;
941  }
942 
943  pImpl->initialStatus = ErrorStatus(XrdCl::errNotSupported,
944  "unsupported HTTP opaque query");
945  }
std::string ToString() const
Convert the buffer to a string.
Definition: XrdClBuffer.hh:215
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition: XrdClUtils.hh:56
const uint16_t errNotSupported
Definition: XrdClStatus.hh:62
@ Opaque
Implementation dependent.
@ Prepare
Query prepare status.

References XrdCl::errInvalidArgs, XrdCl::errNotSupported, XrdCl::QueryCode::Opaque, XrdCl::QueryCode::Prepare, XrdCl::Utils::splitString(), and XrdCl::Buffer::ToString().

+ Here is the call graph for this function:

◆ ~TapeOperation()

XrdClHttp::TapeOperation::~TapeOperation ( )
default

◆ TapeOperation() [3/3]

XrdClHttp::TapeOperation::TapeOperation ( const TapeOperation &  )
delete

Member Function Documentation

◆ Advance()

XrdCl::XRootDStatus XrdClHttp::TapeOperation::Advance ( CURL *  curl,
long  statusCode,
const std::string &  body,
TapeHttpRequest &  request,
std::string &  response,
bool &  complete 
)

Definition at line 973 of file XrdClHttpTape.cc.

980  {
981  complete = false;
982  response.clear();
983 
984  if(pImpl->phase == Impl::Phase::Discovery)
985  {
986  if(statusCode != 200)
987  {
988  complete = true;
989  return UnexpectedStatus(statusCode, body, "Tape REST discovery");
990  }
991 
992  TapeEndpoint endpoint;
993  XrdCl::XRootDStatus status = ParseDiscoveryResponse(body, endpoint);
994  if(!status.IsOK())
995  {
996  complete = true;
997  return status;
998  }
999  if(pImpl->kind == Impl::Kind::Discover)
1000  {
1001  Json result;
1002  result["uri"] = endpoint.uri;
1003  result["version"] = endpoint.version;
1004  result["sitename"] = endpoint.sitename;
1005  response = result.dump();
1006  complete = true;
1007  pImpl->phase = Impl::Phase::Complete;
1008  return XrdCl::XRootDStatus();
1009  }
1010 
1011  request = TapeHttpRequest();
1012  const std::string encodedRequestId = pImpl->requestId.empty()
1013  ? "" : PercentEncodeUrlPathSegment(pImpl->requestId, curl);
1014  switch(pImpl->kind)
1015  {
1016  case Impl::Kind::Stage:
1017  {
1018  std::string error;
1019  Json stageBody = StageRequestBody(pImpl->stageFiles, error);
1020  if(!error.empty())
1021  {
1022  complete = true;
1023  return ErrorStatus(XrdCl::errInvalidArgs, error);
1024  }
1025  request.method = HttpVerb::POST;
1026  request.url = XrdOucUtils::JoinUrl(endpoint.uri, "/stage");
1027  request.body = stageBody.dump();
1028  break;
1029  }
1030  case Impl::Kind::StageStatus:
1031  request.url = XrdOucUtils::JoinUrl(
1032  endpoint.uri, "/stage/" + encodedRequestId);
1033  break;
1034  case Impl::Kind::StageCancel:
1035  SetPathsPostRequest(request, endpoint.uri,
1036  "/stage/" + encodedRequestId + "/cancel", pImpl->paths);
1037  break;
1038  case Impl::Kind::StageDelete:
1039  request.method = HttpVerb::DELETE;
1040  request.url = XrdOucUtils::JoinUrl(
1041  endpoint.uri, "/stage/" + encodedRequestId);
1042  break;
1043  case Impl::Kind::Release:
1044  SetPathsPostRequest(request, endpoint.uri,
1045  "/release/" + encodedRequestId, pImpl->paths);
1046  break;
1047  case Impl::Kind::ArchiveInfo:
1048  SetPathsPostRequest(request, endpoint.uri, "/archiveinfo",
1049  pImpl->paths);
1050  break;
1051  case Impl::Kind::Invalid:
1052  case Impl::Kind::Discover:
1053  complete = true;
1054  return ErrorStatus(XrdCl::errInternal,
1055  "invalid Tape REST operation state");
1056  }
1057  pImpl->phase = Impl::Phase::Request;
1058  return XrdCl::XRootDStatus();
1059  }
1060 
1061  if(pImpl->phase != Impl::Phase::Request)
1062  {
1063  complete = true;
1064  return ErrorStatus(XrdCl::errInternal,
1065  "invalid Tape REST response state");
1066  }
1067 
1068  complete = true;
1069  pImpl->phase = Impl::Phase::Complete;
1070  switch(pImpl->kind)
1071  {
1072  case Impl::Kind::Stage:
1073  {
1074  if(statusCode != 201)
1075  return UnexpectedStatus(statusCode, body, "stage request submission");
1076  Json json;
1077  XrdCl::XRootDStatus status =
1078  ParseJsonResponse(body, "stage submission", json);
1079  if(!status.IsOK()) return status;
1080  if(!json.contains("requestId") || !json["requestId"].is_string()
1081  || json["requestId"].get_ref<const std::string &>().empty())
1082  {
1083  return ErrorStatus(XrdCl::errInvalidResponse,
1084  "stage submission response does not contain a non-empty string "
1085  "requestId");
1086  }
1087  response = json["requestId"].get<std::string>();
1088  return XrdCl::XRootDStatus();
1089  }
1090  case Impl::Kind::StageStatus:
1091  {
1092  if(statusCode != 200)
1093  return UnexpectedStatus(statusCode, body, "stage request polling");
1094  Json json;
1095  XrdCl::XRootDStatus status =
1096  ParseJsonResponse(body, "stage polling", json);
1097  if(!status.IsOK()) return status;
1098  Json normalizedStatus;
1099  status = NormalizeStageStatusJson(json, normalizedStatus);
1100  if(status.IsOK()) response = normalizedStatus.dump();
1101  return status;
1102  }
1103  case Impl::Kind::StageCancel:
1104  return EmptyResponseStatus(statusCode, body,
1105  "stage request cancellation");
1106  case Impl::Kind::StageDelete:
1107  return EmptyResponseStatus(statusCode, body, "stage request deletion");
1108  case Impl::Kind::Release:
1109  return EmptyResponseStatus(statusCode, body, "stage request release");
1110  case Impl::Kind::ArchiveInfo:
1111  if(statusCode != 200)
1112  return UnexpectedStatus(statusCode, body, "archiveinfo call");
1113  return ParseArchiveInfoResponse(body, pImpl->urls, pImpl->paths,
1114  response);
1115  case Impl::Kind::Invalid:
1116  case Impl::Kind::Discover:
1117  return ErrorStatus(XrdCl::errInternal,
1118  "invalid Tape REST operation state");
1119  }
1120  return ErrorStatus(XrdCl::errInternal, "invalid Tape REST operation");
1121  }
nlohmann::json json
static std::string JoinUrl(const std::string &base, const std::string &path)
const uint16_t errInternal
Internal error.
Definition: XrdClStatus.hh:56
const uint16_t errInvalidResponse
Definition: XrdClStatus.hh:99
bool IsOK() const
We're fine.
Definition: XrdClStatus.hh:124

References XrdClHttp::TapeHttpRequest::body, XrdCl::errInternal, XrdCl::errInvalidArgs, XrdCl::errInvalidResponse, XrdCl::Status::IsOK(), XrdOucUtils::JoinUrl(), XrdClHttp::TapeHttpRequest::method, and XrdClHttp::TapeHttpRequest::url.

+ Here is the call graph for this function:

◆ operator=()

TapeOperation& XrdClHttp::TapeOperation::operator= ( const TapeOperation &  )
delete

◆ Start()

XrdCl::XRootDStatus XrdClHttp::TapeOperation::Start ( TapeHttpRequest &  request)

Definition at line 949 of file XrdClHttpTape.cc.

950  {
951  if(!pImpl->initialStatus.IsOK()) return pImpl->initialStatus;
952  if(pImpl->kind == Impl::Kind::Invalid)
953  {
954  return ErrorStatus(XrdCl::errNotSupported,
955  "unsupported HTTP Tape REST operation");
956  }
957 
958  std::string endpoint;
959  std::string path;
960  std::string error;
961  if(!UrlEndpointAndPath(pImpl->storageUrl, endpoint, path, error))
962  {
963  return ErrorStatus(XrdCl::errInvalidArgs, error);
964  }
965 
966  request = TapeHttpRequest();
967  request.url = XrdOucUtils::JoinUrl(
968  endpoint, "/.well-known/wlcg-tape-rest-api");
969  pImpl->phase = Impl::Phase::Discovery;
970  return XrdCl::XRootDStatus();
971  }

References XrdCl::errInvalidArgs, XrdCl::errNotSupported, XrdOucUtils::JoinUrl(), and XrdClHttp::TapeHttpRequest::url.

+ Here is the call graph for this function:

The documentation for this class was generated from the following files: