api-net-spec.js 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630
  1. const assert = require('assert')
  2. const {remote} = require('electron')
  3. const {ipcRenderer} = require('electron')
  4. const http = require('http')
  5. const url = require('url')
  6. const {net} = remote
  7. const {session} = remote
  8. function randomBuffer (size, start, end) {
  9. start = start || 0
  10. end = end || 255
  11. let range = 1 + end - start
  12. const buffer = Buffer.allocUnsafe(size)
  13. for (let i = 0; i < size; ++i) {
  14. buffer[i] = start + Math.floor(Math.random() * range)
  15. }
  16. return buffer
  17. }
  18. function randomString (length) {
  19. let buffer = randomBuffer(length, '0'.charCodeAt(0), 'z'.charCodeAt(0))
  20. return buffer.toString()
  21. }
  22. const kOneKiloByte = 1024
  23. const kOneMegaByte = kOneKiloByte * kOneKiloByte
  24. describe('net module', function () {
  25. let server
  26. const connections = new Set()
  27. beforeEach(function (done) {
  28. server = http.createServer()
  29. server.listen(0, '127.0.0.1', function () {
  30. server.url = `http://127.0.0.1:${server.address().port}`
  31. done()
  32. })
  33. server.on('connection', (connection) => {
  34. connections.add(connection)
  35. connection.once('close', () => {
  36. connections.delete(connection)
  37. })
  38. })
  39. })
  40. afterEach(function (done) {
  41. for (const connection of connections) {
  42. connection.destroy()
  43. }
  44. server.close(function () {
  45. server = null
  46. done()
  47. })
  48. })
  49. describe('HTTP basics', function () {
  50. it('should be able to issue a basic GET request', function (done) {
  51. const requestUrl = '/requestUrl'
  52. server.on('request', function (request, response) {
  53. switch (request.url) {
  54. case requestUrl:
  55. assert.equal(request.method, 'GET')
  56. response.end()
  57. break
  58. default:
  59. assert(false)
  60. }
  61. })
  62. const urlRequest = net.request(`${server.url}${requestUrl}`)
  63. urlRequest.on('response', function (response) {
  64. assert.equal(response.statusCode, 200)
  65. response.pause()
  66. response.on('data', function (chunk) {
  67. })
  68. response.on('end', function () {
  69. done()
  70. })
  71. response.resume()
  72. })
  73. urlRequest.end()
  74. })
  75. it('should be able to issue a basic POST request', function (done) {
  76. const requestUrl = '/requestUrl'
  77. server.on('request', function (request, response) {
  78. switch (request.url) {
  79. case requestUrl:
  80. assert.equal(request.method, 'POST')
  81. response.end()
  82. break
  83. default:
  84. assert(false)
  85. }
  86. })
  87. const urlRequest = net.request({
  88. method: 'POST',
  89. url: `${server.url}${requestUrl}`
  90. })
  91. urlRequest.on('response', function (response) {
  92. assert.equal(response.statusCode, 200)
  93. response.pause()
  94. response.on('data', function (chunk) {
  95. })
  96. response.on('end', function () {
  97. done()
  98. })
  99. response.resume()
  100. })
  101. urlRequest.end()
  102. })
  103. it('should fetch correct data in a GET request', function (done) {
  104. const requestUrl = '/requestUrl'
  105. const bodyData = 'Hello World!'
  106. server.on('request', function (request, response) {
  107. switch (request.url) {
  108. case requestUrl:
  109. assert.equal(request.method, 'GET')
  110. response.write(bodyData)
  111. response.end()
  112. break
  113. default:
  114. assert(false)
  115. }
  116. })
  117. const urlRequest = net.request(`${server.url}${requestUrl}`)
  118. urlRequest.on('response', function (response) {
  119. let expectedBodyData = ''
  120. assert.equal(response.statusCode, 200)
  121. response.pause()
  122. response.on('data', function (chunk) {
  123. expectedBodyData += chunk.toString()
  124. })
  125. response.on('end', function () {
  126. assert.equal(expectedBodyData, bodyData)
  127. done()
  128. })
  129. response.resume()
  130. })
  131. urlRequest.end()
  132. })
  133. it('should post the correct data in a POST request', function (done) {
  134. const requestUrl = '/requestUrl'
  135. const bodyData = 'Hello World!'
  136. server.on('request', function (request, response) {
  137. let postedBodyData = ''
  138. switch (request.url) {
  139. case requestUrl:
  140. assert.equal(request.method, 'POST')
  141. request.on('data', function (chunk) {
  142. postedBodyData += chunk.toString()
  143. })
  144. request.on('end', function () {
  145. assert.equal(postedBodyData, bodyData)
  146. response.end()
  147. })
  148. break
  149. default:
  150. assert(false)
  151. }
  152. })
  153. const urlRequest = net.request({
  154. method: 'POST',
  155. url: `${server.url}${requestUrl}`
  156. })
  157. urlRequest.on('response', function (response) {
  158. assert.equal(response.statusCode, 200)
  159. response.pause()
  160. response.on('data', function (chunk) {
  161. })
  162. response.on('end', function () {
  163. done()
  164. })
  165. response.resume()
  166. })
  167. urlRequest.write(bodyData)
  168. urlRequest.end()
  169. })
  170. it('should support chunked encoding', function (done) {
  171. const requestUrl = '/requestUrl'
  172. server.on('request', function (request, response) {
  173. switch (request.url) {
  174. case requestUrl:
  175. response.statusCode = 200
  176. response.statusMessage = 'OK'
  177. response.chunkedEncoding = true
  178. assert.equal(request.method, 'POST')
  179. assert.equal(request.headers['transfer-encoding'], 'chunked')
  180. assert(!request.headers['content-length'])
  181. request.on('data', function (chunk) {
  182. response.write(chunk)
  183. })
  184. request.on('end', function (chunk) {
  185. response.end(chunk)
  186. })
  187. break
  188. default:
  189. assert(false)
  190. }
  191. })
  192. const urlRequest = net.request({
  193. method: 'POST',
  194. url: `${server.url}${requestUrl}`
  195. })
  196. let chunkIndex = 0
  197. let chunkCount = 100
  198. let sentChunks = []
  199. let receivedChunks = []
  200. urlRequest.on('response', function (response) {
  201. assert.equal(response.statusCode, 200)
  202. response.pause()
  203. response.on('data', function (chunk) {
  204. receivedChunks.push(chunk)
  205. })
  206. response.on('end', function () {
  207. let sentData = Buffer.concat(sentChunks)
  208. let receivedData = Buffer.concat(receivedChunks)
  209. assert.equal(sentData.toString(), receivedData.toString())
  210. assert.equal(chunkIndex, chunkCount)
  211. done()
  212. })
  213. response.resume()
  214. })
  215. urlRequest.chunkedEncoding = true
  216. while (chunkIndex < chunkCount) {
  217. ++chunkIndex
  218. let chunk = randomBuffer(kOneKiloByte)
  219. sentChunks.push(chunk)
  220. assert(urlRequest.write(chunk))
  221. }
  222. urlRequest.end()
  223. })
  224. })
  225. describe('ClientRequest API', function () {
  226. afterEach(function () {
  227. session.defaultSession.webRequest.onBeforeRequest(null)
  228. })
  229. it('request/response objects should emit expected events', function (done) {
  230. const requestUrl = '/requestUrl'
  231. let bodyData = randomString(kOneMegaByte)
  232. server.on('request', function (request, response) {
  233. switch (request.url) {
  234. case requestUrl:
  235. response.statusCode = 200
  236. response.statusMessage = 'OK'
  237. response.write(bodyData)
  238. response.end()
  239. break
  240. default:
  241. assert(false)
  242. }
  243. })
  244. let requestResponseEventEmitted = false
  245. let requestFinishEventEmitted = false
  246. let requestCloseEventEmitted = false
  247. let responseDataEventEmitted = false
  248. let responseEndEventEmitted = false
  249. function maybeDone (done) {
  250. if (!requestCloseEventEmitted || !responseEndEventEmitted) {
  251. return
  252. }
  253. assert(requestResponseEventEmitted)
  254. assert(requestFinishEventEmitted)
  255. assert(requestCloseEventEmitted)
  256. assert(responseDataEventEmitted)
  257. assert(responseEndEventEmitted)
  258. done()
  259. }
  260. const urlRequest = net.request({
  261. method: 'GET',
  262. url: `${server.url}${requestUrl}`
  263. })
  264. urlRequest.on('response', function (response) {
  265. requestResponseEventEmitted = true
  266. const statusCode = response.statusCode
  267. assert.equal(statusCode, 200)
  268. let buffers = []
  269. response.pause()
  270. response.on('data', function (chunk) {
  271. buffers.push(chunk)
  272. responseDataEventEmitted = true
  273. })
  274. response.on('end', function () {
  275. let receivedBodyData = Buffer.concat(buffers)
  276. assert(receivedBodyData.toString() === bodyData)
  277. responseEndEventEmitted = true
  278. maybeDone(done)
  279. })
  280. response.resume()
  281. response.on('error', function (error) {
  282. assert.ifError(error)
  283. })
  284. response.on('aborted', function () {
  285. assert(false)
  286. })
  287. })
  288. urlRequest.on('finish', function () {
  289. requestFinishEventEmitted = true
  290. })
  291. urlRequest.on('error', function (error) {
  292. assert.ifError(error)
  293. })
  294. urlRequest.on('abort', function () {
  295. assert(false)
  296. })
  297. urlRequest.on('close', function () {
  298. requestCloseEventEmitted = true
  299. maybeDone(done)
  300. })
  301. urlRequest.end()
  302. })
  303. it('should be able to set a custom HTTP request header before first write', function (done) {
  304. const requestUrl = '/requestUrl'
  305. const customHeaderName = 'Some-Custom-Header-Name'
  306. const customHeaderValue = 'Some-Customer-Header-Value'
  307. server.on('request', function (request, response) {
  308. switch (request.url) {
  309. case requestUrl:
  310. assert.equal(request.headers[customHeaderName.toLowerCase()],
  311. customHeaderValue)
  312. response.statusCode = 200
  313. response.statusMessage = 'OK'
  314. response.end()
  315. break
  316. default:
  317. assert(false)
  318. }
  319. })
  320. const urlRequest = net.request({
  321. method: 'GET',
  322. url: `${server.url}${requestUrl}`
  323. })
  324. urlRequest.on('response', function (response) {
  325. const statusCode = response.statusCode
  326. assert.equal(statusCode, 200)
  327. response.pause()
  328. response.on('data', function (chunk) {
  329. })
  330. response.on('end', function () {
  331. done()
  332. })
  333. response.resume()
  334. })
  335. urlRequest.setHeader(customHeaderName, customHeaderValue)
  336. assert.equal(urlRequest.getHeader(customHeaderName),
  337. customHeaderValue)
  338. assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()),
  339. customHeaderValue)
  340. urlRequest.write('')
  341. assert.equal(urlRequest.getHeader(customHeaderName),
  342. customHeaderValue)
  343. assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()),
  344. customHeaderValue)
  345. urlRequest.end()
  346. })
  347. it('should be able to set a non-string object as a header value', function (done) {
  348. const requestUrl = '/requestUrl'
  349. const customHeaderName = 'Some-Integer-Value'
  350. const customHeaderValue = 900
  351. server.on('request', function (request, response) {
  352. switch (request.url) {
  353. case requestUrl:
  354. assert.equal(request.headers[customHeaderName.toLowerCase()],
  355. customHeaderValue.toString())
  356. response.statusCode = 200
  357. response.statusMessage = 'OK'
  358. response.end()
  359. break
  360. default:
  361. assert.equal(request.url, requestUrl)
  362. }
  363. })
  364. const urlRequest = net.request({
  365. method: 'GET',
  366. url: `${server.url}${requestUrl}`
  367. })
  368. urlRequest.on('response', function (response) {
  369. const statusCode = response.statusCode
  370. assert.equal(statusCode, 200)
  371. response.pause()
  372. response.on('end', function () {
  373. done()
  374. })
  375. response.resume()
  376. })
  377. urlRequest.setHeader(customHeaderName, customHeaderValue)
  378. assert.equal(urlRequest.getHeader(customHeaderName),
  379. customHeaderValue)
  380. assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()),
  381. customHeaderValue)
  382. urlRequest.write('')
  383. assert.equal(urlRequest.getHeader(customHeaderName),
  384. customHeaderValue)
  385. assert.equal(urlRequest.getHeader(customHeaderName.toLowerCase()),
  386. customHeaderValue)
  387. urlRequest.end()
  388. })
  389. it('should not be able to set a custom HTTP request header after first write', function (done) {
  390. const requestUrl = '/requestUrl'
  391. const customHeaderName = 'Some-Custom-Header-Name'
  392. const customHeaderValue = 'Some-Customer-Header-Value'
  393. server.on('request', function (request, response) {
  394. switch (request.url) {
  395. case requestUrl:
  396. assert(!request.headers[customHeaderName.toLowerCase()])
  397. response.statusCode = 200
  398. response.statusMessage = 'OK'
  399. response.end()
  400. break
  401. default:
  402. assert(false)
  403. }
  404. })
  405. const urlRequest = net.request({
  406. method: 'GET',
  407. url: `${server.url}${requestUrl}`
  408. })
  409. urlRequest.on('response', function (response) {
  410. const statusCode = response.statusCode
  411. assert.equal(statusCode, 200)
  412. response.pause()
  413. response.on('data', function (chunk) {
  414. })
  415. response.on('end', function () {
  416. done()
  417. })
  418. response.resume()
  419. })
  420. urlRequest.write('')
  421. assert.throws(() => {
  422. urlRequest.setHeader(customHeaderName, customHeaderValue)
  423. })
  424. assert(!urlRequest.getHeader(customHeaderName))
  425. urlRequest.end()
  426. })
  427. it('should be able to remove a custom HTTP request header before first write', function (done) {
  428. const requestUrl = '/requestUrl'
  429. const customHeaderName = 'Some-Custom-Header-Name'
  430. const customHeaderValue = 'Some-Customer-Header-Value'
  431. server.on('request', function (request, response) {
  432. switch (request.url) {
  433. case requestUrl:
  434. assert(!request.headers[customHeaderName.toLowerCase()])
  435. response.statusCode = 200
  436. response.statusMessage = 'OK'
  437. response.end()
  438. break
  439. default:
  440. assert(false)
  441. }
  442. })
  443. const urlRequest = net.request({
  444. method: 'GET',
  445. url: `${server.url}${requestUrl}`
  446. })
  447. urlRequest.on('response', function (response) {
  448. const statusCode = response.statusCode
  449. assert.equal(statusCode, 200)
  450. response.pause()
  451. response.on('data', function (chunk) {
  452. })
  453. response.on('end', function () {
  454. done()
  455. })
  456. response.resume()
  457. })
  458. urlRequest.setHeader(customHeaderName, customHeaderValue)
  459. assert.equal(urlRequest.getHeader(customHeaderName),
  460. customHeaderValue)
  461. urlRequest.removeHeader(customHeaderName)
  462. assert(!urlRequest.getHeader(customHeaderName))
  463. urlRequest.write('')
  464. urlRequest.end()
  465. })
  466. it('should not be able to remove a custom HTTP request header after first write', function (done) {
  467. const requestUrl = '/requestUrl'
  468. const customHeaderName = 'Some-Custom-Header-Name'
  469. const customHeaderValue = 'Some-Customer-Header-Value'
  470. server.on('request', function (request, response) {
  471. switch (request.url) {
  472. case requestUrl:
  473. assert.equal(request.headers[customHeaderName.toLowerCase()],
  474. customHeaderValue)
  475. response.statusCode = 200
  476. response.statusMessage = 'OK'
  477. response.end()
  478. break
  479. default:
  480. assert(false)
  481. }
  482. })
  483. const urlRequest = net.request({
  484. method: 'GET',
  485. url: `${server.url}${requestUrl}`
  486. })
  487. urlRequest.on('response', function (response) {
  488. const statusCode = response.statusCode
  489. assert.equal(statusCode, 200)
  490. response.pause()
  491. response.on('data', function (chunk) {
  492. })
  493. response.on('end', function () {
  494. done()
  495. })
  496. response.resume()
  497. })
  498. urlRequest.setHeader(customHeaderName, customHeaderValue)
  499. assert.equal(urlRequest.getHeader(customHeaderName),
  500. customHeaderValue)
  501. urlRequest.write('')
  502. assert.throws(function () {
  503. urlRequest.removeHeader(customHeaderName)
  504. })
  505. assert.equal(urlRequest.getHeader(customHeaderName),
  506. customHeaderValue)
  507. urlRequest.end()
  508. })
  509. it('should be able to set cookie header line', function (done) {
  510. const requestUrl = '/requestUrl'
  511. const cookieHeaderName = 'Cookie'
  512. const cookieHeaderValue = 'test=12345'
  513. const customSession = session.fromPartition('test-cookie-header')
  514. server.on('request', function (request, response) {
  515. switch (request.url) {
  516. case requestUrl:
  517. assert.equal(request.headers[cookieHeaderName.toLowerCase()],
  518. cookieHeaderValue)
  519. response.statusCode = 200
  520. response.statusMessage = 'OK'
  521. response.end()
  522. break
  523. default:
  524. assert(false)
  525. }
  526. })
  527. customSession.cookies.set({
  528. url: `${server.url}`,
  529. name: 'test',
  530. value: '11111'
  531. }, function (error) {
  532. if (error) {
  533. return done(error)
  534. }
  535. const urlRequest = net.request({
  536. method: 'GET',
  537. url: `${server.url}${requestUrl}`,
  538. session: customSession
  539. })
  540. urlRequest.on('response', function (response) {
  541. const statusCode = response.statusCode
  542. assert.equal(statusCode, 200)
  543. response.pause()
  544. response.on('data', function (chunk) {
  545. })
  546. response.on('end', function () {
  547. done()
  548. })
  549. response.resume()
  550. })
  551. urlRequest.setHeader(cookieHeaderName, cookieHeaderValue)
  552. assert.equal(urlRequest.getHeader(cookieHeaderName),
  553. cookieHeaderValue)
  554. urlRequest.end()
  555. })
  556. })
  557. it('should be able to abort an HTTP request before first write', function (done) {
  558. const requestUrl = '/requestUrl'
  559. server.on('request', function (request, response) {
  560. assert(false)
  561. })
  562. let requestAbortEventEmitted = false
  563. let requestCloseEventEmitted = false
  564. const urlRequest = net.request({
  565. method: 'GET',
  566. url: `${server.url}${requestUrl}`
  567. })
  568. urlRequest.on('response', function (response) {
  569. assert(false)
  570. })
  571. urlRequest.on('finish', function () {
  572. assert(false)
  573. })
  574. urlRequest.on('error', function () {
  575. assert(false)
  576. })
  577. urlRequest.on('abort', function () {
  578. requestAbortEventEmitted = true
  579. })
  580. urlRequest.on('close', function () {
  581. requestCloseEventEmitted = true
  582. assert(requestAbortEventEmitted)
  583. assert(requestCloseEventEmitted)
  584. done()
  585. })
  586. urlRequest.abort()
  587. assert(!urlRequest.write(''))
  588. urlRequest.end()
  589. })
  590. it('it should be able to abort an HTTP request before request end', function (done) {
  591. const requestUrl = '/requestUrl'
  592. let requestReceivedByServer = false
  593. server.on('request', function (request, response) {
  594. switch (request.url) {
  595. case requestUrl:
  596. requestReceivedByServer = true
  597. cancelRequest()
  598. break
  599. default:
  600. assert(false)
  601. }
  602. })
  603. let requestAbortEventEmitted = false
  604. let requestCloseEventEmitted = false
  605. const urlRequest = net.request({
  606. method: 'GET',
  607. url: `${server.url}${requestUrl}`
  608. })
  609. urlRequest.on('response', function (response) {
  610. assert(false)
  611. })
  612. urlRequest.on('finish', function () {
  613. assert(false)
  614. })
  615. urlRequest.on('error', function () {
  616. assert(false)
  617. })
  618. urlRequest.on('abort', function () {
  619. requestAbortEventEmitted = true
  620. })
  621. urlRequest.on('close', function () {
  622. requestCloseEventEmitted = true
  623. assert(requestReceivedByServer)
  624. assert(requestAbortEventEmitted)
  625. assert(requestCloseEventEmitted)
  626. done()
  627. })
  628. urlRequest.chunkedEncoding = true
  629. urlRequest.write(randomString(kOneKiloByte))
  630. function cancelRequest () {
  631. urlRequest.abort()
  632. }
  633. })
  634. it('it should be able to abort an HTTP request after request end and before response', function (done) {
  635. const requestUrl = '/requestUrl'
  636. let requestReceivedByServer = false
  637. server.on('request', function (request, response) {
  638. switch (request.url) {
  639. case requestUrl:
  640. requestReceivedByServer = true
  641. cancelRequest()
  642. process.nextTick(() => {
  643. response.statusCode = 200
  644. response.statusMessage = 'OK'
  645. response.end()
  646. })
  647. break
  648. default:
  649. assert(false)
  650. }
  651. })
  652. let requestAbortEventEmitted = false
  653. let requestFinishEventEmitted = false
  654. let requestCloseEventEmitted = false
  655. const urlRequest = net.request({
  656. method: 'GET',
  657. url: `${server.url}${requestUrl}`
  658. })
  659. urlRequest.on('response', function (response) {
  660. assert(false)
  661. })
  662. urlRequest.on('finish', function () {
  663. requestFinishEventEmitted = true
  664. })
  665. urlRequest.on('error', function () {
  666. assert(false)
  667. })
  668. urlRequest.on('abort', function () {
  669. requestAbortEventEmitted = true
  670. })
  671. urlRequest.on('close', function () {
  672. requestCloseEventEmitted = true
  673. assert(requestFinishEventEmitted)
  674. assert(requestReceivedByServer)
  675. assert(requestAbortEventEmitted)
  676. assert(requestCloseEventEmitted)
  677. done()
  678. })
  679. urlRequest.end(randomString(kOneKiloByte))
  680. function cancelRequest () {
  681. urlRequest.abort()
  682. }
  683. })
  684. it('it should be able to abort an HTTP request after response start', function (done) {
  685. const requestUrl = '/requestUrl'
  686. let requestReceivedByServer = false
  687. server.on('request', function (request, response) {
  688. switch (request.url) {
  689. case requestUrl:
  690. requestReceivedByServer = true
  691. response.statusCode = 200
  692. response.statusMessage = 'OK'
  693. response.write(randomString(kOneKiloByte))
  694. break
  695. default:
  696. assert(false)
  697. }
  698. })
  699. let requestFinishEventEmitted = false
  700. let requestResponseEventEmitted = false
  701. let requestAbortEventEmitted = false
  702. let requestCloseEventEmitted = false
  703. let responseAbortedEventEmitted = false
  704. const urlRequest = net.request({
  705. method: 'GET',
  706. url: `${server.url}${requestUrl}`
  707. })
  708. urlRequest.on('response', function (response) {
  709. requestResponseEventEmitted = true
  710. const statusCode = response.statusCode
  711. assert.equal(statusCode, 200)
  712. response.pause()
  713. response.on('data', function (chunk) {
  714. })
  715. response.on('end', function () {
  716. assert(false)
  717. })
  718. response.resume()
  719. response.on('error', function () {
  720. assert(false)
  721. })
  722. response.on('aborted', function () {
  723. responseAbortedEventEmitted = true
  724. })
  725. urlRequest.abort()
  726. })
  727. urlRequest.on('finish', function () {
  728. requestFinishEventEmitted = true
  729. })
  730. urlRequest.on('error', function () {
  731. assert(false)
  732. })
  733. urlRequest.on('abort', function () {
  734. requestAbortEventEmitted = true
  735. })
  736. urlRequest.on('close', function () {
  737. requestCloseEventEmitted = true
  738. assert(requestFinishEventEmitted, 'request should emit "finish" event')
  739. assert(requestReceivedByServer, 'request should be received by the server')
  740. assert(requestResponseEventEmitted, '"response" event should be emitted')
  741. assert(requestAbortEventEmitted, 'request should emit "abort" event')
  742. assert(responseAbortedEventEmitted, 'response should emit "aborted" event')
  743. assert(requestCloseEventEmitted, 'request should emit "close" event')
  744. done()
  745. })
  746. urlRequest.end(randomString(kOneKiloByte))
  747. })
  748. it('abort event should be emitted at most once', function (done) {
  749. const requestUrl = '/requestUrl'
  750. let requestReceivedByServer = false
  751. server.on('request', function (request, response) {
  752. switch (request.url) {
  753. case requestUrl:
  754. requestReceivedByServer = true
  755. cancelRequest()
  756. break
  757. default:
  758. assert(false)
  759. }
  760. })
  761. let requestFinishEventEmitted = false
  762. let requestAbortEventCount = 0
  763. let requestCloseEventEmitted = false
  764. const urlRequest = net.request({
  765. method: 'GET',
  766. url: `${server.url}${requestUrl}`
  767. })
  768. urlRequest.on('response', function (response) {
  769. assert(false)
  770. })
  771. urlRequest.on('finish', function () {
  772. requestFinishEventEmitted = true
  773. })
  774. urlRequest.on('error', function () {
  775. assert(false)
  776. })
  777. urlRequest.on('abort', function () {
  778. ++requestAbortEventCount
  779. urlRequest.abort()
  780. })
  781. urlRequest.on('close', function () {
  782. requestCloseEventEmitted = true
  783. // Let all pending async events to be emitted
  784. setTimeout(function () {
  785. assert(requestFinishEventEmitted)
  786. assert(requestReceivedByServer)
  787. assert.equal(requestAbortEventCount, 1)
  788. assert(requestCloseEventEmitted)
  789. done()
  790. }, 500)
  791. })
  792. urlRequest.end(randomString(kOneKiloByte))
  793. function cancelRequest () {
  794. urlRequest.abort()
  795. urlRequest.abort()
  796. }
  797. })
  798. it('Requests should be intercepted by webRequest module', function (done) {
  799. const requestUrl = '/requestUrl'
  800. const redirectUrl = '/redirectUrl'
  801. let requestIsRedirected = false
  802. server.on('request', function (request, response) {
  803. switch (request.url) {
  804. case requestUrl:
  805. assert(false)
  806. break
  807. case redirectUrl:
  808. requestIsRedirected = true
  809. response.end()
  810. break
  811. default:
  812. assert(false)
  813. }
  814. })
  815. let requestIsIntercepted = false
  816. session.defaultSession.webRequest.onBeforeRequest(
  817. function (details, callback) {
  818. if (details.url === `${server.url}${requestUrl}`) {
  819. requestIsIntercepted = true
  820. callback({
  821. redirectURL: `${server.url}${redirectUrl}`
  822. })
  823. } else {
  824. callback({
  825. cancel: false
  826. })
  827. }
  828. })
  829. const urlRequest = net.request(`${server.url}${requestUrl}`)
  830. urlRequest.on('response', function (response) {
  831. assert.equal(response.statusCode, 200)
  832. response.pause()
  833. response.on('data', function (chunk) {
  834. })
  835. response.on('end', function () {
  836. assert(requestIsRedirected, 'The server should receive a request to the forward URL')
  837. assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module')
  838. done()
  839. })
  840. response.resume()
  841. })
  842. urlRequest.end()
  843. })
  844. it('should to able to create and intercept a request using a custom session object', function (done) {
  845. const requestUrl = '/requestUrl'
  846. const redirectUrl = '/redirectUrl'
  847. const customPartitionName = 'custom-partition'
  848. let requestIsRedirected = false
  849. server.on('request', function (request, response) {
  850. switch (request.url) {
  851. case requestUrl:
  852. assert(false)
  853. break
  854. case redirectUrl:
  855. requestIsRedirected = true
  856. response.end()
  857. break
  858. default:
  859. assert(false)
  860. }
  861. })
  862. session.defaultSession.webRequest.onBeforeRequest(
  863. function (details, callback) {
  864. assert(false, 'Request should not be intercepted by the default session')
  865. })
  866. let customSession = session.fromPartition(customPartitionName, {
  867. cache: false
  868. })
  869. let requestIsIntercepted = false
  870. customSession.webRequest.onBeforeRequest(
  871. function (details, callback) {
  872. if (details.url === `${server.url}${requestUrl}`) {
  873. requestIsIntercepted = true
  874. callback({
  875. redirectURL: `${server.url}${redirectUrl}`
  876. })
  877. } else {
  878. callback({
  879. cancel: false
  880. })
  881. }
  882. })
  883. const urlRequest = net.request({
  884. url: `${server.url}${requestUrl}`,
  885. session: customSession
  886. })
  887. urlRequest.on('response', function (response) {
  888. assert.equal(response.statusCode, 200)
  889. response.pause()
  890. response.on('data', function (chunk) {
  891. })
  892. response.on('end', function () {
  893. assert(requestIsRedirected, 'The server should receive a request to the forward URL')
  894. assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module')
  895. done()
  896. })
  897. response.resume()
  898. })
  899. urlRequest.end()
  900. })
  901. it('should throw if given an invalid redirect mode', function () {
  902. const requestUrl = '/requestUrl'
  903. const options = {
  904. url: `${server.url}${requestUrl}`,
  905. redirect: 'custom'
  906. }
  907. assert.throws(function () {
  908. net.request(options)
  909. }, 'redirect mode should be one of follow, error or manual')
  910. })
  911. it('should throw when calling getHeader without a name', function () {
  912. assert.throws(function () {
  913. net.request({url: `${server.url}/requestUrl`}).getHeader()
  914. }, /`name` is required for getHeader\(name\)\./)
  915. assert.throws(function () {
  916. net.request({url: `${server.url}/requestUrl`}).getHeader(null)
  917. }, /`name` is required for getHeader\(name\)\./)
  918. })
  919. it('should throw when calling removeHeader without a name', function () {
  920. assert.throws(function () {
  921. net.request({url: `${server.url}/requestUrl`}).removeHeader()
  922. }, /`name` is required for removeHeader\(name\)\./)
  923. assert.throws(function () {
  924. net.request({url: `${server.url}/requestUrl`}).removeHeader(null)
  925. }, /`name` is required for removeHeader\(name\)\./)
  926. })
  927. it('should follow redirect when no redirect mode is provided', function (done) {
  928. const requestUrl = '/301'
  929. server.on('request', function (request, response) {
  930. switch (request.url) {
  931. case '/301':
  932. response.statusCode = '301'
  933. response.setHeader('Location', '/200')
  934. response.end()
  935. break
  936. case '/200':
  937. response.statusCode = '200'
  938. response.end()
  939. break
  940. default:
  941. assert(false)
  942. }
  943. })
  944. const urlRequest = net.request({
  945. url: `${server.url}${requestUrl}`
  946. })
  947. urlRequest.on('response', function (response) {
  948. assert.equal(response.statusCode, 200)
  949. done()
  950. })
  951. urlRequest.end()
  952. })
  953. it('should follow redirect chain when no redirect mode is provided', function (done) {
  954. const requestUrl = '/redirectChain'
  955. server.on('request', function (request, response) {
  956. switch (request.url) {
  957. case '/redirectChain':
  958. response.statusCode = '301'
  959. response.setHeader('Location', '/301')
  960. response.end()
  961. break
  962. case '/301':
  963. response.statusCode = '301'
  964. response.setHeader('Location', '/200')
  965. response.end()
  966. break
  967. case '/200':
  968. response.statusCode = '200'
  969. response.end()
  970. break
  971. default:
  972. assert(false)
  973. }
  974. })
  975. const urlRequest = net.request({
  976. url: `${server.url}${requestUrl}`
  977. })
  978. urlRequest.on('response', function (response) {
  979. assert.equal(response.statusCode, 200)
  980. done()
  981. })
  982. urlRequest.end()
  983. })
  984. it('should not follow redirect when mode is error', function (done) {
  985. const requestUrl = '/301'
  986. server.on('request', function (request, response) {
  987. switch (request.url) {
  988. case '/301':
  989. response.statusCode = '301'
  990. response.setHeader('Location', '/200')
  991. response.end()
  992. break
  993. case '/200':
  994. response.statusCode = '200'
  995. response.end()
  996. break
  997. default:
  998. assert(false)
  999. }
  1000. })
  1001. const urlRequest = net.request({
  1002. url: `${server.url}${requestUrl}`,
  1003. redirect: 'error'
  1004. })
  1005. urlRequest.on('error', function (error) {
  1006. assert.equal(error.message, 'Request cannot follow redirect with the current redirect mode')
  1007. })
  1008. urlRequest.on('close', function () {
  1009. done()
  1010. })
  1011. urlRequest.end()
  1012. })
  1013. it('should allow follow redirect when mode is manual', function (done) {
  1014. const requestUrl = '/redirectChain'
  1015. let redirectCount = 0
  1016. server.on('request', function (request, response) {
  1017. switch (request.url) {
  1018. case '/redirectChain':
  1019. response.statusCode = '301'
  1020. response.setHeader('Location', '/301')
  1021. response.end()
  1022. break
  1023. case '/301':
  1024. response.statusCode = '301'
  1025. response.setHeader('Location', '/200')
  1026. response.end()
  1027. break
  1028. case '/200':
  1029. response.statusCode = '200'
  1030. response.end()
  1031. break
  1032. default:
  1033. assert(false)
  1034. }
  1035. })
  1036. const urlRequest = net.request({
  1037. url: `${server.url}${requestUrl}`,
  1038. redirect: 'manual'
  1039. })
  1040. urlRequest.on('response', function (response) {
  1041. assert.equal(response.statusCode, 200)
  1042. assert.equal(redirectCount, 2)
  1043. done()
  1044. })
  1045. urlRequest.on('redirect', function (status, method, url) {
  1046. if (url === `${server.url}/301` || url === `${server.url}/200`) {
  1047. redirectCount += 1
  1048. urlRequest.followRedirect()
  1049. }
  1050. })
  1051. urlRequest.end()
  1052. })
  1053. it('should allow cancelling redirect when mode is manual', function (done) {
  1054. const requestUrl = '/redirectChain'
  1055. let redirectCount = 0
  1056. server.on('request', function (request, response) {
  1057. switch (request.url) {
  1058. case '/redirectChain':
  1059. response.statusCode = '301'
  1060. response.setHeader('Location', '/redirect/1')
  1061. response.end()
  1062. break
  1063. case '/redirect/1':
  1064. response.statusCode = '200'
  1065. response.setHeader('Location', '/redirect/2')
  1066. response.end()
  1067. break
  1068. case '/redirect/2':
  1069. response.statusCode = '200'
  1070. response.end()
  1071. break
  1072. default:
  1073. assert(false)
  1074. }
  1075. })
  1076. const urlRequest = net.request({
  1077. url: `${server.url}${requestUrl}`,
  1078. redirect: 'manual'
  1079. })
  1080. urlRequest.on('response', function (response) {
  1081. assert.equal(response.statusCode, 200)
  1082. response.pause()
  1083. response.on('data', function (chunk) {
  1084. })
  1085. response.on('end', function () {
  1086. urlRequest.abort()
  1087. })
  1088. response.resume()
  1089. })
  1090. urlRequest.on('close', function () {
  1091. assert.equal(redirectCount, 1)
  1092. done()
  1093. })
  1094. urlRequest.on('redirect', function (status, method, url) {
  1095. if (url === `${server.url}/redirect/1`) {
  1096. redirectCount += 1
  1097. urlRequest.followRedirect()
  1098. }
  1099. })
  1100. urlRequest.end()
  1101. })
  1102. it('should throw if given an invalid session option', function (done) {
  1103. const requestUrl = '/requestUrl'
  1104. try {
  1105. const urlRequest = net.request({
  1106. url: `${server.url}${requestUrl}`,
  1107. session: 1
  1108. })
  1109. urlRequest
  1110. } catch (exception) {
  1111. done()
  1112. }
  1113. })
  1114. it('should to able to create and intercept a request using a custom partition name', function (done) {
  1115. const requestUrl = '/requestUrl'
  1116. const redirectUrl = '/redirectUrl'
  1117. const customPartitionName = 'custom-partition'
  1118. let requestIsRedirected = false
  1119. server.on('request', function (request, response) {
  1120. switch (request.url) {
  1121. case requestUrl:
  1122. assert(false)
  1123. break
  1124. case redirectUrl:
  1125. requestIsRedirected = true
  1126. response.end()
  1127. break
  1128. default:
  1129. assert(false)
  1130. }
  1131. })
  1132. session.defaultSession.webRequest.onBeforeRequest(
  1133. function (details, callback) {
  1134. assert(false, 'Request should not be intercepted by the default session')
  1135. })
  1136. let customSession = session.fromPartition(customPartitionName, {
  1137. cache: false
  1138. })
  1139. let requestIsIntercepted = false
  1140. customSession.webRequest.onBeforeRequest(
  1141. function (details, callback) {
  1142. if (details.url === `${server.url}${requestUrl}`) {
  1143. requestIsIntercepted = true
  1144. callback({
  1145. redirectURL: `${server.url}${redirectUrl}`
  1146. })
  1147. } else {
  1148. callback({
  1149. cancel: false
  1150. })
  1151. }
  1152. })
  1153. const urlRequest = net.request({
  1154. url: `${server.url}${requestUrl}`,
  1155. partition: customPartitionName
  1156. })
  1157. urlRequest.on('response', function (response) {
  1158. assert.equal(response.statusCode, 200)
  1159. response.pause()
  1160. response.on('data', function (chunk) {
  1161. })
  1162. response.on('end', function () {
  1163. assert(requestIsRedirected, 'The server should receive a request to the forward URL')
  1164. assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module')
  1165. done()
  1166. })
  1167. response.resume()
  1168. })
  1169. urlRequest.end()
  1170. })
  1171. it('should throw if given an invalid partition option', function (done) {
  1172. const requestUrl = '/requestUrl'
  1173. try {
  1174. const urlRequest = net.request({
  1175. url: `${server.url}${requestUrl}`,
  1176. partition: 1
  1177. })
  1178. urlRequest
  1179. } catch (exception) {
  1180. done()
  1181. }
  1182. })
  1183. it('should be able to create a request with options', function (done) {
  1184. const requestUrl = '/'
  1185. const customHeaderName = 'Some-Custom-Header-Name'
  1186. const customHeaderValue = 'Some-Customer-Header-Value'
  1187. server.on('request', function (request, response) {
  1188. switch (request.url) {
  1189. case requestUrl:
  1190. assert.equal(request.method, 'GET')
  1191. assert.equal(request.headers[customHeaderName.toLowerCase()],
  1192. customHeaderValue)
  1193. response.statusCode = 200
  1194. response.statusMessage = 'OK'
  1195. response.end()
  1196. break
  1197. default:
  1198. assert(false)
  1199. }
  1200. })
  1201. const serverUrl = url.parse(server.url)
  1202. let options = {
  1203. port: serverUrl.port,
  1204. hostname: '127.0.0.1',
  1205. headers: {}
  1206. }
  1207. options.headers[customHeaderName] = customHeaderValue
  1208. const urlRequest = net.request(options)
  1209. urlRequest.on('response', function (response) {
  1210. assert.equal(response.statusCode, 200)
  1211. response.pause()
  1212. response.on('data', function (chunk) {
  1213. })
  1214. response.on('end', function () {
  1215. done()
  1216. })
  1217. response.resume()
  1218. })
  1219. urlRequest.end()
  1220. })
  1221. it('should be able to pipe a readable stream into a net request', function (done) {
  1222. const nodeRequestUrl = '/nodeRequestUrl'
  1223. const netRequestUrl = '/netRequestUrl'
  1224. const bodyData = randomString(kOneMegaByte)
  1225. let netRequestReceived = false
  1226. let netRequestEnded = false
  1227. server.on('request', function (request, response) {
  1228. switch (request.url) {
  1229. case nodeRequestUrl:
  1230. response.write(bodyData)
  1231. response.end()
  1232. break
  1233. case netRequestUrl:
  1234. netRequestReceived = true
  1235. let receivedBodyData = ''
  1236. request.on('data', function (chunk) {
  1237. receivedBodyData += chunk.toString()
  1238. })
  1239. request.on('end', function (chunk) {
  1240. netRequestEnded = true
  1241. if (chunk) {
  1242. receivedBodyData += chunk.toString()
  1243. }
  1244. assert.equal(receivedBodyData, bodyData)
  1245. response.end()
  1246. })
  1247. break
  1248. default:
  1249. assert(false)
  1250. }
  1251. })
  1252. let nodeRequest = http.request(`${server.url}${nodeRequestUrl}`)
  1253. nodeRequest.on('response', function (nodeResponse) {
  1254. const netRequest = net.request(`${server.url}${netRequestUrl}`)
  1255. netRequest.on('response', function (netResponse) {
  1256. assert.equal(netResponse.statusCode, 200)
  1257. netResponse.pause()
  1258. netResponse.on('data', function (chunk) {
  1259. })
  1260. netResponse.on('end', function () {
  1261. assert(netRequestReceived)
  1262. assert(netRequestEnded)
  1263. done()
  1264. })
  1265. netResponse.resume()
  1266. })
  1267. nodeResponse.pipe(netRequest)
  1268. })
  1269. nodeRequest.end()
  1270. })
  1271. it('should emit error event on server socket close', function (done) {
  1272. const requestUrl = '/requestUrl'
  1273. server.on('request', function (request, response) {
  1274. switch (request.url) {
  1275. case requestUrl:
  1276. request.socket.destroy()
  1277. break
  1278. default:
  1279. assert(false)
  1280. }
  1281. })
  1282. let requestErrorEventEmitted = false
  1283. const urlRequest = net.request(`${server.url}${requestUrl}`)
  1284. urlRequest.on('error', function (error) {
  1285. assert(error)
  1286. requestErrorEventEmitted = true
  1287. })
  1288. urlRequest.on('close', function () {
  1289. assert(requestErrorEventEmitted)
  1290. done()
  1291. })
  1292. urlRequest.end()
  1293. })
  1294. })
  1295. describe('IncomingMessage API', function () {
  1296. it('response object should implement the IncomingMessage API', function (done) {
  1297. const requestUrl = '/requestUrl'
  1298. const customHeaderName = 'Some-Custom-Header-Name'
  1299. const customHeaderValue = 'Some-Customer-Header-Value'
  1300. server.on('request', function (request, response) {
  1301. switch (request.url) {
  1302. case requestUrl:
  1303. response.statusCode = 200
  1304. response.statusMessage = 'OK'
  1305. response.setHeader(customHeaderName, customHeaderValue)
  1306. response.end()
  1307. break
  1308. default:
  1309. assert(false)
  1310. }
  1311. })
  1312. const urlRequest = net.request({
  1313. method: 'GET',
  1314. url: `${server.url}${requestUrl}`
  1315. })
  1316. urlRequest.on('response', function (response) {
  1317. const statusCode = response.statusCode
  1318. assert(typeof statusCode === 'number')
  1319. assert.equal(statusCode, 200)
  1320. const statusMessage = response.statusMessage
  1321. assert(typeof statusMessage === 'string')
  1322. assert.equal(statusMessage, 'OK')
  1323. const headers = response.headers
  1324. assert(typeof headers === 'object')
  1325. assert.deepEqual(headers[customHeaderName.toLowerCase()],
  1326. [customHeaderValue])
  1327. const httpVersion = response.httpVersion
  1328. assert(typeof httpVersion === 'string')
  1329. assert(httpVersion.length > 0)
  1330. const httpVersionMajor = response.httpVersionMajor
  1331. assert(typeof httpVersionMajor === 'number')
  1332. assert(httpVersionMajor >= 1)
  1333. const httpVersionMinor = response.httpVersionMinor
  1334. assert(typeof httpVersionMinor === 'number')
  1335. assert(httpVersionMinor >= 0)
  1336. response.pause()
  1337. response.on('data', function (chunk) {
  1338. })
  1339. response.on('end', function () {
  1340. done()
  1341. })
  1342. response.resume()
  1343. })
  1344. urlRequest.end()
  1345. })
  1346. it('should be able to pipe a net response into a writable stream', function (done) {
  1347. const nodeRequestUrl = '/nodeRequestUrl'
  1348. const netRequestUrl = '/netRequestUrl'
  1349. const bodyData = randomString(kOneMegaByte)
  1350. server.on('request', function (request, response) {
  1351. switch (request.url) {
  1352. case netRequestUrl:
  1353. response.statusCode = 200
  1354. response.statusMessage = 'OK'
  1355. response.write(bodyData)
  1356. response.end()
  1357. break
  1358. case nodeRequestUrl:
  1359. let receivedBodyData = ''
  1360. request.on('data', function (chunk) {
  1361. receivedBodyData += chunk.toString()
  1362. })
  1363. request.on('end', function (chunk) {
  1364. if (chunk) {
  1365. receivedBodyData += chunk.toString()
  1366. }
  1367. assert.equal(receivedBodyData, bodyData)
  1368. response.end()
  1369. })
  1370. break
  1371. default:
  1372. assert(false)
  1373. }
  1374. })
  1375. ipcRenderer.once('api-net-spec-done', function () {
  1376. done()
  1377. })
  1378. // Execute below code directly within the browser context without
  1379. // using the remote module.
  1380. ipcRenderer.send('eval', `
  1381. const {net} = require('electron')
  1382. const http = require('http')
  1383. const netRequest = net.request('${server.url}${netRequestUrl}')
  1384. netRequest.on('response', function (netResponse) {
  1385. const serverUrl = url.parse('${server.url}')
  1386. const nodeOptions = {
  1387. method: 'POST',
  1388. path: '${nodeRequestUrl}',
  1389. port: serverUrl.port
  1390. }
  1391. let nodeRequest = http.request(nodeOptions)
  1392. nodeRequest.on('response', function (nodeResponse) {
  1393. nodeResponse.on('data', function (chunk) {
  1394. })
  1395. nodeResponse.on('end', function (chunk) {
  1396. event.sender.send('api-net-spec-done')
  1397. })
  1398. })
  1399. netResponse.pipe(nodeRequest)
  1400. })
  1401. netRequest.end()
  1402. `)
  1403. })
  1404. it('should not emit any event after close', function (done) {
  1405. const requestUrl = '/requestUrl'
  1406. let bodyData = randomString(kOneKiloByte)
  1407. server.on('request', function (request, response) {
  1408. switch (request.url) {
  1409. case requestUrl:
  1410. response.statusCode = 200
  1411. response.statusMessage = 'OK'
  1412. response.write(bodyData)
  1413. response.end()
  1414. break
  1415. default:
  1416. assert(false)
  1417. }
  1418. })
  1419. let requestCloseEventEmitted = false
  1420. const urlRequest = net.request({
  1421. method: 'GET',
  1422. url: `${server.url}${requestUrl}`
  1423. })
  1424. urlRequest.on('response', function (response) {
  1425. assert(!requestCloseEventEmitted)
  1426. const statusCode = response.statusCode
  1427. assert.equal(statusCode, 200)
  1428. response.pause()
  1429. response.on('data', function () {
  1430. })
  1431. response.on('end', function () {
  1432. })
  1433. response.resume()
  1434. response.on('error', function () {
  1435. assert(!requestCloseEventEmitted)
  1436. })
  1437. response.on('aborted', function () {
  1438. assert(!requestCloseEventEmitted)
  1439. })
  1440. })
  1441. urlRequest.on('finish', function () {
  1442. assert(!requestCloseEventEmitted)
  1443. })
  1444. urlRequest.on('error', function () {
  1445. assert(!requestCloseEventEmitted)
  1446. })
  1447. urlRequest.on('abort', function () {
  1448. assert(!requestCloseEventEmitted)
  1449. })
  1450. urlRequest.on('close', function () {
  1451. requestCloseEventEmitted = true
  1452. // Wait so that all async events get scheduled.
  1453. setTimeout(function () {
  1454. done()
  1455. }, 100)
  1456. })
  1457. urlRequest.end()
  1458. })
  1459. })
  1460. describe('Stability and performance', function (done) {
  1461. it('should free unreferenced, never-started request objects without crash', function (done) {
  1462. const requestUrl = '/requestUrl'
  1463. ipcRenderer.once('api-net-spec-done', function () {
  1464. done()
  1465. })
  1466. ipcRenderer.send('eval', `
  1467. const {net} = require('electron')
  1468. const urlRequest = net.request('${server.url}${requestUrl}')
  1469. process.nextTick(function () {
  1470. const v8Util = process.atomBinding('v8_util')
  1471. v8Util.requestGarbageCollectionForTesting()
  1472. event.sender.send('api-net-spec-done')
  1473. })
  1474. `)
  1475. })
  1476. it('should not collect on-going requests without crash', function (done) {
  1477. const requestUrl = '/requestUrl'
  1478. server.on('request', function (request, response) {
  1479. switch (request.url) {
  1480. case requestUrl:
  1481. response.statusCode = 200
  1482. response.statusMessage = 'OK'
  1483. response.write(randomString(kOneKiloByte))
  1484. ipcRenderer.once('api-net-spec-resume', function () {
  1485. response.write(randomString(kOneKiloByte))
  1486. response.end()
  1487. })
  1488. break
  1489. default:
  1490. assert(false)
  1491. }
  1492. })
  1493. ipcRenderer.once('api-net-spec-done', function () {
  1494. done()
  1495. })
  1496. // Execute below code directly within the browser context without
  1497. // using the remote module.
  1498. ipcRenderer.send('eval', `
  1499. const {net} = require('electron')
  1500. const urlRequest = net.request('${server.url}${requestUrl}')
  1501. urlRequest.on('response', function (response) {
  1502. response.on('data', function () {
  1503. })
  1504. response.on('end', function () {
  1505. event.sender.send('api-net-spec-done')
  1506. })
  1507. process.nextTick(function () {
  1508. // Trigger a garbage collection.
  1509. const v8Util = process.atomBinding('v8_util')
  1510. v8Util.requestGarbageCollectionForTesting()
  1511. event.sender.send('api-net-spec-resume')
  1512. })
  1513. })
  1514. urlRequest.end()
  1515. `)
  1516. })
  1517. it('should collect unreferenced, ended requests without crash', function (done) {
  1518. const requestUrl = '/requestUrl'
  1519. server.on('request', function (request, response) {
  1520. switch (request.url) {
  1521. case requestUrl:
  1522. response.statusCode = 200
  1523. response.statusMessage = 'OK'
  1524. response.end()
  1525. break
  1526. default:
  1527. assert(false)
  1528. }
  1529. })
  1530. ipcRenderer.once('api-net-spec-done', function () {
  1531. done()
  1532. })
  1533. ipcRenderer.send('eval', `
  1534. const {net} = require('electron')
  1535. const urlRequest = net.request('${server.url}${requestUrl}')
  1536. urlRequest.on('response', function (response) {
  1537. response.on('data', function () {
  1538. })
  1539. response.on('end', function () {
  1540. })
  1541. })
  1542. urlRequest.on('close', function () {
  1543. process.nextTick(function () {
  1544. const v8Util = process.atomBinding('v8_util')
  1545. v8Util.requestGarbageCollectionForTesting()
  1546. event.sender.send('api-net-spec-done')
  1547. })
  1548. })
  1549. urlRequest.end()
  1550. `)
  1551. })
  1552. })
  1553. })