URIReader fixes / improvements
This commit is contained in:
parent
d8fb22a71f
commit
ae6ccb3615
2 changed files with 61 additions and 50 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue