Merge pull request #4569 from ctrlaltdavid/20431

CR for Job #20431 - Remove XMLHttpRequest file reading and model uploading
This commit is contained in:
Brad Hefta-Gaub 2015-04-01 13:00:16 -07:00
commit 1de1527414
5 changed files with 27 additions and 925 deletions

View file

@ -16,8 +16,6 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include([
"libraries/stringHelpers.js",
"libraries/dataviewHelpers.js",
"libraries/httpMultiPart.js",
"libraries/modelUploader.js",
"libraries/toolBars.js",
"libraries/progressDialog.js",

View file

@ -1,693 +0,0 @@
//
// modelUploader.js
// examples/libraries
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
modelUploader = (function () {
var that = {},
modelFile,
modelName,
modelURL,
modelCallback,
isProcessing,
fstBuffer,
fbxBuffer,
//svoBuffer,
mapping,
geometry,
API_URL = "https://metaverse.highfidelity.com/api/v1/models",
MODEL_URL = "http://public.highfidelity.com/models/content",
NAME_FIELD = "name",
SCALE_FIELD = "scale",
FILENAME_FIELD = "filename",
TEXDIR_FIELD = "texdir",
MAX_TEXTURE_SIZE = 1024;
function info(message) {
if (progressDialog.isOpen()) {
progressDialog.update(message);
} else {
progressDialog.open(message);
}
print(message);
}
function error(message) {
if (progressDialog.isOpen()) {
progressDialog.close();
}
print(message);
Window.alert(message);
}
function randomChar(length) {
var characters = "0123457689abcdefghijklmnopqrstuvwxyz",
string = "",
i;
for (i = 0; i < length; i += 1) {
string += characters[Math.floor(Math.random() * 36)];
}
return string;
}
function resetDataObjects() {
fstBuffer = null;
fbxBuffer = null;
//svoBuffer = null;
mapping = {};
geometry = {};
geometry.textures = [];
geometry.embedded = [];
}
function readFile(filename) {
var url = "file:///" + filename,
req = new XMLHttpRequest();
req.open("GET", url, false);
req.responseType = "arraybuffer";
req.send();
if (req.status !== 200) {
error("Could not read file: " + filename + " : " + req.statusText);
return null;
}
return {
filename: filename.fileName(),
buffer: req.response
};
}
function readMapping(buffer) {
var dv = new DataView(buffer.buffer),
lines,
line,
tokens,
i,
name,
value,
remainder,
existing;
mapping = {}; // { name : value | name : { value : [remainder] } }
lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/);
for (i = 0; i < lines.length; i += 1) {
line = lines[i].trim();
if (line.length > 0 && line[0] !== "#") {
tokens = line.split(/\s*=\s*/);
if (tokens.length > 1) {
name = tokens[0];
value = tokens[1];
if (tokens.length > 2) {
remainder = tokens.slice(2, tokens.length).join(" = ");
} else {
remainder = null;
}
if (tokens.length === 2 && mapping[name] === undefined) {
mapping[name] = value;
} else {
if (mapping[name] === undefined) {
mapping[name] = {};
} else if (typeof mapping[name] !== "object") {
existing = mapping[name];
mapping[name] = { existing : null };
}
if (mapping[name][value] === undefined) {
mapping[name][value] = [];
}
mapping[name][value].push(remainder);
}
}
}
}
}
function writeMapping(buffer) {
var name,
value,
remainder,
i,
string = "";
for (name in mapping) {
if (mapping.hasOwnProperty(name)) {
if (typeof mapping[name] === "object") {
for (value in mapping[name]) {
if (mapping[name].hasOwnProperty(value)) {
remainder = mapping[name][value];
if (remainder === null) {
string += (name + " = " + value + "\n");
} else {
for (i = 0; i < remainder.length; i += 1) {
string += (name + " = " + value + " = " + remainder[i] + "\n");
}
}
}
}
} else {
string += (name + " = " + mapping[name] + "\n");
}
}
}
buffer.buffer = string.toArrayBuffer();
}
function readGeometry(fbxBuffer) {
var textures,
view,
index,
EOF,
previousNodeFilename;
// Reference:
// http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/
textures = {};
view = new DataView(fbxBuffer.buffer);
EOF = false;
function parseBinaryFBX() {
var endOffset,
numProperties,
propertyListLength,
nameLength,
name,
filename;
endOffset = view.getUint32(index, true);
numProperties = view.getUint32(index + 4, true);
propertyListLength = view.getUint32(index + 8, true);
nameLength = view.getUint8(index + 12);
index += 13;
if (endOffset === 0) {
return;
}
if (endOffset < index || endOffset > view.byteLength) {
EOF = true;
return;
}
name = view.string(index, nameLength).toLowerCase();
index += nameLength;
if (name === "content" && previousNodeFilename !== "") {
// Blender 2.71 exporter "embeds" external textures as empty binary blobs so ignore these
if (propertyListLength > 5) {
geometry.embedded.push(previousNodeFilename);
}
}
if (name === "relativefilename") {
filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName();
if (!textures.hasOwnProperty(filename)) {
textures[filename] = "";
geometry.textures.push(filename);
}
previousNodeFilename = filename;
} else {
previousNodeFilename = "";
}
index += (propertyListLength);
while (index < endOffset && !EOF) {
parseBinaryFBX();
}
}
function readTextFBX() {
var line,
view,
viewLength,
charCode,
charCodes,
numCharCodes,
filename,
relativeFilename = "",
MAX_CHAR_CODES = 250;
view = new Uint8Array(fbxBuffer.buffer);
viewLength = view.byteLength;
charCodes = [];
numCharCodes = 0;
for (index = 0; index < viewLength; index += 1) {
charCode = view[index];
if (charCode !== 9 && charCode !== 32) {
if (charCode === 10) { // EOL. Can ignore EOF.
line = String.fromCharCode.apply(String, charCodes).toLowerCase();
// For embedded textures, "Content:" line immediately follows "RelativeFilename:" line.
if (line.slice(0, 8) === "content:" && relativeFilename !== "") {
geometry.embedded.push(relativeFilename);
}
if (line.slice(0, 17) === "relativefilename:") {
filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName();
if (!textures.hasOwnProperty(filename)) {
textures[filename] = "";
geometry.textures.push(filename);
}
relativeFilename = filename;
} else {
relativeFilename = "";
}
charCodes = [];
numCharCodes = 0;
} else {
if (numCharCodes < MAX_CHAR_CODES) { // Only interested in start of line
charCodes.push(charCode);
numCharCodes += 1;
}
}
}
}
}
readTextFBX();
}
function readModel() {
var fbxFilename,
//svoFilename,
fileType;
info("Reading model file");
print("Model file: " + modelFile);
if (modelFile.toLowerCase().fileType() === "fst") {
fstBuffer = readFile(modelFile);
if (fstBuffer === null) {
return false;
}
readMapping(fstBuffer);
fileType = mapping[FILENAME_FIELD].toLowerCase().fileType();
if (mapping.hasOwnProperty(FILENAME_FIELD)) {
if (fileType === "fbx") {
fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD];
//} else if (fileType === "svo") {
// svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD];
} else {
error("Unrecognized model type in FST file!");
return false;
}
} else {
error("Model file name not found in FST file!");
return false;
}
} else {
fstBuffer = {
filename: "Interface." + randomChar(6), // Simulate avatar model uploading behaviour
buffer: null
};
if (modelFile.toLowerCase().fileType() === "fbx") {
fbxFilename = modelFile;
mapping[FILENAME_FIELD] = modelFile.fileName();
//} else if (modelFile.toLowerCase().fileType() === "svo") {
// svoFilename = modelFile;
// mapping[FILENAME_FIELD] = modelFile.fileName();
} else {
error("Unrecognized file type: " + modelFile);
return false;
}
}
if (!isProcessing) { return false; }
if (fbxFilename) {
fbxBuffer = readFile(fbxFilename);
if (fbxBuffer === null) {
return false;
}
if (!isProcessing) { return false; }
readGeometry(fbxBuffer);
}
//if (svoFilename) {
// svoBuffer = readFile(svoFilename);
// if (svoBuffer === null) {
// return false;
// }
//}
// Add any missing basic mappings
if (!mapping.hasOwnProperty(NAME_FIELD)) {
mapping[NAME_FIELD] = modelFile.fileName().fileBase();
}
if (!mapping.hasOwnProperty(TEXDIR_FIELD)) {
mapping[TEXDIR_FIELD] = ".";
}
if (!mapping.hasOwnProperty(SCALE_FIELD)) {
mapping[SCALE_FIELD] = 1.0;
}
return true;
}
function setProperties() {
var form = [],
directory,
displayAs,
validateAs;
progressDialog.close();
print("Setting model properties");
form.push({ label: "Name:", value: mapping[NAME_FIELD] });
directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD];
displayAs = new RegExp("^" + modelFile.path().regExpEscape() + "[\\\\\\\/](.*)");
validateAs = new RegExp("^" + modelFile.path().regExpEscape() + "([\\\\\\\/].*)?");
form.push({
label: "Texture directory:",
directory: modelFile.path() + "/" + mapping[TEXDIR_FIELD],
title: "Choose Texture Directory",
displayAs: displayAs,
validateAs: validateAs,
errorMessage: "Texture directory must be subdirectory of the model directory."
});
form.push({ button: "Cancel" });
if (!Window.form("Set Model Properties", form)) {
print("User cancelled uploading model");
return false;
}
mapping[NAME_FIELD] = form[0].value;
mapping[TEXDIR_FIELD] = form[1].directory.slice(modelFile.path().length + 1);
if (mapping[TEXDIR_FIELD] === "") {
mapping[TEXDIR_FIELD] = ".";
}
writeMapping(fstBuffer);
return true;
}
function createHttpMessage(callback) {
var multiparts = [],
lodCount,
lodFile,
lodBuffer,
textureBuffer,
textureSourceFormat,
textureTargetFormat,
embeddedTextures,
i;
info("Preparing to send model");
// Model name
if (mapping.hasOwnProperty(NAME_FIELD)) {
multiparts.push({
name : "model_name",
string : mapping[NAME_FIELD]
});
} else {
error("Model name is missing");
httpMultiPart.clear();
return;
}
// FST file
if (fstBuffer) {
multiparts.push({
name : "fst",
buffer: fstBuffer
});
}
// FBX file
if (fbxBuffer) {
multiparts.push({
name : "fbx",
buffer: fbxBuffer
});
}
// SVO file
//if (svoBuffer) {
// multiparts.push({
// name : "svo",
// buffer: svoBuffer
// });
//}
// LOD files
lodCount = 0;
for (lodFile in mapping.lod) {
if (mapping.lod.hasOwnProperty(lodFile)) {
lodBuffer = readFile(modelFile.path() + "\/" + lodFile);
if (lodBuffer === null) {
return;
}
multiparts.push({
name: "lod" + lodCount,
buffer: lodBuffer
});
lodCount += 1;
}
if (!isProcessing) { return; }
}
// Textures
embeddedTextures = "|" + geometry.embedded.join("|") + "|";
for (i = 0; i < geometry.textures.length; i += 1) {
if (embeddedTextures.indexOf("|" + geometry.textures[i].fileName() + "|") === -1) {
textureBuffer = readFile(modelFile.path() + "\/"
+ (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "")
+ geometry.textures[i]);
if (textureBuffer === null) {
return;
}
textureSourceFormat = geometry.textures[i].fileType().toLowerCase();
textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png");
textureBuffer.buffer =
textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE);
textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat;
multiparts.push({
name: "texture" + i,
buffer: textureBuffer
});
}
if (!isProcessing) { return; }
}
// Model category
multiparts.push({
name : "model_category",
string : "content"
});
// Create HTTP message
httpMultiPart.clear();
Script.setTimeout(function addMultipart() {
var multipart = multiparts.shift();
httpMultiPart.add(multipart);
if (!isProcessing) { return; }
if (multiparts.length > 0) {
Script.setTimeout(addMultipart, 25);
} else {
callback();
}
}, 25);
}
function sendToHighFidelity() {
var req,
uploadedChecks,
HTTP_GET_TIMEOUT = 60, // 1 minute
HTTP_SEND_TIMEOUT = 900, // 15 minutes
UPLOADED_CHECKS = 30,
CHECK_UPLOADED_TIMEOUT = 1, // 1 second
handleCheckUploadedResponses,
handleUploadModelResponses,
handleRequestUploadResponses;
function uploadTimedOut() {
error("Model upload failed: Internet request timed out!");
}
function debugResponse() {
print("req.errorCode = " + req.errorCode);
print("req.readyState = " + req.readyState);
print("req.status = " + req.status);
print("req.statusText = " + req.statusText);
print("req.responseType = " + req.responseType);
print("req.responseText = " + req.responseText);
print("req.response = " + req.response);
print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders());
}
function checkUploaded() {
if (!isProcessing) { return; }
info("Checking uploaded model");
req = new XMLHttpRequest();
req.open("HEAD", modelURL, true);
req.timeout = HTTP_GET_TIMEOUT * 1000;
req.onreadystatechange = handleCheckUploadedResponses;
req.ontimeout = uploadTimedOut;
req.send();
}
handleCheckUploadedResponses = function () {
//debugResponse();
if (req.readyState === req.DONE) {
if (req.status === 200) {
// Note: Unlike avatar models, for content models we don't need to refresh texture cache.
print("Model uploaded: " + modelURL);
progressDialog.close();
if (Window.confirm("Your model has been uploaded as: " + modelURL + "\nDo you want to rez it?")) {
modelCallback(modelURL);
}
} else if (req.status === 404) {
if (uploadedChecks > 0) {
uploadedChecks -= 1;
Script.setTimeout(checkUploaded, CHECK_UPLOADED_TIMEOUT * 1000);
} else {
print("Error: " + req.status + " " + req.statusText);
error("We could not verify that your model was successfully uploaded but it may have been at: "
+ modelURL);
}
} else {
print("Error: " + req.status + " " + req.statusText);
error("There was a problem with your upload, please try again later.");
}
}
};
function uploadModel(method) {
var url;
if (!isProcessing) { return; }
req = new XMLHttpRequest();
if (method === "PUT") {
url = API_URL + "\/" + modelName;
req.open("PUT", url, true); //print("PUT " + url);
} else {
url = API_URL;
req.open("POST", url, true); //print("POST " + url);
}
req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\"");
req.timeout = HTTP_SEND_TIMEOUT * 1000;
req.onreadystatechange = handleUploadModelResponses;
req.ontimeout = uploadTimedOut;
req.send(httpMultiPart.response().buffer);
}
handleUploadModelResponses = function () {
//debugResponse();
if (req.readyState === req.DONE) {
if (req.status === 200) {
uploadedChecks = UPLOADED_CHECKS;
checkUploaded();
} else {
print("Error: " + req.status + " " + req.statusText);
error("There was a problem with your upload, please try again later.");
}
}
};
function requestUpload() {
var url;
if (!isProcessing) { return; }
url = API_URL + "\/" + modelName; // XMLHttpRequest automatically handles authorization of API requests.
req = new XMLHttpRequest();
req.open("GET", url, true); //print("GET " + url);
req.responseType = "json";
req.timeout = HTTP_GET_TIMEOUT * 1000;
req.onreadystatechange = handleRequestUploadResponses;
req.ontimeout = uploadTimedOut;
req.send();
}
handleRequestUploadResponses = function () {
var response;
//debugResponse();
if (req.readyState === req.DONE) {
if (req.status === 200) {
if (req.responseType === "json") {
response = JSON.parse(req.responseText);
if (response.status === "success") {
if (response.exists === false) {
uploadModel("POST");
} else if (response.can_update === true) {
uploadModel("PUT");
} else {
error("This model file already exists and is owned by someone else!");
}
return;
}
}
} else {
print("Error: " + req.status + " " + req.statusText);
}
error("Model upload failed! Something went wrong at the data server.");
}
};
info("Sending model to High Fidelity");
requestUpload();
}
that.upload = function (file, callback) {
modelFile = file;
modelCallback = callback;
isProcessing = true;
progressDialog.onCancel = function () {
print("User cancelled uploading model");
isProcessing = false;
};
resetDataObjects();
if (readModel()) {
if (setProperties()) {
modelName = mapping[NAME_FIELD];
modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST
createHttpMessage(sendToHighFidelity);
}
}
resetDataObjects();
};
return that;
}());

View file

@ -145,98 +145,3 @@ test("Test timeout", function() {
this.assertEquals(0, req.status, "status should be `0`");
this.assertEquals(4, req.errorCode, "4 is the timeout error code for QNetworkReply::NetworkError");
});
var localFile = Window.browse("Find defaultScripts.js file ...", "", "defaultScripts.js (defaultScripts.js)");
if (localFile !== null) {
localFile = "file:///" + localFile;
test("Test GET local file synchronously", function () {
var req = new XMLHttpRequest();
var statesVisited = [true, false, false, false, false]
req.onreadystatechange = function () {
statesVisited[req.readyState] = true;
};
req.open("GET", localFile, false);
req.send();
this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
this.assertEquals(200, req.status, "status should be `200`");
this.assertEquals("OK", req.statusText, "statusText should be `OK`");
this.assertEquals(0, req.errorCode);
this.assertNotEquals("", req.getAllResponseHeaders(), "headers should not be null");
this.assertContains("High Fidelity", req.response.substring(0, 100), "expected text not found in response")
for (var i = 0; i <= req.DONE; i++) {
this.assertEquals(true, statesVisited[i], i + " should be set");
}
});
test("Test GET nonexistent local file", function () {
var nonexistentFile = localFile.replace(".js", "NoExist.js");
var req = new XMLHttpRequest();
req.open("GET", nonexistentFile, false);
req.send();
this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
this.assertEquals(404, req.status, "status should be `404`");
this.assertEquals("Not Found", req.statusText, "statusText should be `Not Found`");
this.assertNotEquals(0, req.errorCode);
});
test("Test GET local file already open", function () {
// Can't open file exclusively in order to test.
});
test("Test GET local file with data not implemented", function () {
var req = new XMLHttpRequest();
req.open("GET", localFile, true);
req.send("data");
this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
this.assertEquals(501, req.status, "status should be `501`");
this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
this.assertNotEquals(0, req.errorCode);
});
test("Test GET local file asynchronously not implemented", function () {
var req = new XMLHttpRequest();
req.open("GET", localFile, true);
req.send();
this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
this.assertEquals(501, req.status, "status should be `501`");
this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
this.assertNotEquals(0, req.errorCode);
});
test("Test POST local file not implemented", function () {
var req = new XMLHttpRequest();
req.open("POST", localFile, false);
req.send();
this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
this.assertEquals(501, req.status, "status should be `501`");
this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
this.assertNotEquals(0, req.errorCode);
});
test("Test local file username and password not implemented", function () {
var req = new XMLHttpRequest();
req.open("GET", localFile, false, "username", "password");
req.send();
this.assertEquals(req.DONE, req.readyState, "readyState should be DONE");
this.assertEquals(501, req.status, "status should be `501`");
this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`");
this.assertNotEquals(0, req.errorCode);
});
} else {
print("Local file operation not tested");
}

View file

@ -13,15 +13,14 @@
//
#include <QEventLoop>
#include <QFile>
#include <qurlquery.h>
#include <AccountManager.h>
#include <NetworkAccessManager.h>
#include <NetworkingConstants.h>
#include <AccountManager.h>
#include "XMLHttpRequestClass.h"
#include "ScriptEngine.h"
#include "XMLHttpRequestClass.h"
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/";
@ -42,7 +41,6 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
_onReadyStateChange(QScriptValue::NullValue),
_readyState(XMLHttpRequestClass::UNSENT),
_errorCode(QNetworkReply::NoError),
_file(NULL),
_timeout(0),
_timer(this),
_numRedirects(0) {
@ -63,22 +61,6 @@ QScriptValue XMLHttpRequestClass::getStatus() const {
if (_reply) {
return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
}
if(_url.isLocalFile()) {
switch (_errorCode) {
case QNetworkReply::NoError:
return QScriptValue(200);
case QNetworkReply::ContentNotFoundError:
return QScriptValue(404);
case QNetworkReply::ContentConflictError:
return QScriptValue(409);
case QNetworkReply::TimeoutError:
return QScriptValue(408);
case QNetworkReply::ContentOperationNotPermittedError:
return QScriptValue(501);
default:
break;
}
}
return QScriptValue(0);
}
@ -86,22 +68,6 @@ QString XMLHttpRequestClass::getStatusText() const {
if (_reply) {
return _reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
}
if (_url.isLocalFile()) {
switch (_errorCode) {
case QNetworkReply::NoError:
return "OK";
case QNetworkReply::ContentNotFoundError:
return "Not Found";
case QNetworkReply::ContentConflictError:
return "Conflict";
case QNetworkReply::TimeoutError:
return "Timeout";
case QNetworkReply::ContentOperationNotPermittedError:
return "Not Implemented";
default:
break;
}
}
return "";
}
@ -147,13 +113,6 @@ QScriptValue XMLHttpRequestClass::getAllResponseHeaders() const {
}
return QString(headers.data());
}
if (_url.isLocalFile()) {
QString headers = QString("Content-Type: application/octet-stream\n");
headers.append("Content-Length: ");
headers.append(QString("%1").arg(_rawResponseData.length()));
headers.append("\n");
return headers;
}
return QScriptValue("");
}
@ -161,14 +120,6 @@ QScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const {
if (_reply && _reply->hasRawHeader(name.toLatin1())) {
return QScriptValue(QString(_reply->rawHeader(name.toLatin1())));
}
if (_url.isLocalFile()) {
if (name.toLower() == "content-type") {
return QString("application/octet-stream");
}
if (name.toLower() == "content-length") {
return QString("%1").arg(_rawResponseData.length());
}
}
return QScriptValue::NullValue;
}
@ -188,47 +139,24 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
_url.setUrl(url);
_async = async;
if (_url.isLocalFile()) {
if (_method.toUpper() == "GET" && !_async && username.isEmpty() && password.isEmpty()) {
_file = new QFile(_url.toLocalFile());
if (!_file->exists()) {
qDebug() << "Can't find file " << _url.fileName();
abortRequest();
_errorCode = QNetworkReply::ContentNotFoundError;
setReadyState(DONE);
emit requestComplete();
} else if (!_file->open(QIODevice::ReadOnly)) {
qDebug() << "Can't open file " << _url.fileName();
abortRequest();
_errorCode = QNetworkReply::ContentConflictError;
setReadyState(DONE);
emit requestComplete();
} else {
setReadyState(OPENED);
}
} else {
notImplemented();
}
} else {
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
AccountManager& accountManager = AccountManager::getInstance();
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.hasValidAccessToken()) {
QUrlQuery urlQuery(_url.query());
urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token);
_url.setQuery(urlQuery);
}
if (accountManager.hasValidAccessToken()) {
QUrlQuery urlQuery(_url.query());
urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token);
_url.setQuery(urlQuery);
}
}
if (!username.isEmpty()) {
_url.setUserName(username);
}
if (!password.isEmpty()) {
_url.setPassword(password);
}
_request.setUrl(_url);
setReadyState(OPENED);
}
if (!username.isEmpty()) {
_url.setUserName(username);
}
if (!password.isEmpty()) {
_url.setPassword(password);
}
_request.setUrl(_url);
setReadyState(OPENED);
}
}
@ -239,23 +167,18 @@ void XMLHttpRequestClass::send() {
void XMLHttpRequestClass::send(const QScriptValue& data) {
if (_readyState == OPENED && !_reply) {
if (!data.isNull()) {
if (_url.isLocalFile()) {
notImplemented();
return;
_sendData = new QBuffer(this);
if (data.isObject()) {
QByteArray ba = qscriptvalue_cast<QByteArray>(data);
_sendData->setData(ba);
} else {
_sendData = new QBuffer(this);
if (data.isObject()) {
QByteArray ba = qscriptvalue_cast<QByteArray>(data);
_sendData->setData(ba);
} else {
_sendData->setData(data.toString().toUtf8());
}
_sendData->setData(data.toString().toUtf8());
}
}
doSend();
if (!_async && !_url.isLocalFile()) {
if (!_async) {
QEventLoop loop;
connect(this, SIGNAL(requestComplete()), &loop, SLOT(quit()));
loop.exec();
@ -265,23 +188,13 @@ void XMLHttpRequestClass::send(const QScriptValue& data) {
void XMLHttpRequestClass::doSend() {
if (!_url.isLocalFile()) {
_reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
connectToReply(_reply);
}
_reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData);
connectToReply(_reply);
if (_timeout > 0) {
_timer.start(_timeout);
connect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout()));
}
if (_url.isLocalFile()) {
setReadyState(HEADERS_RECEIVED);
setReadyState(LOADING);
_rawResponseData = _file->readAll();
_file->close();
requestFinished();
}
}
void XMLHttpRequestClass::requestTimeout() {
@ -300,16 +213,10 @@ void XMLHttpRequestClass::requestError(QNetworkReply::NetworkError code) {
void XMLHttpRequestClass::requestFinished() {
disconnect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout()));
if (!_url.isLocalFile()) {
_errorCode = _reply->error();
} else {
_errorCode = QNetworkReply::NoError;
}
_errorCode = _reply->error();
if (_errorCode == QNetworkReply::NoError) {
if (!_url.isLocalFile()) {
_rawResponseData.append(_reply->readAll());
}
_rawResponseData.append(_reply->readAll());
if (_responseType == "json") {
_responseData = _engine->evaluate("(" + QString(_rawResponseData.data()) + ")");
@ -338,19 +245,6 @@ void XMLHttpRequestClass::abortRequest() {
_reply->deleteLater();
_reply = NULL;
}
if (_file != NULL) {
_file->close();
_file = NULL;
}
}
void XMLHttpRequestClass::notImplemented() {
abortRequest();
//_errorCode = QNetworkReply::OperationNotImplementedError; TODO: Use this status code when update to Qt 5.3
_errorCode = QNetworkReply::ContentOperationNotPermittedError;
setReadyState(DONE);
emit requestComplete();
}
void XMLHttpRequestClass::connectToReply(QNetworkReply* reply) {

View file

@ -97,7 +97,6 @@ private:
void connectToReply(QNetworkReply* reply);
void disconnectFromReply(QNetworkReply* reply);
void abortRequest();
void notImplemented();
QScriptEngine* _engine;
bool _async;
@ -113,7 +112,6 @@ private:
QScriptValue _onReadyStateChange;
ReadyState _readyState;
QNetworkReply::NetworkError _errorCode;
QFile* _file;
int _timeout;
QTimer _timer;
int _numRedirects;