void UploaderImp::TranslateRequest() { std::istream s( &request_ ); std::string line; s >> line; //method if( line == "GET" ) method_ = GET; else if( line == "HEAD" ) method_ = HEAD; else throw Unhandled(400, "Unknown method" ); s >> line; //object if( !starts_with( line, "/uri-res/N2R?" ) ) throw Unhandled(400, "Requested uri type is not supported"); std::string last = urn_; urn_ = line.substr(line.find('?') + 1); fileInfo_ = System::GetShareMgr()->GetByUrn( urn_ ); if(last != urn_) { System::LogBas() << "Host " << endpoint_ << " requested file: " << fileInfo_.Name() << std::endl; fileInfo_.IncreaseRequests(); } while( std::getline( s, line ) && line != "\r" ) { std::string value = boost::trim_copy( line.substr( line.find( ':' ) + 1 ) ); if( istarts_with( line, "Connection:" ) ) keepAlive_ = iequals( value, "keep-alive" ); else if( istarts_with( line, "X-Nick:" ) ) nick_ = value; else if(istarts_with(line, "User-Agent:") && client_ != value) { client_ = value; if(System::GetSecurity()->AgentRestricted(client_)) throw Unhandled(403, "Client software is restricted"); } else if( istarts_with( line, "Range:" ) ) { file_offset_t first = 0; file_offset_t last = 0; int result = sscanf( value.c_str(), "bytes=%llu-%llu", &first, &last ); if( result == 0 ) throw Unhandled(416, "Couldn't parse range"); if( result == 1 ) range_.SetBoundary( first, fileInfo_.Size() - 1); if( result == 2 ) range_.SetBoundary( first, last ); } } if( range_.Empty() ) throw std::range_error( "Range is empty" ); // std::cout << range_.Last() << " " << fileInfo.Size() << std::endl; if( range_.Last() >= fileInfo_.Size() ) throw Unhandled(416, "Range is too large" ); }
void DownloaderImpl::HandleResponse() { std::istream s(&response_); int code; offset_ = 0; char debug[200]; std::string header; if( !(s >> header >> code) ) throw std::runtime_error("Can't parse reply code"); getline(s, header); file_offset_t first = 0, last = 0, total = 0, contentLength = 0; while(std::getline(s, header) && header != "\r") { std::string value = boost::trim_copy(header.substr(header.find(':') + 1)); if(istarts_with(header, "X-Available-Ranges:")) { ranges_.clear(); ExtractAvailableRanges(value, std::back_inserter(ranges_)); } else if(istarts_with(header, "Alt-Location:")) { ExtractAltLocation(value, download_); } else if(tigerUri_.empty() && istarts_with(header, "X-Thex-URI:")) { //urn:tree:tiger/:BASE32HASH std::string::size_type i = value.find("urn:tree:tiger/:"); if(i != std::string::npos) { tigerUri_ = "/gnutella/tigertree/v3?"; while(i < value.size() && value[i] != '&' && value[i] != ';') tigerUri_.push_back(value[i++]); } } else if(istarts_with(header, "X-PerHost:")) { uint n = lexical_cast<uint>(value); if( n < 4 ) pHost_->maxConnections = n; } else if(istarts_with(header, "Retry-After:")) { //pHost_->connectAfter = System::Now() + lexical_cast<uint>(value); //handled in downloader } else if(istarts_with(header, "Content-Length:")) contentLength = lexical_cast<file_offset_t>(value); else if(istarts_with(header, "X-Queue:")) { if(code == 503) { CancelTask(); status_ = QUEUE; UpdateQueue(value); } } else if(istarts_with(header, "Content-Range:")) { sprintf(debug, "set content range of host %s %s", pHost_->endpoint.ToString().c_str(), value.c_str()); __android_log_write(ANDROID_LOG_DEBUG, "sharelin", debug); if(sscanf(value.c_str(), "bytes%*c%u-%u/%u", &first, &last, &total) < 3 || first > last || total == 0) throw std::range_error("Host provided invalid range info"); } else { } } switch (code) { case 200: case 206: { if(task_ == FETCH_FILE) { if(myRange_.First() != first || myRange_.Last() != last) { System::LogAdv() << "Host " << pHost_->endpoint << " is forcing range " << first << "-" << last << " instead of " << myRange_.First() << "-" << myRange_.Last() << std::endl; sprintf(debug, "check content range of host not valid %s ", pHost_->endpoint.ToString().c_str()); __android_log_write(ANDROID_LOG_DEBUG, "sharelin", debug); throw std::range_error("Forced ranges are not allowed"); } //std::cout << "Getting range " << myRange_.First() << "-" << myRange_.Last() << // " from " << pHost_->endpoint << std::endl; } else { assert(task_ == FETCH_TIGER); if(contentLength == 0) throw std::range_error("Length of tiger tree is 0"); if(contentLength >= 24 * 1024) throw std::range_error("Tiger tree is too large"); myRange_.Set(0, contentLength); System::LogAdv() << "Getting tiger tree from " << pHost_->endpoint << std::endl; } status_ = TRANSFER; offset_ = 0; timestamp_ = System::Now(); transferStart_ = System::Now(); buffer_.clear(); if(response_.size() > 0) { uint n = response_.size(); buffer_.reserve(n); while(n --> 0 ) buffer_.push_back(s.get()); OnData(); } else Transfer(); break; } case 503: { System::LogAdv() << "Host " << pHost_->endpoint << " busy to upload."; if(status_ == QUEUE) System::Log() << " Waiting in queue " << queue_.pos << " of " << queue_.total; System::Log() << std::endl; if(status_ != QUEUE) throw std::runtime_error("Refused"); break; } default: throw std::runtime_error("Refused"); } }