Experimental support for https transfers in stagefright.
Change-Id: If1bd0f265dda136c7c34b53317f64383023b53a3
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -189,7 +189,8 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) {
|
||||
|
||||
if (!strncasecmp(url, "file://", 7)) {
|
||||
source = new FileSource(url + 7);
|
||||
} else if (strncasecmp(url, "http://", 7)) {
|
||||
} else if (strncasecmp(url, "http://", 7)
|
||||
&& strncasecmp(url, "https://", 8)) {
|
||||
return ERROR_UNSUPPORTED;
|
||||
} else {
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
HTTPStream();
|
||||
~HTTPStream();
|
||||
|
||||
status_t connect(const char *server, int port = 80);
|
||||
status_t connect(const char *server, int port = -1, bool https = false);
|
||||
status_t disconnect();
|
||||
|
||||
status_t send(const char *data, size_t size);
|
||||
@@ -71,6 +71,9 @@ private:
|
||||
|
||||
KeyedVector<AString, AString> mHeaders;
|
||||
|
||||
void *mSSLContext;
|
||||
void *mSSL;
|
||||
|
||||
HTTPStream(const HTTPStream &);
|
||||
HTTPStream &operator=(const HTTPStream &);
|
||||
};
|
||||
|
||||
@@ -57,6 +57,7 @@ private:
|
||||
String8 mHost;
|
||||
unsigned mPort;
|
||||
String8 mPath;
|
||||
bool mHTTPS;
|
||||
String8 mHeaders;
|
||||
String8 mUri;
|
||||
|
||||
@@ -83,6 +84,7 @@ private:
|
||||
|
||||
status_t connect(
|
||||
const char *host, unsigned port, const char *path,
|
||||
bool https,
|
||||
const String8 &headers,
|
||||
off64_t offset);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user