Indy Http Server with resume support
c++builder, delphi, httpserver, indy, tcp
Solution
The `IdCustomHTTPServer` unit has a `TIdHTTPRangeStream` helper class for this very purpose.
If the client requests a ranged download, create an instance of `TIdHTTPRangeStream` and pass it your intended `TStream` and the client's requested range, then assign it as the `ContentStream` to be sent. `TIdHTTPRangeStream` also has a `ResponseCode` property that you need to assign to the response's `ResponseNo` property.
For example:
void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo)
{
// create file stream ...
// THTTPServer parses the ranges for you
if (ARequestInfo->Ranges->Count > 0)
{
if (ARequestInfo->Ranges->Count > 1)
{
AResponseInfo->ResponseNo = 416;
return;
}
TIdEntityRange *range = ARequestInfo->Ranges->Range[0];
TIdHTTPRangeStream *rstream = new TIdHTTPRangeStream(stream, range->StartPos, range->EndPos, true);
AResponseInfo->ResponseNo = rstream->ResponseCode;
AResponseInfo->ContentRangeStart = rstream->RangeStart;
AResponseInfo->ContentRangeEnd = rstream->RangeEnd;
AResponseInfo->ContentStream = rstream;
AResponseInfo->AcceptRanges = "bytes";
}
else
{
AResponseInfo->ContentStream = stream;
}
// no need to seek the target stream manually
// no need to set the ContentLength manually
// no need to call WriteHeader() and WriteContent() manually
//
// TIdHTTPServer handles all that for you internally!
}
Problem
I have written an indy http server, I want to serve file download with resume support. When I use IDM to download file, the download is single threaded: Note that the Resume capability is Yes, but When I pause and resume the download, It starts form beginning. My Indy Http Server is as: ``` void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo) { Beep(1000, 100); string fileName = ExtractFileDir(Application->ExeName) + ARequestInfo->Document; fileName = fileName.replace("/", "\\"); TFileStream *stream = new TFileStream(fileName, fmOpenRead | fmShareDenyNone); int start = 0, end = 0; string range = ARequestInfo->Range; if(!range.empty()) { int dash_pos = range.find("-"); start = range.substr(0, dash_pos).intValue(); end = range.substr(dash_pos + 1).intValue(); if(end == 0) // Endless Range: start- end = stream->Size; } else { start = 0; end = stream->Size; } OutputDebugStringW(string("ctx=[] start=[] end=[]") << IntToHex((int)AContext, 8) << start << end); stream->Seek((__int64)start, soBeginning); AResponseInfo->ContentStream = stream; AResponseInfo->FreeContentStream = true; AResponseInfo->ContentLength = stream->Size; if(!range.empty()) { AResponseInfo->ContentRangeStart = start; AResponseInfo->ContentRangeEnd = end; AResponseInfo->ResponseNo = 206; AResponseInfo->ContentRangeInstanceLength = end + 1; AResponseInfo->ContentLength = end - start + 1; AResponseInfo->AcceptRanges = "bytes"; } AResponseInfo->WriteHeader(); AResponseInfo->WriteContent(); } ``` any help would be appreciated.