2006-04-25 23:04:48 +02:00
/*
2014-02-23 20:12:25 +01:00
Copyright ( c ) 2003 - 2014 , Arvid Norberg
2006-04-25 23:04:48 +02:00
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in
the documentation and / or other materials provided with the distribution .
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE .
*/
2007-03-17 18:15:16 +01:00
# include "libtorrent/pch.hpp"
2006-04-25 23:04:48 +02:00
# include <vector>
2009-11-28 23:41:21 +01:00
# include <boost/limits.hpp>
2006-04-25 23:04:48 +02:00
# include <boost/bind.hpp>
2009-01-27 09:24:48 +01:00
# include <stdlib.h>
2006-04-25 23:04:48 +02:00
# include "libtorrent/web_peer_connection.hpp"
# include "libtorrent/session.hpp"
# include "libtorrent/identify_client.hpp"
# include "libtorrent/entry.hpp"
# include "libtorrent/bencode.hpp"
# include "libtorrent/alert_types.hpp"
# include "libtorrent/invariant_check.hpp"
# include "libtorrent/io.hpp"
# include "libtorrent/version.hpp"
2006-10-11 16:02:21 +02:00
# include "libtorrent/aux_/session_impl.hpp"
2008-05-17 16:19:34 +02:00
# include "libtorrent/parse_url.hpp"
2009-11-26 06:45:43 +01:00
# include "libtorrent/peer_info.hpp"
2006-04-25 23:04:48 +02:00
using boost : : shared_ptr ;
2006-10-11 16:02:21 +02:00
using libtorrent : : aux : : session_impl ;
2006-04-25 23:04:48 +02:00
namespace libtorrent
{
2012-04-07 02:35:25 +02:00
enum
{
request_size_overhead = 5000
} ;
2006-04-25 23:04:48 +02:00
web_peer_connection : : web_peer_connection (
2006-10-11 16:02:21 +02:00
session_impl & ses
2006-04-25 23:04:48 +02:00
, boost : : weak_ptr < torrent > t
2007-04-23 23:36:21 +02:00
, boost : : shared_ptr < socket_type > s
2006-04-25 23:04:48 +02:00
, tcp : : endpoint const & remote
2013-10-20 04:40:43 +02:00
, web_seed_entry & web )
: web_connection_base ( ses , t , s , remote , web )
, m_url ( web . url )
, m_web ( web )
2012-05-03 04:05:34 +02:00
, m_received_body ( 0 )
2008-06-03 17:17:09 +02:00
, m_range_pos ( 0 )
2009-04-11 22:45:14 +02:00
, m_block_pos ( 0 )
2010-10-27 08:39:18 +02:00
, m_chunk_pos ( 0 )
, m_partial_chunk_header ( 0 )
2013-10-20 04:40:43 +02:00
, m_num_responses ( 0 )
2006-04-25 23:04:48 +02:00
{
INVARIANT_CHECK ;
2010-07-15 08:27:44 +02:00
if ( ! ses . settings ( ) . report_web_seed_downloads )
ignore_stats ( true ) ;
2006-11-14 01:08:16 +01:00
shared_ptr < torrent > tor = t . lock ( ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( tor ) ;
2007-09-03 23:16:24 +02:00
2012-04-15 01:36:16 +02:00
// we always prefer downloading 1 MiB chunks
// from web seeds, or whole pieces if pieces
// are larger than a MiB
2013-10-20 04:40:43 +02:00
int preferred_size = 1024 * 1024 ;
// if the web server is known not to support keep-alive.
// request even larger blocks at a time
if ( ! web . supports_keepalive ) preferred_size * = 4 ;
prefer_whole_pieces ( ( std : : max ) ( preferred_size / tor - > torrent_file ( ) . piece_length ( ) , 1 ) ) ;
2006-11-14 01:08:16 +01:00
2010-10-17 18:15:32 +02:00
// we want large blocks as well, so
// we can request more bytes at once
// this setting will merge adjacent requests
// into single larger ones
request_large_blocks ( true ) ;
2006-04-25 23:04:48 +02:00
# ifdef TORRENT_VERBOSE_LOGGING
2013-10-20 04:40:43 +02:00
peer_log ( " *** web_peer_connection %s " , web . url . c_str ( ) ) ;
2006-04-25 23:04:48 +02:00
# endif
2009-08-08 17:27:07 +02:00
}
2010-04-09 07:51:31 +02:00
void web_peer_connection : : disconnect ( error_code const & ec , int error )
2010-02-12 07:10:20 +01:00
{
boost : : shared_ptr < torrent > t = associated_torrent ( ) . lock ( ) ;
2010-04-09 07:51:31 +02:00
peer_connection : : disconnect ( ec , error ) ;
2010-10-10 20:43:58 +02:00
if ( t ) t - > disconnect_web_seed ( this ) ;
2010-02-12 07:10:20 +01:00
}
2006-04-25 23:04:48 +02:00
boost : : optional < piece_block_progress >
web_peer_connection : : downloading_piece_progress ( ) const
{
2007-05-11 20:40:22 +02:00
if ( m_requests . empty ( ) )
2006-04-25 23:04:48 +02:00
return boost : : optional < piece_block_progress > ( ) ;
boost : : shared_ptr < torrent > t = associated_torrent ( ) . lock ( ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( t ) ;
2006-04-25 23:04:48 +02:00
piece_block_progress ret ;
ret . piece_index = m_requests . front ( ) . piece ;
2010-06-22 20:09:04 +02:00
ret . bytes_downloaded = m_block_pos % t - > block_size ( ) ;
2010-10-17 21:19:17 +02:00
// this is used to make sure that the block_index stays within
// bounds. If the entire piece is downloaded, the block_index
// would otherwise point to one past the end
int correction = m_block_pos ? - 1 : 0 ;
ret . block_index = ( m_requests . front ( ) . start + m_block_pos + correction ) / t - > block_size ( ) ;
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( ret . block_index < int ( piece_block : : invalid . block_index ) ) ;
TORRENT_ASSERT ( ret . piece_index < int ( piece_block : : invalid . piece_index ) ) ;
2009-04-11 22:45:14 +02:00
2006-12-18 02:23:30 +01:00
ret . full_block_bytes = t - > block_size ( ) ;
const int last_piece = t - > torrent_file ( ) . num_pieces ( ) - 1 ;
if ( ret . piece_index = = last_piece & & ret . block_index
= = t - > torrent_file ( ) . piece_size ( last_piece ) / t - > block_size ( ) )
ret . full_block_bytes = t - > torrent_file ( ) . piece_size ( last_piece ) % t - > block_size ( ) ;
2006-04-25 23:04:48 +02:00
return ret ;
}
void web_peer_connection : : write_request ( peer_request const & r )
{
INVARIANT_CHECK ;
boost : : shared_ptr < torrent > t = associated_torrent ( ) . lock ( ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( t ) ;
2006-04-25 23:04:48 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( t - > valid_metadata ( ) ) ;
2006-04-25 23:04:48 +02:00
2009-05-07 22:27:07 +02:00
bool single_file_request = t - > torrent_file ( ) . num_files ( ) = = 1 ;
2009-08-19 00:00:52 +02:00
if ( ! single_file_request )
{
// handle incorrect .torrent files which are multi-file
// but have web seeds not ending with a slash
if ( m_path . empty ( ) | | m_path [ m_path . size ( ) - 1 ] ! = ' / ' ) m_path + = " / " ;
if ( m_url . empty ( ) | | m_url [ m_url . size ( ) - 1 ] ! = ' / ' ) m_url + = " / " ;
}
else
{
// handle .torrent files that don't include the filename in the url
if ( m_path . empty ( ) ) m_path + = " / " + t - > torrent_file ( ) . name ( ) ;
2011-11-28 12:22:51 +01:00
else if ( m_path [ m_path . size ( ) - 1 ] = = ' / ' )
{
std : : string tmp = t - > torrent_file ( ) . files ( ) . at ( 0 ) . path ;
# ifdef TORRENT_WINDOWS
convert_path_to_posix ( tmp ) ;
# endif
m_path + = tmp ;
}
else if ( ! m_url . empty ( ) & & m_url [ m_url . size ( ) - 1 ] = = ' / ' )
{
std : : string tmp = t - > torrent_file ( ) . files ( ) . at ( 0 ) . path ;
# ifdef TORRENT_WINDOWS
convert_path_to_posix ( tmp ) ;
# endif
m_url + = tmp ;
}
2009-08-19 00:00:52 +02:00
}
2006-04-25 23:04:48 +02:00
torrent_info const & info = t - > torrent_file ( ) ;
std : : string request ;
2007-05-23 10:45:12 +02:00
request . reserve ( 400 ) ;
2006-04-25 23:04:48 +02:00
2006-12-18 02:23:30 +01:00
int size = r . length ;
const int block_size = t - > block_size ( ) ;
2007-09-03 23:16:24 +02:00
const int piece_size = t - > torrent_file ( ) . piece_length ( ) ;
peer_request pr ;
2006-12-18 02:23:30 +01:00
while ( size > 0 )
{
2007-09-03 23:16:24 +02:00
int request_offset = r . start + r . length - size ;
pr . start = request_offset % piece_size ;
pr . length = ( std : : min ) ( block_size , size ) ;
pr . piece = r . piece + request_offset / piece_size ;
2006-12-18 02:23:30 +01:00
m_requests . push_back ( pr ) ;
2007-09-03 23:16:24 +02:00
size - = pr . length ;
2006-12-18 02:23:30 +01:00
}
2006-04-25 23:04:48 +02:00
2010-08-23 08:27:18 +02:00
proxy_settings const & ps = m_ses . proxy ( ) ;
2010-10-12 10:57:43 +02:00
bool using_proxy = ( ps . type = = proxy_settings : : http
| | ps . type = = proxy_settings : : http_pw ) & & ! m_ssl ;
2006-07-27 20:07:51 +02:00
2006-04-25 23:04:48 +02:00
if ( single_file_request )
{
request + = " GET " ;
2007-03-07 01:21:36 +01:00
// do not encode single file paths, they are
// assumed to be encoded in the torrent file
request + = using_proxy ? m_url : m_path ;
2006-04-25 23:04:48 +02:00
request + = " HTTP/1.1 \r \n " ;
2010-10-10 20:43:58 +02:00
add_headers ( request , ps , using_proxy ) ;
2006-04-25 23:04:48 +02:00
request + = " \r \n Range: bytes= " ;
2009-01-27 07:17:55 +01:00
request + = to_string ( size_type ( r . piece ) * info . piece_length ( ) + r . start ) . elems ;
2006-04-25 23:04:48 +02:00
request + = " - " ;
2010-01-14 00:49:04 +01:00
request + = to_string ( size_type ( r . piece ) * info . piece_length ( ) + r . start + r . length - 1 ) . elems ;
2006-04-25 23:04:48 +02:00
request + = " \r \n \r \n " ;
m_first_request = false ;
m_file_requests . push_back ( 0 ) ;
}
else
{
2008-12-24 21:07:34 +01:00
std : : vector < file_slice > files = info . orig_files ( ) . map_block ( r . piece , r . start
2006-04-25 23:04:48 +02:00
, r . length ) ;
for ( std : : vector < file_slice > : : iterator i = files . begin ( ) ;
i ! = files . end ( ) ; + + i )
{
file_slice const & f = * i ;
2013-08-12 09:30:57 +02:00
if ( info . orig_files ( ) . pad_file_at ( f . file_index ) )
2011-11-26 21:48:31 +01:00
{
m_file_requests . push_back ( f . file_index ) ;
continue ;
}
2006-04-25 23:04:48 +02:00
request + = " GET " ;
2006-07-27 20:07:51 +02:00
if ( using_proxy )
{
2013-08-16 18:38:09 +02:00
// m_url is already a properly escaped URL
// with the correct slashes. Don't encode it again
2006-07-27 20:07:51 +02:00
request + = m_url ;
2013-08-12 09:30:57 +02:00
std : : string path = info . orig_files ( ) . file_path ( f . file_index ) ;
2009-10-30 04:42:29 +01:00
# ifdef TORRENT_WINDOWS
convert_path_to_posix ( path ) ;
# endif
2006-07-27 20:07:51 +02:00
request + = escape_path ( path . c_str ( ) , path . length ( ) ) ;
}
else
{
2013-08-16 18:38:09 +02:00
// m_path is already a properly escaped URL
// with the correct slashes. Don't encode it again
request + = m_path ;
std : : string path = info . orig_files ( ) . file_path ( f . file_index ) ;
2009-10-30 04:42:29 +01:00
# ifdef TORRENT_WINDOWS
convert_path_to_posix ( path ) ;
# endif
2006-07-27 20:07:51 +02:00
request + = escape_path ( path . c_str ( ) , path . length ( ) ) ;
}
2006-04-25 23:04:48 +02:00
request + = " HTTP/1.1 \r \n " ;
2010-10-10 20:43:58 +02:00
add_headers ( request , ps , using_proxy ) ;
2006-04-25 23:04:48 +02:00
request + = " \r \n Range: bytes= " ;
2009-01-27 07:17:55 +01:00
request + = to_string ( f . offset ) . elems ;
2006-04-25 23:04:48 +02:00
request + = " - " ;
2009-01-27 07:17:55 +01:00
request + = to_string ( f . offset + f . size - 1 ) . elems ;
2006-04-25 23:04:48 +02:00
request + = " \r \n \r \n " ;
m_first_request = false ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( f . file_index > = 0 ) ;
2006-04-25 23:04:48 +02:00
m_file_requests . push_back ( f . file_index ) ;
}
}
2007-02-20 18:38:07 +01:00
# ifdef TORRENT_VERBOSE_LOGGING
2010-10-31 23:12:26 +01:00
peer_log ( " ==> %s " , request . c_str ( ) ) ;
2007-02-20 18:38:07 +01:00
# endif
2008-07-08 02:03:08 +02:00
send_buffer ( request . c_str ( ) , request . size ( ) , message_type_request ) ;
2006-04-25 23:04:48 +02:00
}
// --------------------------
// RECEIVE DATA
// --------------------------
2006-12-21 00:06:24 +01:00
namespace
{
2007-11-26 00:11:29 +01:00
bool range_contains ( peer_request const & range , peer_request const & req , int piece_size )
2006-12-21 00:06:24 +01:00
{
2007-11-26 00:11:29 +01:00
size_type range_start = size_type ( range . piece ) * piece_size + range . start ;
size_type req_start = size_type ( req . piece ) * piece_size + req . start ;
return range_start < = req_start
& & range_start + range . length > = req_start + req . length ;
2006-12-21 00:06:24 +01:00
}
}
2011-11-26 21:48:31 +01:00
bool web_peer_connection : : maybe_harvest_block ( )
{
peer_request const & front_request = m_requests . front ( ) ;
if ( int ( m_piece . size ( ) ) < front_request . length ) return false ;
TORRENT_ASSERT ( int ( m_piece . size ( ) = = front_request . length ) ) ;
// each call to incoming_piece() may result in us becoming
// a seed. If we become a seed, all seeds we're connected to
// will be disconnected, including this web seed. We need to
// check for the disconnect condition after the call.
boost : : shared_ptr < torrent > t = associated_torrent ( ) . lock ( ) ;
TORRENT_ASSERT ( t ) ;
buffer : : const_interval recv_buffer = receive_buffer ( ) ;
incoming_piece ( front_request , & m_piece [ 0 ] ) ;
m_requests . pop_front ( ) ;
if ( associated_torrent ( ) . expired ( ) ) return false ;
TORRENT_ASSERT ( m_block_pos > = front_request . length ) ;
m_block_pos - = front_request . length ;
2012-04-07 02:35:25 +02:00
cut_receive_buffer ( m_body_start , t - > block_size ( ) + request_size_overhead ) ;
2011-11-26 21:48:31 +01:00
m_body_start = 0 ;
recv_buffer = receive_buffer ( ) ;
// TORRENT_ASSERT(m_received_body <= range_end - range_start);
m_piece . clear ( ) ;
TORRENT_ASSERT ( m_piece . empty ( ) ) ;
return true ;
}
2012-09-29 19:46:41 +02:00
bool web_peer_connection : : received_invalid_data ( int index , bool single_peer )
{
if ( ! single_peer ) return peer_connection : : received_invalid_data ( index , single_peer ) ;
// when a web seed fails a hash check, do the following:
// 1. if the whole piece only overlaps a single file, mark that file as not
// have for this peer
// 2. if the piece overlaps more than one file, mark the piece as not have
// for this peer
// 3. if it's a single file torrent, just ban it right away
// this handles the case where web seeds may have some files updated but not other
boost : : shared_ptr < torrent > t = associated_torrent ( ) . lock ( ) ;
file_storage const & fs = t - > torrent_file ( ) . files ( ) ;
// single file torrent
if ( fs . num_files ( ) = = 1 ) return peer_connection : : received_invalid_data ( index , single_peer ) ;
std : : vector < file_slice > files = fs . map_block ( index , 0 , fs . piece_size ( index ) ) ;
if ( files . size ( ) = = 1 )
{
// assume the web seed has a different copy of this specific file
// than what we expect, and pretend not to have it.
int fi = files [ 0 ] . file_index ;
int first_piece = fs . file_offset ( fi ) / fs . piece_length ( ) ;
// one past last piece
int end_piece = ( fs . file_offset ( fi ) + fs . file_size ( fi ) + 1 ) / fs . piece_length ( ) ;
for ( int i = first_piece ; i < end_piece ; + + i )
incoming_dont_have ( i ) ;
}
else
{
incoming_dont_have ( index ) ;
}
peer_connection : : received_invalid_data ( index , single_peer ) ;
// if we don't think we have any of the files, allow banning the web seed
if ( num_have_pieces ( ) = = 0 ) return true ;
// don't disconnect, we won't request anything from this file again
return false ;
}
2008-05-03 18:05:42 +02:00
void web_peer_connection : : on_receive ( error_code const & error
2006-04-25 23:04:48 +02:00
, std : : size_t bytes_transferred )
{
INVARIANT_CHECK ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
2011-02-15 11:05:25 +01:00
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( ) + bytes_transferred < size_t ( INT_MAX ) ) ;
int dl_target = m_statistics . last_payload_downloaded ( )
2010-10-27 08:39:18 +02:00
+ m_statistics . last_protocol_downloaded ( ) + bytes_transferred ;
# endif
2007-08-03 10:19:10 +02:00
if ( error )
{
2009-04-11 04:19:57 +02:00
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2007-08-03 10:19:10 +02:00
# ifdef TORRENT_VERBOSE_LOGGING
2010-10-31 23:12:26 +01:00
peer_log ( " *** web_peer_connection error: %s " , error . message ( ) . c_str ( ) ) ;
2010-10-27 08:39:18 +02:00
# endif
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
2007-08-03 10:19:10 +02:00
# endif
return ;
}
2006-04-25 23:04:48 +02:00
boost : : shared_ptr < torrent > t = associated_torrent ( ) . lock ( ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( t ) ;
2006-04-25 23:04:48 +02:00
for ( ; ; )
{
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
2011-02-21 06:24:41 +01:00
+ m_statistics . last_protocol_downloaded ( ) + int ( bytes_transferred )
2010-10-27 08:39:18 +02:00
= = dl_target ) ;
# endif
2006-04-25 23:04:48 +02:00
buffer : : const_interval recv_buffer = receive_buffer ( ) ;
2007-02-12 06:46:29 +01:00
2006-04-25 23:04:48 +02:00
int payload ;
int protocol ;
2007-02-12 06:46:29 +01:00
bool header_finished = m_parser . header_finished ( ) ;
2007-05-11 20:40:22 +02:00
if ( ! header_finished )
2006-04-25 23:04:48 +02:00
{
2011-02-24 05:25:35 +01:00
bool failed = false ;
boost : : tie ( payload , protocol ) = m_parser . incoming ( recv_buffer , failed ) ;
2008-06-03 17:17:09 +02:00
m_statistics . received_bytes ( 0 , protocol ) ;
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( int ( bytes_transferred ) > = protocol ) ;
2008-06-03 17:17:09 +02:00
bytes_transferred - = protocol ;
2007-05-11 20:40:22 +02:00
2011-02-24 05:25:35 +01:00
if ( failed )
2008-01-07 02:10:46 +01:00
{
2009-04-11 04:19:57 +02:00
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2009-02-07 23:20:13 +01:00
# ifdef TORRENT_VERBOSE_LOGGING
2010-10-31 23:12:26 +01:00
peer_log ( " *** %s " , std : : string ( recv_buffer . begin , recv_buffer . end ) . c_str ( ) ) ;
2009-02-07 23:20:13 +01:00
# endif
2009-11-29 08:06:38 +01:00
disconnect ( errors : : http_parse_error , 2 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2008-01-07 02:10:46 +01:00
return ;
}
2007-12-29 19:24:50 +01:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( recv_buffer . left ( ) = = 0 | | * recv_buffer . begin = = ' H ' ) ;
2007-05-11 20:40:22 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( recv_buffer . left ( ) < = packet_size ( ) ) ;
2007-05-11 20:40:22 +02:00
// this means the entire status line hasn't been received yet
2008-06-03 17:17:09 +02:00
if ( m_parser . status_code ( ) = = - 1 )
{
TORRENT_ASSERT ( payload = = 0 ) ;
TORRENT_ASSERT ( bytes_transferred = = 0 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
2011-02-21 06:24:41 +01:00
+ m_statistics . last_protocol_downloaded ( ) + int ( bytes_transferred )
2010-10-27 08:39:18 +02:00
= = dl_target ) ;
# endif
2008-06-03 17:17:09 +02:00
break ;
}
2007-05-11 20:40:22 +02:00
2008-06-03 17:17:09 +02:00
if ( ! m_parser . header_finished ( ) )
{
TORRENT_ASSERT ( payload = = 0 ) ;
TORRENT_ASSERT ( bytes_transferred = = 0 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
2011-02-21 06:24:41 +01:00
+ m_statistics . last_protocol_downloaded ( ) + int ( bytes_transferred )
2010-10-27 08:39:18 +02:00
= = dl_target ) ;
# endif
2008-06-03 17:17:09 +02:00
break ;
}
2006-04-25 23:04:48 +02:00
2007-05-11 20:40:22 +02:00
m_body_start = m_parser . body_start ( ) ;
m_received_body = 0 ;
}
2006-12-18 02:23:30 +01:00
2007-02-12 06:46:29 +01:00
// we just completed reading the header
if ( ! header_finished )
2006-04-25 23:04:48 +02:00
{
2013-10-20 04:40:43 +02:00
+ + m_num_responses ;
if ( m_parser . connection_close ( ) )
{
incoming_choke ( ) ;
if ( m_num_responses = = 1 )
m_web . supports_keepalive = false ;
}
2009-02-07 23:20:13 +01:00
# ifdef TORRENT_VERBOSE_LOGGING
2010-10-31 23:12:26 +01:00
peer_log ( " *** STATUS: %d %s " , m_parser . status_code ( ) , m_parser . message ( ) . c_str ( ) ) ;
2011-02-16 08:41:44 +01:00
std : : multimap < std : : string , std : : string > const & headers = m_parser . headers ( ) ;
for ( std : : multimap < std : : string , std : : string > : : const_iterator i = headers . begin ( )
2009-02-07 23:20:13 +01:00
, end ( headers . end ( ) ) ; i ! = end ; + + i )
2010-10-31 23:12:26 +01:00
peer_log ( " %s: %s " , i - > first . c_str ( ) , i - > second . c_str ( ) ) ;
2009-02-07 23:20:13 +01:00
# endif
2009-11-25 17:32:09 +01:00
// if the status code is not one of the accepted ones, abort
2010-09-21 08:34:13 +02:00
if ( ! is_ok_status ( m_parser . status_code ( ) ) )
2009-11-25 17:32:09 +01:00
{
2013-11-02 04:26:53 +01:00
// TODO: 3 just make this peer not have the pieces
// associated with the file we just requested. Only
// when it doesn't have any of the file do the following
2010-09-21 08:34:13 +02:00
int retry_time = atoi ( m_parser . header ( " retry-after " ) . c_str ( ) ) ;
2013-08-22 04:55:19 +02:00
if ( retry_time < = 0 ) retry_time = m_ses . settings ( ) . urlseed_wait_retry ;
2010-09-21 08:34:13 +02:00
// temporarily unavailable, retry later
t - > retry_web_seed ( this , retry_time ) ;
2009-11-25 17:32:09 +01:00
std : : string error_msg = to_string ( m_parser . status_code ( ) ) . elems
+ ( " " + m_parser . message ( ) ) ;
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
{
2011-11-25 11:56:33 +01:00
m_ses . m_alerts . post_alert ( url_seed_alert ( t - > get_handle ( ) , m_url
2009-11-25 17:32:09 +01:00
, error_msg ) ) ;
}
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2011-01-16 03:54:59 +01:00
disconnect ( error_code ( m_parser . status_code ( ) , get_http_category ( ) ) , 1 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2009-11-25 17:32:09 +01:00
return ;
}
2010-09-21 08:34:13 +02:00
if ( is_redirect ( m_parser . status_code ( ) ) )
2007-02-12 06:46:29 +01:00
{
// this means we got a redirection request
// look for the location header
2007-09-25 05:14:05 +02:00
std : : string location = m_parser . header ( " location " ) ;
2009-05-14 01:02:08 +02:00
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2007-02-12 06:46:29 +01:00
if ( location . empty ( ) )
{
// we should not try this server again.
2010-04-14 08:22:00 +02:00
t - > remove_web_seed ( this ) ;
2009-11-29 08:06:38 +01:00
disconnect ( errors : : missing_location , 2 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2008-01-07 02:10:46 +01:00
return ;
2007-02-12 06:46:29 +01:00
}
bool single_file_request = false ;
if ( ! m_path . empty ( ) & & m_path [ m_path . size ( ) - 1 ] ! = ' / ' )
single_file_request = true ;
// add the redirected url and remove the current one
if ( ! single_file_request )
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( ! m_file_requests . empty ( ) ) ;
2007-02-12 06:46:29 +01:00
int file_index = m_file_requests . front ( ) ;
2013-11-02 04:26:53 +01:00
// TODO: 2 create a mapping of file-index to redirection URLs. Use that to form URLs instead. Support to reconnect to a new server without destructing this peer_connection
2007-02-12 06:46:29 +01:00
torrent_info const & info = t - > torrent_file ( ) ;
2013-08-12 09:30:57 +02:00
std : : string path = info . orig_files ( ) . file_path ( file_index ) ;
2009-10-30 04:42:29 +01:00
# ifdef TORRENT_WINDOWS
convert_path_to_posix ( path ) ;
# endif
2007-02-12 06:46:29 +01:00
path = escape_path ( path . c_str ( ) , path . length ( ) ) ;
size_t i = location . rfind ( path ) ;
if ( i = = std : : string : : npos )
{
2010-04-14 08:22:00 +02:00
t - > remove_web_seed ( this ) ;
2009-11-29 08:06:38 +01:00
disconnect ( errors : : invalid_redirection , 2 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2008-01-07 02:10:46 +01:00
return ;
2007-02-12 06:46:29 +01:00
}
location . resize ( i ) ;
}
2010-10-27 08:39:18 +02:00
t - > add_web_seed ( location , web_seed_entry : : url_seed , m_external_auth , m_extra_headers ) ;
2010-04-14 08:22:00 +02:00
t - > remove_web_seed ( this ) ;
2009-11-29 08:06:38 +01:00
disconnect ( errors : : redirecting , 2 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2008-01-07 02:10:46 +01:00
return ;
2007-02-12 06:46:29 +01:00
}
2007-09-25 05:14:05 +02:00
std : : string const & server_version = m_parser . header ( " server " ) ;
2007-02-12 06:46:29 +01:00
if ( ! server_version . empty ( ) )
{
m_server_string = " URL seed @ " ;
m_server_string + = m_host ;
m_server_string + = " ( " ;
m_server_string + = server_version ;
m_server_string + = " ) " ;
}
2007-05-11 20:40:22 +02:00
m_body_start = m_parser . body_start ( ) ;
m_received_body = 0 ;
2008-06-03 17:17:09 +02:00
m_range_pos = 0 ;
2006-04-25 23:04:48 +02:00
}
2007-05-11 20:40:22 +02:00
recv_buffer . begin + = m_body_start ;
2008-06-03 17:17:09 +02:00
2007-05-17 21:57:48 +02:00
// we only received the header, no data
2010-10-27 08:39:18 +02:00
if ( recv_buffer . left ( ) = = 0 )
{
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
break ;
}
2007-02-12 06:46:29 +01:00
2006-04-25 23:04:48 +02:00
size_type range_start ;
size_type range_end ;
2006-12-21 00:06:24 +01:00
if ( m_parser . status_code ( ) = = 206 )
2006-04-25 23:04:48 +02:00
{
2009-04-12 19:52:25 +02:00
boost : : tie ( range_start , range_end ) = m_parser . content_range ( ) ;
if ( range_start < 0 | | range_end < range_start )
2006-12-21 00:06:24 +01:00
{
2009-04-11 04:19:57 +02:00
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2006-12-21 00:06:24 +01:00
// we should not try this server again.
2010-04-14 08:22:00 +02:00
t - > remove_web_seed ( this ) ;
2009-11-29 08:06:38 +01:00
disconnect ( errors : : invalid_range ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2008-01-07 02:10:46 +01:00
return ;
2006-12-21 00:06:24 +01:00
}
// the http range is inclusive
range_end + + ;
}
else
{
range_start = 0 ;
2009-01-27 09:24:48 +01:00
range_end = m_parser . content_length ( ) ;
2006-12-21 00:06:24 +01:00
if ( range_end = = - 1 )
{
2009-04-11 04:19:57 +02:00
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2006-12-21 00:06:24 +01:00
// we should not try this server again.
2010-04-14 08:22:00 +02:00
t - > remove_web_seed ( this ) ;
2009-11-29 08:06:38 +01:00
disconnect ( errors : : no_content_length , 2 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
2008-01-07 02:10:46 +01:00
return ;
2006-12-21 00:06:24 +01:00
}
2006-04-25 23:04:48 +02:00
}
2010-10-27 08:39:18 +02:00
// =========================
// === CHUNKED ENCODING ===
// =========================
while ( m_parser . chunked_encoding ( )
& & m_chunk_pos > = 0
& & m_chunk_pos < recv_buffer . left ( ) )
{
int header_size = 0 ;
size_type chunk_size = 0 ;
buffer : : const_interval chunk_start = recv_buffer ;
chunk_start . begin + = m_chunk_pos ;
TORRENT_ASSERT ( chunk_start . begin [ 0 ] = = ' \r ' | | is_hex ( chunk_start . begin , 1 ) ) ;
bool ret = m_parser . parse_chunk_header ( chunk_start , & chunk_size , & header_size ) ;
if ( ! ret )
{
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( int ( bytes_transferred ) > = chunk_start . left ( ) - m_partial_chunk_header ) ;
2010-10-27 08:39:18 +02:00
bytes_transferred - = chunk_start . left ( ) - m_partial_chunk_header ;
m_statistics . received_bytes ( 0 , chunk_start . left ( ) - m_partial_chunk_header ) ;
m_partial_chunk_header = chunk_start . left ( ) ;
2010-10-31 04:05:11 +01:00
if ( bytes_transferred = = 0 ) return ;
2010-10-27 08:39:18 +02:00
break ;
}
else
{
# ifdef TORRENT_VERBOSE_LOGGING
2010-10-31 23:12:26 +01:00
peer_log ( " *** parsed chunk: %d header_size: %d " , chunk_size , header_size ) ;
2010-10-27 08:39:18 +02:00
# endif
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( int ( bytes_transferred ) > = header_size - m_partial_chunk_header ) ;
2010-10-27 08:39:18 +02:00
bytes_transferred - = header_size - m_partial_chunk_header ;
m_statistics . received_bytes ( 0 , header_size - m_partial_chunk_header ) ;
m_partial_chunk_header = 0 ;
TORRENT_ASSERT ( chunk_size ! = 0 | | chunk_start . left ( ) < = header_size | | chunk_start . begin [ header_size ] = = ' H ' ) ;
// cut out the chunk header from the receive buffer
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( m_body_start + m_chunk_pos < INT_MAX ) ;
2012-04-07 02:35:25 +02:00
cut_receive_buffer ( header_size , t - > block_size ( ) + request_size_overhead , int ( m_body_start + m_chunk_pos ) ) ;
2010-10-27 08:39:18 +02:00
recv_buffer = receive_buffer ( ) ;
recv_buffer . begin + = m_body_start ;
m_chunk_pos + = chunk_size ;
if ( chunk_size = = 0 )
{
# ifdef TORRENT_DEBUG
chunk_start = recv_buffer ;
chunk_start . begin + = m_chunk_pos ;
TORRENT_ASSERT ( chunk_start . left ( ) = = 0 | | chunk_start . begin [ 0 ] = = ' H ' ) ;
# endif
m_chunk_pos = - 1 ;
}
2014-01-21 10:14:00 +01:00
// if all of hte receive buffer was just consumed as chunk
// header, we're done
if ( bytes_transferred = = 0 ) return ;
2010-10-27 08:39:18 +02:00
}
}
2014-01-21 10:14:00 +01:00
if ( m_requests . empty ( ) | | m_file_requests . empty ( ) )
{
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
disconnect ( errors : : http_error , 2 ) ;
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
return ;
}
2011-02-21 06:24:41 +01:00
size_type left_in_response = range_end - range_start - m_range_pos ;
int payload_transferred = int ( ( std : : min ) ( left_in_response , size_type ( bytes_transferred ) ) ) ;
2009-04-11 22:45:14 +02:00
torrent_info const & info = t - > torrent_file ( ) ;
peer_request front_request = m_requests . front ( ) ;
TORRENT_ASSERT ( m_block_pos > = 0 ) ;
2010-06-22 20:09:04 +02:00
# ifdef TORRENT_VERBOSE_LOGGING
2010-10-31 23:12:26 +01:00
peer_log ( " *** payload_transferred: %d [ %d:%d = %d ] "
, payload_transferred , front_request . piece
, front_request . start , front_request . length ) ;
2010-06-22 20:09:04 +02:00
# endif
2008-06-03 17:17:09 +02:00
m_statistics . received_bytes ( payload_transferred , 0 ) ;
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( int ( bytes_transferred ) > = payload_transferred ) ;
2008-06-03 17:17:09 +02:00
bytes_transferred - = payload_transferred ;
2009-04-11 22:45:14 +02:00
m_range_pos + = payload_transferred ;
m_block_pos + = payload_transferred ;
2008-06-03 17:17:09 +02:00
if ( m_range_pos > range_end - range_start ) m_range_pos = range_end - range_start ;
2010-06-22 20:09:04 +02:00
#if 0
std : : cerr < < " REQUESTS: m_requests: " < < m_requests . size ( )
< < " file_requests: " < < m_file_requests . size ( ) < < std : : endl ;
# endif
2007-11-26 00:11:29 +01:00
2006-04-25 23:04:48 +02:00
int file_index = m_file_requests . front ( ) ;
2008-12-24 21:07:34 +01:00
peer_request in_range = info . orig_files ( ) . map_file ( file_index , range_start
2008-02-25 11:28:53 +01:00
, int ( range_end - range_start ) ) ;
2006-04-25 23:04:48 +02:00
2011-03-25 05:08:43 +01:00
// request start
2007-09-03 23:16:24 +02:00
size_type rs = size_type ( in_range . piece ) * info . piece_length ( ) + in_range . start ;
2011-03-25 05:08:43 +01:00
// request end
2007-09-03 23:16:24 +02:00
size_type re = rs + in_range . length ;
2011-03-25 05:08:43 +01:00
// file start
2007-09-03 23:16:24 +02:00
size_type fs = size_type ( front_request . piece ) * info . piece_length ( ) + front_request . start ;
2010-06-22 20:09:04 +02:00
#if 0
2007-09-03 23:16:24 +02:00
size_type fe = fs + front_request . length ;
2006-12-18 02:23:30 +01:00
2007-11-26 00:11:29 +01:00
std : : cerr < < " RANGE: r = ( " < < rs < < " , " < < re < < " ) "
" f = ( " < < fs < < " , " < < fe < < " ) "
" file_index = " < < file_index < < " received_body = " < < m_received_body < < std : : endl ;
2010-06-22 20:09:04 +02:00
# endif
2006-12-21 00:06:24 +01:00
// the http response body consists of 3 parts
// 1. the middle of a block or the ending of a block
// 2. a number of whole blocks
// 3. the start of a block
// in that order, these parts are parsed.
2006-11-14 01:08:16 +01:00
2013-10-03 03:40:34 +02:00
bool range_overlaps_request = re > = fs + int ( m_piece . size ( ) ) ;
2006-12-21 00:06:24 +01:00
2007-11-26 00:11:29 +01:00
if ( ! range_overlaps_request )
{
2010-06-22 20:09:04 +02:00
incoming_piece_fragment ( ( std : : min ) ( payload_transferred
, front_request . length - m_block_pos ) ) ;
2009-04-11 04:19:57 +02:00
m_statistics . received_bytes ( 0 , bytes_transferred ) ;
2007-11-26 19:45:24 +01:00
// this means the end of the incoming request ends _before_ the
// first expected byte (fs + m_piece.size())
2009-11-29 08:06:38 +01:00
disconnect ( errors : : invalid_range , 2 ) ;
2008-01-07 02:10:46 +01:00
return ;
2007-11-26 00:11:29 +01:00
}
2006-12-21 00:06:24 +01:00
// if the request is contained in the range (i.e. the entire request
// fits in the range) we should not start a partial piece, since we soon
// will receive enough to call incoming_piece() and pass the read buffer
// directly (in the next loop below).
2007-11-26 00:11:29 +01:00
if ( range_overlaps_request & & ! range_contains ( in_range , front_request , info . piece_length ( ) ) )
2006-04-25 23:04:48 +02:00
{
2006-12-18 02:23:30 +01:00
// the start of the next block to receive is stored
// in m_piece. We need to append the rest of that
// block from the http receive buffer and then
// (if it completed) call incoming_piece() with
// m_piece as buffer.
2007-05-10 20:15:53 +02:00
int piece_size = int ( m_piece . size ( ) ) ;
2007-08-21 06:46:17 +02:00
int copy_size = ( std : : min ) ( ( std : : min ) ( front_request . length - piece_size
2007-05-11 20:40:22 +02:00
, recv_buffer . left ( ) ) , int ( range_end - range_start - m_received_body ) ) ;
2011-11-26 21:48:31 +01:00
if ( copy_size > m_chunk_pos & & m_chunk_pos > 0 ) copy_size = m_chunk_pos ;
2010-10-31 04:05:11 +01:00
if ( copy_size > 0 )
{
2012-04-07 02:35:25 +02:00
TORRENT_ASSERT ( m_piece . size ( ) = = m_received_in_piece ) ;
2010-10-31 04:05:11 +01:00
m_piece . resize ( piece_size + copy_size ) ;
std : : memcpy ( & m_piece [ 0 ] + piece_size , recv_buffer . begin , copy_size ) ;
TORRENT_ASSERT ( int ( m_piece . size ( ) ) < = front_request . length ) ;
recv_buffer . begin + = copy_size ;
m_received_body + = copy_size ;
m_body_start + = copy_size ;
if ( m_chunk_pos > 0 )
{
TORRENT_ASSERT ( m_chunk_pos > = copy_size ) ;
m_chunk_pos - = copy_size ;
}
TORRENT_ASSERT ( m_received_body < = range_end - range_start ) ;
TORRENT_ASSERT ( int ( m_piece . size ( ) ) < = front_request . length ) ;
incoming_piece_fragment ( copy_size ) ;
2012-04-07 02:35:25 +02:00
TORRENT_ASSERT ( m_piece . size ( ) = = m_received_in_piece ) ;
2010-10-31 04:05:11 +01:00
}
2011-11-26 21:48:31 +01:00
if ( maybe_harvest_block ( ) )
2007-05-11 20:40:22 +02:00
recv_buffer = receive_buffer ( ) ;
2011-11-26 21:48:31 +01:00
if ( associated_torrent ( ) . expired ( ) ) return ;
2006-12-18 02:23:30 +01:00
}
// report all received blocks to the bittorrent engine
2006-12-21 00:06:24 +01:00
while ( ! m_requests . empty ( )
2007-11-26 00:11:29 +01:00
& & range_contains ( in_range , m_requests . front ( ) , info . piece_length ( ) )
2011-11-02 09:04:16 +01:00
& & m_block_pos > = m_requests . front ( ) . length )
2006-12-18 02:23:30 +01:00
{
2006-12-21 00:06:24 +01:00
peer_request r = m_requests . front ( ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( recv_buffer . left ( ) > = r . length ) ;
2007-02-12 06:46:29 +01:00
2010-06-22 20:09:04 +02:00
incoming_piece_fragment ( r . length ) ;
2007-05-11 20:40:22 +02:00
incoming_piece ( r , recv_buffer . begin ) ;
2009-04-11 22:45:14 +02:00
m_requests . pop_front ( ) ;
2007-04-27 04:54:33 +02:00
if ( associated_torrent ( ) . expired ( ) ) return ;
2011-10-30 07:13:34 +01:00
TORRENT_ASSERT ( m_block_pos > = r . length ) ;
2010-06-22 20:09:04 +02:00
m_block_pos - = r . length ;
2007-05-11 20:40:22 +02:00
m_received_body + = r . length ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( receive_buffer ( ) . begin + m_body_start = = recv_buffer . begin ) ;
TORRENT_ASSERT ( m_received_body < = range_end - range_start ) ;
2012-04-07 02:35:25 +02:00
cut_receive_buffer ( m_body_start + r . length , t - > block_size ( ) + request_size_overhead ) ;
2010-10-27 08:39:18 +02:00
if ( m_chunk_pos > 0 )
{
TORRENT_ASSERT ( m_chunk_pos > = r . length ) ;
m_chunk_pos - = r . length ;
}
2007-05-11 20:40:22 +02:00
m_body_start = 0 ;
recv_buffer = receive_buffer ( ) ;
2006-12-21 00:06:24 +01:00
}
2007-01-08 16:29:17 +01:00
if ( ! m_requests . empty ( ) )
2006-12-21 00:06:24 +01:00
{
2007-01-08 16:29:17 +01:00
if ( in_range . start + in_range . length < m_requests . front ( ) . start + m_requests . front ( ) . length
2007-05-11 20:40:22 +02:00
& & ( m_received_body + recv_buffer . left ( ) > = range_end - range_start ) )
2007-01-08 16:29:17 +01:00
{
2007-05-10 20:15:53 +02:00
int piece_size = int ( m_piece . size ( ) ) ;
2007-08-21 06:46:17 +02:00
int copy_size = ( std : : min ) ( ( std : : min ) ( m_requests . front ( ) . length - piece_size
2007-05-11 20:40:22 +02:00
, recv_buffer . left ( ) ) , int ( range_end - range_start - m_received_body ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( copy_size > = 0 ) ;
2007-05-16 03:58:00 +02:00
if ( copy_size > 0 )
2007-05-17 21:57:48 +02:00
{
2012-04-07 02:35:25 +02:00
TORRENT_ASSERT ( m_piece . size ( ) = = m_received_in_piece ) ;
2007-05-17 21:57:48 +02:00
m_piece . resize ( piece_size + copy_size ) ;
2007-05-16 03:58:00 +02:00
std : : memcpy ( & m_piece [ 0 ] + piece_size , recv_buffer . begin , copy_size ) ;
2007-05-17 21:57:48 +02:00
recv_buffer . begin + = copy_size ;
m_received_body + = copy_size ;
m_body_start + = copy_size ;
2012-04-07 02:35:25 +02:00
incoming_piece_fragment ( copy_size ) ;
TORRENT_ASSERT ( m_piece . size ( ) = = m_received_in_piece ) ;
2007-05-17 21:57:48 +02:00
}
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_received_body = = range_end - range_start ) ;
2007-01-08 16:29:17 +01:00
}
2006-04-25 23:04:48 +02:00
}
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_received_body < = range_end - range_start ) ;
2010-10-31 04:05:11 +01:00
// if we're in chunked encoding mode, we have to wait for the complete
// tail header before we can consider have received the block, otherwise
// we'll get out of sync with the next http response. m_chunk_pos is set
// to -1 when the tail header has been received
if ( m_received_body = = range_end - range_start
& & ( ! m_parser . chunked_encoding ( ) | | m_chunk_pos = = - 1 ) )
2006-12-18 02:23:30 +01:00
{
2010-10-27 08:39:18 +02:00
int size_to_cut = recv_buffer . begin - receive_buffer ( ) . begin ;
2010-10-31 04:05:11 +01:00
TORRENT_ASSERT ( receive_buffer ( ) . left ( ) < size_to_cut + 1
| | receive_buffer ( ) [ size_to_cut ] = = ' H ' ) ;
2012-04-07 02:35:25 +02:00
cut_receive_buffer ( size_to_cut , t - > block_size ( ) + request_size_overhead ) ;
2010-10-27 08:39:18 +02:00
if ( m_chunk_pos > 0 )
{
TORRENT_ASSERT ( m_chunk_pos > = size_to_cut ) ;
m_chunk_pos - = size_to_cut ;
}
2007-05-11 20:40:22 +02:00
recv_buffer = receive_buffer ( ) ;
2006-12-18 02:23:30 +01:00
m_file_requests . pop_front ( ) ;
m_parser . reset ( ) ;
2007-05-11 20:40:22 +02:00
m_body_start = 0 ;
m_received_body = 0 ;
2010-10-27 08:39:18 +02:00
m_chunk_pos = 0 ;
m_partial_chunk_header = 0 ;
2011-11-26 21:48:31 +01:00
torrent_info const & info = t - > torrent_file ( ) ;
while ( ! m_file_requests . empty ( )
2013-08-12 09:30:57 +02:00
& & info . orig_files ( ) . pad_file_at ( m_file_requests . front ( ) ) )
2011-11-26 21:48:31 +01:00
{
// the next file is a pad file. We didn't actually send
// a request for this since it most likely doesn't exist on
// the web server anyway. Just pretend that we received a
// bunch of zeroes here and pop it again
int file_index = m_file_requests . front ( ) ;
m_file_requests . pop_front ( ) ;
2013-08-12 09:30:57 +02:00
size_type file_size = info . orig_files ( ) . file_size ( file_index ) ;
2011-11-26 21:48:31 +01:00
TORRENT_ASSERT ( m_block_pos < front_request . length ) ;
int pad_size = ( std : : min ) ( file_size , size_type ( front_request . length - m_block_pos ) ) ;
// insert zeroes to represent the pad file
m_piece . resize ( m_piece . size ( ) + pad_size , 0 ) ;
m_block_pos + = pad_size ;
incoming_piece_fragment ( pad_size ) ;
if ( maybe_harvest_block ( ) )
recv_buffer = receive_buffer ( ) ;
if ( associated_torrent ( ) . expired ( ) ) return ;
}
2006-12-18 02:23:30 +01:00
continue ;
}
2012-06-05 05:12:36 +02:00
if ( bytes_transferred = = 0 | | payload_transferred = = 0 )
2010-10-27 08:39:18 +02:00
{
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( )
= = dl_target ) ;
# endif
break ;
}
2010-06-22 20:09:04 +02:00
TORRENT_ASSERT ( payload_transferred > 0 ) ;
2006-04-25 23:04:48 +02:00
}
2008-06-03 17:17:09 +02:00
TORRENT_ASSERT ( bytes_transferred = = 0 ) ;
2010-10-27 08:39:18 +02:00
# ifdef TORRENT_DEBUG
TORRENT_ASSERT ( m_statistics . last_payload_downloaded ( )
+ m_statistics . last_protocol_downloaded ( ) = = dl_target ) ;
# endif
2006-04-25 23:04:48 +02:00
}
2007-05-25 21:42:10 +02:00
void web_peer_connection : : get_specific_peer_info ( peer_info & p ) const
2006-04-25 23:04:48 +02:00
{
2010-10-10 20:43:58 +02:00
web_connection_base : : get_specific_peer_info ( p ) ;
p . flags | = peer_info : : local_connection ;
2006-04-25 23:04:48 +02:00
p . connection_type = peer_info : : web_seed ;
}
}