[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