function parseRaw(req, msg, propName) {
  const { [kResponseType]: responseType } = req;
  let res, ct, tmp;
  if (kRaw in req) {
    res = req[kRaw];
    if (!req[kXhrType]) {
      tmp = res;
      res = '';
      tmp::forEach(chunk => res += chunk);
      req[kRaw] = [res];
      req[kResponseText] = res;
    }
    if (responseType === kDocument && (ct = kContentTextHtml)
    || !responseType
      && propName === kResponseXML
      && PARSEABLE_TYPES::indexOf(ct = getContentType(msg) || kContentTextHtml) >= 0
    || responseType === 'json') {
      try { res = ct ? new SafeDOMParser()::parseFromString(res, ct) : jsonParse(res); }
      catch (e) { res = null; /* per specification */ }
    }
    if (responseType === kDocument) {
      const otherPropName = propName === kResponse ? kResponseXML : kResponse;
      setOwnProp(this, otherPropName, res);
      req[otherPropName] = res;
    }
    // TODO: should we implement this spec behavior?
    // if (propName === kResponseXML && responseType && responseType !== kDocument) {
    //   throw new SafeError('responseXML failed: responseType must be "document" or "" or absent.');
    // }
    if (responseType) {
      delete req[kRaw];
    }
    req[propName] = res;
  } else {
    res = req[propName];
  }
  if (res === undefined) {
    res = null;
  }
  setOwnProp(this, propName, res);
  return res;
}
`response` is sent only when changed so we need to remember it for response-less events
`raw` is decoded once per `response` change so we reuse the result just like native XHR
@this {VMScriptResponseObject}
@param {GMReq.Web} req
@param {GMReq.Message.BG} msg
@param {string} propName
@returns {string | Blob | ArrayBuffer | null}