`
{-----------------------------------------------------------}
// Ignore: Ignore the Range header and send the full content.
// Partial: A valid byte range was parsed; send HTTP 206 Partial Content.
// Unsatisfiable: The requested range cannot be satisfied; send HTTP 416.
TALHttpRangeResult = (Ignore, Partial, Unsatisfiable);
{**************************************************************************************************************************}
function ALParseHttpByteRange(const ARange: AnsiString; const ASize: Int64; out AStart, ALength: Int64): TALHttpRangeResult;
{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
function ParseDecimal(const AText: AnsiString; out AValue: Int64): Boolean;
begin
AValue := 0;
Result := False;
if AText = '' then Exit;
for var C in AText do begin
if not (C in ['0'..'9']) then Exit;
var LDigit := Ord(C) - Ord('0');
// Saturate rather than overflow: huge ends/suffixes cover the whole file,
// while huge starting offsets cannot overlap an Int64-sized file.
if AValue > (High(Int64) - LDigit) div 10 then AValue := High(Int64)
else AValue := AValue * 10 + LDigit;
end;
Result := True;
end;
begin
Result := TALHttpRangeResult.Ignore;
AStart := 0;
ALength := ASize;
var LRange := ALLowerCase(ALTrim(ARange));
if AlPosA('bytes=', ARange) <> 1 then Exit;
// Multipart responses are not implemented; HTTP permits ignoring Range.
if Pos(',', LRange) > 0 then Exit;
Delete(LRange, 1, 6);
var LDash := Pos('-', LRange);
if LDash = 0 then Exit;
var LFirst := Copy(LRange, 1, LDash - 1);
var LLast := Copy(LRange, LDash + 1, MaxInt);
var LStart, LEnd: Int64;
if LFirst = '' then begin
if not ParseDecimal(LLast, LEnd) then Exit;
if (LEnd = 0) or (ASize = 0) then Exit(TALHttpRangeResult.Unsatisfiable);
if LEnd > ASize then LEnd := ASize;
AStart := ASize - LEnd;
ALength := LEnd;
end
else begin
if not ParseDecimal(LFirst, LStart) then Exit;
if LLast <> '' then begin
if not ParseDecimal(LLast, LEnd) then Exit;
if LEnd < LStart then Exit;
end
else LEnd := High(Int64);
if LStart >= ASize then Exit(TALHttpRangeResult.Unsatisfiable);
if LEnd >= ASize then LEnd := ASize - 1;
AStart := LStart;
ALength := LEnd - LStart + 1;
end;
Result := TALHttpRangeResult.Partial;
end;
`
`
{-----------------------------------------------------------}
// Ignore: Ignore the Range header and send the full content.
// Partial: A valid byte range was parsed; send HTTP 206 Partial Content.
// Unsatisfiable: The requested range cannot be satisfied; send HTTP 416.
TALHttpRangeResult = (Ignore, Partial, Unsatisfiable);
{**************************************************************************************************************************}
function ALParseHttpByteRange(const ARange: AnsiString; const ASize: Int64; out AStart, ALength: Int64): TALHttpRangeResult;
{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
function ParseDecimal(const AText: AnsiString; out AValue: Int64): Boolean;
begin
AValue := 0;
Result := False;
if AText = '' then Exit;
for var C in AText do begin
if not (C in ['0'..'9']) then Exit;
var LDigit := Ord(C) - Ord('0');
// Saturate rather than overflow: huge ends/suffixes cover the whole file,
// while huge starting offsets cannot overlap an Int64-sized file.
if AValue > (High(Int64) - LDigit) div 10 then AValue := High(Int64)
else AValue := AValue * 10 + LDigit;
end;
Result := True;
end;
begin
Result := TALHttpRangeResult.Ignore;
AStart := 0;
ALength := ASize;
var LRange := ALLowerCase(ALTrim(ARange));
if AlPosA('bytes=', ARange) <> 1 then Exit;
// Multipart responses are not implemented; HTTP permits ignoring Range.
if Pos(',', LRange) > 0 then Exit;
Delete(LRange, 1, 6);
var LDash := Pos('-', LRange);
if LDash = 0 then Exit;
var LFirst := Copy(LRange, 1, LDash - 1);
var LLast := Copy(LRange, LDash + 1, MaxInt);
var LStart, LEnd: Int64;
if LFirst = '' then begin
if not ParseDecimal(LLast, LEnd) then Exit;
if (LEnd = 0) or (ASize = 0) then Exit(TALHttpRangeResult.Unsatisfiable);
if LEnd > ASize then LEnd := ASize;
AStart := ASize - LEnd;
ALength := LEnd;
end
else begin
if not ParseDecimal(LFirst, LStart) then Exit;
if LLast <> '' then begin
if not ParseDecimal(LLast, LEnd) then Exit;
if LEnd < LStart then Exit;
end
else LEnd := High(Int64);
if LStart >= ASize then Exit(TALHttpRangeResult.Unsatisfiable);
if LEnd >= ASize then LEnd := ASize - 1;
AStart := LStart;
ALength := LEnd - LStart + 1;
end;
Result := TALHttpRangeResult.Partial;
end;
`