api-net-spec.js 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
  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. describe('HTTP basics', function () {
  26. let server
  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. })
  34. afterEach(function () {
  35. server.close(function () {
  36. })
  37. server = null
  38. })
  39. it('should be able to issue a basic GET request', function (done) {
  40. const requestUrl = '/requestUrl'
  41. server.on('request', function (request, response) {
  42. switch (request.url) {
  43. case requestUrl:
  44. assert.equal(request.method, 'GET')
  45. response.end()
  46. break
  47. default:
  48. assert(false)
  49. }
  50. })
  51. const urlRequest = net.request(`${server.url}${requestUrl}`)
  52. urlRequest.on('response', function (response) {
  53. assert.equal(response.statusCode, 200)
  54. response.pause()
  55. response.on('data', function (chunk) {
  56. })
  57. response.on('end', function () {
  58. done()
  59. })
  60. response.resume()
  61. })
  62. urlRequest.end()
  63. })
  64. it('should be able to issue a basic POST request', function (done) {
  65. const requestUrl = '/requestUrl'
  66. server.on('request', function (request, response) {
  67. switch (request.url) {
  68. case requestUrl:
  69. assert.equal(request.method, 'POST')
  70. response.end()
  71. break
  72. default:
  73. assert(false)
  74. }
  75. })
  76. const urlRequest = net.request({
  77. method: 'POST',
  78. url: `${server.url}${requestUrl}`
  79. })
  80. urlRequest.on('response', function (response) {
  81. assert.equal(response.statusCode, 200)
  82. response.pause()
  83. response.on('data', function (chunk) {
  84. })
  85. response.on('end', function () {
  86. done()
  87. })
  88. response.resume()
  89. })
  90. urlRequest.end()
  91. })
  92. it('should fetch correct data in a GET request', function (done) {
  93. const requestUrl = '/requestUrl'
  94. const bodyData = 'Hello World!'
  95. server.on('request', function (request, response) {
  96. switch (request.url) {
  97. case requestUrl:
  98. assert.equal(request.method, 'GET')
  99. response.write(bodyData)
  100. response.end()
  101. break
  102. default:
  103. assert(false)
  104. }
  105. })
  106. const urlRequest = net.request(`${server.url}${requestUrl}`)
  107. urlRequest.on('response', function (response) {
  108. let expectedBodyData = ''
  109. assert.equal(response.statusCode, 200)
  110. response.pause()
  111. response.on('data', function (chunk) {
  112. expectedBodyData += chunk.toString()
  113. })
  114. response.on('end', function () {
  115. assert.equal(expectedBodyData, bodyData)
  116. done()
  117. })
  118. response.resume()
  119. })
  120. urlRequest.end()
  121. })
  122. it('should post the correct data in a POST request', function (done) {
  123. const requestUrl = '/requestUrl'
  124. const bodyData = 'Hello World!'
  125. server.on('request', function (request, response) {
  126. let postedBodyData = ''
  127. switch (request.url) {
  128. case requestUrl:
  129. assert.equal(request.method, 'POST')
  130. request.on('data', function (chunk) {
  131. postedBodyData += chunk.toString()
  132. })
  133. request.on('end', function () {
  134. assert.equal(postedBodyData, bodyData)
  135. response.end()
  136. })
  137. break
  138. default:
  139. assert(false)
  140. }
  141. })
  142. const urlRequest = net.request({
  143. method: 'POST',
  144. url: `${server.url}${requestUrl}`
  145. })
  146. urlRequest.on('response', function (response) {
  147. assert.equal(response.statusCode, 200)
  148. response.pause()
  149. response.on('data', function (chunk) {
  150. })
  151. response.on('end', function () {
  152. done()
  153. })
  154. response.resume()
  155. })
  156. urlRequest.write(bodyData)
  157. urlRequest.end()
  158. })
  159. it('should support chunked encoding', function (done) {
  160. const requestUrl = '/requestUrl'
  161. server.on('request', function (request, response) {
  162. switch (request.url) {
  163. case requestUrl:
  164. response.statusCode = 200
  165. response.statusMessage = 'OK'
  166. response.chunkedEncoding = true
  167. assert.equal(request.method, 'POST')
  168. assert.equal(request.headers['transfer-encoding'], 'chunked')
  169. assert(!request.headers['content-length'])
  170. request.on('data', function (chunk) {
  171. response.write(chunk)
  172. })
  173. request.on('end', function (chunk) {
  174. response.end(chunk)
  175. })
  176. break
  177. default:
  178. assert(false)
  179. }
  180. })
  181. const urlRequest = net.request({
  182. method: 'POST',
  183. url: `${server.url}${requestUrl}`
  184. })
  185. let chunkIndex = 0
  186. let chunkCount = 100
  187. let sentChunks = []
  188. let receivedChunks = []
  189. urlRequest.on('response', function (response) {
  190. assert.equal(response.statusCode, 200)
  191. response.pause()
  192. response.on('data', function (chunk) {
  193. receivedChunks.push(chunk)
  194. })
  195. response.on('end', function () {
  196. let sentData = Buffer.concat(sentChunks)
  197. let receivedData = Buffer.concat(receivedChunks)
  198. assert.equal(sentData.toString(), receivedData.toString())
  199. assert.equal(chunkIndex, chunkCount)
  200. done()
  201. })
  202. response.resume()
  203. })
  204. urlRequest.chunkedEncoding = true
  205. while (chunkIndex < chunkCount) {
  206. ++chunkIndex
  207. let chunk = randomBuffer(kOneKiloByte)
  208. sentChunks.push(chunk)
  209. assert(urlRequest.write(chunk))
  210. }
  211. urlRequest.end()
  212. })
  213. })
  214. describe('ClientRequest API', function () {
  215. let server
  216. beforeEach(function (done) {
  217. server = http.createServer()
  218. server.listen(0, '127.0.0.1', function () {
  219. server.url = 'http://127.0.0.1:' + server.address().port
  220. done()
  221. })
  222. })
  223. afterEach(function () {
  224. server.close(function () {
  225. })
  226. server = null
  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 not be able to set a custom HTTP request header after first write', function (done) {
  348. const requestUrl = '/requestUrl'
  349. const customHeaderName = 'Some-Custom-Header-Name'
  350. const customHeaderValue = 'Some-Customer-Header-Value'
  351. server.on('request', function (request, response) {
  352. switch (request.url) {
  353. case requestUrl:
  354. assert(!request.headers[customHeaderName.toLowerCase()])
  355. response.statusCode = 200
  356. response.statusMessage = 'OK'
  357. response.end()
  358. break
  359. default:
  360. assert(false)
  361. }
  362. })
  363. const urlRequest = net.request({
  364. method: 'GET',
  365. url: `${server.url}${requestUrl}`
  366. })
  367. urlRequest.on('response', function (response) {
  368. const statusCode = response.statusCode
  369. assert.equal(statusCode, 200)
  370. response.pause()
  371. response.on('data', function (chunk) {
  372. })
  373. response.on('end', function () {
  374. done()
  375. })
  376. response.resume()
  377. })
  378. urlRequest.write('')
  379. assert.throws(() => {
  380. urlRequest.setHeader(customHeaderName, customHeaderValue)
  381. })
  382. assert(!urlRequest.getHeader(customHeaderName))
  383. urlRequest.end()
  384. })
  385. it('should be able to remove a custom HTTP request header before first write', function (done) {
  386. const requestUrl = '/requestUrl'
  387. const customHeaderName = 'Some-Custom-Header-Name'
  388. const customHeaderValue = 'Some-Customer-Header-Value'
  389. server.on('request', function (request, response) {
  390. switch (request.url) {
  391. case requestUrl:
  392. assert(!request.headers[customHeaderName.toLowerCase()])
  393. response.statusCode = 200
  394. response.statusMessage = 'OK'
  395. response.end()
  396. break
  397. default:
  398. assert(false)
  399. }
  400. })
  401. const urlRequest = net.request({
  402. method: 'GET',
  403. url: `${server.url}${requestUrl}`
  404. })
  405. urlRequest.on('response', function (response) {
  406. const statusCode = response.statusCode
  407. assert.equal(statusCode, 200)
  408. response.pause()
  409. response.on('data', function (chunk) {
  410. })
  411. response.on('end', function () {
  412. done()
  413. })
  414. response.resume()
  415. })
  416. urlRequest.setHeader(customHeaderName, customHeaderValue)
  417. assert.equal(urlRequest.getHeader(customHeaderName),
  418. customHeaderValue)
  419. urlRequest.removeHeader(customHeaderName)
  420. assert(!urlRequest.getHeader(customHeaderName))
  421. urlRequest.write('')
  422. urlRequest.end()
  423. })
  424. it('should not be able to remove a custom HTTP request header after first write', function (done) {
  425. const requestUrl = '/requestUrl'
  426. const customHeaderName = 'Some-Custom-Header-Name'
  427. const customHeaderValue = 'Some-Customer-Header-Value'
  428. server.on('request', function (request, response) {
  429. switch (request.url) {
  430. case requestUrl:
  431. assert.equal(request.headers[customHeaderName.toLowerCase()],
  432. customHeaderValue)
  433. response.statusCode = 200
  434. response.statusMessage = 'OK'
  435. response.end()
  436. break
  437. default:
  438. assert(false)
  439. }
  440. })
  441. const urlRequest = net.request({
  442. method: 'GET',
  443. url: `${server.url}${requestUrl}`
  444. })
  445. urlRequest.on('response', function (response) {
  446. const statusCode = response.statusCode
  447. assert.equal(statusCode, 200)
  448. response.pause()
  449. response.on('data', function (chunk) {
  450. })
  451. response.on('end', function () {
  452. done()
  453. })
  454. response.resume()
  455. })
  456. urlRequest.setHeader(customHeaderName, customHeaderValue)
  457. assert.equal(urlRequest.getHeader(customHeaderName),
  458. customHeaderValue)
  459. urlRequest.write('')
  460. assert.throws(function () {
  461. urlRequest.removeHeader(customHeaderName)
  462. })
  463. assert.equal(urlRequest.getHeader(customHeaderName),
  464. customHeaderValue)
  465. urlRequest.end()
  466. })
  467. it('should be able to set cookie header line', function (done) {
  468. const requestUrl = '/requestUrl'
  469. const cookieHeaderName = 'Cookie'
  470. const cookieHeaderValue = 'test=12345'
  471. const customSession = session.fromPartition('test-cookie-header')
  472. server.on('request', function (request, response) {
  473. switch (request.url) {
  474. case requestUrl:
  475. assert.equal(request.headers[cookieHeaderName.toLowerCase()],
  476. cookieHeaderValue)
  477. response.statusCode = 200
  478. response.statusMessage = 'OK'
  479. response.end()
  480. break
  481. default:
  482. assert(false)
  483. }
  484. })
  485. customSession.cookies.set({
  486. url: `${server.url}`,
  487. name: 'test',
  488. value: '11111'
  489. }, function (error) {
  490. if (error) {
  491. return done(error)
  492. }
  493. const urlRequest = net.request({
  494. method: 'GET',
  495. url: `${server.url}${requestUrl}`,
  496. session: customSession
  497. })
  498. urlRequest.on('response', function (response) {
  499. const statusCode = response.statusCode
  500. assert.equal(statusCode, 200)
  501. response.pause()
  502. response.on('data', function (chunk) {
  503. })
  504. response.on('end', function () {
  505. done()
  506. })
  507. response.resume()
  508. })
  509. urlRequest.setHeader(cookieHeaderName, cookieHeaderValue)
  510. assert.equal(urlRequest.getHeader(cookieHeaderName),
  511. cookieHeaderValue)
  512. urlRequest.end()
  513. })
  514. })
  515. it('should be able to abort an HTTP request before first write', function (done) {
  516. const requestUrl = '/requestUrl'
  517. server.on('request', function (request, response) {
  518. assert(false)
  519. })
  520. let requestAbortEventEmitted = false
  521. let requestCloseEventEmitted = false
  522. const urlRequest = net.request({
  523. method: 'GET',
  524. url: `${server.url}${requestUrl}`
  525. })
  526. urlRequest.on('response', function (response) {
  527. assert(false)
  528. })
  529. urlRequest.on('finish', function () {
  530. assert(false)
  531. })
  532. urlRequest.on('error', function () {
  533. assert(false)
  534. })
  535. urlRequest.on('abort', function () {
  536. requestAbortEventEmitted = true
  537. })
  538. urlRequest.on('close', function () {
  539. requestCloseEventEmitted = true
  540. assert(requestAbortEventEmitted)
  541. assert(requestCloseEventEmitted)
  542. done()
  543. })
  544. urlRequest.abort()
  545. assert(!urlRequest.write(''))
  546. urlRequest.end()
  547. })
  548. it('it should be able to abort an HTTP request before request end', function (done) {
  549. const requestUrl = '/requestUrl'
  550. let requestReceivedByServer = false
  551. server.on('request', function (request, response) {
  552. switch (request.url) {
  553. case requestUrl:
  554. requestReceivedByServer = true
  555. cancelRequest()
  556. break
  557. default:
  558. assert(false)
  559. }
  560. })
  561. let requestAbortEventEmitted = false
  562. let requestCloseEventEmitted = false
  563. const urlRequest = net.request({
  564. method: 'GET',
  565. url: `${server.url}${requestUrl}`
  566. })
  567. urlRequest.on('response', function (response) {
  568. assert(false)
  569. })
  570. urlRequest.on('finish', function () {
  571. assert(false)
  572. })
  573. urlRequest.on('error', function () {
  574. assert(false)
  575. })
  576. urlRequest.on('abort', function () {
  577. requestAbortEventEmitted = true
  578. })
  579. urlRequest.on('close', function () {
  580. requestCloseEventEmitted = true
  581. assert(requestReceivedByServer)
  582. assert(requestAbortEventEmitted)
  583. assert(requestCloseEventEmitted)
  584. done()
  585. })
  586. urlRequest.chunkedEncoding = true
  587. urlRequest.write(randomString(kOneKiloByte))
  588. function cancelRequest () {
  589. urlRequest.abort()
  590. }
  591. })
  592. it('it should be able to abort an HTTP request after request end and before response', function (done) {
  593. const requestUrl = '/requestUrl'
  594. let requestReceivedByServer = false
  595. server.on('request', function (request, response) {
  596. switch (request.url) {
  597. case requestUrl:
  598. requestReceivedByServer = true
  599. cancelRequest()
  600. process.nextTick(() => {
  601. response.statusCode = 200
  602. response.statusMessage = 'OK'
  603. response.end()
  604. })
  605. break
  606. default:
  607. assert(false)
  608. }
  609. })
  610. let requestAbortEventEmitted = false
  611. let requestFinishEventEmitted = false
  612. let requestCloseEventEmitted = false
  613. const urlRequest = net.request({
  614. method: 'GET',
  615. url: `${server.url}${requestUrl}`
  616. })
  617. urlRequest.on('response', function (response) {
  618. assert(false)
  619. })
  620. urlRequest.on('finish', function () {
  621. requestFinishEventEmitted = true
  622. })
  623. urlRequest.on('error', function () {
  624. assert(false)
  625. })
  626. urlRequest.on('abort', function () {
  627. requestAbortEventEmitted = true
  628. })
  629. urlRequest.on('close', function () {
  630. requestCloseEventEmitted = true
  631. assert(requestFinishEventEmitted)
  632. assert(requestReceivedByServer)
  633. assert(requestAbortEventEmitted)
  634. assert(requestCloseEventEmitted)
  635. done()
  636. })
  637. urlRequest.end(randomString(kOneKiloByte))
  638. function cancelRequest () {
  639. urlRequest.abort()
  640. }
  641. })
  642. it('it should be able to abort an HTTP request after response start', function (done) {
  643. const requestUrl = '/requestUrl'
  644. let requestReceivedByServer = false
  645. server.on('request', function (request, response) {
  646. switch (request.url) {
  647. case requestUrl:
  648. requestReceivedByServer = true
  649. response.statusCode = 200
  650. response.statusMessage = 'OK'
  651. response.write(randomString(kOneKiloByte))
  652. break
  653. default:
  654. assert(false)
  655. }
  656. })
  657. let requestFinishEventEmitted = false
  658. let requestResponseEventEmitted = false
  659. let requestAbortEventEmitted = false
  660. let requestCloseEventEmitted = false
  661. let responseAbortedEventEmitted = false
  662. const urlRequest = net.request({
  663. method: 'GET',
  664. url: `${server.url}${requestUrl}`
  665. })
  666. urlRequest.on('response', function (response) {
  667. requestResponseEventEmitted = true
  668. const statusCode = response.statusCode
  669. assert.equal(statusCode, 200)
  670. response.pause()
  671. response.on('data', function (chunk) {
  672. })
  673. response.on('end', function () {
  674. assert(false)
  675. })
  676. response.resume()
  677. response.on('error', function () {
  678. assert(false)
  679. })
  680. response.on('aborted', function () {
  681. responseAbortedEventEmitted = true
  682. })
  683. urlRequest.abort()
  684. })
  685. urlRequest.on('finish', function () {
  686. requestFinishEventEmitted = true
  687. })
  688. urlRequest.on('error', function () {
  689. assert(false)
  690. })
  691. urlRequest.on('abort', function () {
  692. requestAbortEventEmitted = true
  693. })
  694. urlRequest.on('close', function () {
  695. requestCloseEventEmitted = true
  696. assert(requestFinishEventEmitted, 'request should emit "finish" event')
  697. assert(requestReceivedByServer, 'request should be received by the server')
  698. assert(requestResponseEventEmitted, '"response" event should be emitted')
  699. assert(requestAbortEventEmitted, 'request should emit "abort" event')
  700. assert(responseAbortedEventEmitted, 'response should emit "aborted" event')
  701. assert(requestCloseEventEmitted, 'request should emit "close" event')
  702. done()
  703. })
  704. urlRequest.end(randomString(kOneKiloByte))
  705. })
  706. it('abort event should be emitted at most once', function (done) {
  707. const requestUrl = '/requestUrl'
  708. let requestReceivedByServer = false
  709. server.on('request', function (request, response) {
  710. switch (request.url) {
  711. case requestUrl:
  712. requestReceivedByServer = true
  713. cancelRequest()
  714. break
  715. default:
  716. assert(false)
  717. }
  718. })
  719. let requestFinishEventEmitted = false
  720. let requestAbortEventCount = 0
  721. let requestCloseEventEmitted = false
  722. const urlRequest = net.request({
  723. method: 'GET',
  724. url: `${server.url}${requestUrl}`
  725. })
  726. urlRequest.on('response', function (response) {
  727. assert(false)
  728. })
  729. urlRequest.on('finish', function () {
  730. requestFinishEventEmitted = true
  731. })
  732. urlRequest.on('error', function () {
  733. assert(false)
  734. })
  735. urlRequest.on('abort', function () {
  736. ++requestAbortEventCount
  737. urlRequest.abort()
  738. })
  739. urlRequest.on('close', function () {
  740. requestCloseEventEmitted = true
  741. // Let all pending async events to be emitted
  742. setTimeout(function () {
  743. assert(requestFinishEventEmitted)
  744. assert(requestReceivedByServer)
  745. assert.equal(requestAbortEventCount, 1)
  746. assert(requestCloseEventEmitted)
  747. done()
  748. }, 500)
  749. })
  750. urlRequest.end(randomString(kOneKiloByte))
  751. function cancelRequest () {
  752. urlRequest.abort()
  753. urlRequest.abort()
  754. }
  755. })
  756. it('Requests should be intercepted by webRequest module', function (done) {
  757. const requestUrl = '/requestUrl'
  758. const redirectUrl = '/redirectUrl'
  759. let requestIsRedirected = false
  760. server.on('request', function (request, response) {
  761. switch (request.url) {
  762. case requestUrl:
  763. assert(false)
  764. break
  765. case redirectUrl:
  766. requestIsRedirected = true
  767. response.end()
  768. break
  769. default:
  770. assert(false)
  771. }
  772. })
  773. let requestIsIntercepted = false
  774. session.defaultSession.webRequest.onBeforeRequest(
  775. function (details, callback) {
  776. if (details.url === `${server.url}${requestUrl}`) {
  777. requestIsIntercepted = true
  778. callback({
  779. redirectURL: `${server.url}${redirectUrl}`
  780. })
  781. } else {
  782. callback({
  783. cancel: false
  784. })
  785. }
  786. })
  787. const urlRequest = net.request(`${server.url}${requestUrl}`)
  788. urlRequest.on('response', function (response) {
  789. assert.equal(response.statusCode, 200)
  790. response.pause()
  791. response.on('data', function (chunk) {
  792. })
  793. response.on('end', function () {
  794. assert(requestIsRedirected, 'The server should receive a request to the forward URL')
  795. assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module')
  796. done()
  797. })
  798. response.resume()
  799. })
  800. urlRequest.end()
  801. })
  802. it('should to able to create and intercept a request using a custom session object', function (done) {
  803. const requestUrl = '/requestUrl'
  804. const redirectUrl = '/redirectUrl'
  805. const customPartitionName = 'custom-partition'
  806. let requestIsRedirected = false
  807. server.on('request', function (request, response) {
  808. switch (request.url) {
  809. case requestUrl:
  810. assert(false)
  811. break
  812. case redirectUrl:
  813. requestIsRedirected = true
  814. response.end()
  815. break
  816. default:
  817. assert(false)
  818. }
  819. })
  820. session.defaultSession.webRequest.onBeforeRequest(
  821. function (details, callback) {
  822. assert(false, 'Request should not be intercepted by the default session')
  823. })
  824. let customSession = session.fromPartition(customPartitionName, {
  825. cache: false
  826. })
  827. let requestIsIntercepted = false
  828. customSession.webRequest.onBeforeRequest(
  829. function (details, callback) {
  830. if (details.url === `${server.url}${requestUrl}`) {
  831. requestIsIntercepted = true
  832. callback({
  833. redirectURL: `${server.url}${redirectUrl}`
  834. })
  835. } else {
  836. callback({
  837. cancel: false
  838. })
  839. }
  840. })
  841. const urlRequest = net.request({
  842. url: `${server.url}${requestUrl}`,
  843. session: customSession
  844. })
  845. urlRequest.on('response', function (response) {
  846. assert.equal(response.statusCode, 200)
  847. response.pause()
  848. response.on('data', function (chunk) {
  849. })
  850. response.on('end', function () {
  851. assert(requestIsRedirected, 'The server should receive a request to the forward URL')
  852. assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module')
  853. done()
  854. })
  855. response.resume()
  856. })
  857. urlRequest.end()
  858. })
  859. it('should throw if given an invalid session option', function (done) {
  860. const requestUrl = '/requestUrl'
  861. try {
  862. const urlRequest = net.request({
  863. url: `${server.url}${requestUrl}`,
  864. session: 1
  865. })
  866. urlRequest
  867. } catch (exception) {
  868. done()
  869. }
  870. })
  871. it('should to able to create and intercept a request using a custom partition name', function (done) {
  872. const requestUrl = '/requestUrl'
  873. const redirectUrl = '/redirectUrl'
  874. const customPartitionName = 'custom-partition'
  875. let requestIsRedirected = false
  876. server.on('request', function (request, response) {
  877. switch (request.url) {
  878. case requestUrl:
  879. assert(false)
  880. break
  881. case redirectUrl:
  882. requestIsRedirected = true
  883. response.end()
  884. break
  885. default:
  886. assert(false)
  887. }
  888. })
  889. session.defaultSession.webRequest.onBeforeRequest(
  890. function (details, callback) {
  891. assert(false, 'Request should not be intercepted by the default session')
  892. })
  893. let customSession = session.fromPartition(customPartitionName, {
  894. cache: false
  895. })
  896. let requestIsIntercepted = false
  897. customSession.webRequest.onBeforeRequest(
  898. function (details, callback) {
  899. if (details.url === `${server.url}${requestUrl}`) {
  900. requestIsIntercepted = true
  901. callback({
  902. redirectURL: `${server.url}${redirectUrl}`
  903. })
  904. } else {
  905. callback({
  906. cancel: false
  907. })
  908. }
  909. })
  910. const urlRequest = net.request({
  911. url: `${server.url}${requestUrl}`,
  912. partition: customPartitionName
  913. })
  914. urlRequest.on('response', function (response) {
  915. assert.equal(response.statusCode, 200)
  916. response.pause()
  917. response.on('data', function (chunk) {
  918. })
  919. response.on('end', function () {
  920. assert(requestIsRedirected, 'The server should receive a request to the forward URL')
  921. assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module')
  922. done()
  923. })
  924. response.resume()
  925. })
  926. urlRequest.end()
  927. })
  928. it('should throw if given an invalid partition option', function (done) {
  929. const requestUrl = '/requestUrl'
  930. try {
  931. const urlRequest = net.request({
  932. url: `${server.url}${requestUrl}`,
  933. partition: 1
  934. })
  935. urlRequest
  936. } catch (exception) {
  937. done()
  938. }
  939. })
  940. it('should be able to create a request with options', function (done) {
  941. const requestUrl = '/'
  942. const customHeaderName = 'Some-Custom-Header-Name'
  943. const customHeaderValue = 'Some-Customer-Header-Value'
  944. server.on('request', function (request, response) {
  945. switch (request.url) {
  946. case requestUrl:
  947. assert.equal(request.method, 'GET')
  948. assert.equal(request.headers[customHeaderName.toLowerCase()],
  949. customHeaderValue)
  950. response.statusCode = 200
  951. response.statusMessage = 'OK'
  952. response.end()
  953. break
  954. default:
  955. assert(false)
  956. }
  957. })
  958. const serverUrl = url.parse(server.url)
  959. let options = {
  960. port: serverUrl.port,
  961. hostname: '127.0.0.1',
  962. headers: {}
  963. }
  964. options.headers[customHeaderName] = customHeaderValue
  965. const urlRequest = net.request(options)
  966. urlRequest.on('response', function (response) {
  967. assert.equal(response.statusCode, 200)
  968. response.pause()
  969. response.on('data', function (chunk) {
  970. })
  971. response.on('end', function () {
  972. done()
  973. })
  974. response.resume()
  975. })
  976. urlRequest.end()
  977. })
  978. it('should be able to pipe a readable stream into a net request', function (done) {
  979. const nodeRequestUrl = '/nodeRequestUrl'
  980. const netRequestUrl = '/netRequestUrl'
  981. const bodyData = randomString(kOneMegaByte)
  982. let netRequestReceived = false
  983. let netRequestEnded = false
  984. server.on('request', function (request, response) {
  985. switch (request.url) {
  986. case nodeRequestUrl:
  987. response.write(bodyData)
  988. response.end()
  989. break
  990. case netRequestUrl:
  991. netRequestReceived = true
  992. let receivedBodyData = ''
  993. request.on('data', function (chunk) {
  994. receivedBodyData += chunk.toString()
  995. })
  996. request.on('end', function (chunk) {
  997. netRequestEnded = true
  998. if (chunk) {
  999. receivedBodyData += chunk.toString()
  1000. }
  1001. assert.equal(receivedBodyData, bodyData)
  1002. response.end()
  1003. })
  1004. break
  1005. default:
  1006. assert(false)
  1007. }
  1008. })
  1009. let nodeRequest = http.request(`${server.url}${nodeRequestUrl}`)
  1010. nodeRequest.on('response', function (nodeResponse) {
  1011. const netRequest = net.request(`${server.url}${netRequestUrl}`)
  1012. netRequest.on('response', function (netResponse) {
  1013. assert.equal(netResponse.statusCode, 200)
  1014. netResponse.pause()
  1015. netResponse.on('data', function (chunk) {
  1016. })
  1017. netResponse.on('end', function () {
  1018. assert(netRequestReceived)
  1019. assert(netRequestEnded)
  1020. done()
  1021. })
  1022. netResponse.resume()
  1023. })
  1024. nodeResponse.pipe(netRequest)
  1025. })
  1026. nodeRequest.end()
  1027. })
  1028. it('should emit error event on server socket close', function (done) {
  1029. const requestUrl = '/requestUrl'
  1030. server.on('request', function (request, response) {
  1031. switch (request.url) {
  1032. case requestUrl:
  1033. request.socket.destroy()
  1034. break
  1035. default:
  1036. assert(false)
  1037. }
  1038. })
  1039. let requestErrorEventEmitted = false
  1040. const urlRequest = net.request(`${server.url}${requestUrl}`)
  1041. urlRequest.on('error', function (error) {
  1042. assert(error)
  1043. requestErrorEventEmitted = true
  1044. })
  1045. urlRequest.on('close', function () {
  1046. assert(requestErrorEventEmitted)
  1047. done()
  1048. })
  1049. urlRequest.end()
  1050. })
  1051. })
  1052. describe('IncomingMessage API', function () {
  1053. let server
  1054. beforeEach(function (done) {
  1055. server = http.createServer()
  1056. server.listen(0, '127.0.0.1', function () {
  1057. server.url = 'http://127.0.0.1:' + server.address().port
  1058. done()
  1059. })
  1060. })
  1061. afterEach(function () {
  1062. server.close()
  1063. server = null
  1064. })
  1065. it('response object should implement the IncomingMessage API', function (done) {
  1066. const requestUrl = '/requestUrl'
  1067. const customHeaderName = 'Some-Custom-Header-Name'
  1068. const customHeaderValue = 'Some-Customer-Header-Value'
  1069. server.on('request', function (request, response) {
  1070. switch (request.url) {
  1071. case requestUrl:
  1072. response.statusCode = 200
  1073. response.statusMessage = 'OK'
  1074. response.setHeader(customHeaderName, customHeaderValue)
  1075. response.end()
  1076. break
  1077. default:
  1078. assert(false)
  1079. }
  1080. })
  1081. const urlRequest = net.request({
  1082. method: 'GET',
  1083. url: `${server.url}${requestUrl}`
  1084. })
  1085. urlRequest.on('response', function (response) {
  1086. const statusCode = response.statusCode
  1087. assert(typeof statusCode === 'number')
  1088. assert.equal(statusCode, 200)
  1089. const statusMessage = response.statusMessage
  1090. assert(typeof statusMessage === 'string')
  1091. assert.equal(statusMessage, 'OK')
  1092. const headers = response.headers
  1093. assert(typeof headers === 'object')
  1094. assert.deepEqual(headers[customHeaderName.toLowerCase()],
  1095. [customHeaderValue])
  1096. const httpVersion = response.httpVersion
  1097. assert(typeof httpVersion === 'string')
  1098. assert(httpVersion.length > 0)
  1099. const httpVersionMajor = response.httpVersionMajor
  1100. assert(typeof httpVersionMajor === 'number')
  1101. assert(httpVersionMajor >= 1)
  1102. const httpVersionMinor = response.httpVersionMinor
  1103. assert(typeof httpVersionMinor === 'number')
  1104. assert(httpVersionMinor >= 0)
  1105. response.pause()
  1106. response.on('data', function (chunk) {
  1107. })
  1108. response.on('end', function () {
  1109. done()
  1110. })
  1111. response.resume()
  1112. })
  1113. urlRequest.end()
  1114. })
  1115. it('should be able to pipe a net response into a writable stream', function (done) {
  1116. const nodeRequestUrl = '/nodeRequestUrl'
  1117. const netRequestUrl = '/netRequestUrl'
  1118. const bodyData = randomString(kOneMegaByte)
  1119. server.on('request', function (request, response) {
  1120. switch (request.url) {
  1121. case netRequestUrl:
  1122. response.statusCode = 200
  1123. response.statusMessage = 'OK'
  1124. response.write(bodyData)
  1125. response.end()
  1126. break
  1127. case nodeRequestUrl:
  1128. let receivedBodyData = ''
  1129. request.on('data', function (chunk) {
  1130. receivedBodyData += chunk.toString()
  1131. })
  1132. request.on('end', function (chunk) {
  1133. if (chunk) {
  1134. receivedBodyData += chunk.toString()
  1135. }
  1136. assert.equal(receivedBodyData, bodyData)
  1137. response.end()
  1138. })
  1139. break
  1140. default:
  1141. assert(false)
  1142. }
  1143. })
  1144. ipcRenderer.once('api-net-spec-done', function () {
  1145. done()
  1146. })
  1147. // Execute below code directly within the browser context without
  1148. // using the remote module.
  1149. ipcRenderer.send('eval', `
  1150. const {net} = require('electron')
  1151. const http = require('http')
  1152. const netRequest = net.request('${server.url}${netRequestUrl}')
  1153. netRequest.on('response', function (netResponse) {
  1154. const serverUrl = url.parse('${server.url}')
  1155. const nodeOptions = {
  1156. method: 'POST',
  1157. path: '${nodeRequestUrl}',
  1158. port: serverUrl.port
  1159. }
  1160. let nodeRequest = http.request(nodeOptions)
  1161. nodeRequest.on('response', function (nodeResponse) {
  1162. nodeResponse.on('data', function (chunk) {
  1163. })
  1164. nodeResponse.on('end', function (chunk) {
  1165. event.sender.send('api-net-spec-done')
  1166. })
  1167. })
  1168. netResponse.pipe(nodeRequest)
  1169. })
  1170. netRequest.end()
  1171. `)
  1172. })
  1173. it('should not emit any event after close', function (done) {
  1174. const requestUrl = '/requestUrl'
  1175. let bodyData = randomString(kOneKiloByte)
  1176. server.on('request', function (request, response) {
  1177. switch (request.url) {
  1178. case requestUrl:
  1179. response.statusCode = 200
  1180. response.statusMessage = 'OK'
  1181. response.write(bodyData)
  1182. response.end()
  1183. break
  1184. default:
  1185. assert(false)
  1186. }
  1187. })
  1188. let requestCloseEventEmitted = false
  1189. const urlRequest = net.request({
  1190. method: 'GET',
  1191. url: `${server.url}${requestUrl}`
  1192. })
  1193. urlRequest.on('response', function (response) {
  1194. assert(!requestCloseEventEmitted)
  1195. const statusCode = response.statusCode
  1196. assert.equal(statusCode, 200)
  1197. response.pause()
  1198. response.on('data', function () {
  1199. })
  1200. response.on('end', function () {
  1201. })
  1202. response.resume()
  1203. response.on('error', function () {
  1204. assert(!requestCloseEventEmitted)
  1205. })
  1206. response.on('aborted', function () {
  1207. assert(!requestCloseEventEmitted)
  1208. })
  1209. })
  1210. urlRequest.on('finish', function () {
  1211. assert(!requestCloseEventEmitted)
  1212. })
  1213. urlRequest.on('error', function () {
  1214. assert(!requestCloseEventEmitted)
  1215. })
  1216. urlRequest.on('abort', function () {
  1217. assert(!requestCloseEventEmitted)
  1218. })
  1219. urlRequest.on('close', function () {
  1220. requestCloseEventEmitted = true
  1221. // Wait so that all async events get scheduled.
  1222. setTimeout(function () {
  1223. done()
  1224. }, 100)
  1225. })
  1226. urlRequest.end()
  1227. })
  1228. })
  1229. describe('Stability and performance', function (done) {
  1230. let server
  1231. beforeEach(function (done) {
  1232. server = http.createServer()
  1233. server.listen(0, '127.0.0.1', function () {
  1234. server.url = 'http://127.0.0.1:' + server.address().port
  1235. done()
  1236. })
  1237. })
  1238. afterEach(function () {
  1239. server.close()
  1240. server = null
  1241. })
  1242. it('should free unreferenced, never-started request objects without crash', function (done) {
  1243. const requestUrl = '/requestUrl'
  1244. ipcRenderer.once('api-net-spec-done', function () {
  1245. done()
  1246. })
  1247. ipcRenderer.send('eval', `
  1248. const {net} = require('electron')
  1249. const urlRequest = net.request('${server.url}${requestUrl}')
  1250. process.nextTick(function () {
  1251. const v8Util = process.atomBinding('v8_util')
  1252. v8Util.requestGarbageCollectionForTesting()
  1253. event.sender.send('api-net-spec-done')
  1254. })
  1255. `)
  1256. })
  1257. it('should not collect on-going requests without crash', function (done) {
  1258. const requestUrl = '/requestUrl'
  1259. server.on('request', function (request, response) {
  1260. switch (request.url) {
  1261. case requestUrl:
  1262. response.statusCode = 200
  1263. response.statusMessage = 'OK'
  1264. response.write(randomString(kOneKiloByte))
  1265. ipcRenderer.once('api-net-spec-resume', function () {
  1266. response.write(randomString(kOneKiloByte))
  1267. response.end()
  1268. })
  1269. break
  1270. default:
  1271. assert(false)
  1272. }
  1273. })
  1274. ipcRenderer.once('api-net-spec-done', function () {
  1275. done()
  1276. })
  1277. // Execute below code directly within the browser context without
  1278. // using the remote module.
  1279. ipcRenderer.send('eval', `
  1280. const {net} = require('electron')
  1281. const urlRequest = net.request('${server.url}${requestUrl}')
  1282. urlRequest.on('response', function (response) {
  1283. response.on('data', function () {
  1284. })
  1285. response.on('end', function () {
  1286. event.sender.send('api-net-spec-done')
  1287. })
  1288. process.nextTick(function () {
  1289. // Trigger a garbage collection.
  1290. const v8Util = process.atomBinding('v8_util')
  1291. v8Util.requestGarbageCollectionForTesting()
  1292. event.sender.send('api-net-spec-resume')
  1293. })
  1294. })
  1295. urlRequest.end()
  1296. `)
  1297. })
  1298. it('should collect unreferenced, ended requests without crash', function (done) {
  1299. const requestUrl = '/requestUrl'
  1300. server.on('request', function (request, response) {
  1301. switch (request.url) {
  1302. case requestUrl:
  1303. response.statusCode = 200
  1304. response.statusMessage = 'OK'
  1305. response.end()
  1306. break
  1307. default:
  1308. assert(false)
  1309. }
  1310. })
  1311. ipcRenderer.once('api-net-spec-done', function () {
  1312. done()
  1313. })
  1314. ipcRenderer.send('eval', `
  1315. const {net} = require('electron')
  1316. const urlRequest = net.request('${server.url}${requestUrl}')
  1317. urlRequest.on('response', function (response) {
  1318. response.on('data', function () {
  1319. })
  1320. response.on('end', function () {
  1321. })
  1322. })
  1323. urlRequest.on('close', function () {
  1324. process.nextTick(function () {
  1325. const v8Util = process.atomBinding('v8_util')
  1326. v8Util.requestGarbageCollectionForTesting()
  1327. event.sender.send('api-net-spec-done')
  1328. })
  1329. })
  1330. urlRequest.end()
  1331. `)
  1332. })
  1333. })
  1334. })