[vlc-devel] [PATCH] demux/adaptive: handle redirections in HTTPConnection
Zhao Zhili
wantlamy at gmail.com
Fri Jul 7 03:44:53 CEST 2017
On Wed, Jul 5, 2017 at 6:28 PM, Zhao Zhili <wantlamy at gmail.com> wrote:
> ---
> modules/demux/adaptive/http/HTTPConnection.cpp | 66
> +++++++++++++++++---------
> modules/demux/adaptive/http/HTTPConnection.hpp | 16 +++++--
> 2 files changed, 55 insertions(+), 27 deletions(-)
>
> diff --git a/modules/demux/adaptive/http/HTTPConnection.cpp
> b/modules/demux/adaptive/http/HTTPConnection.cpp
> index a250d87..0b2f7f8 100644
> --- a/modules/demux/adaptive/http/HTTPConnection.cpp
> +++ b/modules/demux/adaptive/http/HTTPConnection.cpp
> @@ -65,7 +65,6 @@ HTTPConnection::HTTPConnection(vlc_object_t *p_object_,
> Socket *socket_, bool pe
> socket = socket_;
> psz_useragent = var_InheritString(p_object_, "http-user-agent");
> queryOk = false;
> - retries = 0;
> connectionClose = !persistent;
> chunked = false;
> chunked_eof = false;
> @@ -108,27 +107,24 @@ void HTTPConnection::disconnect()
> socket->disconnect();
> }
>
> -int HTTPConnection::request(const std::string &path, const BytesRange
> &range)
> +HTTPConnection::HTTPErrorType HTTPConnection::doRequest(const BytesRange
> &range)
> {
> queryOk = false;
> chunked = false;
> chunked_eof = false;
> chunkLength = 0;
>
> - /* Set new path for this query */
> - params.setPath(path);
> -
> msg_Dbg(p_object, "Retrieving %s @%zu", params.getUrl().c_str(),
> range.isValid() ? range.getStartByte() : 0);
>
> if(!connected() && ( params.getHostname().empty() || !connect() ))
> - return VLC_EGENERIC;
> + return HTTPGenericError;
>
> bytesRange = range;
> if(range.isValid() && range.getEndByte() > 0)
> contentLength = range.getEndByte() - range.getStartByte() + 1;
>
> - std::string header = buildRequestHeader(path);
> + std::string header = buildRequestHeader();
> if(connectionClose)
> header.append("Connection: close\r\n");
> header.append("\r\n");
> @@ -140,17 +136,20 @@ int HTTPConnection::request(const std::string &path,
> const BytesRange &range)
> {
> /* server closed connection pipeline after last req. need new
> */
> connectionClose = true;
> - return request(path, range);
> + return doRequest(range);
> + }
> + else
> + {
> + return HTTPGenericError;
> }
> - return VLC_EGENERIC;
> }
>
> - int i_ret = parseReply();
> - if(i_ret == VLC_SUCCESS)
> + HTTPConnection::HTTPErrorType i_ret = parseReply();
> + if(i_ret == HTTPSuccess)
> {
> queryOk = true;
> }
> - else if(i_ret == VLC_ETIMEOUT) /* redir */
> + else if(i_ret == HTTPRedirect) /* redir */
> {
> socket->disconnect();
> if(locationparams.getScheme().empty())
> @@ -159,19 +158,40 @@ int HTTPConnection::request(const std::string &path,
> const BytesRange &range)
> params = locationparams;
> locationparams = ConnectionParams();
> }
> - else if(i_ret == VLC_EGENERIC)
> + else if(i_ret == HTTPGenericError)
> {
> socket->disconnect();
> if(!connectionClose)
> {
> connectionClose = true;
> - return request(path, range);
> + return doRequest(range);
> }
> }
>
> return i_ret;
> }
>
> +int HTTPConnection::request(const std::string &path, const BytesRange
> &range)
> +{
> + /* Set new path for this query */
> + params.setPath(path);
> +
> + for(int retries = 0; retries < maxRedirectCount; retries++)
> + {
> + HTTPConnection::HTTPErrorType ret = doRequest(range);
> + if (ret == HTTPSuccess)
> + return VLC_SUCCESS;
> + else if (ret == HTTPGenericError)
> + return VLC_EGENERIC;
> + else if (ret == HTTPRedirect)
> + continue;
> + else
> + break;
> + }
> +
> + return VLC_EGENERIC;
> +}
> +
> ssize_t HTTPConnection::read(void *p_buffer, size_t len)
> {
> if( !connected() ||
> @@ -215,17 +235,17 @@ bool HTTPConnection::send(const void *buf, size_t
> size)
> return socket->send(p_object, buf, size);
> }
>
> -int HTTPConnection::parseReply()
> +HTTPConnection::HTTPErrorType HTTPConnection::parseReply()
> {
> std::string line = readLine();
>
> if(line.empty())
> - return VLC_EGENERIC;
> + return HTTPGenericError;
>
> if (line.compare(0, 9, "HTTP/1.1 ")!=0)
> {
> if(line.compare(0, 9, "HTTP/1.0 ")!=0)
> - return VLC_ENOOBJ;
> + return HTTPGenericError;
> else
> connectionClose = true;
> }
> @@ -254,15 +274,15 @@ int HTTPConnection::parseReply()
> !locationparams.getUrl().empty())
> {
> msg_Info(p_object, "%d redirection to %s", replycode,
> locationparams.getUrl().c_str());
> - return VLC_ETIMEOUT;
> + return HTTPRedirect;
> }
> else if (replycode != 200 && replycode != 206)
> {
> - msg_Err(p_object, "Failed reading %s: %s",
> params.getUrl().c_str(), line.c_str());
> - return VLC_ENOOBJ;
> + msg_Err(p_object, "%d Failed reading %s: %s", replycode,
> params.getUrl().c_str(), line.c_str());
> + return HTTPGenericError;
> }
>
> - return VLC_SUCCESS;
> + return HTTPSuccess;
> }
>
> ssize_t HTTPConnection::readChunk(void *p_buffer, size_t len)
> @@ -360,10 +380,10 @@ void HTTPConnection::onHeader(const std::string &key,
> }
> }
>
> -std::string HTTPConnection::buildRequestHeader(const std::string &path)
> const
> +std::string HTTPConnection::buildRequestHeader() const
> {
> std::stringstream req;
> - req << "GET " << path << " HTTP/1.1\r\n" <<
> + req << "GET " << params.getPath() << " HTTP/1.1\r\n" <<
> "Host: " << params.getHostname() << "\r\n" <<
> "Cache-Control: no-cache" << "\r\n" <<
> "User-Agent: " << std::string(psz_useragent) << "\r\n";
> diff --git a/modules/demux/adaptive/http/HTTPConnection.hpp
> b/modules/demux/adaptive/http/HTTPConnection.hpp
> index 85ca53b..707e604 100644
> --- a/modules/demux/adaptive/http/HTTPConnection.hpp
> +++ b/modules/demux/adaptive/http/HTTPConnection.hpp
> @@ -73,6 +73,15 @@ namespace adaptive
> void setUsed( bool );
>
> protected:
> + enum HTTPErrorType
> + {
> + HTTPSuccess = 0,
> + HTTPGenericError,
> + HTTPRedirect,
> + };
> +
> + virtual HTTPConnection::HTTPErrorType doRequest(const
> BytesRange &range);
> +
> virtual bool connected () const;
> virtual bool connect ();
> virtual void disconnect ();
> @@ -82,10 +91,10 @@ namespace adaptive
> 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;
> + virtual std::string buildRequestHeader() const;
>
> ssize_t readChunk (void *p_buffer, size_t len);
> - int parseReply();
> + HTTPConnection::HTTPErrorType parseReply();
> std::string readLine();
> char * psz_useragent;
>
> @@ -95,8 +104,7 @@ namespace adaptive
> bool chunked_eof;
> size_t chunkLength;
> bool queryOk;
> - int retries;
> - static const int retryCount = 5;
> + static const int maxRedirectCount = 5;
>
> private:
> Socket *socket;
> --
> 2.7.4
>
Ping for review.
HTTPChunkSource::prepare() didn't handle redirect to a different path since
it always pass
the old path to connection->request(params.getPath(), bytesRange).
There are two choices:
1. Add an interface to extract the new params from AbstractConnection
2. Handle redirect in HTTPConnection::request().
Since StreamUrlConnection::request() already handle redirect by
access_New(), I prefer the
second choice.
Any opinion is welcome.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20170707/42926c9e/attachment.html>
More information about the vlc-devel
mailing list