api-session-spec.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. const assert = require('assert')
  2. const http = require('http')
  3. const https = require('https')
  4. const path = require('path')
  5. const fs = require('fs')
  6. const send = require('send')
  7. const auth = require('basic-auth')
  8. const {closeWindow} = require('./window-helpers')
  9. const {ipcRenderer, remote} = require('electron')
  10. const {ipcMain, session, BrowserWindow, net} = remote
  11. describe('session module', function () {
  12. var fixtures = path.resolve(__dirname, 'fixtures')
  13. var w = null
  14. var webview = null
  15. var url = 'http://127.0.0.1'
  16. beforeEach(function () {
  17. w = new BrowserWindow({
  18. show: false,
  19. width: 400,
  20. height: 400
  21. })
  22. })
  23. afterEach(function () {
  24. if (webview != null) {
  25. if (!document.body.contains(webview)) {
  26. document.body.appendChild(webview)
  27. }
  28. webview.remove()
  29. }
  30. return closeWindow(w).then(function () { w = null })
  31. })
  32. describe('session.defaultSession', function () {
  33. it('returns the default session', function () {
  34. assert.equal(session.defaultSession, session.fromPartition(''))
  35. })
  36. })
  37. describe('session.fromPartition(partition, options)', function () {
  38. it('returns existing session with same partition', function () {
  39. assert.equal(session.fromPartition('test'), session.fromPartition('test'))
  40. })
  41. it('created session is ref-counted', function () {
  42. const partition = 'test2'
  43. const userAgent = 'test-agent'
  44. const ses1 = session.fromPartition(partition)
  45. ses1.setUserAgent(userAgent)
  46. assert.equal(ses1.getUserAgent(), userAgent)
  47. ses1.destroy()
  48. const ses2 = session.fromPartition(partition)
  49. assert.notEqual(ses2.getUserAgent(), userAgent)
  50. })
  51. })
  52. describe('ses.cookies', function () {
  53. it('should get cookies', function (done) {
  54. var server = http.createServer(function (req, res) {
  55. res.setHeader('Set-Cookie', ['0=0'])
  56. res.end('finished')
  57. server.close()
  58. })
  59. server.listen(0, '127.0.0.1', function () {
  60. var port = server.address().port
  61. w.loadURL(url + ':' + port)
  62. w.webContents.on('did-finish-load', function () {
  63. w.webContents.session.cookies.get({
  64. url: url
  65. }, function (error, list) {
  66. var cookie, i, len
  67. if (error) {
  68. return done(error)
  69. }
  70. for (i = 0, len = list.length; i < len; i++) {
  71. cookie = list[i]
  72. if (cookie.name === '0') {
  73. if (cookie.value === '0') {
  74. return done()
  75. } else {
  76. return done('cookie value is ' + cookie.value + ' while expecting 0')
  77. }
  78. }
  79. }
  80. done('Can not find cookie')
  81. })
  82. })
  83. })
  84. })
  85. it('calls back with an error when setting a cookie with missing required fields', function (done) {
  86. session.defaultSession.cookies.set({
  87. url: '',
  88. name: '1',
  89. value: '1'
  90. }, function (error) {
  91. assert.equal(error.message, 'Setting cookie failed')
  92. done()
  93. })
  94. })
  95. it('should over-write the existent cookie', function (done) {
  96. session.defaultSession.cookies.set({
  97. url: url,
  98. name: '1',
  99. value: '1'
  100. }, function (error) {
  101. if (error) {
  102. return done(error)
  103. }
  104. session.defaultSession.cookies.get({
  105. url: url
  106. }, function (error, list) {
  107. var cookie, i, len
  108. if (error) {
  109. return done(error)
  110. }
  111. for (i = 0, len = list.length; i < len; i++) {
  112. cookie = list[i]
  113. if (cookie.name === '1') {
  114. if (cookie.value === '1') {
  115. return done()
  116. } else {
  117. return done('cookie value is ' + cookie.value + ' while expecting 1')
  118. }
  119. }
  120. }
  121. done('Can not find cookie')
  122. })
  123. })
  124. })
  125. it('should remove cookies', function (done) {
  126. session.defaultSession.cookies.set({
  127. url: url,
  128. name: '2',
  129. value: '2'
  130. }, function (error) {
  131. if (error) {
  132. return done(error)
  133. }
  134. session.defaultSession.cookies.remove(url, '2', function () {
  135. session.defaultSession.cookies.get({
  136. url: url
  137. }, function (error, list) {
  138. var cookie, i, len
  139. if (error) {
  140. return done(error)
  141. }
  142. for (i = 0, len = list.length; i < len; i++) {
  143. cookie = list[i]
  144. if (cookie.name === '2') {
  145. return done('Cookie not deleted')
  146. }
  147. }
  148. done()
  149. })
  150. })
  151. })
  152. })
  153. it('should set cookie for standard scheme', function (done) {
  154. const standardScheme = remote.getGlobal('standardScheme')
  155. const origin = standardScheme + '://fake-host'
  156. session.defaultSession.cookies.set({
  157. url: origin,
  158. name: 'custom',
  159. value: '1'
  160. }, function (error) {
  161. if (error) {
  162. return done(error)
  163. }
  164. session.defaultSession.cookies.get({
  165. url: origin
  166. }, function (error, list) {
  167. if (error) {
  168. return done(error)
  169. }
  170. assert.equal(list.length, 1)
  171. assert.equal(list[0].name, 'custom')
  172. assert.equal(list[0].value, '1')
  173. assert.equal(list[0].domain, 'fake-host')
  174. done()
  175. })
  176. })
  177. })
  178. it('emits a changed event when a cookie is added or removed', function (done) {
  179. const {cookies} = session.fromPartition('cookies-changed')
  180. cookies.once('changed', function (event, cookie, cause, removed) {
  181. assert.equal(cookie.name, 'foo')
  182. assert.equal(cookie.value, 'bar')
  183. assert.equal(cause, 'explicit')
  184. assert.equal(removed, false)
  185. cookies.once('changed', function (event, cookie, cause, removed) {
  186. assert.equal(cookie.name, 'foo')
  187. assert.equal(cookie.value, 'bar')
  188. assert.equal(cause, 'explicit')
  189. assert.equal(removed, true)
  190. done()
  191. })
  192. cookies.remove(url, 'foo', function (error) {
  193. if (error) return done(error)
  194. })
  195. })
  196. cookies.set({
  197. url: url,
  198. name: 'foo',
  199. value: 'bar'
  200. }, function (error) {
  201. if (error) return done(error)
  202. })
  203. })
  204. describe('ses.cookies.flushStore(callback)', function () {
  205. it('flushes the cookies to disk and invokes the callback when done', function (done) {
  206. session.defaultSession.cookies.set({
  207. url: url,
  208. name: 'foo',
  209. value: 'bar'
  210. }, (error) => {
  211. if (error) return done(error)
  212. session.defaultSession.cookies.flushStore(() => {
  213. done()
  214. })
  215. })
  216. })
  217. })
  218. })
  219. describe('ses.clearStorageData(options)', function () {
  220. fixtures = path.resolve(__dirname, 'fixtures')
  221. it('clears localstorage data', function (done) {
  222. ipcMain.on('count', function (event, count) {
  223. ipcMain.removeAllListeners('count')
  224. assert.equal(count, 0)
  225. done()
  226. })
  227. w.loadURL('file://' + path.join(fixtures, 'api', 'localstorage.html'))
  228. w.webContents.on('did-finish-load', function () {
  229. var options = {
  230. origin: 'file://',
  231. storages: ['localstorage'],
  232. quotas: ['persistent']
  233. }
  234. w.webContents.session.clearStorageData(options, function () {
  235. w.webContents.send('getcount')
  236. })
  237. })
  238. })
  239. })
  240. describe('will-download event', function () {
  241. beforeEach(function () {
  242. if (w != null) w.destroy()
  243. w = new BrowserWindow({
  244. show: false,
  245. width: 400,
  246. height: 400
  247. })
  248. })
  249. it('can cancel default download behavior', function (done) {
  250. const mockFile = new Buffer(1024)
  251. const contentDisposition = 'inline; filename="mockFile.txt"'
  252. const downloadServer = http.createServer(function (req, res) {
  253. res.writeHead(200, {
  254. 'Content-Length': mockFile.length,
  255. 'Content-Type': 'application/plain',
  256. 'Content-Disposition': contentDisposition
  257. })
  258. res.end(mockFile)
  259. downloadServer.close()
  260. })
  261. downloadServer.listen(0, '127.0.0.1', function () {
  262. const port = downloadServer.address().port
  263. const url = 'http://127.0.0.1:' + port + '/'
  264. ipcRenderer.sendSync('set-download-option', false, true)
  265. w.loadURL(url)
  266. ipcRenderer.once('download-error', function (event, downloadUrl, filename, error) {
  267. assert.equal(downloadUrl, url)
  268. assert.equal(filename, 'mockFile.txt')
  269. assert.equal(error, 'Object has been destroyed')
  270. done()
  271. })
  272. })
  273. })
  274. })
  275. describe('DownloadItem', function () {
  276. var mockPDF = new Buffer(1024 * 1024 * 5)
  277. var contentDisposition = 'inline; filename="mock.pdf"'
  278. var downloadFilePath = path.join(fixtures, 'mock.pdf')
  279. var downloadServer = http.createServer(function (req, res) {
  280. if (req.url === '/?testFilename') {
  281. contentDisposition = 'inline'
  282. }
  283. res.writeHead(200, {
  284. 'Content-Length': mockPDF.length,
  285. 'Content-Type': 'application/pdf',
  286. 'Content-Disposition': contentDisposition
  287. })
  288. res.end(mockPDF)
  289. downloadServer.close()
  290. })
  291. var assertDownload = function (event, state, url, mimeType,
  292. receivedBytes, totalBytes, disposition,
  293. filename, port, savePath) {
  294. assert.equal(state, 'completed')
  295. assert.equal(filename, 'mock.pdf')
  296. assert.equal(savePath, path.join(__dirname, 'fixtures', 'mock.pdf'))
  297. assert.equal(url, 'http://127.0.0.1:' + port + '/')
  298. assert.equal(mimeType, 'application/pdf')
  299. assert.equal(receivedBytes, mockPDF.length)
  300. assert.equal(totalBytes, mockPDF.length)
  301. assert.equal(disposition, contentDisposition)
  302. assert(fs.existsSync(downloadFilePath))
  303. fs.unlinkSync(downloadFilePath)
  304. }
  305. it('can download using WebContents.downloadURL', function (done) {
  306. downloadServer.listen(0, '127.0.0.1', function () {
  307. var port = downloadServer.address().port
  308. ipcRenderer.sendSync('set-download-option', false, false)
  309. w.webContents.downloadURL(url + ':' + port)
  310. ipcRenderer.once('download-done', function (event, state, url,
  311. mimeType, receivedBytes,
  312. totalBytes, disposition,
  313. filename, savePath) {
  314. assertDownload(event, state, url, mimeType, receivedBytes,
  315. totalBytes, disposition, filename, port, savePath)
  316. done()
  317. })
  318. })
  319. })
  320. it('can download using WebView.downloadURL', function (done) {
  321. downloadServer.listen(0, '127.0.0.1', function () {
  322. var port = downloadServer.address().port
  323. ipcRenderer.sendSync('set-download-option', false, false)
  324. webview = new WebView()
  325. webview.src = 'file://' + fixtures + '/api/blank.html'
  326. webview.addEventListener('did-finish-load', function () {
  327. webview.downloadURL(url + ':' + port + '/')
  328. })
  329. ipcRenderer.once('download-done', function (event, state, url,
  330. mimeType, receivedBytes,
  331. totalBytes, disposition,
  332. filename, savePath) {
  333. assertDownload(event, state, url, mimeType, receivedBytes,
  334. totalBytes, disposition, filename, port, savePath)
  335. document.body.removeChild(webview)
  336. done()
  337. })
  338. document.body.appendChild(webview)
  339. })
  340. })
  341. it('can cancel download', function (done) {
  342. downloadServer.listen(0, '127.0.0.1', function () {
  343. var port = downloadServer.address().port
  344. ipcRenderer.sendSync('set-download-option', true, false)
  345. w.webContents.downloadURL(url + ':' + port + '/')
  346. ipcRenderer.once('download-done', function (event, state, url,
  347. mimeType, receivedBytes,
  348. totalBytes, disposition,
  349. filename) {
  350. assert.equal(state, 'cancelled')
  351. assert.equal(filename, 'mock.pdf')
  352. assert.equal(mimeType, 'application/pdf')
  353. assert.equal(receivedBytes, 0)
  354. assert.equal(totalBytes, mockPDF.length)
  355. assert.equal(disposition, contentDisposition)
  356. done()
  357. })
  358. })
  359. })
  360. it('can generate a default filename', function (done) {
  361. // Somehow this test always fail on appveyor.
  362. if (process.env.APPVEYOR === 'True') return done()
  363. downloadServer.listen(0, '127.0.0.1', function () {
  364. var port = downloadServer.address().port
  365. ipcRenderer.sendSync('set-download-option', true, false)
  366. w.webContents.downloadURL(url + ':' + port + '/?testFilename')
  367. ipcRenderer.once('download-done', function (event, state, url,
  368. mimeType, receivedBytes,
  369. totalBytes, disposition,
  370. filename) {
  371. assert.equal(state, 'cancelled')
  372. assert.equal(filename, 'download.pdf')
  373. assert.equal(mimeType, 'application/pdf')
  374. assert.equal(receivedBytes, 0)
  375. assert.equal(totalBytes, mockPDF.length)
  376. assert.equal(disposition, contentDisposition)
  377. done()
  378. })
  379. })
  380. })
  381. describe('when a save path is specified and the URL is unavailable', function () {
  382. it('does not display a save dialog and reports the done state as interrupted', function (done) {
  383. ipcRenderer.sendSync('set-download-option', false, false)
  384. ipcRenderer.once('download-done', (event, state) => {
  385. assert.equal(state, 'interrupted')
  386. done()
  387. })
  388. w.webContents.downloadURL('file://' + path.join(__dirname, 'does-not-exist.txt'))
  389. })
  390. })
  391. })
  392. describe('ses.protocol', function () {
  393. const partitionName = 'temp'
  394. const protocolName = 'sp'
  395. const partitionProtocol = session.fromPartition(partitionName).protocol
  396. const protocol = session.defaultSession.protocol
  397. const handler = function (ignoredError, callback) {
  398. callback({data: 'test', mimeType: 'text/html'})
  399. }
  400. beforeEach(function (done) {
  401. if (w != null) w.destroy()
  402. w = new BrowserWindow({
  403. show: false,
  404. webPreferences: {
  405. partition: partitionName
  406. }
  407. })
  408. partitionProtocol.registerStringProtocol(protocolName, handler, function (error) {
  409. done(error != null ? error : undefined)
  410. })
  411. })
  412. afterEach(function (done) {
  413. partitionProtocol.unregisterProtocol(protocolName, () => done())
  414. })
  415. it('does not affect defaultSession', function (done) {
  416. protocol.isProtocolHandled(protocolName, function (result) {
  417. assert.equal(result, false)
  418. partitionProtocol.isProtocolHandled(protocolName, function (result) {
  419. assert.equal(result, true)
  420. done()
  421. })
  422. })
  423. })
  424. xit('handles requests from partition', function (done) {
  425. w.webContents.on('did-finish-load', function () {
  426. done()
  427. })
  428. w.loadURL(`${protocolName}://fake-host`)
  429. })
  430. })
  431. describe('ses.setProxy(options, callback)', function () {
  432. it('allows configuring proxy settings', function (done) {
  433. const config = {
  434. proxyRules: 'http=myproxy:80'
  435. }
  436. session.defaultSession.setProxy(config, function () {
  437. session.defaultSession.resolveProxy('http://localhost', function (proxy) {
  438. assert.equal(proxy, 'PROXY myproxy:80')
  439. done()
  440. })
  441. })
  442. })
  443. it('allows bypassing proxy settings', function (done) {
  444. const config = {
  445. proxyRules: 'http=myproxy:80',
  446. proxyBypassRules: '<local>'
  447. }
  448. session.defaultSession.setProxy(config, function () {
  449. session.defaultSession.resolveProxy('http://localhost', function (proxy) {
  450. assert.equal(proxy, 'DIRECT')
  451. done()
  452. })
  453. })
  454. })
  455. })
  456. describe('ses.getBlobData(identifier, callback)', function () {
  457. it('returns blob data for uuid', function (done) {
  458. const scheme = 'temp'
  459. const protocol = session.defaultSession.protocol
  460. const url = scheme + '://host'
  461. before(function () {
  462. if (w != null) w.destroy()
  463. w = new BrowserWindow({show: false})
  464. })
  465. after(function (done) {
  466. protocol.unregisterProtocol(scheme, () => {
  467. closeWindow(w).then(() => {
  468. w = null
  469. done()
  470. })
  471. })
  472. })
  473. const postData = JSON.stringify({
  474. type: 'blob',
  475. value: 'hello'
  476. })
  477. const content = `<html>
  478. <script>
  479. const {webFrame} = require('electron')
  480. webFrame.registerURLSchemeAsPrivileged('${scheme}')
  481. let fd = new FormData();
  482. fd.append('file', new Blob(['${postData}'], {type:'application/json'}));
  483. fetch('${url}', {method:'POST', body: fd });
  484. </script>
  485. </html>`
  486. protocol.registerStringProtocol(scheme, function (request, callback) {
  487. if (request.method === 'GET') {
  488. callback({data: content, mimeType: 'text/html'})
  489. } else if (request.method === 'POST') {
  490. let uuid = request.uploadData[1].blobUUID
  491. assert(uuid)
  492. session.defaultSession.getBlobData(uuid, function (result) {
  493. assert.equal(result.toString(), postData)
  494. done()
  495. })
  496. }
  497. }, function (error) {
  498. if (error) return done(error)
  499. w.loadURL(url)
  500. })
  501. })
  502. })
  503. describe('ses.setCertificateVerifyProc(callback)', function () {
  504. var server = null
  505. beforeEach(function (done) {
  506. var certPath = path.join(__dirname, 'fixtures', 'certificates')
  507. var options = {
  508. key: fs.readFileSync(path.join(certPath, 'server.key')),
  509. cert: fs.readFileSync(path.join(certPath, 'server.pem')),
  510. ca: [
  511. fs.readFileSync(path.join(certPath, 'rootCA.pem')),
  512. fs.readFileSync(path.join(certPath, 'intermediateCA.pem'))
  513. ],
  514. requestCert: true,
  515. rejectUnauthorized: false
  516. }
  517. server = https.createServer(options, function (req, res) {
  518. res.writeHead(200)
  519. res.end('<title>hello</title>')
  520. })
  521. server.listen(0, '127.0.0.1', done)
  522. })
  523. afterEach(function () {
  524. session.defaultSession.setCertificateVerifyProc(null)
  525. server.close()
  526. })
  527. it('accepts the request when the callback is called with 0', function (done) {
  528. session.defaultSession.setCertificateVerifyProc(function ({hostname, certificate, verificationResult}, callback) {
  529. assert(['net::ERR_CERT_AUTHORITY_INVALID', 'net::ERR_CERT_COMMON_NAME_INVALID'].includes(verificationResult), verificationResult)
  530. callback(0)
  531. })
  532. w.webContents.once('did-finish-load', function () {
  533. assert.equal(w.webContents.getTitle(), 'hello')
  534. done()
  535. })
  536. w.loadURL(`https://127.0.0.1:${server.address().port}`)
  537. })
  538. describe('deprecated function signature', function () {
  539. it('supports accepting the request', function (done) {
  540. session.defaultSession.setCertificateVerifyProc(function (hostname, certificate, callback) {
  541. assert.equal(hostname, '127.0.0.1')
  542. callback(true)
  543. })
  544. w.webContents.once('did-finish-load', function () {
  545. assert.equal(w.webContents.getTitle(), 'hello')
  546. done()
  547. })
  548. w.loadURL(`https://127.0.0.1:${server.address().port}`)
  549. })
  550. it('supports rejecting the request', function (done) {
  551. session.defaultSession.setCertificateVerifyProc(function (hostname, certificate, callback) {
  552. assert.equal(hostname, '127.0.0.1')
  553. callback(false)
  554. })
  555. var url = `https://127.0.0.1:${server.address().port}`
  556. w.webContents.once('did-finish-load', function () {
  557. assert.equal(w.webContents.getTitle(), url)
  558. done()
  559. })
  560. w.loadURL(url)
  561. })
  562. })
  563. it('rejects the request when the callback is called with -2', function (done) {
  564. session.defaultSession.setCertificateVerifyProc(function ({hostname, certificate, verificationResult}, callback) {
  565. assert.equal(hostname, '127.0.0.1')
  566. assert.equal(certificate.issuerName, 'Intermediate CA')
  567. assert.equal(certificate.subjectName, 'localhost')
  568. assert.equal(certificate.issuer.commonName, 'Intermediate CA')
  569. assert.equal(certificate.subject.commonName, 'localhost')
  570. assert.equal(certificate.issuerCert.issuer.commonName, 'Root CA')
  571. assert.equal(certificate.issuerCert.subject.commonName, 'Intermediate CA')
  572. assert.equal(certificate.issuerCert.issuerCert.issuer.commonName, 'Root CA')
  573. assert.equal(certificate.issuerCert.issuerCert.subject.commonName, 'Root CA')
  574. assert.equal(certificate.issuerCert.issuerCert.issuerCert, undefined)
  575. assert(['net::ERR_CERT_AUTHORITY_INVALID', 'net::ERR_CERT_COMMON_NAME_INVALID'].includes(verificationResult), verificationResult)
  576. callback(-2)
  577. })
  578. var url = `https://127.0.0.1:${server.address().port}`
  579. w.webContents.once('did-finish-load', function () {
  580. assert.equal(w.webContents.getTitle(), url)
  581. done()
  582. })
  583. w.loadURL(url)
  584. })
  585. })
  586. describe('ses.createInterruptedDownload(options)', function () {
  587. it('can create an interrupted download item', function (done) {
  588. ipcRenderer.sendSync('set-download-option', true, false)
  589. const filePath = path.join(__dirname, 'fixtures', 'mock.pdf')
  590. const options = {
  591. path: filePath,
  592. urlChain: ['http://127.0.0.1/'],
  593. mimeType: 'application/pdf',
  594. offset: 0,
  595. length: 5242880
  596. }
  597. w.webContents.session.createInterruptedDownload(options)
  598. ipcRenderer.once('download-created', function (event, state, urlChain,
  599. mimeType, receivedBytes,
  600. totalBytes, filename,
  601. savePath) {
  602. assert.equal(state, 'interrupted')
  603. assert.deepEqual(urlChain, ['http://127.0.0.1/'])
  604. assert.equal(mimeType, 'application/pdf')
  605. assert.equal(receivedBytes, 0)
  606. assert.equal(totalBytes, 5242880)
  607. assert.equal(savePath, filePath)
  608. done()
  609. })
  610. })
  611. it('can be resumed', function (done) {
  612. const fixtures = path.join(__dirname, 'fixtures')
  613. const downloadFilePath = path.join(fixtures, 'logo.png')
  614. const rangeServer = http.createServer(function (req, res) {
  615. let options = {
  616. root: fixtures
  617. }
  618. send(req, req.url, options)
  619. .on('error', function (error) {
  620. done(error)
  621. }).pipe(res)
  622. })
  623. ipcRenderer.sendSync('set-download-option', true, false, downloadFilePath)
  624. rangeServer.listen(0, '127.0.0.1', function () {
  625. const port = rangeServer.address().port
  626. const downloadUrl = `http://127.0.0.1:${port}/assets/logo.png`
  627. const callback = function (event, state, url, mimeType,
  628. receivedBytes, totalBytes, disposition,
  629. filename, savePath, urlChain,
  630. lastModifiedTime, eTag) {
  631. if (state === 'cancelled') {
  632. const options = {
  633. path: savePath,
  634. urlChain: urlChain,
  635. mimeType: mimeType,
  636. offset: receivedBytes,
  637. length: totalBytes,
  638. lastModified: lastModifiedTime,
  639. eTag: eTag
  640. }
  641. ipcRenderer.sendSync('set-download-option', false, false, downloadFilePath)
  642. w.webContents.session.createInterruptedDownload(options)
  643. } else {
  644. assert.equal(state, 'completed')
  645. assert.equal(filename, 'logo.png')
  646. assert.equal(savePath, downloadFilePath)
  647. assert.equal(url, downloadUrl)
  648. assert.equal(mimeType, 'image/png')
  649. assert.equal(receivedBytes, 14022)
  650. assert.equal(totalBytes, 14022)
  651. assert(fs.existsSync(downloadFilePath))
  652. fs.unlinkSync(downloadFilePath)
  653. rangeServer.close()
  654. ipcRenderer.removeListener('download-done', callback)
  655. done()
  656. }
  657. }
  658. ipcRenderer.on('download-done', callback)
  659. w.webContents.downloadURL(downloadUrl)
  660. })
  661. })
  662. })
  663. describe('ses.clearAuthCache(options[, callback])', function () {
  664. it('can clear http auth info from cache', function (done) {
  665. const ses = session.fromPartition('auth-cache')
  666. const server = http.createServer(function (req, res) {
  667. var credentials = auth(req)
  668. if (!credentials || credentials.name !== 'test' || credentials.pass !== 'test') {
  669. res.statusCode = 401
  670. res.setHeader('WWW-Authenticate', 'Basic realm="Restricted"')
  671. res.end()
  672. } else {
  673. res.end('authenticated')
  674. }
  675. })
  676. server.listen(0, '127.0.0.1', function () {
  677. const port = server.address().port
  678. function issueLoginRequest (attempt = 1) {
  679. if (attempt > 2) {
  680. server.close()
  681. return done()
  682. }
  683. const request = net.request({
  684. url: `http://127.0.0.1:${port}`,
  685. session: ses
  686. })
  687. request.on('login', function (info, callback) {
  688. attempt++
  689. assert.equal(info.scheme, 'basic')
  690. assert.equal(info.realm, 'Restricted')
  691. callback('test', 'test')
  692. })
  693. request.on('response', function (response) {
  694. let data = ''
  695. response.pause()
  696. response.on('data', function (chunk) {
  697. data += chunk
  698. })
  699. response.on('end', function () {
  700. assert.equal(data, 'authenticated')
  701. ses.clearAuthCache({type: 'password'}, function () {
  702. issueLoginRequest(attempt)
  703. })
  704. })
  705. response.on('error', function (error) {
  706. done(error)
  707. })
  708. response.resume()
  709. })
  710. // Internal api to bypass cache for testing.
  711. request.urlRequest._setLoadFlags(1 << 1)
  712. request.end()
  713. }
  714. issueLoginRequest()
  715. })
  716. })
  717. })
  718. describe('ses.setPermissionRequestHandler(handler)', () => {
  719. it('cancels any pending requests when cleared', (done) => {
  720. const ses = session.fromPartition('permissionTest')
  721. ses.setPermissionRequestHandler(() => {
  722. ses.setPermissionRequestHandler(null)
  723. })
  724. webview = new WebView()
  725. webview.addEventListener('ipc-message', function (e) {
  726. assert.equal(e.channel, 'message')
  727. assert.deepEqual(e.args, ['SecurityError'])
  728. done()
  729. })
  730. webview.src = 'file://' + fixtures + '/pages/permissions/midi-sysex.html'
  731. webview.partition = 'permissionTest'
  732. webview.setAttribute('nodeintegration', 'on')
  733. document.body.appendChild(webview)
  734. })
  735. })
  736. })