mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 18:15:28 -04:00
Merge pull request #767 from UnknownShadow200/MinFetch
Webclient: Use manual XmlHttpRequest implementation
This commit is contained in:
commit
86425cb6b1
@ -65,24 +65,3 @@ and change to
|
|||||||
```
|
```
|
||||||
eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, { useCapture: eventHandler.useCapture, passive: false });
|
eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, { useCapture: eventHandler.useCapture, passive: false });
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Texture pack confirm dialog always shows *Download size: Determining*..
|
|
||||||
Unfortunately emscripten doesn't store content-length for HEAD http requests. This can be fixed.
|
|
||||||
|
|
||||||
First you need to find at what offset emscripten stores content-length. Look for something like:
|
|
||||||
```
|
|
||||||
xhr.onprogress = function(e) {
|
|
||||||
...
|
|
||||||
Fetch.setu64(fetch + 32, e.total);
|
|
||||||
```
|
|
||||||
then look for
|
|
||||||
```
|
|
||||||
xhr.onload = function(e) {
|
|
||||||
...
|
|
||||||
```
|
|
||||||
and finally change that to
|
|
||||||
```
|
|
||||||
xhr.onload = function(e) {
|
|
||||||
Fetch.setu64(fetch + 32, e.total);
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
@ -124,7 +124,7 @@ NOTE: You have to change entry->d_type == DT_DIR to Directory_Exists(&path) (TOD
|
|||||||
|
|
||||||
#### Web
|
#### Web
|
||||||
|
|
||||||
```emcc *.c -s FETCH=1 -s ALLOW_MEMORY_GROWTH=1 --preload-file texpacks/default.zip```
|
```emcc *.c -s ALLOW_MEMORY_GROWTH=1 --preload-file texpacks/default.zip```
|
||||||
|
|
||||||
The generated javascript file has some issues. [See here for how to fix](doc/compile-fixes.md#webclient-patches)
|
The generated javascript file has some issues. [See here for how to fix](doc/compile-fixes.md#webclient-patches)
|
||||||
|
|
||||||
|
@ -52,6 +52,8 @@ enum ERRORS_ALL {
|
|||||||
AL_ERR_INIT_DEVICE, AL_ERR_INIT_CONTEXT,
|
AL_ERR_INIT_DEVICE, AL_ERR_INIT_CONTEXT,
|
||||||
/* Inflate errors */
|
/* Inflate errors */
|
||||||
INF_ERR_BLOCKTYPE, INF_ERR_LEN_VERIFY, INF_ERR_REPEAT_BEG, INF_ERR_REPEAT_END,
|
INF_ERR_BLOCKTYPE, INF_ERR_LEN_VERIFY, INF_ERR_REPEAT_BEG, INF_ERR_REPEAT_END,
|
||||||
INF_ERR_INVALID_CODE
|
INF_ERR_INVALID_CODE,
|
||||||
|
/* Misc other errors */
|
||||||
|
ERR_DOWNLOAD_INVALID
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
105
src/Http.c
105
src/Http.c
@ -305,36 +305,27 @@ static void Http_SetRequestHeaders(struct HttpRequest* req) {
|
|||||||
*------------------------------------------------Emscripten implementation------------------------------------------------*
|
*------------------------------------------------Emscripten implementation------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
#ifdef CC_BUILD_WEB
|
#ifdef CC_BUILD_WEB
|
||||||
/* Use fetch/XMLHttpRequest api for Emscripten */
|
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#include <emscripten/fetch.h>
|
#include "Errors.h"
|
||||||
|
|
||||||
cc_bool Http_DescribeError(cc_result res, cc_string* dst) { return false; }
|
cc_bool Http_DescribeError(cc_result res, cc_string* dst) { return false; }
|
||||||
/* web browsers do caching already, so don't need last modified/etags */
|
/* web browsers do caching already, so don't need last modified/etags */
|
||||||
static void Http_AddHeader(struct HttpRequest* req, const char* key, const cc_string* value) { }
|
static void Http_AddHeader(struct HttpRequest* req, const char* key, const cc_string* value) { }
|
||||||
|
|
||||||
static void Http_UpdateProgress(emscripten_fetch_t* fetch) {
|
static void OnUpdateProgress(int read, int total) {
|
||||||
if (!fetch->totalBytes) return;
|
if (!total) return;
|
||||||
http_curProgress = (int)(100.0f * fetch->dataOffset / fetch->totalBytes);
|
http_curProgress = (int)(100.0f * read / total);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Http_FinishedAsync(emscripten_fetch_t* fetch) {
|
static void OnFinishedAsync(void* data, int len, int status) {
|
||||||
struct HttpRequest* req = &http_curRequest;
|
struct HttpRequest* req = &http_curRequest;
|
||||||
req->data = (cc_uint8*)fetch->data;
|
req->data = data;
|
||||||
req->size = fetch->numBytes;
|
req->size = len;
|
||||||
req->statusCode = fetch->status;
|
req->statusCode = status;
|
||||||
req->contentLength = fetch->totalBytes;
|
req->contentLength = len;
|
||||||
|
|
||||||
/* Remove error handler to avoid potential infinite recurison */
|
/* Usually because of denied by CORS */
|
||||||
/* Sometimes calling emscripten_fetch_close calls fetch->__attributes.onerror */
|
if (!status && !data) req->result = ERR_DOWNLOAD_INVALID;
|
||||||
/* But attr.onerror is actually Http_FinishedAsync, so this will end up doing */
|
|
||||||
/* Http_FinishedAsync --> emscripten_fetch_close --> Http_FinishedAsync .. */
|
|
||||||
/* .. and eventually the browser kills it from too much recursion */
|
|
||||||
fetch->__attributes.onerror = NULL;
|
|
||||||
|
|
||||||
/* data needs to persist beyond closing of fetch data */
|
|
||||||
fetch->data = NULL;
|
|
||||||
emscripten_fetch_close(fetch);
|
|
||||||
|
|
||||||
if (req->data) Platform_Log1("HTTP returned data: %i bytes", &req->size);
|
if (req->data) Platform_Log1("HTTP returned data: %i bytes", &req->size);
|
||||||
Http_FinishRequest(req);
|
Http_FinishRequest(req);
|
||||||
@ -342,50 +333,50 @@ static void Http_FinishedAsync(emscripten_fetch_t* fetch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void Http_DownloadAsync(struct HttpRequest* req) {
|
static void Http_DownloadAsync(struct HttpRequest* req) {
|
||||||
emscripten_fetch_attr_t attr;
|
|
||||||
emscripten_fetch_attr_init(&attr);
|
|
||||||
|
|
||||||
char urlBuffer[URL_MAX_SIZE]; cc_string url;
|
char urlBuffer[URL_MAX_SIZE]; cc_string url;
|
||||||
char urlStr[NATIVE_STR_LEN];
|
char urlStr[NATIVE_STR_LEN];
|
||||||
|
|
||||||
switch (req->requestType) {
|
|
||||||
case REQUEST_TYPE_GET: Mem_Copy(attr.requestMethod, "GET", 4); break;
|
|
||||||
case REQUEST_TYPE_HEAD: Mem_Copy(attr.requestMethod, "HEAD", 5); break;
|
|
||||||
case REQUEST_TYPE_POST: Mem_Copy(attr.requestMethod, "POST", 5); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req->requestType == REQUEST_TYPE_POST) {
|
|
||||||
attr.requestData = (const char*)req->data;
|
|
||||||
attr.requestDataSize = req->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Can't use this for all URLs, because cache-control isn't in allowed CORS headers */
|
|
||||||
/* For example, if you try this with dropbox, you'll get a '404' with */
|
|
||||||
/* Access to XMLHttpRequest at 'https://dl.dropbox.com/s/a/a.zip' from */
|
|
||||||
/* origin 'http://www.classicube.net' has been blocked by CORS policy: */
|
|
||||||
/* Response to preflight request doesn't pass access control check: */
|
|
||||||
/* Redirect is not allowed for a preflight request. */
|
|
||||||
/* printed to console. But this is still used for skins, that way when users change */
|
|
||||||
/* their skins, the change shows up instantly. But 99% of the time we'll get a 304 */
|
|
||||||
/* response and can avoid downloading the whole skin over and over. */
|
|
||||||
if (req->url[0] == '/') {
|
|
||||||
static const char* const headers[3] = { "cache-control", "max-age=0", NULL };
|
|
||||||
attr.requestHeaders = headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If EMSCRIPTEN_FETCH_REPLACE is not specified, then skins/texture packs */
|
|
||||||
/* won't download in FireFox private browsing (because no IndexedDB there) */
|
|
||||||
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_REPLACE;
|
|
||||||
attr.onsuccess = Http_FinishedAsync;
|
|
||||||
attr.onerror = Http_FinishedAsync;
|
|
||||||
attr.onprogress = Http_UpdateProgress;
|
|
||||||
|
|
||||||
String_InitArray(url, urlBuffer);
|
String_InitArray(url, urlBuffer);
|
||||||
Http_BeginRequest(req, &url);
|
Http_BeginRequest(req, &url);
|
||||||
Platform_EncodeString(urlStr, &url);
|
Platform_EncodeString(urlStr, &url);
|
||||||
|
|
||||||
/* TODO: SET requestHeaders!!! */
|
EM_ASM_({
|
||||||
emscripten_fetch(&attr, urlStr);
|
var url = UTF8ToString($0);
|
||||||
|
var reqMethod = $1 == 1 ? 'HEAD' : 'GET';
|
||||||
|
|
||||||
|
var onFinished = function(data, len, status) {
|
||||||
|
Module['dynCall_viii']($2, data, len, status);
|
||||||
|
};
|
||||||
|
var onProgress = function(read, total) {
|
||||||
|
Module['dynCall_vii']($3, read, total);
|
||||||
|
};
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open(reqMethod, url);
|
||||||
|
xhr.responseType = 'arraybuffer';
|
||||||
|
|
||||||
|
var getContentLength = function(e) {
|
||||||
|
if (e.total) return e.total;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var len = xhr.getResponseHeader('Content-Length');
|
||||||
|
return parseInt(len, 10);
|
||||||
|
} catch (ex) { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onload = function(e) {
|
||||||
|
var src = new Uint8Array(xhr.response);
|
||||||
|
var len = src.byteLength;
|
||||||
|
var data = _malloc(len);
|
||||||
|
HEAPU8.set(src, data);
|
||||||
|
onFinished(data, len || getContentLength(e), xhr.status);
|
||||||
|
};
|
||||||
|
xhr.onerror = function(e) { onFinished(0, 0, xhr.status); };
|
||||||
|
xhr.ontimeout = function(e) { onFinished(0, 0, xhr.status); };
|
||||||
|
xhr.onprogress = function(e) { onProgress(e.loaded, e.total); };
|
||||||
|
|
||||||
|
try { xhr.send(); } catch (e) { onFinished(0, 0, 0); }
|
||||||
|
}, urlStr, req->requestType, OnFinishedAsync, OnUpdateProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Http_WorkerInit(void) {
|
static void Http_WorkerInit(void) {
|
||||||
|
@ -79,6 +79,8 @@ static const char* GetCCErrorDesc(cc_result res) {
|
|||||||
case NBT_ERR_UNKNOWN: return "Unknown NBT tag type";
|
case NBT_ERR_UNKNOWN: return "Unknown NBT tag type";
|
||||||
case CW_ERR_ROOT_TAG: return "Invalid root NBT tag";
|
case CW_ERR_ROOT_TAG: return "Invalid root NBT tag";
|
||||||
case CW_ERR_STRING_LEN: return "NBT string too long";
|
case CW_ERR_STRING_LEN: return "NBT string too long";
|
||||||
|
|
||||||
|
case ERR_DOWNLOAD_INVALID: return "Website denied download or doesn't exist";
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user