11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ciif (!common.hasCrypto)
41cb0ef41Sopenharmony_ci  common.skip('missing crypto');
51cb0ef41Sopenharmony_ciconst assert = require('assert');
61cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
71cb0ef41Sopenharmony_ciconst fs = require('fs');
81cb0ef41Sopenharmony_ciconst http2 = require('http2');
91cb0ef41Sopenharmony_ciconst path = require('path');
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir');
121cb0ef41Sopenharmony_citmpdir.refresh();
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci// This test assesses whether long-running writes can complete
151cb0ef41Sopenharmony_ci// or timeout because the session or stream are not aware that the
161cb0ef41Sopenharmony_ci// backing stream is still writing.
171cb0ef41Sopenharmony_ci// To simulate a slow client, we write a really large chunk and
181cb0ef41Sopenharmony_ci// then proceed through the following cycle:
191cb0ef41Sopenharmony_ci// 1) Receive first 'data' event and record currently written size
201cb0ef41Sopenharmony_ci// 2) Once we've read up to currently written size recorded above,
211cb0ef41Sopenharmony_ci//    we pause the stream and wait longer than the server timeout
221cb0ef41Sopenharmony_ci// 3) Socket.prototype._onTimeout triggers and should confirm
231cb0ef41Sopenharmony_ci//    that the backing stream is still active and writing
241cb0ef41Sopenharmony_ci// 4) Our timer fires, we resume the socket and start at 1)
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ciconst writeSize = 3000000;
271cb0ef41Sopenharmony_ciconst minReadSize = 500000;
281cb0ef41Sopenharmony_ciconst serverTimeout = common.platformTimeout(500);
291cb0ef41Sopenharmony_cilet offsetTimeout = common.platformTimeout(100);
301cb0ef41Sopenharmony_cilet didReceiveData = false;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ciconst content = Buffer.alloc(writeSize, 0x44);
331cb0ef41Sopenharmony_ciconst filepath = path.join(tmpdir.path, 'http2-large-write.tmp');
341cb0ef41Sopenharmony_cifs.writeFileSync(filepath, content, 'binary');
351cb0ef41Sopenharmony_ciconst fd = fs.openSync(filepath, 'r');
361cb0ef41Sopenharmony_ciprocess.on('beforeExit', () => fs.closeSync(fd));
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciconst server = http2.createSecureServer({
391cb0ef41Sopenharmony_ci  key: fixtures.readKey('agent1-key.pem'),
401cb0ef41Sopenharmony_ci  cert: fixtures.readKey('agent1-cert.pem')
411cb0ef41Sopenharmony_ci});
421cb0ef41Sopenharmony_ciserver.on('stream', common.mustCall((stream) => {
431cb0ef41Sopenharmony_ci  stream.respondWithFD(fd, {
441cb0ef41Sopenharmony_ci    'Content-Type': 'application/octet-stream',
451cb0ef41Sopenharmony_ci    'Content-Length': content.length.toString(),
461cb0ef41Sopenharmony_ci    'Vary': 'Accept-Encoding'
471cb0ef41Sopenharmony_ci  });
481cb0ef41Sopenharmony_ci  stream.end();
491cb0ef41Sopenharmony_ci}));
501cb0ef41Sopenharmony_ciserver.setTimeout(serverTimeout);
511cb0ef41Sopenharmony_ciserver.on('timeout', () => {
521cb0ef41Sopenharmony_ci  assert.ok(!didReceiveData, 'Should not timeout');
531cb0ef41Sopenharmony_ci});
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciserver.listen(0, common.mustCall(() => {
561cb0ef41Sopenharmony_ci  const client = http2.connect(`https://localhost:${server.address().port}`,
571cb0ef41Sopenharmony_ci                               { rejectUnauthorized: false });
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  const req = client.request({ ':path': '/' });
601cb0ef41Sopenharmony_ci  req.end();
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  const resume = () => req.resume();
631cb0ef41Sopenharmony_ci  let receivedBufferLength = 0;
641cb0ef41Sopenharmony_ci  let firstReceivedAt;
651cb0ef41Sopenharmony_ci  req.on('data', common.mustCallAtLeast((buf) => {
661cb0ef41Sopenharmony_ci    if (receivedBufferLength === 0) {
671cb0ef41Sopenharmony_ci      didReceiveData = false;
681cb0ef41Sopenharmony_ci      firstReceivedAt = Date.now();
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci    receivedBufferLength += buf.length;
711cb0ef41Sopenharmony_ci    if (receivedBufferLength >= minReadSize &&
721cb0ef41Sopenharmony_ci        receivedBufferLength < writeSize) {
731cb0ef41Sopenharmony_ci      didReceiveData = true;
741cb0ef41Sopenharmony_ci      receivedBufferLength = 0;
751cb0ef41Sopenharmony_ci      req.pause();
761cb0ef41Sopenharmony_ci      setTimeout(
771cb0ef41Sopenharmony_ci        resume,
781cb0ef41Sopenharmony_ci        serverTimeout + offsetTimeout - (Date.now() - firstReceivedAt)
791cb0ef41Sopenharmony_ci      );
801cb0ef41Sopenharmony_ci      offsetTimeout = 0;
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci  }, 1));
831cb0ef41Sopenharmony_ci  req.on('end', common.mustCall(() => {
841cb0ef41Sopenharmony_ci    client.close();
851cb0ef41Sopenharmony_ci    server.close();
861cb0ef41Sopenharmony_ci  }));
871cb0ef41Sopenharmony_ci}));
88