commit b7c6cbfadcc72c9ee1d5048087c840398422a72c
parent 863de76fb6cb97d6b908a63d57f956c2da13fa0f
Author: Sergej Orlov <wladimirych@gmail.com>
Date: Fri, 16 Dec 2016 18:17:19 +0300
[tracks] read binary text from xhr using arraybuffer instead of overriding mime-type; strip Byte Order Mark when parsing gpx and kml
Chrome always overrides encoding when file contains BOM
Diffstat:
4 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/src/lib/leaflet.control.track-list/lib/geo_file_formats.js b/src/lib/leaflet.control.track-list/lib/geo_file_formats.js
@@ -1,5 +1,6 @@
import JSUnzip from 'vendored/github.com/augustl/js-unzip/js-unzip';
import RawDeflate from 'vendored/github.com/dankogai/js-deflate/rawinflate';
+import stripBom from 'lib/stripBom';
import {decode as utf8_decode} from 'utf8';
@@ -65,6 +66,7 @@ function parseGpx(txt, name) {
return waypoints;
};
+ txt = stripBom(txt);
// remove namespaces
txt = txt.replace(/<([^ >]+):([^ >]+)/g, '<$1_$2');
var dom = (new DOMParser()).parseFromString(txt, "text/xml");
@@ -248,6 +250,7 @@ function parseKml(txt, name) {
return points;
}
+ txt = stripBom(txt);
txt = txt.replace(/<([^ >]+):([^ >]+)/g, '<$1_$2');
var dom = (new DOMParser()).parseFromString(txt, "text/xml");
if (dom.documentElement.nodeName === 'parsererror') {
diff --git a/src/lib/leaflet.control.track-list/track-list.js b/src/lib/leaflet.control.track-list/track-list.js
@@ -241,7 +241,7 @@ L.Control.TrackList = L.Control.extend({
.pop();
fetch(url_for_request, {responseType: 'binarystring'})
.then(function(xhr) {
- var geodata = parseGeoFile(name, xhr.response);
+ var geodata = parseGeoFile(name, xhr.responseBinaryText);
this.addTracksFromGeodataArray(geodata);
}.bind(this),
function() {
diff --git a/src/lib/stripBom/index.js b/src/lib/stripBom/index.js
@@ -0,0 +1,6 @@
+export default function stripBom(s) {
+ if (s.substr(0, 3) === '\xef\xbb\xbf') {
+ s = s.substr(3);
+ }
+ return s;
+}
diff --git a/src/lib/xhr-promise/index.js b/src/lib/xhr-promise/index.js
@@ -6,6 +6,20 @@ function retryIfNetworkErrorOrServerError(xhr) {
return (xhr.status === 0 || xhr.status >= 500);
}
+
+function arrayBufferToString(arBuf) {
+ const result = [];
+ const arr = new Uint8Array(arBuf);
+ let chunk;
+ for (let i = 0; i < arr.length; i += 4096) {
+ chunk = arr.subarray(i, i + 4096);
+ chunk = String.fromCharCode.apply(null, chunk);
+ result.push(chunk);
+ }
+ return result.join('');
+}
+
+
class XMLHttpRequestPromise {
constructor(
url, {method='GET', data=null, responseType='', timeout=30000, maxTries=3, retryTimeWait=1000,
@@ -20,6 +34,7 @@ class XMLHttpRequestPromise {
this.catch = promise.catch.bind(promise);
this.method = method;
this.url = url;
+ this.responseType = responseType;
this.postData = data;
this._isResponseSuccess = isResponseSuccess;
this._responseNeedsRetry = responseNeedsRetry;
@@ -31,8 +46,7 @@ class XMLHttpRequestPromise {
this._open();
xhr.timeout = timeout;
if (responseType === 'binarystring') {
- xhr.responseType = 'text';
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ xhr.responseType = 'arraybuffer';
} else {
xhr.responseType = responseType;
}
@@ -47,6 +61,9 @@ class XMLHttpRequestPromise {
const xhr = this.xhr;
if (xhr.readyState === 4 && !this._aborted) {
// console.log('ready state 4', this.url);
+ if (this.responseType === 'binarystring' && xhr.response && xhr.response.byteLength) {
+ xhr.responseBinaryText = arrayBufferToString(xhr.response);
+ }
if (this._isResponseSuccess(xhr)) {
// console.log('success', this.url);
this._resolve(xhr);