diff --git a/system/lib/fetch/emscripten_fetch.cpp b/system/lib/fetch/emscripten_fetch.cpp index e5feda8de907f..16344eeb72bf8 100644 --- a/system/lib/fetch/emscripten_fetch.cpp +++ b/system/lib/fetch/emscripten_fetch.cpp @@ -75,7 +75,27 @@ emscripten_fetch_t *emscripten_fetch(emscripten_fetch_attr_t *fetch_attr, const fetch->__attributes.destinationPath = fetch->__attributes.destinationPath ? strdup(fetch->__attributes.destinationPath) : 0; // TODO: free fetch->__attributes.userName = fetch->__attributes.userName ? strdup(fetch->__attributes.userName) : 0; // TODO: free fetch->__attributes.password = fetch->__attributes.password ? strdup(fetch->__attributes.password) : 0; // TODO: free - fetch->__attributes.requestHeaders = 0;// TODO:strdup(fetch->__attributes.requestHeaders); + if (fetch_attr->requestHeaders) { + size_t n_values = 0; + { + const char * const *headers = fetch_attr->requestHeaders; + while (*headers) { + n_values++; + headers++; + } + } + + // Allocate our own array. +1 for null-termination. + size_t n_bytes = sizeof(const char*) * (n_values + 1); + const char** headers = (const char**)malloc(n_bytes); + memset(headers, 0, n_bytes); + + // Copy in keys and values. + for (size_t i = 0; i < n_values; ++i) { + headers[i] = strdup(fetch_attr->requestHeaders[i]); + } + fetch->__attributes.requestHeaders = headers; + } fetch->__attributes.overriddenMimeType = fetch->__attributes.overriddenMimeType ? strdup(fetch->__attributes.overriddenMimeType) : 0; // TODO: free #if __EMSCRIPTEN_PTHREADS__ @@ -146,6 +166,15 @@ EMSCRIPTEN_RESULT emscripten_fetch_close(emscripten_fetch_t *fetch) } fetch->id = 0; free((void*)fetch->data); + if (fetch->__attributes.requestHeaders) { + const char* const* headers = fetch->__attributes.requestHeaders; + while (*headers) { + free((char*)*headers); + headers++; + } + free((void*)headers); + fetch->__attributes.requestHeaders = 0; + } free(fetch); return EMSCRIPTEN_RESULT_SUCCESS; } diff --git a/tests/fetch/response_headers.cpp b/tests/fetch/response_headers.cpp new file mode 100644 index 0000000000000..c76c87c425f26 --- /dev/null +++ b/tests/fetch/response_headers.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include + +int result = 0; + +int main() +{ + static const char* const headers[] = { + "X-Emscripten-Test", + "1", + 0, + }; + const size_t n_values = sizeof(headers) / sizeof(headers[0]) - 1; + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + strcpy(attr.requestMethod, "GET"); + attr.attributes = EMSCRIPTEN_FETCH_REPLACE | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_SYNCHRONOUS; + attr.requestHeaders = headers; + + attr.onsuccess = [](emscripten_fetch_t *fetch) { + assert(fetch->__attributes.requestHeaders != 0); + assert(fetch->__attributes.requestHeaders != headers); + for (size_t i = 0; i < n_values; ++i) { + const char* origHeader = headers[i]; + const char* header = fetch->__attributes.requestHeaders[i]; + assert(origHeader != header); + assert(strcmp(origHeader, header) == 0); + } + assert(fetch->__attributes.requestHeaders[n_values] == 0); + + printf("Finished downloading %llu bytes\n", fetch->numBytes); + // Compute rudimentary checksum of data + uint8_t checksum = 0; + for(int i = 0; i < fetch->numBytes; ++i) + checksum ^= fetch->data[i]; + printf("Data checksum: %02X\n", checksum); + assert(checksum == 0x08); + emscripten_fetch_close(fetch); + + if (result == 0) result = 1; +#ifdef REPORT_RESULT + REPORT_RESULT(result); +#endif + }; + + attr.onprogress = [](emscripten_fetch_t *fetch) { + if (fetch->totalBytes > 0) { + printf("Downloading.. %.2f%% complete.\n", (fetch->dataOffset + fetch->numBytes) * 100.0 / fetch->totalBytes); + } else { + printf("Downloading.. %lld bytes complete.\n", fetch->dataOffset + fetch->numBytes); + } + }; + + attr.onerror = [](emscripten_fetch_t *fetch) { + printf("Download failed!\n"); + assert(false && "Shouldn't fail!"); + }; + + emscripten_fetch_t *fetch = emscripten_fetch(&attr, "gears.png"); + if (result == 0) { + result = 2; + printf("emscripten_fetch() failed to run synchronously!\n"); + } +#ifdef REPORT_RESULT + REPORT_RESULT(result); +#endif +} diff --git a/tests/test_browser.py b/tests/test_browser.py index 391e93647286c..9f27ad73aa96a 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3709,6 +3709,11 @@ def test_fetch_cached_xhr(self): shutil.copyfile(path_from_root('tests', 'gears.png'), os.path.join(self.get_dir(), 'gears.png')) self.btest('fetch/cached_xhr.cpp', expected='1', args=['--std=c++11', '-s', 'FETCH_DEBUG=1', '-s', 'FETCH=1']) + # Tests that response headers get set on emscripten_fetch_t values. + def test_fetch_response_headers(self): + shutil.copyfile(path_from_root('tests', 'gears.png'), os.path.join(self.get_dir(), 'gears.png')) + self.btest('fetch/response_headers.cpp', expected='1', args=['--std=c++11', '-s', 'FETCH_DEBUG=1', '-s', 'FETCH=1', '-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1']) + # Test emscripten_fetch() usage to stream a XHR in to memory without storing the full file in memory def test_fetch_stream_file(self): # Strategy: create a large 128MB file, and compile with a small 16MB Emscripten heap, so that the tested file