XRootD
Loading...
Searching...
No Matches
XrdHttpReadRangeHandler Class Reference

#include <XrdHttpReadRangeHandler.hh>

+ Collaboration diagram for XrdHttpReadRangeHandler:

Classes

struct  Configuration
 
struct  Error
 
struct  UserRange
 

Public Types

typedef std::vector< UserRangeUserRangeList
 

Public Member Functions

 XrdHttpReadRangeHandler (const Configuration &conf)
 
const ErrorgetError () const
 return the Error object
 
size_t getMaxRanges () const
 return the maximum number of ranges that may be requested
 
bool isFullFile ()
 indicates when there were no valid Range head ranges supplied
 
bool isSingleRange ()
 indicates a single range (implied whole file, or single range) or empty file
 
const UserRangeListListResolvedRanges ()
 return resolved (i.e. obsolute start and end) byte ranges desired
 
const XrdHttpIOListNextReadList ()
 return XrdHttpIOList for sending to read or readv
 
void NotifyError ()
 Force handler to enter error state.
 
int NotifyReadResult (const ssize_t ret, const UserRange **const urp, bool &start, bool &allend)
 Advance internal counters concerning received bytes.
 
void ParseContentRange (const char *const line)
 parse the line after a "Range: " http request header
 
void reset ()
 resets this handler
 
int SetFilesize (const off_t sz)
 sets the filesize, used during resolving and issuing range requests
 

Static Public Member Functions

static int Configure (XrdSysError &Eroute, const char *const parms, Configuration &cfg)
 

Static Public Attributes

static constexpr size_t READV_MAXCHUNKS = 512
 
static constexpr size_t READV_MAXCHUNKSIZE = 512*1024
 
static constexpr size_t RREQ_MAXSIZE = 8*1024*1024
 

Detailed Description

Class responsible for parsing the HTTP Content-Range header coming from the client, generating appropriate read ranges for read or readv and tracking the responses to the requests.

Definition at line 36 of file XrdHttpReadRangeHandler.hh.

Member Typedef Documentation

◆ UserRangeList

Definition at line 103 of file XrdHttpReadRangeHandler.hh.

Constructor & Destructor Documentation

◆ XrdHttpReadRangeHandler()

XrdHttpReadRangeHandler::XrdHttpReadRangeHandler ( const Configuration & conf)
inline

Constructor. Supplied with an Configuration object. The supplied object remains owned by the caller, but should remain valid throughout the lifetime of the ReadRangeHandler.

Parameters

conf Configuration object.

Definition at line 113 of file XrdHttpReadRangeHandler.hh.

114 {
115 rRequestMaxBytes_ = RREQ_MAXSIZE;
116 vectorReadMaxChunkSize_ = READV_MAXCHUNKSIZE;
117 vectorReadMaxChunks_ = READV_MAXCHUNKS;
118
119 if( conf.haveSizes )
120 {
121 vectorReadMaxChunkSize_ = conf.readv_ior_max;
122 vectorReadMaxChunks_ = conf.readv_iov_max;
123 rRequestMaxBytes_ = conf.reqs_max;
124 }
125 reset();
126 }
static constexpr size_t READV_MAXCHUNKSIZE
void reset()
resets this handler
static constexpr size_t RREQ_MAXSIZE
static constexpr size_t READV_MAXCHUNKS

References XrdHttpReadRangeHandler::Configuration::haveSizes, XrdHttpReadRangeHandler::Configuration::readv_ior_max, XrdHttpReadRangeHandler::Configuration::readv_iov_max, READV_MAXCHUNKS, READV_MAXCHUNKSIZE, XrdHttpReadRangeHandler::Configuration::reqs_max, reset(), and RREQ_MAXSIZE.

+ Here is the call graph for this function:

Member Function Documentation

◆ Configure()

int XrdHttpReadRangeHandler::Configure ( XrdSysError & Eroute,
const char *const parms,
Configuration & cfg )
static

Parses a configuration into a Configuration object.

Parameters

Eroute Error reporting object

Parameters

parms Configuration string.

Parameters

cfg an output Configuration object

Returns
0 for success, otherwise failure.

static, class method: initialise a configuraiton object. parms is currently only content of environment variable XRD_READV_LIMITS, to get the specific kXR_readv limits.

Definition at line 42 of file XrdHttpReadRangeHandler.cc.

47{
48 if( !parms ) return 0;
49
50 std::vector<std::string> splitArgs;
51 XrdOucTUtils::splitString( splitArgs, parms, "," );
52 if( splitArgs.size() < 2 ) return 0;
53
54 //----------------------------------------------------------------------------
55 // params is expected to be "<readv_ior_max>,<readv_iov_max>"
56 //----------------------------------------------------------------------------
57 std::string iorstr = splitArgs[0];
58 std::string iovstr = splitArgs[1];
59 XrdOucUtils::trim( iorstr );
60 XrdOucUtils::trim( iovstr );
61
62 int val;
63 if( XrdOuca2x::a2i( Eroute, "Error reading specific value of readv_ior_max",
64 iorstr.c_str(), &val, 1, -1 ) )
65 {
66 return -1;
67 }
68
69 cfg.readv_ior_max = val;
70 if( XrdOuca2x::a2i( Eroute, "Error reading specific value of readv_iov_max",
71 iovstr.c_str(), &val, 1, -1 ) )
72 {
73 return -1;
74 }
75
76 cfg.readv_iov_max = val;
77 cfg.reqs_max = RREQ_MAXSIZE;
78 cfg.haveSizes = true;
79
80 return 0;
81}
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
static void trim(std::string &str)
static int a2i(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition XrdOuca2x.cc:45

References XrdOuca2x::a2i(), XrdHttpReadRangeHandler::Configuration::haveSizes, XrdHttpReadRangeHandler::Configuration::readv_ior_max, XrdHttpReadRangeHandler::Configuration::readv_iov_max, XrdHttpReadRangeHandler::Configuration::reqs_max, RREQ_MAXSIZE, XrdOucTUtils::splitString(), and XrdOucUtils::trim().

+ Here is the call graph for this function:

◆ getError()

const XrdHttpReadRangeHandler::Error & XrdHttpReadRangeHandler::getError ( ) const

return the Error object

getter for the Error object. The object can be inspected with its operator bool() method to indicate an error has happened. Error code and message are available in other members of Error.

Definition at line 86 of file XrdHttpReadRangeHandler.cc.

87{
88 return error_;
89}

◆ getMaxRanges()

size_t XrdHttpReadRangeHandler::getMaxRanges ( ) const

return the maximum number of ranges that may be requested

Return the maximum number of expected ranges for the request. Used to determine whether a vector range request may be used at open time. At that time, isSingleRange() cannot be invoked because it internally resolves the correct ranges which requires the file size to be set (which only occurs after file-open). The use case is to determine whether we should set the sequential I/O flag at open time.

Definition at line 102 of file XrdHttpReadRangeHandler.cc.

103{
104 return rawUserRanges_.empty() ? 1 : rawUserRanges_.size();
105}

◆ isFullFile()

bool XrdHttpReadRangeHandler::isFullFile ( )

indicates when there were no valid Range head ranges supplied

Indicates no valid Range header was given and thus the implication is that whole file is required. A range or ranges may be given that cover the whole file but that situation is not detected.

Definition at line 94 of file XrdHttpReadRangeHandler.cc.

95{
96 return rawUserRanges_.empty();
97}

◆ isSingleRange()

bool XrdHttpReadRangeHandler::isSingleRange ( )

indicates a single range (implied whole file, or single range) or empty file

Incidcates whether there is a single range, either given by a Range header with single range or implied by having no Range header. Also returns true for an empty file, although there is no range of bytes.

Returns
true if there is a single range.

Definition at line 110 of file XrdHttpReadRangeHandler.cc.

111{
112 if( !rangesResolved_ )
113 resolveRanges();
114
115 return( resolvedUserRanges_.size() <= 1 );
116}

◆ ListResolvedRanges()

const XrdHttpReadRangeHandler::UserRangeList & XrdHttpReadRangeHandler::ListResolvedRanges ( )

return resolved (i.e. obsolute start and end) byte ranges desired

Returns a reference of the list of ranges. These are resolved, meaning that if there was no Range header, or it was in the form -N or N-, the file size is used to compute the actual range of bytes that are needed. The list remains owned by the handler and may be invalidated on reset().

Returns
List of ranges in a UserRangeList object. The returned list may be empty, i.e. for an empty file or if there is an error. Use getError() to see if there is an error.

Definition at line 121 of file XrdHttpReadRangeHandler.cc.

122{
123 static const UserRangeList emptyList;
124
125 if( !rangesResolved_ )
126 resolveRanges();
127
128 if( error_ )
129 return emptyList;
130
131 return resolvedUserRanges_;
132}
std::vector< UserRange > UserRangeList

◆ NextReadList()

const XrdHttpIOList & XrdHttpReadRangeHandler::NextReadList ( )

return XrdHttpIOList for sending to read or readv

Requests a XrdHttpIOList (vector of XrdOucIOVec2) that describes the next bytes that need to be fetched from a file. If there is more than one chunk it is size appropriately for a readv request, if there is one request it should be sent as a read request. Therefore the chunks do not necessarily correspond to the ranges the user requested. The caller issue the requests in the order provided and call NotifyReadResult with the ordered results.

Returns
a reference to a XrdHttpIOList. The object remains owned by the handler. It may be invalided by a new call to NextReadList() or reset(). The returned list may be empty, which implies no more reads are needed One can use getError() to see if there is an error.

Definition at line 137 of file XrdHttpReadRangeHandler.cc.

138{
139 static const XrdHttpIOList emptyList;
140
141 if( !rangesResolved_ )
142 resolveRanges();
143
144 if( error_ )
145 return emptyList;
146
147 if( !splitRange_.empty() )
148 {
149 if( currSplitRangeIdx_ == 0 && currSplitRangeOff_ == 0 )
150 {
151 //------------------------------------------------------------------------
152 // Nothing read: Prevent scenario where data is expected but none is
153 // actually read E.g. Accessing files which return the results of a script
154 //------------------------------------------------------------------------
155 error_.set( 500, "Stopping request because more data is expected "
156 "but no data has been read." );
157 return emptyList;
158 }
159
160 //--------------------------------------------------------------------------
161 // we may have some unacknowledged portion of the last range; maybe due to a
162 // short read. so remove what was received and potentially reissue.
163 //--------------------------------------------------------------------------
164
165 trimSplit();
166 if( !splitRange_.empty() )
167 return splitRange_;
168 }
169
170 if( splitRangeIdx_ >= resolvedUserRanges_.size() )
171 return emptyList;
172
173 splitRanges();
174
175 return splitRange_;
176}
std::vector< XrdOucIOVec2 > XrdHttpIOList

◆ NotifyError()

void XrdHttpReadRangeHandler::NotifyError ( )

Force handler to enter error state.

Force the handler to enter error state. Sets a generic error message if there was not already an error.

Definition at line 181 of file XrdHttpReadRangeHandler.cc.

182{
183 if( error_ )
184 return;
185
186 error_.set( 500, "An error occurred." );
187}

◆ NotifyReadResult()

int XrdHttpReadRangeHandler::NotifyReadResult ( const ssize_t ret,
const UserRange **const urp,
bool & start,
bool & allend )

Advance internal counters concerning received bytes.

Notifies the handler about the arrival of bytes from a read or readv request. The handler tracks the progress of the arriving bytes against the bytes ranges the user requested.

Parameters
retthe number of bytes received
urpa pointer to a pointer of a UserRange object. If urp is not nullptr, the pointer to a UserRange is returned that describes the current range associated with the received bytes. The handler retains ownership of the returned object. reset() of the handler invalidates the UserRange object.
startis an output bool parameter that indicates whether the received bytes mark the start of a UserRange.
allendis an output bool parameter that indicates whether the received bytes mark the end of all the UserRanges
Returns
0 upon success, -1 if an error happened. One needs to call the getError() method to return the error.

Definition at line 192 of file XrdHttpReadRangeHandler.cc.

199{
200 if( error_ )
201 return -1;
202
203 if( ret == 0 )
204 return 0;
205
206 if( ret < 0 )
207 {
208 error_.set( 500, "Range handler read failure." );
209 return -1;
210 }
211
212 if( !rangesResolved_ )
213 {
214 error_.set( 500, "Range handler ranges not yet resolved." );
215 return -1;
216 }
217
218 if( splitRange_.empty() )
219 {
220 error_.set( 500, "No ranges being read." );
221 return -1;
222 }
223
224 start = false;
225 allend = false;
226
227 if( currSplitRangeIdx_ >= splitRange_.size() ||
228 resolvedRangeIdx_ >= resolvedUserRanges_.size() )
229 {
230 error_.set( 500, "Range handler index invalid." );
231 return -1;
232 }
233
234 if( urp )
235 *urp = &resolvedUserRanges_[resolvedRangeIdx_];
236
237 if( resolvedRangeOff_ == 0 )
238 start = true;
239
240 const int clen = splitRange_[currSplitRangeIdx_].size;
241
242 const off_t ulen = resolvedUserRanges_[resolvedRangeIdx_].end
243 - resolvedUserRanges_[resolvedRangeIdx_].start + 1;
244
245 currSplitRangeOff_ += ret;
246 resolvedRangeOff_ += ret;
247
248 if( currSplitRangeOff_ > clen || resolvedRangeOff_ > ulen )
249 {
250 error_.set( 500, "Range handler read crossing chunk boundary." );
251 return -1;
252 }
253
254 if( currSplitRangeOff_ == clen )
255 {
256 currSplitRangeOff_ = 0;
257 currSplitRangeIdx_++;
258
259 if( currSplitRangeIdx_ >= splitRange_.size() )
260 {
261 currSplitRangeIdx_ = 0;
262 splitRange_.clear();
263 }
264 }
265
266 if( resolvedRangeOff_ == ulen )
267 {
268 resolvedRangeIdx_++;
269 resolvedRangeOff_ = 0;
270 if( resolvedRangeIdx_ >= resolvedUserRanges_.size() )
271 allend = true;
272 }
273
274 return 0;
275}

References XrdHttpReadRangeHandler::UserRange::end.

◆ ParseContentRange()

void XrdHttpReadRangeHandler::ParseContentRange ( const char *const line)

parse the line after a "Range: " http request header

Parses the Content-Range header value and sets the ranges within the object.

Parameters
linethe line under the format "bytes=0-19, 25-30" In case the parsing fails any partial results are cleared. There is no error notification as the rest of the request processing should continue in any case.

Definition at line 280 of file XrdHttpReadRangeHandler.cc.

281{
282 char *str1, *saveptr1, *token;
283
284 std::unique_ptr< char, decltype(std::free)* >
285 line_copy { strdup( line ), std::free };
286
287 //----------------------------------------------------------------------------
288 // line_copy is argument of the Range header.
289 //
290 // e.g. "bytes=15-17,20-25"
291 // We skip the unit prefix (upto first '='). We don't
292 // enforce this prefix nor check what it is (e.g. 'bytes')
293 //----------------------------------------------------------------------------
294
295 str1 = line_copy.get();
296 token = strchr(str1,'=');
297 if (token) str1 = token + 1;
298
299 //----------------------------------------------------------------------------
300 // break up the ranges and process each
301 //----------------------------------------------------------------------------
302
303 for( ; ; str1 = NULL )
304 {
305 token = strtok_r( str1, " ,\n\r", &saveptr1 );
306 if( token == NULL )
307 break;
308
309 if( !strlen(token) ) continue;
310
311 const int rc = parseOneRange( token );
312 if( rc )
313 {
314 //------------------------------------------------------------------------
315 // on error we ignore the whole range header
316 //------------------------------------------------------------------------
317 rawUserRanges_.clear();
318 return;
319 }
320 }
321}

◆ reset()

void XrdHttpReadRangeHandler::reset ( )

resets this handler

Resets the object state, ready for handling a new request.

Definition at line 326 of file XrdHttpReadRangeHandler.cc.

327{
328 error_.reset();
329 rawUserRanges_.clear();
330 rawUserRanges_.shrink_to_fit();
331 resolvedUserRanges_.clear();
332 resolvedUserRanges_.shrink_to_fit();
333 splitRange_.clear();
334 splitRange_.shrink_to_fit();
335 rangesResolved_ = false;
336 splitRangeIdx_ = 0;
337 splitRangeOff_ = 0;
338 currSplitRangeIdx_ = 0;
339 currSplitRangeOff_ = 0;
340 resolvedRangeIdx_ = 0;
341 resolvedRangeOff_ = 0;
342 filesize_ = 0;
343}

Referenced by XrdHttpReadRangeHandler().

+ Here is the caller graph for this function:

◆ SetFilesize()

int XrdHttpReadRangeHandler::SetFilesize ( const off_t sz)

sets the filesize, used during resolving and issuing range requests

Notifies of the current file size. This information is required for processing range requests that imply reading to the end or a certain position before the end of a file. It is also used to determine when read or readv need no longer be issued when reading the whole file. Can be called once or more, after reset() but before isSingleRange(), ListResolvedRanges() or NextReadList() methods.

Parameters
szthe size of the file
Returns
0 upon success, -1 if an error happened. One needs to call the getError() method to return the error.

Definition at line 348 of file XrdHttpReadRangeHandler.cc.

349{
350 if( error_ )
351 return -1;
352
353 if( rangesResolved_ )
354 {
355 error_.set( 500, "Filesize notified after ranges resolved." );
356 return -1;
357 }
358
359 filesize_ = fs;
360 return 0;
361}

Member Data Documentation

◆ READV_MAXCHUNKS

size_t XrdHttpReadRangeHandler::READV_MAXCHUNKS = 512
staticconstexpr

These are defaults for: READV_MAXCHUNKS Max length of the XrdHttpIOList vector. READV_MAXCHUNKSIZE Max length of a XrdOucIOVec2 element. RREQ_MAXSIZE Max bytes to issue in a whole readv/read.

Definition at line 45 of file XrdHttpReadRangeHandler.hh.

Referenced by XrdHttpReadRangeHandler().

◆ READV_MAXCHUNKSIZE

size_t XrdHttpReadRangeHandler::READV_MAXCHUNKSIZE = 512*1024
staticconstexpr

Definition at line 46 of file XrdHttpReadRangeHandler.hh.

Referenced by XrdHttpReadRangeHandler().

◆ RREQ_MAXSIZE

size_t XrdHttpReadRangeHandler::RREQ_MAXSIZE = 8*1024*1024
staticconstexpr

Definition at line 47 of file XrdHttpReadRangeHandler.hh.

Referenced by XrdHttpReadRangeHandler(), and Configure().


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