3 *****************************************************************************
4 * Copyright (C) 2010 - 2011 Klagenfurt University
6 * Created on: Aug 10, 2010
7 * Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
8 * Christian Timmerer <christian.timmerer@itec.uni-klu.ac.at>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include "HTTPConnection.hpp"
30 #include "HTTPConnectionManager.h"
31 #include "Downloader.hpp"
33 #include <vlc_common.h>
34 #include <vlc_block.h>
38 using namespace adaptive::http
;
40 AbstractChunkSource::AbstractChunkSource()
45 AbstractChunkSource::~AbstractChunkSource()
50 void AbstractChunkSource::setBytesRange(const BytesRange
&range
)
53 if(bytesRange
.isValid() && bytesRange
.getEndByte())
54 contentLength
= bytesRange
.getEndByte() - bytesRange
.getStartByte();
57 const BytesRange
& AbstractChunkSource::getBytesRange() const
62 AbstractChunk::AbstractChunk(AbstractChunkSource
*source_
)
68 AbstractChunk::~AbstractChunk()
73 size_t AbstractChunk::getBytesRead() const
75 return this->bytesRead
;
78 uint64_t AbstractChunk::getStartByteInFile() const
80 if(!source
|| !source
->getBytesRange().isValid())
83 return source
->getBytesRange().getStartByte();
86 block_t
* AbstractChunk::doRead(size_t size
, bool b_block
)
91 block_t
*block
= (b_block
) ? source
->readBlock() : source
->read(size
);
95 block
->i_flags
|= BLOCK_FLAG_HEADER
;
96 bytesRead
+= block
->i_buffer
;
98 block
->i_flags
&= ~BLOCK_FLAG_HEADER
;
104 bool AbstractChunk::isEmpty() const
106 return !source
->hasMoreData();
109 block_t
* AbstractChunk::readBlock()
111 return doRead(0, true);
114 block_t
* AbstractChunk::read(size_t size
)
116 return doRead(size
, false);
119 HTTPChunkSource::HTTPChunkSource(const std::string
& url
, AbstractConnectionManager
*manager
,
120 const adaptive::ID
&id
) :
121 AbstractChunkSource(),
123 connManager (manager
),
133 HTTPChunkSource::~HTTPChunkSource()
136 connection
->setUsed(false);
139 bool HTTPChunkSource::init(const std::string
&url
)
141 params
= ConnectionParams(url
);
143 if(params
.getScheme() != "http" && params
.getScheme() != "https")
146 if(params
.getPath().empty() || params
.getHostname().empty())
152 bool HTTPChunkSource::hasMoreData() const
156 else if(contentLength
)
157 return consumed
< contentLength
;
161 block_t
* HTTPChunkSource::read(size_t readsize
)
169 if(consumed
== contentLength
&& consumed
> 0)
175 if(contentLength
&& readsize
> contentLength
- consumed
)
176 readsize
= contentLength
- consumed
;
178 block_t
*p_block
= block_Alloc(readsize
);
185 mtime_t time
= mdate();
186 ssize_t ret
= connection
->read(p_block
->p_buffer
, readsize
);
187 time
= mdate() - time
;
190 block_Release(p_block
);
196 p_block
->i_buffer
= (size_t) ret
;
197 consumed
+= p_block
->i_buffer
;
198 if((size_t)ret
< readsize
)
200 connManager
->updateDownloadRate(sourceid
, p_block
->i_buffer
, time
);
206 bool HTTPChunkSource::prepare(int i_redir
)
216 connection
= connManager
->getConnection(params
);
221 int i_ret
= connection
->request(params
.getPath(), bytesRange
);
222 if(i_ret
!= VLC_SUCCESS
)
224 if(i_ret
== VLC_ETIMEOUT
&& i_redir
< 3)
225 return HTTPChunkSource::prepare(i_redir
+ 1);
228 /* Because we don't know Chunk size at start, we need to get size
229 from content length */
230 contentLength
= connection
->getContentLength();
236 block_t
* HTTPChunkSource::readBlock()
238 return read(HTTPChunkSource::CHUNK_SIZE
);
241 HTTPChunkBufferedSource::HTTPChunkBufferedSource(const std::string
& url
, AbstractConnectionManager
*manager
,
242 const adaptive::ID
&sourceid
) :
243 HTTPChunkSource(url
, manager
, sourceid
),
248 vlc_mutex_init(&lock
);
249 vlc_cond_init(&avail
);
255 HTTPChunkBufferedSource::~HTTPChunkBufferedSource()
257 vlc_mutex_lock(&lock
);
260 block_ChainRelease(p_head
);
266 vlc_mutex_unlock(&lock
);
268 connManager
->cancel(this);
270 vlc_cond_destroy(&avail
);
271 vlc_mutex_destroy(&lock
);
274 bool HTTPChunkBufferedSource::isDone() const
277 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
279 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
283 void HTTPChunkBufferedSource::bufferize(size_t readsize
)
285 vlc_mutex_lock(&lock
);
290 vlc_cond_signal(&avail
);
291 vlc_mutex_unlock(&lock
);
295 if(readsize
< HTTPChunkSource::CHUNK_SIZE
)
296 readsize
= HTTPChunkSource::CHUNK_SIZE
;
298 if(contentLength
&& readsize
> contentLength
- buffered
)
299 readsize
= contentLength
- buffered
;
301 vlc_mutex_unlock(&lock
);
303 block_t
*p_block
= block_Alloc(readsize
);
316 ssize_t ret
= connection
->read(p_block
->p_buffer
, readsize
);
319 block_Release(p_block
);
320 vlc_mutex_lock(&lock
);
322 rate
.size
= buffered
+ consumed
;
323 rate
.time
= mdate() - downloadstart
;
325 vlc_mutex_unlock(&lock
);
329 p_block
->i_buffer
= (size_t) ret
;
330 vlc_mutex_lock(&lock
);
331 buffered
+= p_block
->i_buffer
;
332 block_ChainLastAppend(&pp_tail
, p_block
);
333 if((size_t) ret
< readsize
)
336 rate
.size
= buffered
+ consumed
;
337 rate
.time
= mdate() - downloadstart
;
340 vlc_mutex_unlock(&lock
);
345 connManager
->updateDownloadRate(sourceid
, rate
.size
, rate
.time
);
348 vlc_cond_signal(&avail
);
351 bool HTTPChunkBufferedSource::prepare()
355 downloadstart
= mdate();
356 return HTTPChunkSource::prepare();
361 bool HTTPChunkBufferedSource::hasMoreData() const
364 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
366 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
370 block_t
* HTTPChunkBufferedSource::readBlock()
372 block_t
*p_block
= NULL
;
374 vlc_mutex_lock(&lock
);
376 while(!p_head
&& !done
)
377 vlc_cond_wait(&avail
, &lock
);
382 p_block
= block_Alloc(0);
384 vlc_mutex_unlock(&lock
);
390 p_head
= p_head
->p_next
;
397 p_block
->p_next
= NULL
;
399 consumed
+= p_block
->i_buffer
;
400 buffered
-= p_block
->i_buffer
;
402 vlc_mutex_unlock(&lock
);
407 block_t
* HTTPChunkBufferedSource::read(size_t readsize
)
409 vlc_mutex_lock(&lock
);
411 while(readsize
> buffered
&& !done
)
412 vlc_cond_wait(&avail
, &lock
);
414 block_t
*p_block
= NULL
;
415 if(!readsize
|| !buffered
|| !(p_block
= block_Alloc(readsize
)) )
418 vlc_mutex_unlock(&lock
);
423 while(buffered
&& readsize
)
425 const size_t toconsume
= std::min(p_head
->i_buffer
, readsize
);
426 memcpy(&p_block
->p_buffer
[copied
], p_head
->p_buffer
, toconsume
);
428 readsize
-= toconsume
;
429 buffered
-= toconsume
;
430 p_head
->i_buffer
-= toconsume
;
431 p_head
->p_buffer
+= toconsume
;
432 if(p_head
->i_buffer
== 0)
434 block_t
*next
= p_head
->p_next
;
435 p_head
->p_next
= NULL
;
436 block_Release(p_head
);
444 p_block
->i_buffer
= copied
;
446 if(copied
< readsize
)
449 vlc_mutex_unlock(&lock
);
454 HTTPChunk::HTTPChunk(const std::string
&url
, AbstractConnectionManager
*manager
,
455 const adaptive::ID
&id
):
456 AbstractChunk(new HTTPChunkSource(url
, manager
, id
))
461 HTTPChunk::~HTTPChunk()