URIReader fixes / improvements

This commit is contained in:
Thulinma 2020-03-09 20:01:32 +01:00
parent d8fb22a71f
commit ae6ccb3615
2 changed files with 61 additions and 50 deletions

View file

@ -8,10 +8,11 @@
namespace HTTP{ namespace HTTP{
URIReader::URIReader(){
void URIReader::init(){
char workDir[512]; char workDir[512];
getcwd(workDir, 512); getcwd(workDir, 512);
myURI = HTTP::URL(std::string("file://") + workDir); myURI = HTTP::URL(std::string("file://") + workDir + "/");
cbProgress = 0; cbProgress = 0;
minLen = 1; minLen = 1;
maxLen = std::string::npos; maxLen = std::string::npos;
@ -19,17 +20,21 @@ namespace HTTP{
supportRangeRequest = false; supportRangeRequest = false;
endPos = std::string::npos; endPos = std::string::npos;
totalSize = std::string::npos; totalSize = std::string::npos;
stateType = URIType::Closed; stateType = HTTP::Closed;
clearPointer = true; clearPointer = true;
} }
URIReader::URIReader(){
init();
}
URIReader::URIReader(const HTTP::URL &uri){ URIReader::URIReader(const HTTP::URL &uri){
URIReader(); init();
open(uri); open(uri);
} }
URIReader::URIReader(const std::string &reluri){ URIReader::URIReader(const std::string &reluri){
URIReader(); init();
open(reluri); open(reluri);
} }
@ -48,77 +53,82 @@ namespace HTTP{
if (!myURI.protocol.size() || myURI.protocol == "file"){ if (!myURI.protocol.size() || myURI.protocol == "file"){
if (!myURI.path.size() || myURI.path == "-"){ if (!myURI.path.size() || myURI.path == "-"){
downer.getSocket().open(-1, fileno(stdin)); downer.getSocket().open(-1, fileno(stdin));
stateType = URIType::Stream; stateType = HTTP::Stream;
startPos = 0; startPos = 0;
endPos = std::string::npos; endPos = std::string::npos;
totalSize = std::string::npos; totalSize = std::string::npos;
if (!downer.getSocket()){ if (!downer.getSocket()){
FAIL_MSG("Could not open '%s': %s", myURI.getUrl().c_str(), strerror(errno)); FAIL_MSG("Could not open '%s': %s", myURI.getUrl().c_str(), downer.getSocket().getError().c_str());
stateType = URIType::Closed; stateType = HTTP::Closed;
return false; return false;
} }
return true; return true;
}else{ }else{
// int handle = ::open(myURI.getFilePath().c_str(), O_RDONLY);
//
/// \todo Use ACCESSPERMS instead of 0600?
int handle = ::open(myURI.getFilePath().c_str(), O_RDWR, (mode_t)0600);
if (handle == -1){ if (handle == -1){
FAIL_MSG("opening file: %s failed: %s", myURI.getFilePath().c_str(), strerror(errno)); FAIL_MSG("Opening file '%s' failed: %s", myURI.getFilePath().c_str(), strerror(errno));
stateType = URIType::Closed; stateType = HTTP::Closed;
return false; return false;
} }
struct stat buffStats; struct stat buffStats;
int xRes = fstat(handle, &buffStats); int xRes = fstat(handle, &buffStats);
if (xRes < 0){ if (xRes < 0){
FAIL_MSG("Cheking size of %s failed: %s", myURI.getFilePath().c_str(), strerror(errno)); FAIL_MSG("Checking size of '%s' failed: %s", myURI.getFilePath().c_str(), strerror(errno));
stateType = URIType::Closed; stateType = HTTP::Closed;
return false; return false;
} }
totalSize = buffStats.st_size; totalSize = buffStats.st_size;
// INFO_MSG("size: %llu", totalSize); // INFO_MSG("size: %llu", totalSize);
mapped = (char *)mmap(0, totalSize, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0); mapped = (char *)mmap(0, totalSize, PROT_READ, MAP_SHARED, handle, 0);
if (mapped == MAP_FAILED){ if (mapped == MAP_FAILED){
FAIL_MSG("Memory-mapping file '%s' failed: %s", myURI.getFilePath().c_str(), strerror(errno));
mapped = 0; mapped = 0;
stateType = URIType::Closed; stateType = HTTP::Closed;
return false; return false;
} }
startPos = 0; startPos = 0;
stateType = URIType::File; stateType = HTTP::File;
return true; return true;
} }
} }
// HTTP, stream or regular download? // HTTP, stream or regular download?
if (myURI.protocol == "http" || myURI.protocol == "https"){ if (myURI.protocol == "http" || myURI.protocol == "https"){
stateType = URIType::HTTP; stateType = HTTP::HTTP;
// Send HEAD request to determine range request is supported, and get total length // Send HEAD request to determine range request is supported, and get total length
if (!downer.head(myURI)){FAIL_MSG("Error sending HEAD request");} if (!downer.head(myURI) || !downer.isOk()){
FAIL_MSG("Error getting URI info for '%s': %" PRIu32 " %s", myURI.getUrl().c_str(), downer.getStatusCode(), downer.getStatusText().c_str());
std::string header1 = downer.getHeader("Accept-Ranges"); if (!downer.isOk()){
supportRangeRequest = (header1.size() > 0); return false;
}
header1 = downer.getHeader("Content-Length"); supportRangeRequest = false;
totalSize = atoi(header1.c_str()); totalSize = std::string::npos;
}else{
supportRangeRequest = (downer.getHeader("Accept-Ranges").size() > 0);
std::string header1 = downer.getHeader("Content-Length");
if (header1.size()){totalSize = atoi(header1.c_str());}
myURI = downer.lastURL();
}
// streaming mode when size is unknown // streaming mode when size is unknown
if (!supportRangeRequest){ if (!supportRangeRequest){
downer.getNonBlocking(uri); MEDIUM_MSG("URI get without range request: %s, totalsize: %zu", myURI.getUrl().c_str(), totalSize);
downer.getNonBlocking(myURI);
}else{ }else{
MEDIUM_MSG("download file with range request: %s, totalsize: %llu", myURI.getUrl().c_str(), totalSize); MEDIUM_MSG("URI get with range request: %s, totalsize: %zu", myURI.getUrl().c_str(), totalSize);
if (!downer.getRangeNonBlocking(myURI.getUrl(), curPos, 0)){ if (!downer.getRangeNonBlocking(myURI, curPos, 0)){
FAIL_MSG("error loading url: %s", myURI.getUrl().c_str()); FAIL_MSG("error loading url: %s", myURI.getUrl().c_str());
} }
} }
if (!downer.getSocket()){ if (!downer.getSocket()){
FAIL_MSG("Could not open '%s': %s", myURI.getUrl().c_str(), strerror(errno)); FAIL_MSG("Could not open '%s': %s", myURI.getUrl().c_str(), downer.getStatusText().c_str());
stateType = URIType::Closed; stateType = HTTP::Closed;
return false; return false;
} }
return true; return true;
@ -131,11 +141,11 @@ namespace HTTP{
// seek to pos, return true if succeeded. // seek to pos, return true if succeeded.
bool URIReader::seek(const uint64_t pos){ bool URIReader::seek(const uint64_t pos){
if (isSeekable()){ if (isSeekable()){
if (stateType == URIType::File){ if (stateType == HTTP::File){
curPos = pos; curPos = pos;
return true; return true;
}else if (stateType == URIType::HTTP && supportRangeRequest){ }else if (stateType == HTTP::HTTP && supportRangeRequest){
INFO_MSG("SEEK: RangeRequest to %llu", pos); INFO_MSG("SEEK: RangeRequest to %" PRIu64, pos);
if (!downer.getRangeNonBlocking(myURI.getUrl(), pos, 0)){ if (!downer.getRangeNonBlocking(myURI.getUrl(), pos, 0)){
FAIL_MSG("error loading request"); FAIL_MSG("error loading request");
} }
@ -179,7 +189,7 @@ namespace HTTP{
// readsome with callback // readsome with callback
void URIReader::readSome(size_t wantedLen, Util::DataCallback &cb){ void URIReader::readSome(size_t wantedLen, Util::DataCallback &cb){
if (isEOF()){return;} if (isEOF()){return;}
if (stateType == URIType::File){ if (stateType == HTTP::File){
// dataPtr = mapped + curPos; // dataPtr = mapped + curPos;
uint64_t dataLen = 0; uint64_t dataLen = 0;
@ -199,7 +209,7 @@ namespace HTTP{
curPos += dataLen; curPos += dataLen;
}else if (stateType == URIType::HTTP){ }else if (stateType == HTTP::HTTP){
bool res = downer.continueNonBlocking(cb); bool res = downer.continueNonBlocking(cb);
@ -208,8 +218,8 @@ namespace HTTP{
MEDIUM_MSG("completed"); MEDIUM_MSG("completed");
}else{ }else{
if (supportRangeRequest){ if (supportRangeRequest){
MEDIUM_MSG("do new range request, previous request not completed yet!, curpos: %llu, " MEDIUM_MSG("do new range request, previous request not completed yet!, curpos: %zu, "
"length: %llu", "length: %zu",
curPos, getSize()); curPos, getSize());
} }
} }
@ -231,7 +241,7 @@ namespace HTTP{
/// Readsome blocking function. /// Readsome blocking function.
void URIReader::readSome(char *&dataPtr, size_t &dataLen, size_t wantedLen){ void URIReader::readSome(char *&dataPtr, size_t &dataLen, size_t wantedLen){
if (stateType == URIType::File){ if (stateType == HTTP::File){
dataPtr = mapped + curPos; dataPtr = mapped + curPos;
@ -246,7 +256,7 @@ namespace HTTP{
} }
curPos += dataLen; curPos += dataLen;
}else if (stateType == URIType::HTTP){ }else if (stateType == HTTP::HTTP){
dataLen = downer.data().size(); dataLen = downer.data().size();
curPos += dataLen; curPos += dataLen;
@ -301,15 +311,15 @@ namespace HTTP{
} }
void URIReader::close(){ void URIReader::close(){
if (stateType == URIType::File){ if (stateType == HTTP::File){
if (mapped){ if (mapped){
munmap(mapped, totalSize); munmap(mapped, totalSize);
mapped = 0; mapped = 0;
totalSize = 0; totalSize = 0;
} }
}else if (stateType == URIType::Stream){ }else if (stateType == HTTP::Stream){
downer.getSocket().close(); downer.getSocket().close();
}else if (stateType == URIType::HTTP){ }else if (stateType == HTTP::HTTP){
downer.getSocket().close(); downer.getSocket().close();
}else{ }else{
// INFO_MSG("already closed"); // INFO_MSG("already closed");
@ -326,22 +336,22 @@ namespace HTTP{
} }
bool URIReader::isSeekable(){ bool URIReader::isSeekable(){
if (stateType == URIType::HTTP){ if (stateType == HTTP::HTTP){
if (supportRangeRequest && totalSize > 0){return true;} if (supportRangeRequest && totalSize != std::string::npos){return true;}
} }
return (stateType == URIType::File); return (stateType == HTTP::File);
} }
bool URIReader::isEOF(){ bool URIReader::isEOF(){
if (stateType == URIType::File){ if (stateType == HTTP::File){
return (curPos >= totalSize); return (curPos >= totalSize);
}else if (stateType == URIType::Stream){ }else if (stateType == HTTP::Stream){
if (!downer.getSocket()){return true;} if (!downer.getSocket()){return true;}
// if ((totalSize > 0) && (curPos >= totalSize)){return true;} // if ((totalSize > 0) && (curPos >= totalSize)){return true;}
}else if (stateType == URIType::HTTP){ }else if (stateType == HTTP::HTTP){
// INFO_MSG("iseof, C: %s, seekable: %s", C?"connected":"disconnected", isSeekable()?"yes":"no"); // INFO_MSG("iseof, C: %s, seekable: %s", C?"connected":"disconnected", isSeekable()?"yes":"no");
if (!downer.getSocket() && !downer.getSocket().Received().available(1) && !isSeekable()){ if (!downer.getSocket() && !downer.getSocket().Received().available(1) && !isSeekable()){
return true; return true;

View file

@ -79,5 +79,6 @@ namespace HTTP{
URIType stateType; /// Holds the type of URI this is, for internal processing purposes. URIType stateType; /// Holds the type of URI this is, for internal processing purposes.
std::ifstream fReader; /// For file-based URIs, the ifstream used for the file. std::ifstream fReader; /// For file-based URIs, the ifstream used for the file.
HTTP::Downloader downer; /// For HTTP(S)-based URIs, the Downloader instance used for the download. HTTP::Downloader downer; /// For HTTP(S)-based URIs, the Downloader instance used for the download.
void init();
}; };
}// namespace HTTP }// namespace HTTP