HttpResponseRanges CHTTPWebinterfaceAddonsHandler::GetResponseData() const { HttpResponseRanges ranges; ranges.push_back(m_responseRange); return ranges; }
HttpResponseRanges CHTTPJsonRpcHandler::GetResponseData() const { HttpResponseRanges ranges; ranges.push_back(m_responseRange); return ranges; }
int CWebServer::CreateRangedMemoryDownloadResponse(IHTTPRequestHandler *handler, struct MHD_Response *&response) { if (handler == NULL) return MHD_NO; const HTTPRequest &request = handler->GetRequest(); const HTTPResponseDetails &responseDetails = handler->GetResponseDetails(); HttpResponseRanges responseRanges = handler->GetResponseData(); // if there's no or only one range this is not the right place if (responseRanges.size() <= 1) return CreateMemoryDownloadResponse(handler, response); // extract all the valid ranges and calculate their total length uint64_t firstRangePosition = 0; HttpResponseRanges ranges; for (HttpResponseRanges::const_iterator range = responseRanges.begin(); range != responseRanges.end(); ++range) { // ignore invalid ranges if (!range->IsValid()) continue; // determine the first range position if (ranges.empty()) firstRangePosition = range->GetFirstPosition(); ranges.push_back(*range); } if (ranges.empty()) return CreateMemoryDownloadResponse(request.connection, NULL, 0, false, false, response); // determine the last range position uint64_t lastRangePosition = ranges.back().GetLastPosition(); // adjust the HTTP status of the response handler->SetResponseStatus(MHD_HTTP_PARTIAL_CONTENT); // add Content-Range header handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_RANGE, HttpRangeUtils::GenerateContentRangeHeaderValue(firstRangePosition, lastRangePosition, responseDetails.totalLength)); // generate a multipart boundary std::string multipartBoundary = HttpRangeUtils::GenerateMultipartBoundary(); // and the content-type std::string contentType = HttpRangeUtils::GenerateMultipartBoundaryContentType(multipartBoundary); // add Content-Type header handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_TYPE, contentType); // generate the multipart boundary with the Content-Type header field std::string multipartBoundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(multipartBoundary, contentType); std::string result; // add all the ranges to the result for (HttpResponseRanges::const_iterator range = ranges.begin(); range != ranges.end(); ++range) { // add a newline before any new multipart boundary if (range != ranges.begin()) result += HEADER_NEWLINE; // generate and append the multipart boundary with the full header (Content-Type and Content-Length) result += HttpRangeUtils::GenerateMultipartBoundaryWithHeader(multipartBoundaryWithHeader, &*range); // and append the data of the range result.append(static_cast<const char*>(range->GetData()), static_cast<size_t>(range->GetLength())); // check if we need to free the range data if (responseDetails.type == HTTPMemoryDownloadFreeNoCopy || responseDetails.type == HTTPMemoryDownloadFreeCopy) free(const_cast<void*>(range->GetData())); } result += HttpRangeUtils::GenerateMultipartBoundaryEnd(multipartBoundary); // add Content-Length header handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_LENGTH, StringUtils::Format("%" PRIu64, static_cast<uint64_t>(result.size()))); // finally create the response return CreateMemoryDownloadResponse(request.connection, result.c_str(), result.size(), false, true, response); }