Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 118a150a authored by Andreas Huber's avatar Andreas Huber
Browse files

Experimental support for https transfers in stagefright.

Change-Id: If1bd0f265dda136c7c34b53317f64383023b53a3
parent 572c4a7d
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -58,7 +58,8 @@ LOCAL_C_INCLUDES:= \
        $(TOP)/frameworks/base/include/media/stagefright/openmax \
        $(TOP)/external/flac/include \
        $(TOP)/external/tremolo \
        $(TOP)/frameworks/base/media/libstagefright/rtsp
        $(TOP)/frameworks/base/media/libstagefright/rtsp \
        $(TOP)/external/openssl/include \

LOCAL_SHARED_LIBRARIES := \
        libbinder         \
@@ -72,7 +73,8 @@ LOCAL_SHARED_LIBRARIES := \
        libstagefright_yuv \
        libcamera_client \
        libdrmframework  \
        libcrypto
        libcrypto        \
        libssl

LOCAL_STATIC_LIBRARIES := \
        libstagefright_color_conversion \
+2 −1
Original line number Diff line number Diff line
@@ -1481,7 +1481,8 @@ status_t AwesomePlayer::prepareAsync_l() {
status_t AwesomePlayer::finishSetDataSource_l() {
    sp<DataSource> dataSource;

    if (!strncasecmp("http://", mUri.string(), 7)) {
    if (!strncasecmp("http://", mUri.string(), 7)
            || !strncasecmp("https://", mUri.string(), 8)) {
        mConnectingDataSource = new NuHTTPDataSource;

        mLock.unlock();
+2 −1
Original line number Diff line number Diff line
@@ -125,7 +125,8 @@ sp<DataSource> DataSource::CreateFromURI(
    sp<DataSource> source;
    if (!strncasecmp("file://", uri, 7)) {
        source = new FileSource(uri + 7);
    } else if (!strncasecmp("http://", uri, 7)) {
    } else if (!strncasecmp("http://", uri, 7)
            || !strncasecmp("https://", uri, 8)) {
        sp<NuHTTPDataSource> httpSource = new NuHTTPDataSource;
        if (httpSource->connect(uri, headers) != OK) {
            return NULL;
+94 −5
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@

#include <media/stagefright/foundation/ADebug.h>

#include <openssl/ssl.h>

namespace android {

// static
@@ -41,11 +43,18 @@ const char *HTTPStream::kStatusKey = ":status:"; // MUST be lowercase.

HTTPStream::HTTPStream()
    : mState(READY),
      mSocket(-1) {
      mSocket(-1),
      mSSLContext(NULL),
      mSSL(NULL) {
}

HTTPStream::~HTTPStream() {
    disconnect();

    if (mSSLContext != NULL) {
        SSL_CTX_free((SSL_CTX *)mSSLContext);
        mSSLContext = NULL;
    }
}

static bool MakeSocketBlocking(int s, bool blocking) {
@@ -198,7 +207,11 @@ static ssize_t MyReceive(int s, void *data, size_t size, int flags) {
    return MySendReceive(s, data, size, flags, false /* sendData */);
}

status_t HTTPStream::connect(const char *server, int port) {
status_t HTTPStream::connect(const char *server, int port, bool https) {
    if (port < 0) {
        port = https ? 443 : 80;
    }

    Mutex::Autolock autoLock(mLock);

    status_t err = OK;
@@ -249,6 +262,47 @@ status_t HTTPStream::connect(const char *server, int port) {
        return res;
    }

    if (https) {
        CHECK(mSSL == NULL);

        if (mSSLContext == NULL) {
            SSL_library_init();

            mSSLContext = SSL_CTX_new(TLSv1_client_method());

            if (mSSLContext == NULL) {
                LOGE("failed to create SSL context");
                mState = READY;
                return ERROR_IO;
            }
        }

        mSSL = SSL_new((SSL_CTX *)mSSLContext);

        if (mSSL == NULL) {
            LOGE("failed to create SSL session");

            mState = READY;
            return ERROR_IO;
        }

        int res = SSL_set_fd((SSL *)mSSL, mSocket);

        if (res == 1) {
            res = SSL_connect((SSL *)mSSL);
        }

        if (res != 1) {
            SSL_free((SSL *)mSSL);
            mSSL = NULL;

            LOGE("failed to connect over SSL");
            mState = READY;

            return ERROR_IO;
        }
    }

    mState = CONNECTED;

    return OK;
@@ -261,6 +315,13 @@ status_t HTTPStream::disconnect() {
        return ERROR_NOT_CONNECTED;
    }

    if (mSSL != NULL) {
        SSL_shutdown((SSL *)mSSL);

        SSL_free((SSL *)mSSL);
        mSSL = NULL;
    }

    CHECK(mSocket >= 0);
    close(mSocket);
    mSocket = -1;
@@ -276,7 +337,16 @@ status_t HTTPStream::send(const char *data, size_t size) {
    }

    while (size > 0) {
        ssize_t n = MySend(mSocket, data, size, 0);
        ssize_t n;
        if (mSSL != NULL) {
            n = SSL_write((SSL *)mSSL, data, size);

            if (n < 0) {
                n = -SSL_get_error((SSL *)mSSL, n);
            }
        } else {
            n = MySend(mSocket, data, size, 0);
        }

        if (n < 0) {
            disconnect();
@@ -317,7 +387,17 @@ status_t HTTPStream::receive_line(char *line, size_t size) {

    for (;;) {
        char c;
        ssize_t n = MyReceive(mSocket, &c, 1, 0);
        ssize_t n;
        if (mSSL != NULL) {
            n = SSL_read((SSL *)mSSL, &c, 1);

            if (n < 0) {
                n = -SSL_get_error((SSL *)mSSL, n);
            }
        } else {
            n = MyReceive(mSocket, &c, 1, 0);
        }

        if (n < 0) {
            disconnect();

@@ -437,7 +517,16 @@ status_t HTTPStream::receive_header(int *http_status) {
ssize_t HTTPStream::receive(void *data, size_t size) {
    size_t total = 0;
    while (total < size) {
        ssize_t n = MyReceive(mSocket, (char *)data + total, size - total, 0);
        ssize_t n;
        if (mSSL != NULL) {
            n = SSL_read((SSL *)mSSL, (char *)data + total, size - total);

            if (n < 0) {
                n = -SSL_get_error((SSL *)mSSL, n);
            }
        } else {
            n = MyReceive(mSocket, (char *)data + total, size - total, 0);
        }

        if (n < 0) {
            LOGE("recv failed, errno = %d (%s)", (int)n, strerror(-n));
+23 −11
Original line number Diff line number Diff line
@@ -24,22 +24,30 @@ static bool ParseSingleUnsignedLong(
}

static bool ParseURL(
        const char *url, String8 *host, unsigned *port, String8 *path) {
        const char *url, String8 *host, unsigned *port,
        String8 *path, bool *https) {
    host->setTo("");
    *port = 0;
    path->setTo("");

    if (strncasecmp("http://", url, 7)) {
    size_t hostStart;
    if (!strncasecmp("http://", url, 7)) {
        hostStart = 7;
        *https = false;
    } else if (!strncasecmp("https://", url, 8)) {
        hostStart = 8;
        *https = true;
    } else {
        return false;
    }

    const char *slashPos = strchr(&url[7], '/');
    const char *slashPos = strchr(&url[hostStart], '/');

    if (slashPos == NULL) {
        host->setTo(&url[7]);
        host->setTo(&url[hostStart]);
        path->setTo("/");
    } else {
        host->setTo(&url[7], slashPos - &url[7]);
        host->setTo(&url[hostStart], slashPos - &url[hostStart]);
        path->setTo(slashPos);
    }

@@ -57,7 +65,7 @@ static bool ParseURL(
        String8 tmp(host->string(), colonOffset);
        *host = tmp;
    } else {
        *port = 80;
        *port = (*https) ? 443 : 80;
    }

    return true;
@@ -66,6 +74,7 @@ static bool ParseURL(
NuHTTPDataSource::NuHTTPDataSource()
    : mState(DISCONNECTED),
      mPort(0),
      mHTTPS(false),
      mOffset(0),
      mContentLength(0),
      mContentLengthValid(false),
@@ -111,11 +120,12 @@ status_t NuHTTPDataSource::connect(

    mUri = uri;

    if (!ParseURL(uri, &host, &port, &path)) {
    bool https;
    if (!ParseURL(uri, &host, &port, &path, &https)) {
        return ERROR_MALFORMED;
    }

    return connect(host, port, path, headers, offset);
    return connect(host, port, path, https, headers, offset);
}

static bool IsRedirectStatusCode(int httpStatus) {
@@ -125,6 +135,7 @@ static bool IsRedirectStatusCode(int httpStatus) {

status_t NuHTTPDataSource::connect(
        const char *host, unsigned port, const char *path,
        bool https,
        const String8 &headers,
        off64_t offset) {
    LOGI("connect to %s:%u%s @%lld", host, port, path, offset);
@@ -132,7 +143,7 @@ status_t NuHTTPDataSource::connect(
    bool needsToReconnect = true;

    if (mState == CONNECTED && host == mHost && port == mPort
            && offset == mOffset) {
            && https == mHTTPS && offset == mOffset) {
        if (mContentLengthValid && mOffset == mContentLength) {
            LOGI("Didn't have to reconnect, old one's still good.");
            needsToReconnect = false;
@@ -142,6 +153,7 @@ status_t NuHTTPDataSource::connect(
    mHost = host;
    mPort = port;
    mPath = path;
    mHTTPS = https;
    mHeaders = headers;

    status_t err = OK;
@@ -150,7 +162,7 @@ status_t NuHTTPDataSource::connect(

    if (needsToReconnect) {
        mHTTP.disconnect();
        err = mHTTP.connect(host, port);
        err = mHTTP.connect(host, port, https);
    }

    if (err != OK) {
@@ -353,7 +365,7 @@ ssize_t NuHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
        String8 host = mHost;
        String8 path = mPath;
        String8 headers = mHeaders;
        status_t err = connect(host, mPort, path, headers, offset);
        status_t err = connect(host, mPort, path, mHTTPS, headers, offset);

        if (err != OK) {
            return err;
Loading