blob: 78345fcd99b225e001ec316e80a055f3bc9df2ef [file] [log] [blame] [edit]
// Copyright 2016 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
var Fetch = {
attr_t_offset_requestMethod: 0,
attr_t_offset_userData: 32,
attr_t_offset_onsuccess: 36,
attr_t_offset_onerror: 40,
attr_t_offset_onprogress: 44,
attr_t_offset_attributes: 48,
attr_t_offset_timeoutMSecs: 52,
attr_t_offset_withCredentials: 56,
attr_t_offset_destinationPath: 60,
attr_t_offset_userName: 64,
attr_t_offset_password: 68,
attr_t_offset_requestHeaders: 72,
attr_t_offset_overriddenMimeType: 76,
attr_t_offset_requestData: 80,
attr_t_offset_requestDataSize: 84,
fetch_t_offset_id: 0,
fetch_t_offset_userData: 4,
fetch_t_offset_url: 8,
fetch_t_offset_data: 12,
fetch_t_offset_numBytes: 16,
fetch_t_offset_dataOffset: 24,
fetch_t_offset_totalBytes: 32,
fetch_t_offset_readyState: 40,
fetch_t_offset_status: 42,
fetch_t_offset_statusText: 44,
fetch_t_offset___proxyState: 108,
fetch_t_offset___attributes: 112,
xhrs: [],
// The web worker that runs proxied file I/O requests.
worker: undefined,
// Specifies an instance to the IndexedDB database. The database is opened
// as a preload step before the Emscripten application starts.
dbInstance: undefined,
setu64: function(addr, val) {
HEAPU32[addr >> 2] = val;
HEAPU32[addr + 4 >> 2] = (val / 4294967296)|0;
},
openDatabase: function(dbname, dbversion, onsuccess, onerror) {
try {
#if FETCH_DEBUG
console.log('fetch: indexedDB.open(dbname="' + dbname + '", dbversion="' + dbversion + '");');
#endif
var openRequest = indexedDB.open(dbname, dbversion);
} catch (e) { return onerror(e); }
openRequest.onupgradeneeded = function(event) {
#if FETCH_DEBUG
console.log('fetch: IndexedDB upgrade needed. Clearing database.');
#endif
var db = event.target.result;
if (db.objectStoreNames.contains('FILES')) {
db.deleteObjectStore('FILES');
}
db.createObjectStore('FILES');
};
openRequest.onsuccess = function(event) { onsuccess(event.target.result); };
openRequest.onerror = function(error) { onerror(error); };
},
initFetchWorker: function() {
var stackSize = 128*1024;
var stack = allocate(stackSize>>2, "i32*", ALLOC_DYNAMIC);
Fetch.worker.postMessage({cmd: 'init', TOTAL_MEMORY: TOTAL_MEMORY, DYNAMICTOP_PTR: DYNAMICTOP_PTR, STACKTOP: stack, STACK_MAX: stack + stackSize, queuePtr: _fetch_work_queue, buffer: HEAPU8.buffer});
},
staticInit: function() {
#if USE_PTHREADS
var isMainThread = (typeof ENVIRONMENT_IS_FETCH_WORKER === 'undefined' && !ENVIRONMENT_IS_PTHREAD);
#else
var isMainThread = (typeof ENVIRONMENT_IS_FETCH_WORKER === 'undefined');
#endif
var onsuccess = function(db) {
#if FETCH_DEBUG
console.log('fetch: IndexedDB successfully opened.');
#endif
Fetch.dbInstance = db;
if (isMainThread) {
#if USE_PTHREADS
if (typeof SharedArrayBuffer !== 'undefined') Fetch.initFetchWorker();
#endif
removeRunDependency('library_fetch_init');
}
};
var onerror = function() {
#if FETCH_DEBUG
console.error('fetch: IndexedDB open failed.');
#endif
Fetch.dbInstance = false;
if (isMainThread) {
#if USE_PTHREADS
if (typeof SharedArrayBuffer !== 'undefined') Fetch.initFetchWorker();
#endif
removeRunDependency('library_fetch_init');
}
};
Fetch.openDatabase('emscripten_filesystem', 1, onsuccess, onerror);
#if USE_PTHREADS
if (isMainThread) {
addRunDependency('library_fetch_init');
// Allow HTML module to configure the location where the 'worker.js' file will be loaded from,
// via Module.locateFile() function. If not specified, then the default URL 'worker.js' relative
// to the main html file is loaded.
var fetchJs = locateFile('{{{ FETCH_WORKER_FILE }}}');
Fetch.worker = new Worker(fetchJs);
Fetch.worker.onmessage = function(e) {
out('fetch-worker sent a message: ' + e.filename + ':' + e.lineno + ': ' + e.message);
};
Fetch.worker.onerror = function(e) {
err('fetch-worker sent an error! ' + e.filename + ':' + e.lineno + ': ' + e.message);
};
}
#else
if (typeof ENVIRONMENT_IS_FETCH_WORKER === 'undefined' || !ENVIRONMENT_IS_FETCH_WORKER) addRunDependency('library_fetch_init');
#endif
}
}
function __emscripten_fetch_delete_cached_data(db, fetch, onsuccess, onerror) {
if (!db) {
#if FETCH_DEBUG
console.error('fetch: IndexedDB not available!');
#endif
onerror(fetch, 0, 'IndexedDB not available!');
return;
}
var fetch_attr = fetch + Fetch.fetch_t_offset___attributes;
var path = HEAPU32[fetch_attr + Fetch.attr_t_offset_destinationPath >> 2];
if (!path) path = HEAPU32[fetch + Fetch.fetch_t_offset_url >> 2];
var pathStr = UTF8ToString(path);
try {
var transaction = db.transaction(['FILES'], 'readwrite');
var packages = transaction.objectStore('FILES');
var request = packages.delete(pathStr);
request.onsuccess = function(event) {
var value = event.target.result;
#if FETCH_DEBUG
console.log('fetch: Deleted file ' + pathStr + ' from IndexedDB');
#endif
HEAPU32[fetch + Fetch.fetch_t_offset_data >> 2] = 0;
Fetch.setu64(fetch + Fetch.fetch_t_offset_numBytes, 0);
Fetch.setu64(fetch + Fetch.fetch_t_offset_dataOffset, 0);
Fetch.setu64(fetch + Fetch.fetch_t_offset_dataOffset, 0);
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 200; // Mimic XHR HTTP status code 200 "OK"
stringToUTF8("OK", fetch + Fetch.fetch_t_offset_statusText, 64);
onsuccess(fetch, 0, value);
};
request.onerror = function(error) {
#if FETCH_DEBUG
console.error('fetch: Failed to delete file ' + pathStr + ' from IndexedDB! error: ' + error);
#endif
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found"
stringToUTF8("Not Found", fetch + Fetch.fetch_t_offset_statusText, 64);
onerror(fetch, 0, error);
};
} catch(e) {
#if FETCH_DEBUG
console.error('fetch: Failed to load file ' + pathStr + ' from IndexedDB! Got exception ' + e);
#endif
onerror(fetch, 0, e);
}
}
function __emscripten_fetch_load_cached_data(db, fetch, onsuccess, onerror) {
if (!db) {
#if FETCH_DEBUG
console.error('fetch: IndexedDB not available!');
#endif
onerror(fetch, 0, 'IndexedDB not available!');
return;
}
var fetch_attr = fetch + Fetch.fetch_t_offset___attributes;
var path = HEAPU32[fetch_attr + Fetch.attr_t_offset_destinationPath >> 2];
if (!path) path = HEAPU32[fetch + Fetch.fetch_t_offset_url >> 2];
var pathStr = UTF8ToString(path);
try {
var transaction = db.transaction(['FILES'], 'readonly');
var packages = transaction.objectStore('FILES');
var getRequest = packages.get(pathStr);
getRequest.onsuccess = function(event) {
if (event.target.result) {
var value = event.target.result;
var len = value.byteLength || value.length;
#if FETCH_DEBUG
console.log('fetch: Loaded file ' + pathStr + ' from IndexedDB, length: ' + len);
#endif
// The data pointer malloc()ed here has the same lifetime as the emscripten_fetch_t structure itself has, and is
// freed when emscripten_fetch_close() is called.
var ptr = _malloc(len);
HEAPU8.set(new Uint8Array(value), ptr);
HEAPU32[fetch + Fetch.fetch_t_offset_data >> 2] = ptr;
Fetch.setu64(fetch + Fetch.fetch_t_offset_numBytes, len);
Fetch.setu64(fetch + Fetch.fetch_t_offset_dataOffset, 0);
Fetch.setu64(fetch + Fetch.fetch_t_offset_totalBytes, len);
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 200; // Mimic XHR HTTP status code 200 "OK"
stringToUTF8("OK", fetch + Fetch.fetch_t_offset_statusText, 64);
onsuccess(fetch, 0, value);
} else {
// Succeeded to load, but the load came back with the value of undefined, treat that as an error since we never store undefined in db.
#if FETCH_DEBUG
console.error('fetch: File ' + pathStr + ' not found in IndexedDB');
#endif
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found"
stringToUTF8("Not Found", fetch + Fetch.fetch_t_offset_statusText, 64);
onerror(fetch, 0, 'no data');
}
};
getRequest.onerror = function(error) {
#if FETCH_DEBUG
console.error('fetch: Failed to load file ' + pathStr + ' from IndexedDB!');
#endif
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found"
stringToUTF8("Not Found", fetch + Fetch.fetch_t_offset_statusText, 64);
onerror(fetch, 0, error);
};
} catch(e) {
#if FETCH_DEBUG
console.error('fetch: Failed to load file ' + pathStr + ' from IndexedDB! Got exception ' + e);
#endif
onerror(fetch, 0, e);
}
}
function __emscripten_fetch_cache_data(db, fetch, data, onsuccess, onerror) {
if (!db) {
#if FETCH_DEBUG
console.error('fetch: IndexedDB not available!');
#endif
onerror(fetch, 0, 'IndexedDB not available!');
return;
}
var fetch_attr = fetch + Fetch.fetch_t_offset___attributes;
var destinationPath = HEAPU32[fetch_attr + Fetch.attr_t_offset_destinationPath >> 2];
if (!destinationPath) destinationPath = HEAPU32[fetch + Fetch.fetch_t_offset_url >> 2];
var destinationPathStr = UTF8ToString(destinationPath);
try {
var transaction = db.transaction(['FILES'], 'readwrite');
var packages = transaction.objectStore('FILES');
var putRequest = packages.put(data, destinationPathStr);
putRequest.onsuccess = function(event) {
#if FETCH_DEBUG
console.log('fetch: Stored file "' + destinationPathStr + '" to IndexedDB cache.');
#endif
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 200; // Mimic XHR HTTP status code 200 "OK"
stringToUTF8("OK", fetch + Fetch.fetch_t_offset_statusText, 64);
onsuccess(fetch, 0, destinationPathStr);
};
putRequest.onerror = function(error) {
#if FETCH_DEBUG
console.error('fetch: Failed to store file "' + destinationPathStr + '" to IndexedDB cache!');
#endif
// Most likely we got an error if IndexedDB is unwilling to store any more data for this page.
// TODO: Can we identify and break down different IndexedDB-provided errors and convert those
// to more HTTP status codes for more information?
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete'
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = 413; // Mimic XHR HTTP status code 413 "Payload Too Large"
stringToUTF8("Payload Too Large", fetch + Fetch.fetch_t_offset_statusText, 64);
onerror(fetch, 0, error);
};
} catch(e) {
#if FETCH_DEBUG
console.error('fetch: Failed to store file "' + destinationPathStr + '" to IndexedDB cache! Exception: ' + e);
#endif
onerror(fetch, 0, e);
}
}
function __emscripten_fetch_xhr(fetch, onsuccess, onerror, onprogress) {
var url = HEAPU32[fetch + Fetch.fetch_t_offset_url >> 2];
if (!url) {
#if FETCH_DEBUG
console.error('fetch: XHR failed, no URL specified!');
#endif
onerror(fetch, 0, 'no url specified!');
return;
}
var url_ = UTF8ToString(url);
var fetch_attr = fetch + Fetch.fetch_t_offset___attributes;
var requestMethod = UTF8ToString(fetch_attr);
if (!requestMethod) requestMethod = 'GET';
var userData = HEAPU32[fetch_attr + Fetch.attr_t_offset_userData >> 2];
var fetchAttributes = HEAPU32[fetch_attr + Fetch.attr_t_offset_attributes >> 2];
var timeoutMsecs = HEAPU32[fetch_attr + Fetch.attr_t_offset_timeoutMSecs >> 2];
var withCredentials = !!HEAPU32[fetch_attr + Fetch.attr_t_offset_withCredentials >> 2];
var destinationPath = HEAPU32[fetch_attr + Fetch.attr_t_offset_destinationPath >> 2];
var userName = HEAPU32[fetch_attr + Fetch.attr_t_offset_userName >> 2];
var password = HEAPU32[fetch_attr + Fetch.attr_t_offset_password >> 2];
var requestHeaders = HEAPU32[fetch_attr + Fetch.attr_t_offset_requestHeaders >> 2];
var overriddenMimeType = HEAPU32[fetch_attr + Fetch.attr_t_offset_overriddenMimeType >> 2];
var dataPtr = HEAPU32[fetch_attr + Fetch.attr_t_offset_requestData >> 2];
var dataLength = HEAPU32[fetch_attr + Fetch.attr_t_offset_requestDataSize >> 2];
var fetchAttrLoadToMemory = !!(fetchAttributes & 1/*EMSCRIPTEN_FETCH_LOAD_TO_MEMORY*/);
var fetchAttrStreamData = !!(fetchAttributes & 2/*EMSCRIPTEN_FETCH_STREAM_DATA*/);
var fetchAttrPersistFile = !!(fetchAttributes & 4/*EMSCRIPTEN_FETCH_PERSIST_FILE*/);
var fetchAttrAppend = !!(fetchAttributes & 8/*EMSCRIPTEN_FETCH_APPEND*/);
var fetchAttrReplace = !!(fetchAttributes & 16/*EMSCRIPTEN_FETCH_REPLACE*/);
var fetchAttrNoDownload = !!(fetchAttributes & 32/*EMSCRIPTEN_FETCH_NO_DOWNLOAD*/);
var fetchAttrSynchronous = !!(fetchAttributes & 64/*EMSCRIPTEN_FETCH_SYNCHRONOUS*/);
var fetchAttrWaitable = !!(fetchAttributes & 128/*EMSCRIPTEN_FETCH_WAITABLE*/);
var userNameStr = userName ? UTF8ToString(userName) : undefined;
var passwordStr = password ? UTF8ToString(password) : undefined;
var overriddenMimeTypeStr = overriddenMimeType ? UTF8ToString(overriddenMimeType) : undefined;
var xhr = new XMLHttpRequest();
xhr.withCredentials = withCredentials;
#if FETCH_DEBUG
console.log('fetch: xhr.timeout: ' + xhr.timeout + ', xhr.withCredentials: ' + xhr.withCredentials);
console.log('fetch: xhr.open(requestMethod="' + requestMethod + '", url: "' + url_ +'", userName: ' + userNameStr + ', password: ' + passwordStr + ');');
#endif
xhr.open(requestMethod, url_, !fetchAttrSynchronous, userNameStr, passwordStr);
if (!fetchAttrSynchronous) xhr.timeout = timeoutMsecs; // XHR timeout field is only accessible in async XHRs, and must be set after .open() but before .send().
xhr.url_ = url_; // Save the url for debugging purposes (and for comparing to the responseURL that server side advertised)
xhr.responseType = fetchAttrStreamData ? 'moz-chunked-arraybuffer' : 'arraybuffer';
if (overriddenMimeType) {
#if FETCH_DEBUG
console.log('fetch: xhr.overrideMimeType("' + overriddenMimeTypeStr + '");');
#endif
xhr.overrideMimeType(overriddenMimeTypeStr);
}
if (requestHeaders) {
for(;;) {
var key = HEAPU32[requestHeaders >> 2];
if (!key) break;
var value = HEAPU32[requestHeaders + 4 >> 2];
if (!value) break;
requestHeaders += 8;
var keyStr = UTF8ToString(key);
var valueStr = UTF8ToString(value);
#if FETCH_DEBUG
console.log('fetch: xhr.setRequestHeader("' + keyStr + '", "' + valueStr + '");');
#endif
xhr.setRequestHeader(keyStr, valueStr);
}
}
Fetch.xhrs.push(xhr);
var id = Fetch.xhrs.length;
HEAPU32[fetch + Fetch.fetch_t_offset_id >> 2] = id;
var data = (dataPtr && dataLength) ? HEAPU8.slice(dataPtr, dataPtr + dataLength) : null;
// TODO: Support specifying custom headers to the request.
xhr.onload = function(e) {
var len = xhr.response ? xhr.response.byteLength : 0;
var ptr = 0;
var ptrLen = 0;
if (fetchAttrLoadToMemory && !fetchAttrStreamData) {
ptrLen = len;
#if FETCH_DEBUG
console.log('fetch: allocating ' + ptrLen + ' bytes in Emscripten heap for xhr data');
#endif
// The data pointer malloc()ed here has the same lifetime as the emscripten_fetch_t structure itself has, and is
// freed when emscripten_fetch_close() is called.
ptr = _malloc(ptrLen);
HEAPU8.set(new Uint8Array(xhr.response), ptr);
}
HEAPU32[fetch + Fetch.fetch_t_offset_data >> 2] = ptr;
Fetch.setu64(fetch + Fetch.fetch_t_offset_numBytes, ptrLen);
Fetch.setu64(fetch + Fetch.fetch_t_offset_dataOffset, 0);
if (len) {
// If the final XHR.onload handler receives the bytedata to compute total length, report that,
// otherwise don't write anything out here, which will retain the latest byte size reported in
// the most recent XHR.onprogress handler.
Fetch.setu64(fetch + Fetch.fetch_t_offset_totalBytes, len);
}
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = xhr.readyState;
if (xhr.readyState === 4 && xhr.status === 0) {
if (len > 0) xhr.status = 200; // If loading files from a source that does not give HTTP status code, assume success if we got data bytes.
else xhr.status = 404; // Conversely, no data bytes is 404.
}
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = xhr.status;
if (xhr.statusText) stringToUTF8(xhr.statusText, fetch + Fetch.fetch_t_offset_statusText, 64);
if (xhr.status >= 200 && xhr.status < 300) {
#if FETCH_DEBUG
console.log('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" succeeded with status 200');
#endif
if (onsuccess) onsuccess(fetch, xhr, e);
} else {
#if FETCH_DEBUG
console.error('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" failed with status ' + xhr.status);
#endif
if (onerror) onerror(fetch, xhr, e);
}
}
xhr.onerror = function(e) {
var status = xhr.status; // XXX TODO: Overwriting xhr.status doesn't work here, so don't override anywhere else either.
if (xhr.readyState == 4 && status == 0) status = 404; // If no error recorded, pretend it was 404 Not Found.
#if FETCH_DEBUG
console.error('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" finished with error, readyState ' + xhr.readyState + ' and status ' + status);
#endif
HEAPU32[fetch + Fetch.fetch_t_offset_data >> 2] = 0;
Fetch.setu64(fetch + Fetch.fetch_t_offset_numBytes, 0);
Fetch.setu64(fetch + Fetch.fetch_t_offset_dataOffset, 0);
Fetch.setu64(fetch + Fetch.fetch_t_offset_totalBytes, 0);
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = xhr.readyState;
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = status;
if (onerror) onerror(fetch, xhr, e);
}
xhr.ontimeout = function(e) {
#if FETCH_DEBUG
console.error('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" timed out, readyState ' + xhr.readyState + ' and status ' + xhr.status);
#endif
if (onerror) onerror(fetch, xhr, e);
}
xhr.onprogress = function(e) {
var ptrLen = (fetchAttrLoadToMemory && fetchAttrStreamData && xhr.response) ? xhr.response.byteLength : 0;
var ptr = 0;
if (fetchAttrLoadToMemory && fetchAttrStreamData) {
#if FETCH_DEBUG
console.log('fetch: allocating ' + ptrLen + ' bytes in Emscripten heap for xhr data');
#endif
// The data pointer malloc()ed here has the same lifetime as the emscripten_fetch_t structure itself has, and is
// freed when emscripten_fetch_close() is called.
ptr = _malloc(ptrLen);
HEAPU8.set(new Uint8Array(xhr.response), ptr);
}
HEAPU32[fetch + Fetch.fetch_t_offset_data >> 2] = ptr;
Fetch.setu64(fetch + Fetch.fetch_t_offset_numBytes, ptrLen);
Fetch.setu64(fetch + Fetch.fetch_t_offset_dataOffset, e.loaded - ptrLen);
Fetch.setu64(fetch + Fetch.fetch_t_offset_totalBytes, e.total);
HEAPU16[fetch + Fetch.fetch_t_offset_readyState >> 1] = xhr.readyState;
if (xhr.readyState >= 3 && xhr.status === 0 && e.loaded > 0) xhr.status = 200; // If loading files from a source that does not give HTTP status code, assume success if we get data bytes
HEAPU16[fetch + Fetch.fetch_t_offset_status >> 1] = xhr.status;
if (xhr.statusText) stringToUTF8(xhr.statusText, fetch + Fetch.fetch_t_offset_statusText, 64);
if (onprogress) onprogress(fetch, xhr, e);
}
#if FETCH_DEBUG
console.log('fetch: xhr.send(data=' + data + ')');
#endif
try {
xhr.send(data);
} catch(e) {
#if FETCH_DEBUG
console.error('fetch: xhr failed with exception: ' + e);
#endif
if (onerror) onerror(fetch, xhr, e);
}
}
function emscripten_start_fetch(fetch, successcb, errorcb, progresscb) {
if (typeof Module !== 'undefined') Module['noExitRuntime'] = true; // If we are the main Emscripten runtime, we should not be closing down.
var fetch_attr = fetch + Fetch.fetch_t_offset___attributes;
var requestMethod = UTF8ToString(fetch_attr);
var onsuccess = HEAPU32[fetch_attr + Fetch.attr_t_offset_onsuccess >> 2];
var onerror = HEAPU32[fetch_attr + Fetch.attr_t_offset_onerror >> 2];
var onprogress = HEAPU32[fetch_attr + Fetch.attr_t_offset_onprogress >> 2];
var fetchAttributes = HEAPU32[fetch_attr + Fetch.attr_t_offset_attributes >> 2];
var fetchAttrLoadToMemory = !!(fetchAttributes & 1/*EMSCRIPTEN_FETCH_LOAD_TO_MEMORY*/);
var fetchAttrStreamData = !!(fetchAttributes & 2/*EMSCRIPTEN_FETCH_STREAM_DATA*/);
var fetchAttrPersistFile = !!(fetchAttributes & 4/*EMSCRIPTEN_FETCH_PERSIST_FILE*/);
var fetchAttrAppend = !!(fetchAttributes & 8/*EMSCRIPTEN_FETCH_APPEND*/);
var fetchAttrReplace = !!(fetchAttributes & 16/*EMSCRIPTEN_FETCH_REPLACE*/);
var fetchAttrNoDownload = !!(fetchAttributes & 32/*EMSCRIPTEN_FETCH_NO_DOWNLOAD*/);
var reportSuccess = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.log('fetch: operation success. e: ' + e);
#endif
if (onsuccess) Module['dynCall_vi'](onsuccess, fetch);
else if (successcb) successcb(fetch);
};
var cacheResultAndReportSuccess = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.log('fetch: operation success. Caching result.. e: ' + e);
#endif
var storeSuccess = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.log('fetch: IndexedDB store succeeded.');
#endif
if (onsuccess) Module['dynCall_vi'](onsuccess, fetch);
else if (successcb) successcb(fetch);
};
var storeError = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.error('fetch: IndexedDB store failed.');
#endif
if (onsuccess) Module['dynCall_vi'](onsuccess, fetch);
else if (successcb) successcb(fetch);
};
__emscripten_fetch_cache_data(Fetch.dbInstance, fetch, xhr.response, storeSuccess, storeError);
};
var reportProgress = function(fetch, xhr, e) {
if (onprogress) Module['dynCall_vi'](onprogress, fetch);
else if (progresscb) progresscb(fetch);
};
var reportError = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.error('fetch: operation failed: ' + e);
#endif
if (onerror) Module['dynCall_vi'](onerror, fetch);
else if (errorcb) errorcb(fetch);
};
var performUncachedXhr = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.error('fetch: starting (uncached) XHR: ' + e);
#endif
__emscripten_fetch_xhr(fetch, reportSuccess, reportError, reportProgress);
};
var performCachedXhr = function(fetch, xhr, e) {
#if FETCH_DEBUG
console.error('fetch: starting (cached) XHR: ' + e);
#endif
__emscripten_fetch_xhr(fetch, cacheResultAndReportSuccess, reportError, reportProgress);
};
// Should we try IndexedDB first?
if (!fetchAttrReplace || requestMethod === 'EM_IDB_STORE' || requestMethod === 'EM_IDB_DELETE') {
if (!Fetch.dbInstance) {
#if FETCH_DEBUG
console.error('fetch: failed to read IndexedDB! Database is not open.');
#endif
reportError(fetch, 0, 'IndexedDB is not open');
return 0; // todo: free
}
if (requestMethod === 'EM_IDB_STORE') {
var dataPtr = HEAPU32[fetch_attr + Fetch.attr_t_offset_requestData >> 2];
var dataLength = HEAPU32[fetch_attr + Fetch.attr_t_offset_requestDataSize >> 2];
var data = HEAPU8.slice(dataPtr, dataPtr + dataLength); // TODO(?): Here we perform a clone of the data, because storing shared typed arrays to IndexedDB does not seem to be allowed.
__emscripten_fetch_cache_data(Fetch.dbInstance, fetch, data, reportSuccess, reportError);
} else if (requestMethod === 'EM_IDB_DELETE') {
__emscripten_fetch_delete_cached_data(Fetch.dbInstance, fetch, reportSuccess, reportError);
} else if (fetchAttrNoDownload) {
__emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, reportError);
} else if (fetchAttrPersistFile) {
__emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, performCachedXhr);
} else {
__emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, performUncachedXhr);
}
} else if (!fetchAttrNoDownload) {
if (fetchAttrPersistFile) {
__emscripten_fetch_xhr(fetch, cacheResultAndReportSuccess, reportError, reportProgress);
} else {
__emscripten_fetch_xhr(fetch, reportSuccess, reportError, reportProgress);
}
} else {
#if FETCH_DEBUG
console.error('fetch: Invalid combination of flags passed.');
#endif
return 0; // todo: free
}
return fetch;
}