35 CurlOperation(handler, url, timeout, logger, callout, header_callout),
36 m_response_info(set_response_info),
37 m_host_addr(host_addr)
46 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEFUNCTION, CurlListdirOp::WriteCallback);
47 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEDATA,
this);
48 curl_easy_setopt(
m_curl.get(), CURLOPT_CUSTOMREQUEST,
"PROPFIND");
57 if (
m_curl ==
nullptr)
return;
58 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEFUNCTION,
nullptr);
59 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEDATA,
nullptr);
60 curl_easy_setopt(
m_curl.get(), CURLOPT_CUSTOMREQUEST,
nullptr);
61 curl_easy_setopt(
m_curl.get(), CURLOPT_HTTPHEADER,
nullptr);
66 CurlListdirOp::WriteCallback(
char *buffer,
size_t size,
size_t nitems,
void *this_ptr)
69 if (size * nitems + me->m_response.size() > 10'000'000) {
72 me->UpdateBytes(size * nitems);
73 me->m_response.append(buffer, size * nitems);
77 bool CurlListdirOp::ParseProp(DavEntry &entry, TiXmlElement *prop)
79 for (
auto child = prop->FirstChildElement();
child !=
nullptr;
child =
child->NextSiblingElement()) {
80 if (!strcasecmp(
child->Value(),
"D:resourcetype") || !strcasecmp(
child->Value(),
"lp1:resourcetype")) {
81 auto collection =
child->FirstChildElement(
"D:collection");
82 entry.m_isdir = collection !=
nullptr;
83 if (entry.m_isdir && entry.m_size < 0) {
86 }
else if (!strcasecmp(
child->Value(),
"D:getcontentlength") || !strcasecmp(
child->Value(),
"lp1:getcontentlength")) {
87 auto size =
child->GetText();
88 if (size ==
nullptr) {
92 entry.m_size = std::stoll(size);
93 }
catch (std::invalid_argument &e) {
96 }
else if (!strcasecmp(
child->Value(),
"D:getlastmodified") || !strcasecmp(
child->Value(),
"lp1:getlastmodified")) {
97 auto lastmod =
child->GetText();
98 if (lastmod ==
nullptr) {
102 if (strptime(lastmod,
"%a, %d %b %Y %H:%M:%S", &tm) ==
nullptr) {
105 entry.m_lastmodified = timegm(&tm);
106 }
else if (strcasecmp(
child->Value(),
"D:href") == 0) {
107 auto href =
child->GetText();
108 if (href ==
nullptr) {
112 }
else if (!strcasecmp(
child->Value(),
"D:executable") || !strcasecmp(
child->Value(),
"lp1:executable")) {
113 auto val =
child->GetText();
114 if (val ==
nullptr) {
117 if (strcasecmp(val,
"T") == 0) {
118 entry.m_isexec =
true;
125 std::pair<CurlListdirOp::DavEntry, bool>
126 CurlListdirOp::ParseResponse(TiXmlElement *response)
129 bool success =
false;
130 for (
auto child = response->FirstChildElement();
child !=
nullptr;
child =
child->NextSiblingElement()) {
131 if (!strcasecmp(
child->Value(),
"D:href")) {
132 auto href =
child->GetText();
133 if (href ==
nullptr) {
134 return {entry,
false};
138 std::string_view href_str(href);
139 auto first_non_slash = href_str.find_last_not_of(
'/');
140 if (first_non_slash != std::string_view::npos) {
141 href_str = href_str.substr(0, first_non_slash + 1);
143 auto last_slash = href_str.find_last_of(
'/');
144 if (last_slash != std::string_view::npos) {
145 entry.m_name = href_str.substr(last_slash + 1);
151 if (strcasecmp(
child->Value(),
"D:propstat")) {
154 for (
auto propstat =
child->FirstChildElement(); propstat !=
nullptr; propstat = propstat->NextSiblingElement()) {
155 if (strcasecmp(propstat->Value(),
"D:prop")) {
158 success = ParseProp(entry, propstat);
160 return {entry, success};
164 return {entry, success};
176 doc.Parse(m_response.c_str());
183 auto elem = doc.RootElement();
184 if (strcasecmp(elem->Value(),
"D:multistatus")) {
190 for (
auto response = elem->FirstChildElement(); response !=
nullptr; response = response->NextSiblingElement()) {
191 if (strcasecmp(response->Value(),
"D:response")) {
195 auto [entry, success] = ParseResponse(response);
205 uint32_t flags = XrdCl::StatInfo::Flags::IsReadable;
207 flags |= XrdCl::StatInfo::Flags::IsDir;
209 if (entry.m_isexec) {
210 flags |= XrdCl::StatInfo::Flags::XBitSet;
216 m_logger->
Debug(
kLogXrdClHttp,
"Successful propfind directory listing operation on %s (%u items)",
m_url.c_str(),
static_cast<unsigned>(dirlist->GetSize()));
219 if (m_response_info) {
223 obj->Set(dirlist.release());
bool Setup(CURL *curl, CurlWorker &) override
CurlListdirOp(XrdCl::ResponseHandler *handler, const std::string &url, const std::string &host_addr, bool response_info, struct timespec timeout, XrdCl::Log *logger, CreateConnCalloutType callout, HeaderCallout *header_callout)
void ReleaseHandle() override
void SetDone(bool has_failed)
int FailCallback(XErrorCode ecode, const std::string &emsg)
std::unique_ptr< CURL, void(*)(CURL *)> m_curl
virtual void Fail(uint16_t errCode, uint32_t errNum, const std::string &)
virtual void ReleaseHandle()
std::vector< std::pair< std::string, std::string > > m_headers_list
XrdCl::ResponseHandler * m_handler
std::unique_ptr< ResponseInfo > MoveResponseInfo()
virtual bool Setup(CURL *curl, CurlWorker &)
void Error(uint64_t topic, const char *format,...)
Report an error.
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Handle an async response.
virtual void HandleResponse(XRootDStatus *status, AnyObject *response)
const uint16_t errErrorResponse
ConnectionCallout *(*)(const std::string &, const ResponseInfo &) CreateConnCalloutType
const uint64_t kLogXrdClHttp