XRootD
Loading...
Searching...
No Matches
XrdClHttpFilesystem.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* Copyright (C) 2025, Pelican Project, Morgridge Institute for Research */
3/* */
4/* This file is part of the XrdClHttp client plugin for XRootD. */
5/* */
6/* XRootD is free software: you can redistribute it and/or modify it under */
7/* the terms of the GNU Lesser General Public License as published by the */
8/* Free Software Foundation, either version 3 of the License, or (at your */
9/* option) any later version. */
10/* */
11/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
12/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
13/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
14/* License for more details. */
15/* */
16/* The copyright holder's institutional names and contributor's names may not */
17/* be used to endorse or promote products derived from this software without */
18/* specific prior written permission of the institution or contributor. */
19/******************************************************************************/
20
21#include "XrdClHttpFactory.hh"
23#include "XrdClHttpOps.hh"
24#include "XrdClHttpResponses.hh"
25
26using namespace XrdClHttp;
27
28Filesystem::Filesystem(const std::string &url, std::shared_ptr<HandlerQueue> queue, XrdCl::Log *log)
29 : m_queue(queue),
30 m_logger(log),
31 m_url(url)
32{
33 m_logger->Debug(kLogXrdClHttp, "Constructing filesystem object with base URL %s", url.c_str());
34 // When constructed from the root protocol handler, we've observed it include the
35 // path here (the code paths appear to be slightly different from http://). Strip
36 // it out so it's not included twice later.
37 m_url.SetPath("/");
39 m_url.SetParams(map);
40}
41
43
45Filesystem::DirList(const std::string &path,
48 time_t timeout )
49{
51
52 auto full_url = GetCurrentURL(path);
53
54 m_logger->Debug(kLogXrdClHttp, "Filesystem::DirList path %s", path.c_str());
55 std::unique_ptr<XrdClHttp::CurlListdirOp> listdirOp(
57 handler, full_url,
58 m_url.GetHostName() + ":" + std::to_string(m_url.GetPort()),
59 SendResponseInfo(), ts, m_logger,
60 GetConnCallout(), m_header_callout.load(std::memory_order_acquire)
61 )
62 );
63
64 try {
65 m_queue->Produce(std::move(listdirOp));
66 } catch (...) {
67 m_logger->Warning(kLogXrdClHttp, "Failed to add dirlist op to queue");
69 }
70
71 return XrdCl::XRootDStatus();
72}
73
75Filesystem::GetConnCallout() const {
76 std::string pointer_str;
77 if (!GetProperty("XrdClConnectionCallout", pointer_str) && pointer_str.empty()) {
78 return nullptr;
79 }
80 long long pointer;
81 try {
82 pointer = std::stoll(pointer_str, nullptr, 16);
83 } catch (...) {
84 return nullptr;
85 }
86 if (!pointer) {
87 return nullptr;
88 }
89 return reinterpret_cast<CreateConnCalloutType>(pointer);
90}
91
92bool
93Filesystem::GetProperty(const std::string &name,
94 std::string &value) const
95{
96 std::shared_lock lock(m_properties_mutex);
97
98 const auto p = m_properties.find(name);
99 if (p == std::end(m_properties)) {
100 return false;
101 }
102
103 value = p->second;
104 return true;
105}
106
107// Trivial implementation of the "locate" call
108//
109// On Linux, this is invoked by the XrdCl client prior to directory listings.
110// Given there's no concept of multiple locations currently, we just return
111// the original host and port as the available "location".
113Filesystem::Locate( const std::string &path,
115 XrdCl::ResponseHandler *handler,
116 time_t timeout )
117{
118 if (!handler) return XrdCl::XRootDStatus();
119
120 auto locateInfo = std::make_unique<XrdCl::LocationInfo>();
121 locateInfo->Add(XrdCl::LocationInfo::Location(m_url.GetHostName() + ":" + std::to_string(m_url.GetPort()), XrdCl::LocationInfo::ServerOnline, XrdCl::LocationInfo::Read));
122
123 auto obj = std::make_unique<XrdCl::AnyObject>();
124 obj->Set(locateInfo.release());
125 handler->HandleResponse(new XrdCl::XRootDStatus(), obj.release());
126
127 return XrdCl::XRootDStatus();
128}
129
133 XrdCl::ResponseHandler *handler,
134 time_t timeout)
135{
137
138 auto full_url = GetCurrentURL(path);
139 m_logger->Debug(kLogXrdClHttp, "Filesystem::MkDir path %s", full_url.c_str());
140
141 std::unique_ptr<CurlMkcolOp> mkdirOp(
142 new CurlMkcolOp(
143 handler, full_url, ts, m_logger, SendResponseInfo(), GetConnCallout(),
144 m_header_callout.load(std::memory_order_acquire)
145 )
146 );
147 try {
148 m_queue->Produce(std::move(mkdirOp));
149 } catch (...) {
150 m_logger->Warning(kLogXrdClHttp, "Failed to add filesystem mkdir op to queue");
152 }
153
154 return XrdCl::XRootDStatus();
155}
156
158 const XrdCl::Buffer &arg,
159 XrdCl::ResponseHandler *handler,
160 time_t timeout)
161{
163
164 if (queryCode == XrdCl::QueryCode::Checksum)
165 {
166 auto url = GetCurrentURL(arg.ToString());
167 m_logger->Debug(kLogXrdClHttp, "XrdClHttp::Filesystem::Query checksum path %s", url.c_str());
168
170 XrdCl::URL url_obj;
171 url_obj.FromString(url);
172 auto iter = url_obj.GetParams().find("cks.type");
173 if (iter != url_obj.GetParams().end())
174 {
175 preferred = XrdClHttp::GetTypeFromString(iter->second);
176 if (preferred == XrdClHttp::ChecksumType::kUnknown)
177 {
178 m_logger->Error(kLogXrdClHttp, "Unknown checksum type %s", iter->second.c_str());
180 }
181 }
182 // On miss, queue a checksum operation
183 std::unique_ptr<CurlChecksumOp> cksumOp(
184 new CurlChecksumOp(
185 handler, url, preferred, ts, m_logger, SendResponseInfo(),
186 GetConnCallout(), m_header_callout.load(std::memory_order_acquire)
187 )
188 );
189 try
190 {
191 m_queue->Produce(std::move(cksumOp));
192 }
193 catch (...)
194 {
195 m_logger->Warning(kLogXrdClHttp, "Failed to add checksum operation to queue");
197 }
198 }
199 else if (queryCode == XrdCl::QueryCode::XAttr)
200 {
201 std::string path = arg.ToString();
202 std::string full_url = m_url.GetURL();
203 m_logger->Debug(kLogXrdClHttp, "XrdClHttp::Filesystem::Query xattr full_url %s, path %s", full_url.c_str(), path.c_str());
204 full_url = m_url.GetURL();
205 std::unique_ptr<CurlQueryOp> queryOp(
206 new CurlQueryOp(
207 handler, path, ts, m_logger,SendResponseInfo(),
208 GetConnCallout(), queryCode, m_header_callout.load(std::memory_order_acquire)
209 )
210 );
211 try
212 {
213 m_queue->Produce(std::move(queryOp));
214 }
215 catch (...)
216 {
217 m_logger->Warning(kLogXrdClHttp, "Failed to add xattr query operation to queue");
219 }
220 }
221 else
222 {
224 }
225 return XrdCl::XRootDStatus();
226}
227
229Filesystem::Rm(const std::string &path,
230 XrdCl::ResponseHandler *handler,
231 time_t timeout)
232{
234
235 auto full_url = GetCurrentURL(path);
236 m_logger->Debug(kLogXrdClHttp, "Filesystem::Rm path %s", full_url.c_str());
237
238 std::unique_ptr<CurlDeleteOp> deleteOp(
239 new CurlDeleteOp(
240 handler, full_url, ts, m_logger, SendResponseInfo(),
241 GetConnCallout(), m_header_callout.load(std::memory_order_acquire)
242 )
243 );
244 try {
245 m_queue->Produce(std::move(deleteOp));
246 } catch (...) {
247 m_logger->Warning(kLogXrdClHttp, "Failed to add filesystem delete op to queue");
249 }
250
251 return XrdCl::XRootDStatus();
252}
253
255Filesystem::RmDir(const std::string &path,
256 XrdCl::ResponseHandler *handler,
257 time_t timeout)
258{
259 return Rm(path, handler, timeout);
260}
261
262bool
263Filesystem::SetProperty(const std::string &name,
264 const std::string &value)
265{
266 if (name == "XrdClHttpHeaderCallout") {
267 long long pointer;
268 try {
269 pointer = std::stoll(value, nullptr, 16);
270 } catch (...) {
271 pointer = 0;
272 }
273 if (!pointer) {
274 pointer = 0;
275 }
276 m_header_callout.store(reinterpret_cast<XrdClHttp::HeaderCallout*>(pointer), std::memory_order_release);
277 }
278
279 std::unique_lock lock(m_properties_mutex);
280 m_properties[name] = value;
281 return true;
282}
283
285Filesystem::Stat(const std::string &path,
286 XrdCl::ResponseHandler *handler,
287 time_t timeout)
288{
290
291 auto full_url = GetCurrentURL(path);
292 m_logger->Debug(kLogXrdClHttp, "Filesystem::Stat path %s", full_url.c_str());
293
294 std::unique_ptr<CurlStatOp> statOp(
295 new CurlStatOp(
296 handler, full_url, ts, m_logger, SendResponseInfo(),
297 GetConnCallout(), m_header_callout.load(std::memory_order_acquire)
298 )
299 );
300 try {
301 m_queue->Produce(std::move(statOp));
302 } catch (...) {
303 m_logger->Warning(kLogXrdClHttp, "Failed to add filesystem stat op to queue");
305 }
306
307 return XrdCl::XRootDStatus();
308}
309
310bool Filesystem::SendResponseInfo() const {
311 std::string val;
312 return GetProperty(ResponseInfoProperty, val) && val == "true";
313}
314
315std::string Filesystem::GetCurrentURL(const std::string &path) const {
316
317 // Compute the URL without trailing slash.
318 auto prefix = m_url.GetURL();
319 std::string_view prefix_view = prefix;
320 while (!prefix_view.empty() && prefix_view[prefix_view.size() - 1] == '/')
321 prefix_view = prefix_view.substr(0, prefix_view.size() - 1);
322
323 // Compute the target path without the '/' prefix
324 std::string_view path_view = path;
325 while (!path_view.empty() && path_view[0] == '/')
326 path_view = path_view.substr(1);
327 auto retval = std::string(prefix_view) + "/" + std::string(path_view);
328
329 // Add in the query parameters, if relevant.
330 {
331 std::shared_lock lock(m_properties_mutex);
332 auto iter = m_properties.find("XrdClHttpQueryParam");
333 if (iter != m_properties.end() && !iter->second.empty()) {
334 retval += ((retval.find('?') == std::string::npos) ? '?' : ':') + iter->second;
335 }
336 }
337 return retval;
338}
static std::string ts()
timestamp output for logging messages
Definition XrdCephOss.cc:53
#define ResponseInfoProperty
static struct timespec GetHeaderTimeoutWithDefault(time_t oper_timeout)
virtual XrdCl::XRootDStatus MkDir(const std::string &path, XrdCl::MkDirFlags::Flags flags, XrdCl::Access::Mode mode, XrdCl::ResponseHandler *handler, time_t timeout) override
virtual bool SetProperty(const std::string &name, const std::string &value) override
XrdCl::XRootDStatus DirList(const std::string &path, XrdCl::DirListFlags::Flags flags, XrdCl::ResponseHandler *handler, time_t timeout) override
virtual XrdCl::XRootDStatus Rm(const std::string &path, XrdCl::ResponseHandler *handler, time_t timeout) override
virtual XrdCl::XRootDStatus Stat(const std::string &path, XrdCl::ResponseHandler *handler, time_t timeout) override
virtual XrdCl::XRootDStatus Locate(const std::string &path, XrdCl::OpenFlags::Flags flags, XrdCl::ResponseHandler *handler, time_t timeout) override
virtual ~Filesystem() noexcept
virtual XrdCl::XRootDStatus RmDir(const std::string &path, XrdCl::ResponseHandler *handler, time_t timeout) override
virtual bool GetProperty(const std::string &name, std::string &value) const override
virtual XrdCl::XRootDStatus Query(XrdCl::QueryCode::Code queryCode, const XrdCl::Buffer &arg, XrdCl::ResponseHandler *handler, time_t timeout) override
Filesystem(const std::string &, std::shared_ptr< HandlerQueue > queue, XrdCl::Log *log)
Binary blob representation.
std::string ToString() const
Convert the buffer to a string.
@ Read
read access is allowed
@ ServerOnline
server node where the file is online
Handle diagnostics.
Definition XrdClLog.hh:101
Handle an async response.
virtual void HandleResponse(XRootDStatus *status, AnyObject *response)
URL representation.
Definition XrdClURL.hh:31
std::map< std::string, std::string > ParamsMap
Definition XrdClURL.hh:33
bool FromString(const std::string &url)
Parse a string and fill the URL fields.
Definition XrdClURL.cc:62
std::string GetURL() const
Get the URL.
Definition XrdClURL.hh:86
const ParamsMap & GetParams() const
Get the URL params.
Definition XrdClURL.hh:244
ConnectionCallout *(*)(const std::string &, const ResponseInfo &) CreateConnCalloutType
ChecksumType GetTypeFromString(const std::string &str)
const uint64_t kLogXrdClHttp
const uint16_t errNotImplemented
Operation is not implemented.
const uint16_t stError
An error occurred that could potentially be retried.
const uint16_t errOSError
Flags
Open flags, may be or'd when appropriate.
Code
XRootD query request codes.
@ XAttr
Query file extended attributes.
@ Checksum
Query file checksum.