40 auto verbs = instance.Get(target.empty() ?
m_url : target);
42 curl_easy_setopt(
m_curl.get(), CURLOPT_CUSTOMREQUEST,
"PROPFIND");
44 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 0L);
47 m_is_propfind =
false;
48 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 1L);
61 auto verbs = instance.Get(target);
68 curl_easy_setopt(
m_curl.get(), CURLOPT_CUSTOMREQUEST,
"PROPFIND");
70 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 0L);
73 m_is_propfind =
false;
74 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 1L);
83 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEFUNCTION, CurlStatOp::WriteCallback);
84 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEDATA,
this);
87 auto verbs = instance.Get(
m_url);
89 curl_easy_setopt(
m_curl.get(), CURLOPT_CUSTOMREQUEST,
"PROPFIND");
91 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 0L);
94 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 1L);
102 if (
m_curl ==
nullptr)
return;
103 curl_easy_setopt(
m_curl.get(), CURLOPT_NOBODY, 0L);
105 curl_easy_setopt(
m_curl.get(), CURLOPT_CUSTOMREQUEST,
nullptr);
107 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEFUNCTION,
nullptr);
108 curl_easy_setopt(
m_curl.get(), CURLOPT_WRITEDATA,
nullptr);
113CurlStatOp::WriteCallback(
char *buffer,
size_t size,
size_t nitems,
void *this_ptr)
116 if (me->m_is_propfind) {
117 if (size * nitems + me->m_response.size() > 1'000'000) {
118 me->m_logger->Error(
kLogXrdClHttp,
"Response too large for PROPFIND operation");
121 me->UpdateBytes(size * nitems);
122 me->m_response.append(buffer, size * nitems);
124 return size * nitems;
127std::pair<int64_t, bool>
128CurlStatOp::ParseProp(TiXmlElement *prop) {
129 if (prop ==
nullptr) {
132 for (
auto child = prop->FirstChildElement();
child !=
nullptr;
child =
child->NextSiblingElement()) {
133 if (!strcasecmp(
child->Value(),
"D:getcontentlength") || !strcasecmp(
child->Value(),
"lp1:getcontentlength")) {
134 auto len =
child->GetText();
136 m_length = std::stoll(len);
138 }
else if (!strcasecmp(
child->Value(),
"D:resourcetype") || !strcasecmp(
child->Value(),
"lp1:resourcetype")) {
139 m_is_dir =
child->FirstChildElement(
"D:collection") !=
nullptr;
140 }
else if (!strcasecmp(
child->Value(),
"D:getlastmodified") || !strcasecmp(
child->Value(),
"lp1:getlastmodified")) {
141 auto lastmod =
child->GetText();
144 if (strptime(lastmod,
"%a, %d %b %Y %H:%M:%S", &tm) !=
nullptr) {
145 m_modtime = timegm(&tm);
150 if (m_length < 0 && m_is_dir) {
154 return {m_length, m_is_dir};
157std::pair<int64_t, bool>
159 if (!m_is_propfind) {
161 return {m_length,
false};
164 return {m_length, m_is_dir};
168 doc.Parse(m_response.c_str());
170 m_logger->Error(
kLogXrdClHttp,
"Failed to parse XML response: %s", m_response.substr(0, 1024).c_str());
174 auto elem = doc.RootElement();
175 if (strcasecmp(elem->Value(),
"D:multistatus")) {
179 auto found_response =
false;
180 for (
auto response = elem->FirstChildElement(); response !=
nullptr; response = response->NextSiblingElement()) {
181 if (!strcasecmp(response->Value(),
"D:response")) {
182 found_response =
true;
187 if (!found_response) {
188 m_logger->Error(
kLogXrdClHttp,
"Failed to find response element in XML response: %s", m_response.substr(0, 1024).c_str());
191 for (
auto child = elem->FirstChildElement();
child !=
nullptr;
child =
child->NextSiblingElement()) {
192 if (strcasecmp(
child->Value(),
"D:propstat")) {
195 for (
auto prop =
child->FirstChildElement(); prop !=
nullptr; prop = prop->NextSiblingElement()) {
196 if (!strcasecmp(prop->Value(),
"D:prop")) {
197 return ParseProp(prop);
201 m_logger->Error(
kLogXrdClHttp,
"Failed to find properties in XML response: %s", m_response.substr(0, 1024).c_str());
208 auto verbs = instance.Get(
m_url);
232 m_logger->Debug(
kLogXrdClHttp,
"Successful propfind operation on %s (size %lld, isdir %d)",
m_url.c_str(),
static_cast<long long>(size), isdir);
237 time_t mtime = m_is_propfind ? m_modtime :
m_headers.GetModTime();
242 if (m_response_info){
253 }
else if (m_response_info) {
void SetDone(bool has_failed)
std::unique_ptr< ResponseInfo > MoveResponseInfo()
std::unique_ptr< CURL, void(*)(CURL *)> m_curl
virtual void ReleaseHandle()
std::vector< std::pair< std::string, std::string > > m_headers_list
virtual RedirectAction Redirect(std::string &target)
XrdCl::ResponseHandler * m_handler
virtual bool Setup(CURL *curl, CurlWorker &)
void ReleaseHandle() override
void SuccessImpl(bool returnObj)
virtual bool RequiresOptions() const override
bool Setup(CURL *curl, CurlWorker &) override
RedirectAction Redirect(std::string &target) override
std::pair< int64_t, bool > GetStatInfo()
virtual void OptionsDone() override
static VerbsCache & Instance()
void Set(Type object, bool own=true)
@ IsReadable
Read access is allowed.
@ IsDir
This is a directory.
const uint64_t kLogXrdClHttp
const uint16_t errErrorResponse