UNPKG

strophe.js

Version:

Strophe.js is an XMPP library for JavaScript

107 lines (98 loc) 3.88 kB
import log from './log.js'; import Builder from './builder.js'; import { ErrorCondition } from './constants.js'; import { getParserError, xmlHtmlNode } from './utils.js'; /** * _Private_ variable that keeps track of the request ids for connections. */ let _requestId = 0; /** * Helper class that provides a cross implementation abstraction * for a BOSH related XMLHttpRequest. * * The Request class is used internally to encapsulate BOSH request * information. It is not meant to be used from user's code. * * @property {number} id * @property {number} sends * @property {XMLHttpRequest} xhr */ class Request { /** * Create and initialize a new Request object. * * @param {Element} elem - The XML data to be sent in the request. * @param {Function} func - The function that will be called when the * XMLHttpRequest readyState changes. * @param {number} rid - The BOSH rid attribute associated with this request. * @param {number} [sends=0] - The number of times this same request has been sent. */ constructor(elem, func, rid, sends = 0) { this.id = ++_requestId; this.xmlData = elem; this.data = Builder.serialize(elem); // save original function in case we need to make a new request // from this one. this.origFunc = func; this.func = func; this.rid = rid; this.date = NaN; this.sends = sends; this.abort = false; this.dead = null; this.age = () => (this.date ? (new Date().valueOf() - this.date.valueOf()) / 1000 : 0); this.timeDead = () => (this.dead ? (new Date().valueOf() - this.dead.valueOf()) / 1000 : 0); this.xhr = this._newXHR(); } /** * Get a response from the underlying XMLHttpRequest. * This function attempts to get a response from the request and checks * for errors. * @throws "parsererror" - A parser error occured. * @throws "bad-format" - The entity has sent XML that cannot be processed. * @return {Element} - The DOM element tree of the response. */ getResponse() { const node = this.xhr.responseXML?.documentElement; if (node) { if (node.tagName === 'parsererror') { log.error('invalid response received'); log.error('responseText: ' + this.xhr.responseText); log.error('responseXML: ' + Builder.serialize(node)); throw new Error('parsererror'); } } else if (this.xhr.responseText) { // In Node (with xhr2) or React Native, we may get responseText but no responseXML. // We can try to parse it manually. log.debug('Got responseText but no responseXML; attempting to parse it with DOMParser...'); const doc = xmlHtmlNode(this.xhr.responseText); const parserError = getParserError(doc); if (!doc || parserError) { if (parserError) { log.error('invalid response received: ' + parserError); log.error('responseText: ' + this.xhr.responseText); } const error = new Error(); error.name = ErrorCondition.BAD_FORMAT; throw error; } } return node; } /** * _Private_ helper function to create XMLHttpRequests. * This function creates XMLHttpRequests across all implementations. * @private * @return {XMLHttpRequest} */ _newXHR() { const xhr = new XMLHttpRequest(); if (xhr.overrideMimeType) { xhr.overrideMimeType('text/xml; charset=utf-8'); } // use Function.bind() to prepend ourselves as an argument xhr.onreadystatechange = this.func.bind(null, this); return xhr; } } export default Request;