mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-01-18 23:17:59 +01:00
Do a native (Qt) request if the 'Referer' header was supplied
This commit is contained in:
parent
4e9a088af4
commit
655e63f261
@ -277,6 +277,35 @@ Tomahawk.syncRequest = function (url, extraHeaders, options) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal counter used to identify asyncRequest callback from native code.
|
||||
*/
|
||||
Tomahawk.asyncRequestIdCounter = 0;
|
||||
/**
|
||||
* Internal map used to map asyncRequestIds to the respective javascript
|
||||
* callback functions.
|
||||
*/
|
||||
Tomahawk.asyncRequestCallbacks = {};
|
||||
|
||||
/**
|
||||
* Pass the natively retrived reply back to the javascript callback
|
||||
* and augment the fake XMLHttpRequest object.
|
||||
*
|
||||
* Internal use only!
|
||||
*/
|
||||
Tomahawk.nativeAsyncRequestDone = function (reqId, xhr) {
|
||||
// Check we have a matching callback stored.
|
||||
if (!Tomahawk.asyncRequestCallbacks.hasOwnProperty(reqId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the real callback
|
||||
Tomahawk.asyncRequestCallbacks[reqId](xhr);
|
||||
|
||||
// Callback are only used once.
|
||||
delete Tomahawk.asyncRequestCallbacks[reqId];
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible options:
|
||||
* - method: The HTTP request method (default: GET)
|
||||
@ -289,26 +318,40 @@ Tomahawk.asyncRequest = function (url, callback, extraHeaders, options) {
|
||||
// unpack options
|
||||
var opt = options || {};
|
||||
var method = opt.method || 'GET';
|
||||
var doNativeRequest = false;
|
||||
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open(method, url, true, opt.username, opt.password);
|
||||
if (extraHeaders) {
|
||||
for (var headerName in extraHeaders) {
|
||||
xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]);
|
||||
}
|
||||
if (extraHeaders && (extraHeaders.hasOwnProperty("Referer") || extraHeaders.hasOwnProperty("referer"))) {
|
||||
doNativeRequest = true;
|
||||
}
|
||||
xmlHttpRequest.onreadystatechange = function () {
|
||||
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) {
|
||||
callback.call(window, xmlHttpRequest);
|
||||
} else if (xmlHttpRequest.readyState === 4) {
|
||||
Tomahawk.log("Failed to do " + method + " request: to: " + url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
if (opt.hasOwnProperty('errorHandler')) {
|
||||
opt.errorHandler.call(window, xmlHttpRequest);
|
||||
|
||||
if (doNativeRequest) {
|
||||
// Assign a request Id to the callback so we can use it when we are
|
||||
// returning from the native call.
|
||||
var reqId = Tomahawk.asyncRequestIdCounter;
|
||||
Tomahawk.asyncRequestIdCounter++;
|
||||
Tomahawk.asyncRequestCallbacks[reqId] = callback;
|
||||
Tomahawk.nativeAsyncRequest(reqId, url, extraHeaders, options);
|
||||
} else {
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open(method, url, true, opt.username, opt.password);
|
||||
if (extraHeaders) {
|
||||
for (var headerName in extraHeaders) {
|
||||
xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlHttpRequest.send(opt.data || null);
|
||||
xmlHttpRequest.onreadystatechange = function () {
|
||||
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) {
|
||||
callback.call(window, xmlHttpRequest);
|
||||
} else if (xmlHttpRequest.readyState === 4) {
|
||||
Tomahawk.log("Failed to do " + method + " request: to: " + url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
if (opt.hasOwnProperty('errorHandler')) {
|
||||
opt.errorHandler.call(window, xmlHttpRequest);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlHttpRequest.send(opt.data || null);
|
||||
}
|
||||
};
|
||||
|
||||
Tomahawk.sha256 = Tomahawk.sha256 || CryptoJS.SHA256;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "resolvers/ScriptEngine.h"
|
||||
#include "network/Servent.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/Json.h"
|
||||
#include "utils/NetworkAccessManager.h"
|
||||
#include "utils/NetworkReply.h"
|
||||
#include "utils/Logger.h"
|
||||
@ -487,6 +488,69 @@ JSResolverHelper::reportStreamUrl( const QString& qid,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::nativeAsyncRequest( const int requestId, const QString& url,
|
||||
const QVariantMap& headers,
|
||||
const QVariantMap& options )
|
||||
{
|
||||
QNetworkRequest req( url );
|
||||
foreach ( const QString& key , headers.keys() ) {
|
||||
req.setRawHeader( key.toLatin1(), headers[key].toString().toLatin1() );
|
||||
}
|
||||
|
||||
if ( options.contains( "username" ) && options.contains( "password" ) )
|
||||
{
|
||||
// If we have sufficient authentication data, we will send
|
||||
// username+password as HTTP Basic Auth
|
||||
QString credentials = QString( "Basic %1" )
|
||||
.arg( QString( QString("%1:%2")
|
||||
.arg( options["username"].toString() )
|
||||
.arg( options["password"].toString() )
|
||||
.toLatin1().toBase64() )
|
||||
);
|
||||
req.setRawHeader( "Authorization", credentials.toLatin1() );
|
||||
}
|
||||
|
||||
NetworkReply* reply = NULL;
|
||||
if ( options.contains( "method") && options["method"].toString().toUpper() == "POST" ) {
|
||||
QByteArray data;
|
||||
if ( options.contains( "data" ) ) {
|
||||
data = options["data"].toString().toLatin1();
|
||||
}
|
||||
reply = new NetworkReply( Tomahawk::Utils::nam()->post( req, data ) );
|
||||
} else if ( options.contains( "method") && options["method"].toString().toUpper() == "HEAD" ) {
|
||||
reply = new NetworkReply( Tomahawk::Utils::nam()->head( req ) );
|
||||
} else {
|
||||
reply = new NetworkReply( Tomahawk::Utils::nam()->get( req ) );
|
||||
}
|
||||
|
||||
NewClosure( reply , SIGNAL( finished() ), this, SLOT( nativeAsyncRequestDone( int, NetworkReply* ) ), requestId, reply );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSResolverHelper::nativeAsyncRequestDone( int requestId, NetworkReply* reply )
|
||||
{
|
||||
QVariantMap map;
|
||||
map["response"] = QString::fromUtf8( reply->reply()->readAll() );
|
||||
map["responseText"] = map["response"];
|
||||
map["responseType"] = QString(); // Default, indicates a string in map["response"]
|
||||
map["readyState"] = 4;
|
||||
map["status"] = reply->reply()->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
|
||||
map["statusText"] = QString("%1 %2").arg( map["status"].toString() )
|
||||
.arg( reply->reply()->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString() );
|
||||
|
||||
bool ok = false;
|
||||
QString json = QString::fromUtf8( TomahawkUtils::toJson( map, &ok ) );
|
||||
Q_ASSERT( ok );
|
||||
|
||||
QString javascript = QString( "Tomahawk.nativeAsyncRequestDone( %1, %2 );" )
|
||||
.arg( QString::number( requestId ) )
|
||||
.arg( json );
|
||||
m_resolver->d_func()->engine->mainFrame()->evaluateJavaScript( javascript );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
JSResolverHelper::hasFuzzyIndex()
|
||||
{
|
||||
|
@ -49,6 +49,19 @@ public:
|
||||
Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl );
|
||||
Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl, const QVariantMap& headers );
|
||||
|
||||
/**
|
||||
* Native handler for asynchronous HTTP requests.
|
||||
*
|
||||
* This handler shall only be used if we cannot achieve the request with
|
||||
* XMLHttpRequest as that would be more efficient.
|
||||
* Use cases are:
|
||||
* * Referer header: Stripped on MacOS and the specification says it
|
||||
* should be stripped
|
||||
*/
|
||||
Q_INVOKABLE void nativeAsyncRequest( int requestId, const QString& url,
|
||||
const QVariantMap& headers,
|
||||
const QVariantMap& options );
|
||||
|
||||
/**
|
||||
* Clucene indices for JS resolvers
|
||||
**/
|
||||
@ -89,6 +102,7 @@ private slots:
|
||||
void gotStreamUrl( IODeviceCallback callback, NetworkReply* reply );
|
||||
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::ModelMode, const Tomahawk::collection_ptr& collection );
|
||||
void pltemplateTracksLoadedForUrl( const QString& url, const Tomahawk::playlisttemplate_ptr& pltemplate );
|
||||
void nativeAsyncRequestDone( int requestId, NetworkReply* reply );
|
||||
|
||||
private:
|
||||
Tomahawk::query_ptr parseTrack( const QVariantMap& track );
|
||||
|
Loading…
x
Reference in New Issue
Block a user