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 return rawUserRanges_.empty() ? 1 : rawUserRanges_.size();
112 if( !rangesResolved_ )
115 return( resolvedUserRanges_.size() <= 1 );
125 if( !rangesResolved_ )
131 return resolvedUserRanges_;
141 if( !rangesResolved_ )
147 if( !splitRange_.empty() )
149 if( currSplitRangeIdx_ == 0 && currSplitRangeOff_ == 0 )
155 error_.
set( 500,
"Stopping request because more data is expected "
156 "but no data has been read." );
166 if( !splitRange_.empty() )
170 if( splitRangeIdx_ >= resolvedUserRanges_.size() )
186 error_.
set( 500,
"An error occurred." );
208 error_.
set( 500,
"Range handler read failure." );
212 if( !rangesResolved_ )
214 error_.
set( 500,
"Range handler ranges not yet resolved." );
218 if( splitRange_.empty() )
220 error_.
set( 500,
"No ranges being read." );
227 if( currSplitRangeIdx_ >= splitRange_.size() ||
228 resolvedRangeIdx_ >= resolvedUserRanges_.size() )
230 error_.
set( 500,
"Range handler index invalid." );
235 *urp = &resolvedUserRanges_[resolvedRangeIdx_];
237 if( resolvedRangeOff_ == 0 )
240 const int clen = splitRange_[currSplitRangeIdx_].size;
242 const off_t ulen = resolvedUserRanges_[resolvedRangeIdx_].end
243 - resolvedUserRanges_[resolvedRangeIdx_].start + 1;
245 currSplitRangeOff_ += ret;
246 resolvedRangeOff_ += ret;
248 if( currSplitRangeOff_ > clen || resolvedRangeOff_ > ulen )
250 error_.
set( 500,
"Range handler read crossing chunk boundary." );
254 if( currSplitRangeOff_ == clen )
256 currSplitRangeOff_ = 0;
257 currSplitRangeIdx_++;
259 if( currSplitRangeIdx_ >= splitRange_.size() )
261 currSplitRangeIdx_ = 0;
266 if( resolvedRangeOff_ == ulen )
269 resolvedRangeOff_ = 0;
270 if( resolvedRangeIdx_ >= resolvedUserRanges_.size() )
282 char *str1, *saveptr1, *token;
284 std::unique_ptr< char, decltype(std::free)* >
285 line_copy { strdup( line ), std::free };
295 str1 = line_copy.get();
296 token = strchr(str1,
'=');
297 if (token) str1 = token + 1;
303 for( ; ; str1 = NULL )
305 token = strtok_r( str1,
" ,\n\r", &saveptr1 );
309 if( !strlen(token) )
continue;
311 const int rc = parseOneRange( token );
317 rawUserRanges_.clear();
329 rawUserRanges_.clear();
330 rawUserRanges_.shrink_to_fit();
331 resolvedUserRanges_.clear();
332 resolvedUserRanges_.shrink_to_fit();
334 splitRange_.shrink_to_fit();
335 rangesResolved_ =
false;
338 currSplitRangeIdx_ = 0;
339 currSplitRangeOff_ = 0;
340 resolvedRangeIdx_ = 0;
341 resolvedRangeOff_ = 0;
353 if( rangesResolved_ )
355 error_.
set( 500,
"Filesize notified after ranges resolved." );
366 int XrdHttpReadRangeHandler::parseOneRange(
char*
const str)
378 sep = strchr( str,
'-' );
388 if( rangeFig( str, ur.start_set, ur.start )<0 )
397 if( rangeFig( sep+1, ur.end_set, ur.end )<0 )
405 if( !ur.start_set && !ur.end_set )
413 if( ur.start_set && ur.end_set && ur.start > ur.end )
421 if( !ur.start_set && ur.end_set && ur.end == 0 )
429 rawUserRanges_.push_back(ur);
436 int XrdHttpReadRangeHandler::rangeFig(
const char*
const s,
bool &set, off_t &val)
438 char *endptr = (
char*)s;
440 long long int v = strtoll( s, &endptr, 10 );
441 if( (errno == ERANGE && (v == LONG_MAX || v == LONG_MIN))
442 || (errno != 0 && errno != EINVAL && v == 0) )
446 if( *endptr !=
'\0' )
465 void XrdHttpReadRangeHandler::resolveRanges()
470 resolvedUserRanges_.clear();
472 for(
const auto &rr: rawUserRanges_ )
491 if( start >= filesize_ )
494 if( end >= filesize_ )
508 if( rr.end > filesize_ )
514 start = filesize_ - rr.end;
524 if( !rr.start_set )
continue;
525 if( rr.start >= filesize_ )
530 resolvedUserRanges_.emplace_back( start, end );
533 if( rawUserRanges_.empty() && filesize_>0 )
538 resolvedUserRanges_.emplace_back( 0, filesize_ - 1 );
541 if( !rawUserRanges_.empty() && resolvedUserRanges_.empty() )
543 error_.
set( 416,
"None of the range-specifier values in the Range "
544 "request-header field overlap the current extent of the selected resource." );
547 rangesResolved_ =
true;
555 void XrdHttpReadRangeHandler::splitRanges()
558 currSplitRangeIdx_ = 0;
559 currSplitRangeOff_ = 0;
560 resolvedRangeIdx_ = splitRangeIdx_;
561 resolvedRangeOff_ = splitRangeOff_;
578 size_t maxch = vectorReadMaxChunks_;
579 size_t maxchs = vectorReadMaxChunkSize_;
582 maxchs = rRequestMaxBytes_;
586 splitRange_.reserve( maxch );
592 const size_t cs = resolvedUserRanges_.size();
594 size_t rsr = rRequestMaxBytes_;
597 while( ( splitRangeIdx_ < cs ) && ( rsr > 0 ) )
605 if( !tmpur.start_set )
607 tmpur = resolvedUserRanges_[splitRangeIdx_];
608 tmpur.start += splitRangeOff_;
611 const off_t l = tmpur.end - tmpur.start + 1;
612 size_t maxsize = std::min( rsr, maxchs );
618 if( nc == 0 && l >= (off_t)rRequestMaxBytes_ )
619 maxsize = rRequestMaxBytes_;
621 if( l > (off_t)maxsize )
623 splitRange_.emplace_back(
nullptr, tmpur.start, maxsize );
624 tmpur.start += maxsize;
625 splitRangeOff_ += maxsize;
630 splitRange_.emplace_back(
nullptr, tmpur.start, l );
643 void XrdHttpReadRangeHandler::trimSplit()
645 if( currSplitRangeIdx_ < splitRange_.size() )
647 splitRange_.erase( splitRange_.begin(),
648 splitRange_.begin() + currSplitRangeIdx_ );
653 if( splitRange_.size() > 0 )
655 if( currSplitRangeOff_ < splitRange_[0].size )
657 splitRange_[0].offset += currSplitRangeOff_;
658 splitRange_[0].size -= currSplitRangeOff_;
664 currSplitRangeIdx_ = 0;
665 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.
size_t getMaxRanges() const
return the maximum number of ranges that may be requested
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)