You are not logged in.
while using THttpApiServer, how to response part of file according to 'Range: bytes=***-***' in InHeaders?
thanks.
Offline
OutContentType equals HTTP_RESP_STATICFILE + 'Range: bytes=***-***' in InHeaders is not handled in the current code.
Here is what I found in http://msdn.microsoft.com/en-us/library … s.85).aspx
You may try to add the HTTP_SEND_RESPONSE_FLAG_PROCESS_RANGES flag in THttpApiServer.Execute:
Http.SendHttpResponse(fReqQueue,Req^.RequestId,HTTP_SEND_RESPONSE_FLAG_PROCESS_RANGES,Resp^,nil,bytesSent);
But I'm not sure it will work as expected.
Please provide some feedback about it.
Offline
Here is what i m learning about: http://xxm.sourceforge.net/
Perhaps "hsys" of it is what i m looking for...
Offline
i got it...
here is the code i just modify:
if OutContentType=HTTP_RESP_STATICFILE then begin
// response is file -> let http.sys serve it (OutContent is UTF-8)
FileHandle := FileOpen(
{$ifdef UNICODE}UTF8ToUnicodeString{$else}Utf8ToAnsi{$endif}(OutContent),
fmOpenRead or fmShareDenyNone);
if PtrInt(FileHandle)<0 then
SendError(404,SysErrorMessage(GetLastError)) else
try
DataChunk.DataChunkType := hctFromFileHandle;
DataChunk.FromFileHandle.FileHandle := FileHandle;
rangstart := 0;
ranglength := -1;
getrangstartend;
DataChunk.FromFileHandle.ByteRange.StartingOffset.QuadPart := rangstart;
Int64(DataChunk.FromFileHandle.ByteRange.Length.QuadPart) := ranglength; // to eof
Resp^.EntityChunkCount := 1;
Resp^.pEntityChunks := @DataChunk;
Http.SendHttpResponse(fReqQueue,Req^.RequestId,1,Resp^,nil,bytesSent);
finally
FileClose(FileHandle);
end;
end else begin
getrangstartend is used to get rangstart and ranglength from inHeaders.
the flags of Http.SendHttpResponse is changed to 1 from 0.
and it works now.
thanks,ab.
Offline
procedure THttpApiServer.Execute;
var Req: PHTTP_REQUEST;
ReqID: HTTP_REQUEST_ID;
ReqBuf, RespBuf: TSockData;
i: integer;
flags, bytesRead, bytesSent: cardinal;
Err: HRESULT;
InCompressAccept: THttpSocketCompressSet;
InContentLength, InContentLengthRead: cardinal;
InContentLengthStr: TSockData;
InContentEncoding, InAcceptEncoding: TSockData;
OutContentEncoding: TSockData;
InURL, InMethod, InHeaders, InContent, InContentType: TSockData;
OutContent, OutContentType, OutCustomHeader, OutStatus: TSockData;
OutContentTypeP: PAnsiChar absolute OutContentType;
FileHandle: THandle;
Resp: PHTTP_RESPONSE;
BufRead: PAnsiChar;
Heads: array of HTTP_UNKNOWN_HEADER;
DataChunk: HTTP_DATA_CHUNK;
rangstart,ranglength:int64;
procedure getrangstartend;
var
i,ipos:integer;
ssl:TStringlist;
tmpstr:string;
begin
rangstart := 0;
ranglength := -1;
if (trim(inHeaders) = '') then exit;
ssl := TStringlist.Create;
ssl.Text := inHeaders;
for i := 0 to ssl.Count -1 do
begin
tmpstr := trim(ssl.Strings[i]);
if (pos('range:',lowercase(tmpstr)) = 1) then
begin
tmpstr := trim(copy(tmpstr,7,length(tmpstr) - 6));
if (pos('bytes=',lowercase(tmpstr)) = 1) then
begin
tmpstr := trim(copy(tmpstr,7,length(tmpstr) - 6));
ipos := pos('-',tmpstr);
if (ipos > 0) then
begin
try
rangstart := strtoint64(trim(copy(tmpstr,1,ipos - 1)));
except
rangstart := 0;
end;
try
ranglength := strtoint64(trim(copy(tmpstr,ipos + 1,
length(tmpstr) - ipos + 1)));
except
ranglength := -1;
end;
if (ranglength > rangstart) then
ranglength := ranglength - rangstart
else
ranglength := -1;
end
else
begin
ranglength := -1;
try
rangstart := strtoint64(trim(tmpstr));
except
rangstart := 0;
end;
end;
end;
end;
end;
ssl.free;
end;
procedure SendError(StatusCode: cardinal; const ErrorMsg: string);
begin
Resp^.SetStatus(StatusCode,OutStatus,@DataChunk,TSockData(ErrorMsg));
Http.SendHttpResponse(fReqQueue,Req^.RequestId,0,Resp^,nil,bytesSent);
end;
begin
getrangstartend is not so good
Last edited by profh (2012-09-05 16:42:56)
Offline
Could you try this alternative implementation:
http://synopse.info/fossil/fdiff?v1=e10 … 6b85e7f7d8
Sounds more "mORMot-ish".
Thanks for the feedback.
Offline
Please include this fix:
http://synopse.info/fossil/info/2362d94f07
Offline
thanks, and it s great.
another problem i can not understand is:
i download a file from server using many segments, the range of the last segment perhaps is 12345,678.
if i download the last segment with range of 12345,678, it returns fales, but if i use 12345,-1, it is ok.
BTW,it s terrific about http://blog.synopse.info/post/2012/09/0 … laboration
Offline
sorry,678 means the rang length,so i mean 12345,12345 + 678.
Offline
As far as I understood the standard, you can not use ',' nor '+' in the range.
Examples of byte-content-range-spec values, assuming that the entity contains a total of 1234 bytes:
. The first 500 bytes:
bytes 0-499/1234
. The second 500 bytes:
bytes 500-999/1234
. All except for the first 500 bytes:
bytes 500-1233/1234
. The last 500 bytes:
bytes 734-1233/1234
Offline
yes, what i mean is that it returns false when i get the last 500 bytes,
the syntax is right just like above standard,because the previous segments are all correct.
Offline
Is it not because the last chunk range exceed the file length?
We compute RangeLength := GetNextItemUInt64(R)-RangeStart+1 as it should be (499-0+1=500 bytes for '0-499/1234').
Perhaps your request is too big: last index should be < total length, and be the index of the last character.
Offline
u are right, and i got it.
many thanks.
Offline