api-web-request-spec.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. const chai = require('chai')
  2. const dirtyChai = require('dirty-chai')
  3. const http = require('http')
  4. const qs = require('querystring')
  5. const remote = require('electron').remote
  6. const session = remote.session
  7. const { expect } = chai
  8. chai.use(dirtyChai)
  9. /* The whole webRequest API doesn't use standard callbacks */
  10. /* eslint-disable standard/no-callback-literal */
  11. describe('webRequest module', () => {
  12. const ses = session.defaultSession
  13. const server = http.createServer((req, res) => {
  14. if (req.url === '/serverRedirect') {
  15. res.statusCode = 301
  16. res.setHeader('Location', 'http://' + req.rawHeaders[1])
  17. res.end()
  18. } else {
  19. res.setHeader('Custom', ['Header'])
  20. let content = req.url
  21. if (req.headers.accept === '*/*;test/header') {
  22. content += 'header/received'
  23. }
  24. res.end(content)
  25. }
  26. })
  27. let defaultURL = null
  28. before((done) => {
  29. server.listen(0, '127.0.0.1', () => {
  30. const port = server.address().port
  31. defaultURL = 'http://127.0.0.1:' + port + '/'
  32. done()
  33. })
  34. })
  35. after(() => {
  36. server.close()
  37. })
  38. describe('webRequest.onBeforeRequest', () => {
  39. afterEach(() => {
  40. ses.webRequest.onBeforeRequest(null)
  41. })
  42. it('can cancel the request', (done) => {
  43. ses.webRequest.onBeforeRequest((details, callback) => {
  44. callback({
  45. cancel: true
  46. })
  47. })
  48. $.ajax({
  49. url: defaultURL,
  50. success: () => {
  51. done('unexpected success')
  52. },
  53. error: () => {
  54. done()
  55. }
  56. })
  57. })
  58. it('can filter URLs', (done) => {
  59. const filter = { urls: [defaultURL + 'filter/*'] }
  60. ses.webRequest.onBeforeRequest(filter, (details, callback) => {
  61. callback({ cancel: true })
  62. })
  63. $.ajax({
  64. url: `${defaultURL}nofilter/test`,
  65. success: (data) => {
  66. expect(data).to.equal('/nofilter/test')
  67. $.ajax({
  68. url: `${defaultURL}filter/test`,
  69. success: () => done('unexpected success'),
  70. error: () => done()
  71. })
  72. },
  73. error: (xhr, errorType) => done(errorType)
  74. })
  75. })
  76. it('receives details object', (done) => {
  77. ses.webRequest.onBeforeRequest((details, callback) => {
  78. expect(details.id).to.be.a('number')
  79. expect(details.timestamp).to.be.a('number')
  80. expect(details.webContentsId).to.be.a('number')
  81. expect(details.url).to.be.a('string').that.is.equal(defaultURL)
  82. expect(details.method).to.be.a('string').that.is.equal('GET')
  83. expect(details.resourceType).to.be.a('string').that.is.equal('xhr')
  84. expect(details.uploadData).to.be.undefined()
  85. callback({})
  86. })
  87. $.ajax({
  88. url: defaultURL,
  89. success: (data) => {
  90. expect(data).to.equal('/')
  91. done()
  92. },
  93. error: (xhr, errorType) => done(errorType)
  94. })
  95. })
  96. it('receives post data in details object', (done) => {
  97. const postData = {
  98. name: 'post test',
  99. type: 'string'
  100. }
  101. ses.webRequest.onBeforeRequest((details, callback) => {
  102. expect(details.url).to.equal(defaultURL)
  103. expect(details.method).to.equal('POST')
  104. expect(details.uploadData).to.have.lengthOf(1)
  105. const data = qs.parse(details.uploadData[0].bytes.toString())
  106. expect(data).to.deep.equal(postData)
  107. callback({ cancel: true })
  108. })
  109. $.ajax({
  110. url: defaultURL,
  111. type: 'POST',
  112. data: postData,
  113. success: () => {},
  114. error: () => done()
  115. })
  116. })
  117. it('can redirect the request', (done) => {
  118. ses.webRequest.onBeforeRequest((details, callback) => {
  119. if (details.url === defaultURL) {
  120. callback({ redirectURL: `${defaultURL}redirect` })
  121. } else {
  122. callback({})
  123. }
  124. })
  125. $.ajax({
  126. url: defaultURL,
  127. success: (data) => {
  128. expect(data).to.equal('/redirect')
  129. done()
  130. },
  131. error: (xhr, errorType) => done(errorType)
  132. })
  133. })
  134. })
  135. describe('webRequest.onBeforeSendHeaders', () => {
  136. afterEach(() => {
  137. ses.webRequest.onBeforeSendHeaders(null)
  138. })
  139. it('receives details object', (done) => {
  140. ses.webRequest.onBeforeSendHeaders((details, callback) => {
  141. expect(details.requestHeaders).to.be.an('object')
  142. expect(details.requestHeaders['Foo.Bar']).to.equal('baz')
  143. callback({})
  144. })
  145. $.ajax({
  146. url: defaultURL,
  147. headers: { 'Foo.Bar': 'baz' },
  148. success: (data) => {
  149. expect(data).to.equal('/')
  150. done()
  151. },
  152. error: (xhr, errorType) => done(errorType)
  153. })
  154. })
  155. it('can change the request headers', (done) => {
  156. ses.webRequest.onBeforeSendHeaders((details, callback) => {
  157. const requestHeaders = details.requestHeaders
  158. requestHeaders.Accept = '*/*;test/header'
  159. callback({ requestHeaders: requestHeaders })
  160. })
  161. $.ajax({
  162. url: defaultURL,
  163. success: (data) => {
  164. expect(data).to.equal('/header/received')
  165. done()
  166. },
  167. error: (xhr, errorType) => done(errorType)
  168. })
  169. })
  170. it('resets the whole headers', (done) => {
  171. const requestHeaders = {
  172. Test: 'header'
  173. }
  174. ses.webRequest.onBeforeSendHeaders((details, callback) => {
  175. callback({ requestHeaders: requestHeaders })
  176. })
  177. ses.webRequest.onSendHeaders((details) => {
  178. expect(details.requestHeaders).to.deep.equal(requestHeaders)
  179. done()
  180. })
  181. $.ajax({
  182. url: defaultURL,
  183. error: (xhr, errorType) => done(errorType)
  184. })
  185. })
  186. })
  187. describe('webRequest.onSendHeaders', () => {
  188. afterEach(() => {
  189. ses.webRequest.onSendHeaders(null)
  190. })
  191. it('receives details object', (done) => {
  192. ses.webRequest.onSendHeaders((details) => {
  193. expect(details.requestHeaders).to.be.an('object')
  194. })
  195. $.ajax({
  196. url: defaultURL,
  197. success: (data) => {
  198. expect(data).to.equal('/')
  199. done()
  200. },
  201. error: (xhr, errorType) => done(errorType)
  202. })
  203. })
  204. })
  205. describe('webRequest.onHeadersReceived', () => {
  206. afterEach(() => {
  207. ses.webRequest.onHeadersReceived(null)
  208. })
  209. it('receives details object', (done) => {
  210. ses.webRequest.onHeadersReceived((details, callback) => {
  211. expect(details.statusLine).to.equal('HTTP/1.1 200 OK')
  212. expect(details.statusCode).to.equal(200)
  213. expect(details.responseHeaders['Custom']).to.deep.equal(['Header'])
  214. callback({})
  215. })
  216. $.ajax({
  217. url: defaultURL,
  218. success: (data) => {
  219. expect(data).to.equal('/')
  220. done()
  221. },
  222. error: (xhr, errorType) => done(errorType)
  223. })
  224. })
  225. it('can change the response header', (done) => {
  226. ses.webRequest.onHeadersReceived((details, callback) => {
  227. const responseHeaders = details.responseHeaders
  228. responseHeaders['Custom'] = ['Changed']
  229. callback({ responseHeaders: responseHeaders })
  230. })
  231. $.ajax({
  232. url: defaultURL,
  233. success: (data, status, xhr) => {
  234. expect(xhr.getResponseHeader('Custom')).to.equal('Changed')
  235. expect(data).to.equal('/')
  236. done()
  237. },
  238. error: (xhr, errorType) => done(errorType)
  239. })
  240. })
  241. it('does not change header by default', (done) => {
  242. ses.webRequest.onHeadersReceived((details, callback) => {
  243. callback({})
  244. })
  245. $.ajax({
  246. url: defaultURL,
  247. success: (data, status, xhr) => {
  248. expect(xhr.getResponseHeader('Custom')).to.equal('Header')
  249. expect(data).to.equal('/')
  250. done()
  251. },
  252. error: (xhr, errorType) => done(errorType)
  253. })
  254. })
  255. it('follows server redirect', (done) => {
  256. ses.webRequest.onHeadersReceived((details, callback) => {
  257. const responseHeaders = details.responseHeaders
  258. callback({ responseHeaders: responseHeaders })
  259. })
  260. $.ajax({
  261. url: defaultURL + 'serverRedirect',
  262. success: (data, status, xhr) => {
  263. expect(xhr.getResponseHeader('Custom')).to.equal('Header')
  264. done()
  265. },
  266. error: (xhr, errorType) => done(errorType)
  267. })
  268. })
  269. it('can change the header status', (done) => {
  270. ses.webRequest.onHeadersReceived((details, callback) => {
  271. const responseHeaders = details.responseHeaders
  272. callback({
  273. responseHeaders: responseHeaders,
  274. statusLine: 'HTTP/1.1 404 Not Found'
  275. })
  276. })
  277. $.ajax({
  278. url: defaultURL,
  279. success: (data, status, xhr) => {},
  280. error: (xhr, errorType) => {
  281. expect(xhr.getResponseHeader('Custom')).to.equal('Header')
  282. done()
  283. }
  284. })
  285. })
  286. })
  287. describe('webRequest.onResponseStarted', () => {
  288. afterEach(() => {
  289. ses.webRequest.onResponseStarted(null)
  290. })
  291. it('receives details object', (done) => {
  292. ses.webRequest.onResponseStarted((details) => {
  293. expect(details.fromCache).to.be.a('boolean')
  294. expect(details.statusLine).to.equal('HTTP/1.1 200 OK')
  295. expect(details.statusCode).to.equal(200)
  296. expect(details.responseHeaders['Custom']).to.deep.equal(['Header'])
  297. })
  298. $.ajax({
  299. url: defaultURL,
  300. success: (data, status, xhr) => {
  301. expect(xhr.getResponseHeader('Custom')).to.equal('Header')
  302. expect(data).to.equal('/')
  303. done()
  304. },
  305. error: (xhr, errorType) => done(errorType)
  306. })
  307. })
  308. })
  309. describe('webRequest.onBeforeRedirect', () => {
  310. afterEach(() => {
  311. ses.webRequest.onBeforeRedirect(null)
  312. ses.webRequest.onBeforeRequest(null)
  313. })
  314. it('receives details object', (done) => {
  315. const redirectURL = defaultURL + 'redirect'
  316. ses.webRequest.onBeforeRequest((details, callback) => {
  317. if (details.url === defaultURL) {
  318. callback({ redirectURL: redirectURL })
  319. } else {
  320. callback({})
  321. }
  322. })
  323. ses.webRequest.onBeforeRedirect((details) => {
  324. expect(details.fromCache).to.be.a('boolean')
  325. expect(details.statusLine).to.equal('HTTP/1.1 307 Internal Redirect')
  326. expect(details.statusCode).to.equal(307)
  327. expect(details.redirectURL).to.equal(redirectURL)
  328. })
  329. $.ajax({
  330. url: defaultURL,
  331. success: (data) => {
  332. expect(data).to.equal('/redirect')
  333. done()
  334. },
  335. error: (xhr, errorType) => done(errorType)
  336. })
  337. })
  338. })
  339. describe('webRequest.onCompleted', () => {
  340. afterEach(() => {
  341. ses.webRequest.onCompleted(null)
  342. })
  343. it('receives details object', (done) => {
  344. ses.webRequest.onCompleted((details) => {
  345. expect(details.fromCache).to.be.a('boolean')
  346. expect(details.statusLine).to.equal('HTTP/1.1 200 OK')
  347. expect(details.statusCode).to.equal(200)
  348. })
  349. $.ajax({
  350. url: defaultURL,
  351. success: (data) => {
  352. expect(data).to.equal('/')
  353. done()
  354. },
  355. error: (xhr, errorType) => done(errorType)
  356. })
  357. })
  358. })
  359. describe('webRequest.onErrorOccurred', () => {
  360. afterEach(() => {
  361. ses.webRequest.onErrorOccurred(null)
  362. ses.webRequest.onBeforeRequest(null)
  363. })
  364. it('receives details object', (done) => {
  365. ses.webRequest.onBeforeRequest((details, callback) => {
  366. callback({ cancel: true })
  367. })
  368. ses.webRequest.onErrorOccurred((details) => {
  369. expect(details.error).to.equal('net::ERR_BLOCKED_BY_CLIENT')
  370. done()
  371. })
  372. $.ajax({
  373. url: defaultURL,
  374. success: () => done('unexpected success')
  375. })
  376. })
  377. })
  378. })