fetch-request-body.spec.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import {expect} from 'chai';
  2. import {format} from '@e22m4u/js-format';
  3. import {fetchRequestBody} from './fetch-request-body.js';
  4. import {createRequestMock} from './create-request-mock.js';
  5. describe('fetchRequestBody', function () {
  6. it('requires the first parameter to be an IncomingMessage instance', function () {
  7. const throwable = v => () => fetchRequestBody(v);
  8. const error = v =>
  9. format(
  10. 'The first parameter of "fetchRequestBody" should be ' +
  11. 'an IncomingMessage instance, but %s was given.',
  12. v,
  13. );
  14. expect(throwable('str')).to.throw(error('"str"'));
  15. expect(throwable('')).to.throw(error('""'));
  16. expect(throwable(10)).to.throw(error('10'));
  17. expect(throwable(0)).to.throw(error('0'));
  18. expect(throwable(true)).to.throw(error('true'));
  19. expect(throwable(false)).to.throw(error('false'));
  20. expect(throwable(null)).to.throw(error('null'));
  21. expect(throwable({})).to.throw(error('Object'));
  22. expect(throwable([])).to.throw(error('Array'));
  23. expect(throwable(undefined)).to.throw(error('undefined'));
  24. throwable(createRequestMock())();
  25. });
  26. it('requires the parameter "bodyBytesLimit" to be an IncomingMessage instance', function () {
  27. const req = createRequestMock();
  28. const throwable = v => () => fetchRequestBody(req, v);
  29. const error = v =>
  30. format(
  31. 'The parameter "bodyBytesLimit" of "fetchRequestBody" ' +
  32. 'should be a number, but %s was given.',
  33. v,
  34. );
  35. expect(throwable('str')).to.throw(error('"str"'));
  36. expect(throwable('')).to.throw(error('""'));
  37. expect(throwable(true)).to.throw(error('true'));
  38. expect(throwable(false)).to.throw(error('false'));
  39. expect(throwable(null)).to.throw(error('null'));
  40. expect(throwable({})).to.throw(error('Object'));
  41. expect(throwable([])).to.throw(error('Array'));
  42. throwable(10)();
  43. throwable(0)();
  44. throwable(undefined)();
  45. });
  46. it('returns a string from the string body', async function () {
  47. const body = 'Lorem Ipsum is simply dummy text.';
  48. const req = createRequestMock({body});
  49. const result = await fetchRequestBody(req);
  50. expect(result).to.be.eq(body);
  51. });
  52. it('returns a string from the buffer body', async function () {
  53. const body = 'Lorem Ipsum is simply dummy text.';
  54. const req = createRequestMock({body: Buffer.from(body)});
  55. const result = await fetchRequestBody(req);
  56. expect(result).to.be.eq(body);
  57. });
  58. describe('encoding of the header "content-type"', function () {
  59. it('throws an error for an unsupported encoding', async function () {
  60. const body = 'Lorem Ipsum is simply dummy text.';
  61. const req = createRequestMock({
  62. body,
  63. headers: {'content-type': 'text/plain; charset=unknown'},
  64. });
  65. const promise = fetchRequestBody(req);
  66. await expect(promise).to.be.rejectedWith(
  67. 'Request encoding "unknown" is not supported.',
  68. );
  69. });
  70. it('does not throw an error if the header "content-type" does not have a specified charset', async function () {
  71. const body = 'Lorem Ipsum is simply dummy text.';
  72. const req = createRequestMock({
  73. body,
  74. headers: {'content-type': 'text/plain'},
  75. });
  76. const result = await fetchRequestBody(req);
  77. expect(result).to.be.eq(body);
  78. });
  79. it('decodes non-UTF-8 encoding to a plain text', async function () {
  80. const originalBody = 'Hello, world!';
  81. const req = createRequestMock({
  82. body: originalBody,
  83. encoding: 'latin1',
  84. headers: {'content-type': `text/plain; charset=latin1`},
  85. });
  86. const result = await fetchRequestBody(req);
  87. expect(result).to.be.eq(originalBody);
  88. });
  89. });
  90. describe('the header "content-length"', function () {
  91. it('throws an error if the body length is greater than the header', async function () {
  92. const body = 'Lorem Ipsum is simply dummy text.';
  93. const bodyLength = Buffer.from(body).byteLength;
  94. const contentLength = String(bodyLength + 10);
  95. const req = createRequestMock({
  96. body,
  97. headers: {'content-length': contentLength},
  98. });
  99. const promise = fetchRequestBody(req);
  100. await expect(promise).to.be.rejectedWith(
  101. 'Received bytes do not match the "content-length" header.',
  102. );
  103. });
  104. it('throws an error if the body length is lower than the header', async function () {
  105. const body = 'Lorem Ipsum is simply dummy text.';
  106. const bodyLength = Buffer.from(body).byteLength;
  107. const contentLength = String(bodyLength - 10);
  108. const req = createRequestMock({
  109. body,
  110. headers: {'content-length': contentLength},
  111. });
  112. const promise = fetchRequestBody(req);
  113. await expect(promise).to.be.rejectedWith(
  114. 'Received bytes do not match the "content-length" header.',
  115. );
  116. });
  117. it('does not throw an error if the body length does match with the header', async function () {
  118. const body = 'Lorem Ipsum is simply dummy text.';
  119. const contentLength = String(Buffer.from(body).byteLength);
  120. const req = createRequestMock({
  121. body,
  122. headers: {'content-length': contentLength},
  123. });
  124. const result = await fetchRequestBody(req);
  125. expect(result).to.be.eq(body);
  126. });
  127. });
  128. describe('the parameter "bodyBytesLimit"', function () {
  129. it('throws an error if the "content-length" header is greater than the limit', async function () {
  130. const body = 'Lorem Ipsum is simply dummy text.';
  131. const bodyLength = Buffer.from(body).byteLength;
  132. const bodyLimit = bodyLength - 10;
  133. const req = createRequestMock({
  134. body,
  135. headers: {'content-length': String(bodyLength)},
  136. });
  137. const error = format(
  138. 'Request body limit is %s bytes, but %s bytes given.',
  139. bodyLimit,
  140. bodyLength,
  141. );
  142. const promise = fetchRequestBody(req, bodyLimit);
  143. await expect(promise).to.be.rejectedWith(error);
  144. });
  145. it('does not throw an error if the "content-length" header does match with the limit', async function () {
  146. const body = 'Lorem Ipsum is simply dummy text.';
  147. const bodyLength = Buffer.from(body).byteLength;
  148. const req = createRequestMock({
  149. body,
  150. headers: {'content-length': String(bodyLength)},
  151. });
  152. const result = await fetchRequestBody(req, bodyLength);
  153. expect(result).to.be.eq(body);
  154. });
  155. it('does not throw an error if the "content-length" header is lower than the limit', async function () {
  156. const body = 'Lorem Ipsum is simply dummy text.';
  157. const bodyLength = Buffer.from(body).byteLength;
  158. const req = createRequestMock({
  159. body,
  160. headers: {'content-length': String(bodyLength)},
  161. });
  162. const result = await fetchRequestBody(req, bodyLength + 10);
  163. expect(result).to.be.eq(body);
  164. });
  165. it('throws an error if the body length is greater than the limit', async function () {
  166. const body = 'Lorem Ipsum is simply dummy text.';
  167. const bodyLength = Buffer.from(body).byteLength;
  168. const bodyLimit = bodyLength - 10;
  169. const req = createRequestMock({body});
  170. const error = format(
  171. 'Request body limit is %s bytes, but %s bytes given.',
  172. bodyLimit,
  173. bodyLength,
  174. );
  175. const promise = fetchRequestBody(req, bodyLimit);
  176. await expect(promise).to.be.rejectedWith(error);
  177. });
  178. it('does not throw an error if the body length does match with the limit', async function () {
  179. const body = 'Lorem Ipsum is simply dummy text.';
  180. const bodyLength = Buffer.from(body).byteLength;
  181. const req = createRequestMock({body});
  182. const result = await fetchRequestBody(req, bodyLength);
  183. expect(result).to.be.eq(body);
  184. });
  185. it('does not throw an error if the body length is lower than the limit', async function () {
  186. const body = 'Lorem Ipsum is simply dummy text.';
  187. const bodyLength = Buffer.from(body).byteLength;
  188. const bodyLimit = bodyLength + 10;
  189. const req = createRequestMock({body});
  190. const result = await fetchRequestBody(req, bodyLimit);
  191. expect(result).to.be.eq(body);
  192. });
  193. });
  194. });