* @param {GMReq.Message.Web} opts * @param {GMReq.EventTypeMap[]} events * @param {VMMessageSender} src * @param {function} cb * @returns {Promise }
(opts, events, src, cb)
| 206 | * @returns {Promise<void>} |
| 207 | */ |
| 208 | async function httpRequest(opts, events, src, cb) { |
| 209 | const { tab } = src; |
| 210 | const { incognito } = tab; |
| 211 | const { anonymous, id, overrideMimeType, [kXhrType]: xhrType } = opts; |
| 212 | const url = vetUrl(opts.url, src.url, true); |
| 213 | const req = requests[id]; |
| 214 | if (!req || req.cb) return; |
| 215 | req.cb = cb; |
| 216 | req[kFileName] = opts[kFileName]; |
| 217 | const { xhr } = req; |
| 218 | const vmHeaders = {}; |
| 219 | // Firefox can send Blob/ArrayBuffer directly |
| 220 | const willStringifyBinaries = xhrType && !IS_FIREFOX; |
| 221 | // Chrome can't fetch Blob URL in incognito so we use chunks |
| 222 | const chunked = willStringifyBinaries && incognito; |
| 223 | const blobbed = willStringifyBinaries && !incognito; |
| 224 | const [body, contentType] = decodeBody(opts.data); |
| 225 | // Firefox doesn't send cookies, https://github.com/violentmonkey/violentmonkey/issues/606 |
| 226 | // Both Chrome & FF need explicit routing of cookies in containers or incognito |
| 227 | const shouldSendCookies = !anonymous && (incognito || IS_FIREFOX); |
| 228 | const uaHeaders = []; |
| 229 | req[kCookie] = !anonymous && !shouldSendCookies; |
| 230 | req[kSetCookie] = !anonymous; |
| 231 | xhr.open(opts.method || 'GET', url, true, opts.user || '', opts.password || ''); |
| 232 | xhr.setRequestHeader(VM_VERIFY, id); |
| 233 | if (contentType) xhr.setRequestHeader('Content-Type', contentType); |
| 234 | opts.headers::forEachEntry(([name, value]) => { |
| 235 | const nameLow = name.toLowerCase(); |
| 236 | const i = UA_HEADERS.indexOf(nameLow); |
| 237 | if (i >= 0 && (uaHeaders[i] = true) || FORBIDDEN_HEADER_RE.test(name)) { |
| 238 | pushWebRequestHeader(vmHeaders, name, value, nameLow); |
| 239 | } else { |
| 240 | xhr.setRequestHeader(name, value); |
| 241 | } |
| 242 | }); |
| 243 | opts.ua.forEach((val, i) => { |
| 244 | if (!uaHeaders[i] && !deepEqual(val, !i ? navUA : navUAD[UA_PROPS[i]])) { |
| 245 | const name = UA_HEADERS[i]; |
| 246 | pushWebRequestHeader(vmHeaders, name, UA_GETTERS[name](val), name); |
| 247 | } |
| 248 | }); |
| 249 | xhr[kResponseType] = willStringifyBinaries && 'blob' || xhrType || 'text'; |
| 250 | xhr.timeout = Math.max(0, Math.min(0x7FFF_FFFF, opts.timeout)) || 0; |
| 251 | if (overrideMimeType) xhr.overrideMimeType(overrideMimeType); |
| 252 | if (shouldSendCookies) { |
| 253 | for (const store of await browser.cookies.getAllCookieStores()) { |
| 254 | if (store.tabIds.includes(tab.id)) { |
| 255 | if (IS_FIREFOX ? !store.id.endsWith('-default') : store.id !== '0') { |
| 256 | /* Cookie routing. For the main store we rely on the browser. |
| 257 | * The ids are hard-coded as `stores` may omit the main store if no such tabs are open. */ |
| 258 | req.storeId = store.id; |
| 259 | } |
| 260 | break; |
| 261 | } |
| 262 | } |
| 263 | const now = Date.now() / 1000; |
| 264 | const cookies = (await browser.cookies.getAll({ |
| 265 | url, |
no test coverage detected