XRootD
Loading...
Searching...
No Matches
XrdClHttpUtil.hh
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#ifndef XRDCLHTTPUTIL_HH
22#define XRDCLHTTPUTIL_HH
23
24#include "XrdClHttpChecksum.hh"
27
28#include <chrono>
29#include <condition_variable>
30#include <deque>
31#include <memory>
32#include <mutex>
33#include <string>
34#include <unordered_map>
35#include <vector>
36
37// Forward dec'ls
38typedef void CURL;
39struct curl_slist;
40
41namespace XrdCl {
42
43class ResponseHandler;
44class Log;
45
46}
47
48namespace XrdClHttp {
49
50class CurlOperation;
51
52const uint64_t kLogXrdClHttp = 73173;
53
54bool HTTPStatusIsError(unsigned status);
55
56std::pair<uint16_t, uint32_t> HTTPStatusConvert(unsigned status);
57
58// Trim the left side of a string_view for space
59std::string_view ltrim_view(const std::string_view &input_view);
60
61// Trim the left and right side of a string_view of whitespace
62std::string_view trim_view(const std::string_view &input_view);
63
64// Returns a newly-created curl handle (no internal caching) with the
65// various configurations needed to be used by XrdClHttp
66CURL *GetHandle(bool verbose);
67
68// Parser for headers as emitted by libcurl.
69//
70// Records specific headers known to be used by the project but ignores others.
72public:
74
75 bool Parse(const std::string &headers);
76
77 int64_t GetContentLength() const {return m_content_length;}
78
79 uint64_t GetOffset() const {return m_response_offset;}
80
81 static bool Canonicalize(std::string &headerName);
82
83 bool HeadersDone() const {return m_recv_all_headers;}
84
85 // Move the received headers to the caller.
86 //
87 // Only invoke once HeadersDone() returns true.
88 ResponseInfo::HeaderMap && MoveHeaders() {return std::move(m_headers);}
89
90 int GetStatusCode() const {return m_status_code;}
91
92 // Setter for the status code
93 // Intended for use in unit tests.
94 void SetStatusCode(int sc) {m_status_code = sc;}
95
96 // Return whether the server response specified this is a multipart range.
97 bool IsMultipartByterange() const {return m_multipart_byteranges;}
98
99 // Return the separator specified in the server response with the
100 // `--` prefix included..
101 const std::string &MultipartSeparator() const {return m_multipart_sep;}
102
103 // Set the separator used for multipart messages; a `--` prefix
104 // will be added to the Getter.
105 void SetMultipartSeparator(const std::string_view &sep) {
106 m_multipart_sep = "--" + std::string(sep);
107 m_multipart_byteranges = true;
108 }
109
111 {
112 return VerbsCache::HttpVerbs(m_allow_verbs);
113 }
114
115 std::string GetStatusMessage() const {return m_resp_message;}
116
117 const std::string &GetLocation() const {return m_location;}
118 const std::string &GetETag() const {return m_etag;}
119 const std::string &GetCacheControl() const {return m_cache_control;}
120
121 // Returns a reference to the checksums parsed from the headers.
122 const XrdClHttp::ChecksumInfo &GetChecksums() const {return m_checksums;}
123
124 // Parse a RFC 3230 header, updating the checksum info structure.
125 static void ParseDigest(const std::string &digest, XrdClHttp::ChecksumInfo &info);
126
127 // Decode a base64-encoded string into a binary buffer.
128 static bool Base64Decode(std::string_view input, std::array<unsigned char, 32> &output);
129
130 // Convert a checksum type to a RFC 3230 digest name.
131 static std::string ChecksumTypeToDigestName(XrdClHttp::ChecksumType type);
132
133private:
134
135 static bool validHeaderByte(unsigned char c);
136
137 int64_t m_content_length{-1};
138 uint64_t m_response_offset{0};
139
140 XrdClHttp::ChecksumInfo m_checksums;
141
142 bool m_recv_all_headers{false};
143 bool m_recv_status_line{false};
144 bool m_multipart_byteranges{false};
145
146 int m_status_code{-1};
147 std::string m_resp_protocol;
148 std::string m_resp_message;
149 std::string m_location;
150 std::string m_multipart_sep;
151 std::string m_etag;
152 std::string m_cache_control;
153
154 ResponseInfo::HeaderMap m_headers;
155
157};
158
168public:
169 HandlerQueue(unsigned max_pending_ops);
170
171 void Produce(std::shared_ptr<CurlOperation> handler);
172
173 std::shared_ptr<CurlOperation> Consume(std::chrono::steady_clock::duration);
174 std::shared_ptr<CurlOperation> TryConsume();
175
176 int PollFD() const {return m_read_fd;}
177
178 CURL *GetHandle();
179 void RecycleHandle(CURL *);
180
181 // Check all the operations in queue to see if any have expired.
182 //
183 // Each curl operation has a header timeout; if no headers have been received
184 // by the time the timeout expires, the operation is considered to have
185 // expired. This function checks all operations in the queue and
186 // removes any that have expired.
187 void Expire();
188
189 void Shutdown();
190 // Cleanup all idle handles in current thread.
191 void ReleaseHandles();
192
193 // Returns the class default number of pending operations.
194 static unsigned GetDefaultMaxPendingOps() {return m_default_max_pending_ops;}
195
196 // Returns a summary of the queue's performance statistics.
197 static std::string GetMonitoringJson();
198
199private:
200 bool m_shutdown{false};
201 std::deque<std::shared_ptr<CurlOperation>> m_ops;
202 static std::atomic<uint64_t> m_ops_consumed; // Count of operations consumed from the queue.
203 static std::atomic<uint64_t> m_ops_produced; // Count of operations added to the queue.
204 static std::atomic<uint64_t> m_ops_rejected; // Count of operations rejected by the queue.
205 thread_local static std::vector<CURL*> m_handles;
206 std::condition_variable m_consumer_cv;
207 std::condition_variable m_producer_cv;
208 std::mutex m_mutex;
209 const static unsigned m_default_max_pending_ops{50};
210 const unsigned m_max_pending_ops{50};
211 int m_read_fd{-1};
212 int m_write_fd{-1};
213};
214
215}
216
217#endif // XRDCLHTTPUTIL_HH
void CURL
std::shared_ptr< CurlOperation > Consume(std::chrono::steady_clock::duration)
HandlerQueue(unsigned max_pending_ops)
void Produce(std::shared_ptr< CurlOperation > handler)
static std::string GetMonitoringJson()
static unsigned GetDefaultMaxPendingOps()
std::shared_ptr< CurlOperation > TryConsume()
void SetMultipartSeparator(const std::string_view &sep)
static bool Base64Decode(std::string_view input, std::array< unsigned char, 32 > &output)
static void ParseDigest(const std::string &digest, XrdClHttp::ChecksumInfo &info)
std::string GetStatusMessage() const
const std::string & GetCacheControl() const
uint64_t GetOffset() const
bool IsMultipartByterange() const
const XrdClHttp::ChecksumInfo & GetChecksums() const
int64_t GetContentLength() const
ResponseInfo::HeaderMap && MoveHeaders()
static bool Canonicalize(std::string &headerName)
const std::string & MultipartSeparator() const
bool Parse(const std::string &headers)
VerbsCache::HttpVerbs GetAllowedVerbs() const
static std::string ChecksumTypeToDigestName(XrdClHttp::ChecksumType type)
const std::string & GetLocation() const
const std::string & GetETag() const
std::unordered_map< std::string, HeaderValues > HeaderMap
std::pair< uint16_t, uint32_t > HTTPStatusConvert(unsigned status)
CURL * GetHandle(bool verbose)
bool HTTPStatusIsError(unsigned status)
std::string_view ltrim_view(const std::string_view &input_view)
const uint64_t kLogXrdClHttp
std::string_view trim_view(const std::string_view &input_view)