Commit 0e86ff50 authored by François Cartegnie's avatar François Cartegnie 🤞

demux: adaptative: merge and simplify the http stuff

Allows using tls transport and does
non persistent connection fallback.
parent 6c16d751
......@@ -327,10 +327,8 @@ libdash_plugin_la_SOURCES += \
demux/adaptative/http/HTTPConnection.h \
demux/adaptative/http/HTTPConnectionManager.cpp \
demux/adaptative/http/HTTPConnectionManager.h \
demux/adaptative/http/IHTTPConnection.cpp \
demux/adaptative/http/IHTTPConnection.h \
demux/adaptative/http/PersistentConnection.cpp \
demux/adaptative/http/PersistentConnection.h \
demux/adaptative/http/Sockets.hpp \
demux/adaptative/http/Sockets.cpp \
demux/adaptative/PlaylistManager.cpp \
demux/adaptative/PlaylistManager.h \
demux/adaptative/SegmentTracker.cpp \
......
......@@ -102,7 +102,7 @@ bool PlaylistManager::start(demux_t *demux)
}
}
conManager = new (std::nothrow) HTTPConnectionManager(stream);
conManager = new (std::nothrow) HTTPConnectionManager(VLC_OBJECT(stream));
if(!conManager)
return false;
......
......@@ -20,7 +20,7 @@
#define __STDC_CONSTANT_MACROS
#include "Streams.hpp"
#include "StreamsType.hpp"
#include "http/HTTPConnection.h"
#include "http/HTTPConnection.hpp"
#include "http/HTTPConnectionManager.h"
#include "http/Chunk.h"
#include "logic/AbstractAdaptationLogic.h"
......@@ -179,21 +179,22 @@ size_t Stream::read(HTTPConnectionManager *connManager)
size_t readsize = 0;
/* Because we don't know Chunk size at start, we need to get size
from content length */
/* New chunk, do query */
if(chunk->getBytesRead() == 0)
{
if(chunk->getConnection()->query(chunk->getPath()) == false)
readsize = 32768; /* we don't handle retry here :/ */
else
readsize = chunk->getBytesToRead();
}
else
{
readsize = chunk->getBytesToRead();
if(chunk->getConnection()->query(chunk->getPath()) != VLC_SUCCESS)
{
chunk->getConnection()->releaseChunk();
currentChunk = NULL;
delete chunk;
return 0;
}
}
if (readsize > 128000)
/* Because we don't know Chunk size at start, we need to get size
from content length */
readsize = chunk->getBytesToRead();
if (readsize > 32768)
readsize = 32768;
block_t *block = block_Alloc(readsize);
......@@ -204,7 +205,7 @@ size_t Stream::read(HTTPConnectionManager *connManager)
ssize_t ret = chunk->getConnection()->read(block->p_buffer, readsize);
time = mdate() - time;
if(ret <= 0)
if(ret < 0)
{
block_Release(block);
chunk->getConnection()->releaseChunk();
......
......@@ -44,7 +44,13 @@ Chunk::Chunk (const std::string& url) :
{
this->url = url;
if(url.compare(0, 7, "http://"))
std::size_t pos = url.find("://");
if(pos != std::string::npos)
{
scheme = url.substr(0, pos);
}
if(scheme != "http" && scheme != "https")
throw VLC_EGENERIC;
vlc_url_t url_components;
......@@ -52,7 +58,8 @@ Chunk::Chunk (const std::string& url) :
if(url_components.psz_path)
path = url_components.psz_path;
port = url_components.i_port ? url_components.i_port : 80;
port = url_components.i_port ? url_components.i_port :
((scheme == "https") ? 443 : 80);
if(url_components.psz_host)
hostname = url_components.psz_host;
......@@ -103,6 +110,12 @@ int Chunk::getBitrate ()
{
return this->bitrate;
}
const std::string& Chunk::getScheme () const
{
return scheme;
}
const std::string& Chunk::getHostname () const
{
return hostname;
......
......@@ -44,6 +44,7 @@ namespace adaptative
size_t getEndByte () const;
size_t getStartByte () const;
const std::string& getUrl () const;
const std::string& getScheme () const;
const std::string& getHostname () const;
const std::string& getPath () const;
int getPort () const;
......@@ -68,6 +69,7 @@ namespace adaptative
private:
std::string url;
std::string scheme;
std::string path;
std::string hostname;
std::vector<std::string> optionalUrls;
......
/*
* HTTPConnection.cpp
*****************************************************************************
* Copyright (C) 2010 - 2011 Klagenfurt University
*
* Created on: Aug 10, 2010
* Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
* Christian Timmerer <christian.timmerer@itec.uni-klu.ac.at>
* Copyright (C) 2014-2015 - VideoLAN Authors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
......@@ -21,29 +17,186 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "HTTPConnection.h"
#include "HTTPConnection.hpp"
#include "Sockets.hpp"
#include "Chunk.h"
#include "../adaptative/tools/Helper.h"
#include <sstream>
using namespace adaptative::http;
HTTPConnection::HTTPConnection (stream_t *stream, Chunk *chunk_) :
IHTTPConnection (stream)
HTTPConnection::HTTPConnection(vlc_object_t *stream_, Socket *socket_,
Chunk *chunk_, bool persistent)
{
socket = socket_;
stream = stream_;
psz_useragent = var_InheritString(stream, "http-user-agent");
toRead = 0;
chunk = NULL;
queryOk = false;
retries = 0;
connectionClose = !persistent;
bindChunk(chunk_);
}
std::string HTTPConnection::buildRequestHeader(const std::string &path) const
HTTPConnection::~HTTPConnection()
{
free(psz_useragent);
delete socket;
}
bool HTTPConnection::connect(const std::string &hostname, int port)
{
if(!socket->connect(stream, hostname.c_str(), port))
return false;
this->hostname = hostname;
return true;
}
bool HTTPConnection::connected() const
{
return socket->connected();
}
void HTTPConnection::disconnect()
{
queryOk = false;
toRead = 0;
socket->disconnect();
}
int HTTPConnection::query(const std::string &path)
{
if(!chunk)
return VLC_EGENERIC;
queryOk = false;
if(!connected() &&
!connect(chunk->getHostname(), chunk->getPort()))
return VLC_EGENERIC;
std::string header = buildRequestHeader(path);
if(connectionClose)
header.append("Connection: close\r\n");
header.append("\r\n");
if(!send( header ))
{
socket->disconnect();
if(!connectionClose)
{
/* server closed connection pipeline after last req. need new */
connectionClose = true;
return query(path);
}
return VLC_EGENERIC;
}
int i_ret = parseReply();
if(i_ret == VLC_SUCCESS)
{
queryOk = true;
}
else if(i_ret == VLC_EGENERIC)
{
socket->disconnect();
if(!connectionClose)
{
connectionClose = true;
return query(path);
}
}
return i_ret;
}
ssize_t HTTPConnection::read(void *p_buffer, size_t len)
{
std::string req = IHTTPConnection::buildRequestHeader(path);
return req.append("Connection: close\r\n");
if(!chunk || !connected() ||
(!queryOk && chunk->getBytesRead() == 0) )
return VLC_EGENERIC;
if(len == 0)
return VLC_SUCCESS;
queryOk = false;
if(chunk->getBytesToRead() == 0)
return VLC_SUCCESS;
if(len > chunk->getBytesToRead())
len = chunk->getBytesToRead();
ssize_t ret = socket->read(stream, p_buffer, len, true);
if(ret >= 0)
chunk->setBytesRead(chunk->getBytesRead() + ret);
if(ret < 0 || (size_t)ret < len) /* set EOF */
{
chunk->setBytesToRead(chunk->getBytesRead());
socket->disconnect();
return VLC_EGENERIC;
}
return ret;
}
bool HTTPConnection::send(const std::string &data)
{
return send(data.c_str(), data.length());
}
bool HTTPConnection::send(const void *buf, size_t size)
{
return socket->send(stream, buf, size);
}
int HTTPConnection::parseReply()
{
std::string line = readLine();
if(line.empty())
return VLC_EGENERIC;
if (line.compare(0, 9, "HTTP/1.1 ")!=0)
return VLC_ENOOBJ;
std::istringstream ss(line.substr(9));
int replycode;
ss >> replycode;
if (replycode != 200 && replycode != 206)
return VLC_ENOOBJ;
readLine();
while(!line.empty() && line.compare("\r\n"))
{
size_t split = line.find_first_of(':');
size_t value = split + 1;
while(line.at(value) == ' ')
value++;
onHeader(line.substr(0, split), line.substr(value));
line = readLine();
}
return VLC_SUCCESS;
}
std::string HTTPConnection::readLine()
{
return socket->readline(stream);
}
const std::string& HTTPConnection::getHostname() const
{
return hostname;
}
void HTTPConnection::bindChunk(Chunk *chunk_)
......@@ -57,6 +210,15 @@ void HTTPConnection::bindChunk(Chunk *chunk_)
void HTTPConnection::releaseChunk()
{
if(!connectionClose &&
(!chunk || chunk->getBytesRead() == toRead) ) /* We can't resend request if we haven't finished reading */
{
queryOk = false;
toRead = 0;
}
else
disconnect();
if(chunk)
{
chunk->setConnection(NULL);
......@@ -64,6 +226,11 @@ void HTTPConnection::releaseChunk()
}
}
bool HTTPConnection::isAvailable() const
{
return chunk == NULL;
}
void HTTPConnection::onHeader(const std::string &key,
const std::string &value)
{
......@@ -75,6 +242,20 @@ void HTTPConnection::onHeader(const std::string &key,
chunk->setLength(length);
toRead = length;
}
else if (key == "Connection" && value =="close")
{
connectionClose = true;
}
}
std::string HTTPConnection::buildRequestHeader(const std::string &path) const
{
std::stringstream req;
req << "GET " << path << " HTTP/1.1\r\n" <<
"Host: " << hostname << "\r\n" <<
"User-Agent: " << std::string(psz_useragent) << "\r\n";
req << extraRequestHeaders();
return req.str();
}
std::string HTTPConnection::extraRequestHeaders() const
......@@ -89,13 +270,3 @@ std::string HTTPConnection::extraRequestHeaders() const
}
return ss.str();
}
bool HTTPConnection::isAvailable() const
{
return chunk == NULL;
}
void HTTPConnection::disconnect()
{
toRead = 0;
}
/*
* IHTTPConnection.h
* HTTPConnection.hpp
*****************************************************************************
* Copyright (C) 2010 - 2011 Klagenfurt University
* 2014 - 2015 VideoLAN Authors
*
* Created on: Aug 10, 2010
* Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
......@@ -21,9 +22,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef IHTTPCONNECTION_H_
#define IHTTPCONNECTION_H_
#ifndef HTTPCONNECTION_H_
#define HTTPCONNECTION_H_
#ifdef HAVE_CONFIG_H
# include "config.h"
......@@ -36,37 +36,52 @@ namespace adaptative
{
namespace http
{
class IHTTPConnection
class Socket;
class Chunk;
class HTTPConnection
{
public:
IHTTPConnection(stream_t *stream);
virtual ~IHTTPConnection();
HTTPConnection(vlc_object_t *stream, Socket *, Chunk * = NULL, bool = false);
virtual ~HTTPConnection();
virtual bool connect (const std::string& hostname, int port = 80);
virtual bool connected () const;
virtual bool query (const std::string& path);
virtual int query (const std::string& path);
virtual bool send (const void *buf, size_t size);
virtual ssize_t read (void *p_buffer, size_t len);
virtual void disconnect ();
virtual bool send (const std::string &data);
const std::string& getHostname () const;
virtual void bindChunk (Chunk *chunk);
virtual bool isAvailable () const;
virtual void releaseChunk();
protected:
virtual void onHeader (const std::string &key,
const std::string &value) = 0;
virtual std::string extraRequestHeaders() const = 0;
virtual void onHeader (const std::string &line,
const std::string &value);
virtual std::string extraRequestHeaders() const;
virtual std::string buildRequestHeader(const std::string &path) const;
bool parseReply();
int parseReply();
std::string readLine();
std::string hostname;
char * psz_useragent;
stream_t *stream;
vlc_object_t *stream;
size_t toRead;
Chunk *chunk;
bool connectionClose;
bool queryOk;
int retries;
static const int retryCount = 5;
private:
int httpSocket;
};
Socket *socket;
};
}
}
#endif /* IHTTPCONNECTION_H_ */
#endif /* HTTPCONNECTION_H_ */
......@@ -26,16 +26,15 @@
#endif
#include "HTTPConnectionManager.h"
#include "PersistentConnection.h"
#include "HTTPConnection.hpp"
#include "Chunk.h"
#include <vlc_stream.h>
#include "Sockets.hpp"
using namespace adaptative::http;
const uint64_t HTTPConnectionManager::CHUNKDEFAULTBITRATE = 1;
HTTPConnectionManager::HTTPConnectionManager (stream_t *stream) :
HTTPConnectionManager::HTTPConnectionManager (vlc_object_t *stream) :
stream (stream)
{
}
......@@ -52,14 +51,14 @@ void HTTPConnectionManager::closeAllConnections ()
void HTTPConnectionManager::releaseAllConnections()
{
std::vector<PersistentConnection *>::iterator it;
std::vector<HTTPConnection *>::iterator it;
for(it = connectionPool.begin(); it != connectionPool.end(); ++it)
(*it)->releaseChunk();
}
PersistentConnection * HTTPConnectionManager::getConnectionForHost(const std::string &hostname)
HTTPConnection * HTTPConnectionManager::getConnectionForHost(const std::string &hostname)
{
std::vector<PersistentConnection *>::const_iterator it;
std::vector<HTTPConnection *>::const_iterator it;
for(it = connectionPool.begin(); it != connectionPool.end(); ++it)
{
if(!(*it)->getHostname().compare(hostname) && (*it)->isAvailable())
......@@ -75,14 +74,20 @@ bool HTTPConnectionManager::connectChunk(Chunk *chunk)
if(chunk->getConnection())
return true;
msg_Dbg(stream, "Retrieving %s", chunk->getUrl().c_str());
msg_Dbg(stream, "Retrieving %s @%ld", chunk->getUrl().c_str(), chunk->getStartByte());
PersistentConnection *conn = getConnectionForHost(chunk->getHostname());
HTTPConnection *conn = getConnectionForHost(chunk->getHostname());
if(!conn)
{
conn = new PersistentConnection(stream, chunk);
Socket *socket = new (std::nothrow) Socket();
if(!socket)
return false;
conn = new (std::nothrow) HTTPConnection(stream, socket, chunk, true);
if(!conn)
{
delete socket;
return false;
}
connectionPool.push_back(conn);
if (!chunk->getConnection()->connect(chunk->getHostname(), chunk->getPort()))
return false;
......
......@@ -37,13 +37,13 @@ namespace adaptative
{
namespace http
{
class PersistentConnection;
class HTTPConnection;
class Chunk;
class HTTPConnectionManager
{
public:
HTTPConnectionManager (stream_t *stream);
HTTPConnectionManager (vlc_object_t *stream);
virtual ~HTTPConnectionManager ();
void closeAllConnections ();
......@@ -51,12 +51,12 @@ namespace adaptative
bool connectChunk (Chunk *chunk);
private:
std::vector<PersistentConnection *> connectionPool;
stream_t *stream;
std::vector<HTTPConnection *> connectionPool;
vlc_object_t *stream;
static const uint64_t CHUNKDEFAULTBITRATE;
PersistentConnection * getConnectionForHost (const std::string &hostname);
HTTPConnection * getConnectionForHost (const std::string &hostname);
};
}
}
......
/*
* IHTTPConnection.cpp
*****************************************************************************
* Copyright (C) 2014 - VideoLAN Authors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "IHTTPConnection.h"
#include "Chunk.h"
#include "../adaptative/tools/Helper.h"
#include <vlc_network.h>
#include <vlc_stream.h>