45 const char *
const parms,
48 if( !parms )
return 0;
50 std::vector<std::string> splitArgs;
52 if( splitArgs.size() < 2 )
return 0;
57 std::string iorstr = splitArgs[0];
58 std::string iovstr = splitArgs[1];
63 if(
XrdOuca2x::a2i( Eroute,
"Error reading specific value of readv_ior_max",
64 iorstr.c_str(), &val, 1, -1 ) )
70 if(
XrdOuca2x::a2i( Eroute,
"Error reading specific value of readv_iov_max",
71 iovstr.c_str(), &val, 1, -1 ) )
96 return rawUserRanges_.empty();
104 if( !rangesResolved_ )
107 return( resolvedUserRanges_.size() <= 1 );
117 if( !rangesResolved_ )
123 return resolvedUserRanges_;
133 if( !rangesResolved_ )
139 if( !splitRange_.empty() )
141 if( currSplitRangeIdx_ == 0 && currSplitRangeOff_ == 0 )
147 error_.
set( 500,
"Stopping request because more data is expected "
148 "but no data has been read." );
158 if( !splitRange_.empty() )
162 if( splitRangeIdx_ >= resolvedUserRanges_.size() )
178 error_.
set( 500,
"An error occured." );
200 error_.
set( 500,
"Range handler read failure." );
204 if( !rangesResolved_ )
206 error_.
set( 500,
"Range handler ranges not yet resolved." );
210 if( splitRange_.empty() )
212 error_.
set( 500,
"No ranges being read." );
219 if( currSplitRangeIdx_ >= splitRange_.size() ||
220 resolvedRangeIdx_ >= resolvedUserRanges_.size() )
222 error_.
set( 500,
"Range handler index invalid." );
227 *urp = &resolvedUserRanges_[resolvedRangeIdx_];
229 if( resolvedRangeOff_ == 0 )
232 const int clen = splitRange_[currSplitRangeIdx_].size;
234 const off_t ulen = resolvedUserRanges_[resolvedRangeIdx_].end
235 - resolvedUserRanges_[resolvedRangeIdx_].start + 1;
237 currSplitRangeOff_ += ret;
238 resolvedRangeOff_ += ret;
240 if( currSplitRangeOff_ > clen || resolvedRangeOff_ > ulen )
242 error_.
set( 500,
"Range handler read crossing chunk boundary." );
246 if( currSplitRangeOff_ == clen )
248 currSplitRangeOff_ = 0;
249 currSplitRangeIdx_++;
251 if( currSplitRangeIdx_ >= splitRange_.size() )
253 currSplitRangeIdx_ = 0;
258 if( resolvedRangeOff_ == ulen )
261 resolvedRangeOff_ = 0;
262 if( resolvedRangeIdx_ >= resolvedUserRanges_.size() )
274 char *str1, *saveptr1, *token;
276 std::unique_ptr< char, decltype(std::free)* >
277 line_copy { strdup( line ), std::free };
287 str1 = line_copy.get();
288 token = strchr(str1,
'=');
289 if (token) str1 = token + 1;
295 for( ; ; str1 = NULL )
297 token = strtok_r( str1,
" ,\n\r", &saveptr1 );
301 if( !strlen(token) )
continue;
303 const int rc = parseOneRange( token );
309 rawUserRanges_.clear();
321 rawUserRanges_.clear();
322 rawUserRanges_.shrink_to_fit();
323 resolvedUserRanges_.clear();
324 resolvedUserRanges_.shrink_to_fit();
326 splitRange_.shrink_to_fit();
327 rangesResolved_ =
false;
330 currSplitRangeIdx_ = 0;
331 currSplitRangeOff_ = 0;
332 resolvedRangeIdx_ = 0;
333 resolvedRangeOff_ = 0;
345 if( rangesResolved_ )
347 error_.
set( 500,
"Filesize notified after ranges resolved." );
358 int XrdHttpReadRangeHandler::parseOneRange(
char*
const str)
370 sep = strchr( str,
'-' );
380 if( rangeFig( str, ur.start_set, ur.start )<0 )
389 if( rangeFig( sep+1, ur.end_set, ur.end )<0 )
397 if( !ur.start_set && !ur.end_set )
405 if( ur.start_set && ur.end_set && ur.start > ur.end )
413 if( !ur.start_set && ur.end_set && ur.end == 0 )
421 rawUserRanges_.push_back(ur);
428 int XrdHttpReadRangeHandler::rangeFig(
const char*
const s,
bool &set, off_t &val)
430 char *endptr = (
char*)s;
432 long long int v = strtoll( s, &endptr, 10 );
433 if( (errno == ERANGE && (v == LONG_MAX || v == LONG_MIN))
434 || (errno != 0 && errno != EINVAL && v == 0) )
438 if( *endptr !=
'\0' )
457 void XrdHttpReadRangeHandler::resolveRanges()
462 resolvedUserRanges_.clear();
464 for(
const auto &rr: rawUserRanges_ )
483 if( start >= filesize_ )
486 if( end >= filesize_ )
500 if( rr.end > filesize_ )
506 start = filesize_ - rr.end;
516 if( !rr.start_set )
continue;
517 if( rr.start >= filesize_ )
522 resolvedUserRanges_.emplace_back( start, end );
525 if( rawUserRanges_.empty() && filesize_>0 )
530 resolvedUserRanges_.emplace_back( 0, filesize_ - 1 );
533 if( !rawUserRanges_.empty() && resolvedUserRanges_.empty() )
535 error_.
set( 416,
"None of the range-specifier values in the Range "
536 "request-header field overlap the current extent of the selected resource." );
539 rangesResolved_ =
true;
547 void XrdHttpReadRangeHandler::splitRanges()
550 currSplitRangeIdx_ = 0;
551 currSplitRangeOff_ = 0;
552 resolvedRangeIdx_ = splitRangeIdx_;
553 resolvedRangeOff_ = splitRangeOff_;
570 size_t maxch = vectorReadMaxChunks_;
571 size_t maxchs = vectorReadMaxChunkSize_;
574 maxchs = rRequestMaxBytes_;
578 splitRange_.reserve( maxch );
584 const size_t cs = resolvedUserRanges_.size();
586 size_t rsr = rRequestMaxBytes_;
589 while( ( splitRangeIdx_ < cs ) && ( rsr > 0 ) )
597 if( !tmpur.start_set )
599 tmpur = resolvedUserRanges_[splitRangeIdx_];
600 tmpur.start += splitRangeOff_;
603 const off_t l = tmpur.end - tmpur.start + 1;
604 size_t maxsize = std::min( rsr, maxchs );
610 if( nc == 0 && l >= (off_t)rRequestMaxBytes_ )
611 maxsize = rRequestMaxBytes_;
613 if( l > (off_t)maxsize )
615 splitRange_.emplace_back(
nullptr, tmpur.start, maxsize );
616 tmpur.start += maxsize;
617 splitRangeOff_ += maxsize;
622 splitRange_.emplace_back(
nullptr, tmpur.start, l );
635 void XrdHttpReadRangeHandler::trimSplit()
637 if( currSplitRangeIdx_ < splitRange_.size() )
639 splitRange_.erase( splitRange_.begin(),
640 splitRange_.begin() + currSplitRangeIdx_ );
645 if( splitRange_.size() > 0 )
647 if( currSplitRangeOff_ < splitRange_[0].size )
649 splitRange_[0].offset += currSplitRangeOff_;
650 splitRange_[0].size -= currSplitRangeOff_;
656 currSplitRangeIdx_ = 0;
657 currSplitRangeOff_ = 0;
std::vector< XrdOucIOVec2 > XrdHttpIOList
void reset()
resets this handler
const XrdHttpIOList & NextReadList()
return XrdHttpIOList for sending to read or readv
void ParseContentRange(const char *const line)
parse the line after a "Range: " http request header
int SetFilesize(const off_t sz)
sets the filesize, used during resolving and issuing range requests
static int Configure(XrdSysError &Eroute, const char *const parms, Configuration &cfg)
void NotifyError()
Force handler to enter error state.
bool isFullFile()
indicates when there were no valid Range head ranges supplied
std::vector< UserRange > UserRangeList
int NotifyReadResult(const ssize_t ret, const UserRange **const urp, bool &start, bool &allend)
Advance internal counters concerning received bytes.
const Error & getError() const
return the Error object
bool isSingleRange()
indicates a single range (implied whole file, or single range) or empty file
static constexpr size_t RREQ_MAXSIZE
const UserRangeList & ListResolvedRanges()
return resolved (i.e. obsolute start and end) byte ranges desired
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)
void set(int rc, const std::string &m)