Example #1
0
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" );
}
Example #2
0
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");
	}
}