Skip to content

Implement ALParseHttpByteRange #524

Description

@Zeus64

`
{-----------------------------------------------------------}
// 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;

`

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions