Haraka 2.8.28 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/.eslintrc.yaml +2 -10
  2. package/Changes.md +84 -2
  3. package/Dockerfile +1 -1
  4. package/Plugins.md +9 -4
  5. package/README.md +2 -6
  6. package/bin/haraka +5 -4
  7. package/config/outbound.ini +0 -7
  8. package/config/plugins +1 -1
  9. package/config/smtp.ini +1 -1
  10. package/config/smtp_forward.ini +2 -8
  11. package/config/smtp_proxy.ini +0 -6
  12. package/connection.js +178 -204
  13. package/coverage/lcov.info +13863 -0
  14. package/coverage/tmp/coverage-42958-1658373250585-0.json +1 -0
  15. package/coverage/tmp/coverage-42961-1658373250529-0.json +1 -0
  16. package/dkim.js +66 -73
  17. package/docs/Body.md +1 -22
  18. package/docs/CoreConfig.md +2 -2
  19. package/docs/Header.md +1 -47
  20. package/docs/Outbound.md +8 -36
  21. package/endpoint.js +1 -1
  22. package/haraka.js +1 -1
  23. package/host_pool.js +8 -12
  24. package/logger.js +25 -32
  25. package/outbound/client_pool.js +11 -153
  26. package/outbound/config.js +5 -11
  27. package/outbound/hmail.js +109 -143
  28. package/outbound/index.js +13 -25
  29. package/outbound/mx_lookup.js +10 -7
  30. package/outbound/queue.js +8 -12
  31. package/outbound/timer_queue.js +2 -4
  32. package/outbound/tls.js +17 -18
  33. package/outbound/todo.js +1 -0
  34. package/package.json +57 -55
  35. package/plugins/auth/auth_base.js +39 -63
  36. package/plugins/auth/auth_bridge.js +3 -4
  37. package/plugins/auth/auth_proxy.js +16 -16
  38. package/plugins/auth/auth_vpopmaild.js +30 -37
  39. package/plugins/auth/flat_file.js +9 -13
  40. package/plugins/avg.js +9 -11
  41. package/plugins/backscatterer.js +1 -1
  42. package/plugins/block_me.js +2 -6
  43. package/plugins/bounce.js +106 -124
  44. package/plugins/clamd.js +59 -63
  45. package/plugins/data.signatures.js +6 -6
  46. package/plugins/data.uribl.js +1 -415
  47. package/plugins/delay_deny.js +19 -20
  48. package/plugins/dkim_sign.js +56 -62
  49. package/plugins/dkim_verify.js +9 -8
  50. package/plugins/dns_list_base.js +43 -42
  51. package/plugins/dnsbl.js +41 -46
  52. package/plugins/dnswl.js +23 -26
  53. package/plugins/early_talker.js +24 -28
  54. package/plugins/esets.js +8 -11
  55. package/plugins/greylist.js +161 -190
  56. package/plugins/helo.checks.js +175 -197
  57. package/plugins/mail_from.is_resolvable.js +38 -38
  58. package/plugins/messagesniffer.js +33 -40
  59. package/plugins/prevent_credential_leaks.js +7 -5
  60. package/plugins/process_title.js +16 -17
  61. package/plugins/queue/deliver.js +2 -2
  62. package/plugins/queue/lmtp.js +5 -6
  63. package/plugins/queue/qmail-queue.js +11 -13
  64. package/plugins/queue/quarantine.js +25 -34
  65. package/plugins/queue/rabbitmq.js +3 -2
  66. package/plugins/queue/rabbitmq_amqplib.js +9 -9
  67. package/plugins/queue/smtp_bridge.js +5 -4
  68. package/plugins/queue/smtp_forward.js +81 -89
  69. package/plugins/queue/smtp_proxy.js +21 -22
  70. package/plugins/queue/test.js +2 -1
  71. package/plugins/rcpt_to.host_list_base.js +20 -30
  72. package/plugins/rcpt_to.in_host_list.js +12 -14
  73. package/plugins/rcpt_to.max_count.js +7 -5
  74. package/plugins/record_envelope_addresses.js +4 -6
  75. package/plugins/relay.js +64 -74
  76. package/plugins/reseed_rng.js +1 -2
  77. package/plugins/spamassassin.js +56 -68
  78. package/plugins/status.js +2 -3
  79. package/plugins/tarpit.js +8 -11
  80. package/plugins/tls.js +14 -17
  81. package/plugins/toobusy.js +6 -8
  82. package/plugins/xclient.js +14 -25
  83. package/plugins.js +24 -29
  84. package/rfc1869.js +2 -2
  85. package/server.js +3 -13
  86. package/smtp_client.js +138 -215
  87. package/tests/config/smtp_forward.ini +0 -6
  88. package/tests/fixtures/line_socket.js +1 -1
  89. package/tests/fixtures/util_hmailitem.js +5 -7
  90. package/tests/fixtures/vm_harness.js +2 -2
  91. package/tests/host_pool.js +13 -14
  92. package/tests/installation/plugins/inherits.js +1 -2
  93. package/tests/logger.js +2 -2
  94. package/tests/plugins/bounce.js +6 -8
  95. package/tests/plugins/dkim_signer.js +7 -7
  96. package/tests/plugins/dns_list_base.js +7 -7
  97. package/tests/plugins/helo.checks.js +1 -1
  98. package/tests/plugins/mail_from.is_resolvable.js +10 -54
  99. package/tests/plugins/queue/smtp_forward.js +11 -11
  100. package/tests/plugins/rcpt_to.host_list_base.js +1 -1
  101. package/tests/plugins/rcpt_to.in_host_list.js +1 -1
  102. package/tests/plugins/spamassassin.js +1 -1
  103. package/tests/queue/multibyte +0 -0
  104. package/tests/queue/plain +0 -0
  105. package/tests/rfc1869.js +4 -1
  106. package/tests/server.js +15 -9
  107. package/tests/smtp_client/auth.js +4 -14
  108. package/tests/smtp_client/basic.js +5 -15
  109. package/tests/smtp_client.js +7 -3
  110. package/tests/transaction.js +72 -19
  111. package/tls_socket.js +75 -85
  112. package/transaction.js +7 -9
  113. package/attachment_stream.js +0 -118
  114. package/bin/spf +0 -48
  115. package/chunkemitter.js +0 -75
  116. package/config/data.uribl.excludes +0 -202
  117. package/config/data.uribl.ini +0 -37
  118. package/config/spf.ini +0 -1
  119. package/docs/plugins/attachment.md +0 -92
  120. package/docs/plugins/data.uribl.md +0 -120
  121. package/docs/plugins/spf.md +0 -142
  122. package/mailbody.js +0 -502
  123. package/mailheader.js +0 -304
  124. package/messagestream.js +0 -441
  125. package/plugins/aliases.js +0 -120
  126. package/plugins/attachment.js +0 -503
  127. package/plugins/connect.p0f.js +0 -5
  128. package/plugins/spf.js +0 -327
  129. package/spf.js +0 -689
  130. package/tests/mailbody.js +0 -348
  131. package/tests/mailheader.js +0 -138
  132. package/tests/messagestream.js +0 -34
  133. package/tests/plugins/aliases.js +0 -376
  134. package/tests/plugins/spf.js +0 -251
  135. package/tests/spf.js +0 -96
package/tests/mailbody.js DELETED
@@ -1,348 +0,0 @@
1
- const Body = require('../mailbody').Body;
2
-
3
- function _fill_body (body, quote) {
4
- // Body.bodytext retains the original received text before filters are
5
- // applied so the filtered text isn't tested against URIBLs, etc. Since we
6
- // want to test filter output, we use this hack to pull out the parsed body
7
- // parts that will be passed onward to the transaction.
8
-
9
- quote = quote || "";
10
-
11
- body.state = 'headers';
12
- body.parse_more(`Content-Type: multipart/alternative; boundary=${quote}abcdef${quote}\n`);
13
- body.parse_more("From: =?US-ASCII*EN?Q?Keith_Moore?= <moore@cs.utk.edu>\n");
14
- body.parse_more("\n");
15
- body.parse_more("--abcdef\n");
16
- body.parse_more("Content-Type: text/plain; charset=UTF-8; format=flowed;\n");
17
- body.parse_more(" URL*0=\"ftp://\"\n");
18
- body.parse_more(" URL*1=\"cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar\"\n");
19
- body.parse_more(" title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A\n");
20
- body.parse_more("Content-Transfer-Encoding: quoted-printable\n");
21
- body.parse_more("\n");
22
- body.parse_more("Some text for your =\n");
23
- body.parse_more("testing pleasure. \n");
24
- body.parse_more("Yup that was some text all right.\n");
25
- body.parse_more("\n");
26
- let text = body.parse_more("--abcdef\n");
27
- body.parse_more("Content-Type: text/html; charset=UTF-8;\n");
28
- body.parse_more(" title*0*=us-ascii'en'This%20is%20even%20more%20\n");
29
- body.parse_more(" title*1*=%2A%2A%2Afun%2A%2A%2A%20\n");
30
- body.parse_more(" title*2=\"isn't it!\"\n");
31
- body.parse_more("Content-Disposition: inline; \n");
32
- body.parse_more(" filename*0=\"marketron_lbasubmission_FTA Cricket Brentwood 3006445\n");
33
- body.parse_more(" Jackso\"; filename*1=\"n TN_08282017.xlsx\"\n");
34
- body.parse_more("\n");
35
- body.parse_more("<p>This is some HTML, yo.<br>\n");
36
- body.parse_more("It's pretty rad.</p>\n");
37
- body.parse_more("\n");
38
- let html = body.parse_more("--abcdef--\n");
39
- body.parse_end();
40
-
41
- text = text.toString().replace(/--abcdef\n$/, '').trim();
42
- html = html.toString().replace(/--abcdef--\n$/, '').trim();
43
-
44
- return [text, html];
45
- }
46
-
47
- function _fill_empty_body (body) {
48
- // Body.bodytext retains the original received text before filters are
49
- // applied so the filtered text isn't tested against URIBLs, etc. Since we
50
- // want to test filter output, we use this hack to pull out the parsed body
51
- // parts that will be passed onward to the transaction.
52
-
53
- body.state = 'headers';
54
- body.parse_more("Content-Type: multipart/alternative; boundary=abcdef\n");
55
- body.parse_more("\n");
56
- body.parse_more("--abcdef\n");
57
- body.parse_more("Content-Type: text/plain; charset=UTF-8; format=flowed;\n");
58
- body.parse_more("\n");
59
- let text = body.parse_more("--abcdef\n");
60
- body.parse_more("Content-Type: text/html; charset=UTF-8;\n");
61
- body.parse_more("\n");
62
- let html = body.parse_more("--abcdef--\n");
63
- body.parse_end();
64
-
65
- text = text.toString().replace(/--abcdef\n$/, '').trim();
66
- html = html.toString().replace(/--abcdef--\n$/, '').trim();
67
-
68
- return [text, html];
69
- }
70
-
71
- exports.basic = {
72
- 'children': test => {
73
- test.expect(1);
74
-
75
- const body = new Body();
76
- _fill_body(body);
77
-
78
- test.equal(body.children.length, 2);
79
- test.done();
80
- },
81
-
82
- 'correct mime parsing (#2548)': test => {
83
- const tests = [
84
- ['utf-8', '8-bit', Buffer.from("Grüße, Buß\n"), Buffer.from("Grüße, Buß\n")],
85
- ['utf-8', 'quoted-printable', Buffer.from("Gr=C3=BC=C3=9Fe, Bu=C3=9F\n"), Buffer.from("Grüße, Buß\n")],
86
- ['utf-8', 'base64', Buffer.from("R3LDvMOfZSwgQnXDnw==\n"), Buffer.from("Grüße, Buß")],
87
- ['iso-8859-2', '8-bit', Buffer.from([0x50,0xF8,0x69,0x68,0x6C,0x61,0xB9,0x6F,0x76,0x61,0x63,0xED,0x20,0xFA,0x64,0x61,0x6A,0x65,0x0A]), Buffer.from("Přihlašovací údaje\n")],
88
- ['iso-8859-2', 'quoted-printable', Buffer.from("P=F8ihla=B9ovac=ED =FAdaje\n"), Buffer.from("Přihlašovací údaje\n")],
89
- ['iso-8859-2', 'base64', Buffer.from("UPhpaGxhuW92YWPtIPpkYWplCgo=\n"), Buffer.from("Přihlašovací údaje\n\n")],
90
- ['utf-8', '8-bit', Buffer.from("どうぞ宜しくお願い申し上げます"), Buffer.from("どうぞ宜しくお願い申し上げます")]
91
- ];
92
-
93
- test.expect(tests.length);
94
-
95
- tests.forEach(data => {
96
- const body = new Body();
97
- body.add_filter(() => {});
98
-
99
- body.state = 'headers'; // HACK
100
- [
101
- "Content-type: multipart/alternative;\n",
102
- " boundary=------------D0A00162984CC178E2583417\n",
103
- "\n",
104
- "This is a multi-part message in MIME format.\n",
105
- "--------------D0A00162984CC178E2583417\n",
106
- `Content-Type: text/plain; charset=${data[0]}; format=flowed\n`,
107
- `Content-Transfer-Encoding: ${data[1]}\n`,
108
- "\n",
109
- data[2],
110
- "--------------D0A00162984CC178E2583417--"
111
- ].forEach((line) => body.parse_more(line));
112
- body.parse_end();
113
-
114
- test.equal(data[3], body.children[0].bodytext, `charset: ${data[0]}, encoding: ${data[1]}`);
115
- });
116
-
117
- test.done();
118
- },
119
- }
120
-
121
- exports.banners = {
122
- 'banner': test => {
123
- test.expect(2);
124
-
125
- const body = new Body();
126
- body.set_banner(['A text banner', 'An HTML banner']);
127
- const parts = _fill_body(body);
128
-
129
- test.ok(/A text banner$/.test(parts[0]));
130
- test.ok(/<P>An HTML banner<\/P>$/.test(parts[1]));
131
- test.done();
132
- },
133
-
134
- 'insert_banner': test => {
135
- test.expect(2);
136
-
137
- let content_type;
138
- let buf;
139
- let new_buf;
140
- const enc = 'UTF-8';
141
-
142
- const body = new Body();
143
- const banners = [ 'textbanner', 'htmlbanner' ];
144
-
145
- // this is a kind of roundabout way to get at the insert_banners code
146
- body.set_banner(banners);
147
- const insert_banners_fn = body.filters[0];
148
-
149
- content_type = 'text/html';
150
- buf = Buffer.from("winter </html>");
151
- new_buf = insert_banners_fn (content_type, enc, buf);
152
- test.equal(new_buf.toString(), "winter <P>htmlbanner</P></html>",
153
- "html banner looks ok");
154
-
155
-
156
- content_type = 'text/plain';
157
- buf = Buffer.from("winter");
158
- new_buf = insert_banners_fn (content_type, enc, buf);
159
- test.equal(new_buf.toString(), "winter\ntextbanner\n",
160
- "text banner looks ok");
161
-
162
- test.done();
163
- },
164
-
165
-
166
- // found and fixed bug, if the buffer is empty this was throwing a:
167
- // RangeError: out of range index
168
- 'insert_banner_empty_buffer': test => {
169
- test.expect(2);
170
-
171
- let content_type;
172
- let new_buf;
173
- const enc = 'UTF-8';
174
-
175
- const body = new Body();
176
- const banners = [ 'textbanner', 'htmlbanner' ];
177
-
178
- // this is a kind of roundabout way to get at the insert_banners code
179
- body.set_banner(banners);
180
- const insert_banners_fn = body.filters[0];
181
-
182
-
183
- content_type = 'text/html';
184
- const empty_buf = Buffer.from('');
185
- new_buf = insert_banners_fn (content_type, enc, empty_buf);
186
- test.equal(new_buf.toString(), "<P>htmlbanner</P>",
187
- "empty html part gets a banner" );
188
-
189
- content_type = 'text/plain';
190
- new_buf = insert_banners_fn (content_type, enc, empty_buf);
191
- test.equal(new_buf.toString(), "\ntextbanner\n",
192
- "empty text part gets a banner");
193
-
194
- test.done();
195
- },
196
-
197
- 'insert_banner_empty_body': test => {
198
- test.expect(2);
199
-
200
- const body = new Body();
201
- const banners = [ 'textbanner', 'htmlbanner' ];
202
-
203
- body.set_banner(banners);
204
- const results = _fill_empty_body(body);
205
-
206
- test.equal(results[0], banners[0]);
207
- test.equal(results[1], `<P>${banners[1]}</P>`);
208
-
209
- test.done();
210
- },
211
- }
212
-
213
- exports.filters = {
214
- 'empty': test => {
215
- test.expect(2);
216
-
217
- const body = new Body();
218
- body.add_filter((ct, enc, buf) => { });
219
- const parts = _fill_body(body);
220
-
221
- test.ok(/Some text/.test(parts[0]));
222
- test.ok(/This is some HTML/.test(parts[1]));
223
- test.done();
224
- },
225
-
226
- 'search/replace': test => {
227
- test.expect(2);
228
-
229
- const body = new Body();
230
- body.add_filter((ct, enc, buf) => {
231
- if (/^text\/plain/.test(ct)) {
232
- return Buffer.from("TEXT FILTERED");
233
- }
234
- else if (/text\/html/.test(ct)) {
235
- return Buffer.from("<p>HTML FILTERED</p>");
236
- }
237
- });
238
- const parts = _fill_body(body);
239
-
240
- test.equal(parts[0], "TEXT FILTERED");
241
- test.equal(parts[1], "<p>HTML FILTERED</p>");
242
- test.done();
243
- },
244
-
245
- 'regression: duplicate multi-part preamble when filters added':
246
- test => {
247
- test.expect(1);
248
-
249
- const body = new Body();
250
- body.add_filter(() => {});
251
-
252
- let lines = [];
253
-
254
- body.state = 'headers'; // HACK
255
- [
256
- "Content-Type: multipart/mixed; boundary=abcd\n",
257
- "\n",
258
- "This is a multi-part message in MIME format.\n",
259
- "--abcd\n",
260
- "Content-Type: text/plain\n",
261
- "\n",
262
- "Testing, 1, 2, 3.\n",
263
- "--abcd--\n",
264
- ].forEach(line => {
265
- lines.push(body.parse_more(line));
266
- });
267
- lines.push(body.parse_end());
268
-
269
- // Ignore blank lines.
270
- lines = lines.filter(l => l.toString().trim());
271
-
272
- let dupe = false;
273
- let line;
274
- while ((line = lines.pop())) {
275
- lines.forEach(l => {
276
- dupe = dupe || line === l;
277
- });
278
- }
279
-
280
- test.ok(!dupe, 'no duplicate lines found');
281
- test.done();
282
- },
283
- }
284
-
285
- exports.rfc2231 = {
286
- 'multi-value': test => {
287
- test.expect(2);
288
-
289
- const body = new Body();
290
- _fill_body(body);
291
-
292
- test.ok(body.children[0].header.get_decoded('content-type').indexOf('URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar";') > 0);
293
- test.ok(body.children[1].header.get_decoded('content-disposition').indexOf('filename="marketron_lbasubmission_FTA Cricket Brentwood 3006445 Jackson TN_08282017.xlsx"') > 0);
294
- test.done();
295
- },
296
-
297
- 'enc-and-lang': test => {
298
- test.expect(1);
299
-
300
- const body = new Body();
301
- _fill_body(body);
302
-
303
- test.ok(body.children[0].header.get_decoded('content-type').indexOf('title="This is ***fun***";') > 0);
304
- test.done();
305
- },
306
-
307
- 'multi-value-enc-and-lang': test => {
308
- test.expect(1);
309
-
310
- const body = new Body();
311
- _fill_body(body);
312
-
313
- test.ok(body.children[1].header.get_decoded('content-type').indexOf('title="This is even more ***fun*** isn\'t it!";') > 0);
314
- test.done();
315
- }
316
- }
317
-
318
- exports.boundaries = {
319
- 'with-quotes': test => {
320
- test.expect(1);
321
-
322
- const body = new Body();
323
- _fill_body(body, '"');
324
-
325
- test.equal(body.children.length, 2);
326
- test.done();
327
- },
328
-
329
- 'without-quotes': test => {
330
- test.expect(1);
331
-
332
- const body = new Body();
333
- _fill_body(body, "");
334
-
335
- test.equal(body.children.length, 2);
336
- test.done();
337
- },
338
-
339
- 'with-bad-quotes': test => {
340
- test.expect(1);
341
-
342
- const body = new Body();
343
- _fill_body(body, "'");
344
-
345
- test.equal(body.children.length, 0);
346
- test.done();
347
- }
348
- }
@@ -1,138 +0,0 @@
1
- const Header = require('../mailheader').Header;
2
-
3
- const lines = [
4
- 'Return-Path: <helpme@gmail.com>',
5
- 'Received: from [1.1.1.1] ([2.2.2.2])',
6
- ' by smtp.gmail.com with ESMTPSA id abcdef.28.2016.03.31.12.51.37',
7
- ' for <foo@bar.com>',
8
- ' (version=TLSv1/SSLv3 cipher=OTHER);',
9
- ' Thu, 31 Mar 2016 12:51:37 -0700 (PDT)',
10
- 'From: Matt Sergeant <helpme@gmail.com>',
11
- `FromUTF8: =?UTF-8?B?S29obOKAmXM=?=
12
- <Kohls@s.kohls.com>`,
13
- 'Content-Type: multipart/alternative;',
14
- ' boundary=Apple-Mail-F2C5DAD3-7EB3-409D-9FE0-135C9FD43B69',
15
- 'Content-Type2: multipart/mixed; boundary="nqp=nb64=()I9WT8XjoN"',
16
- 'Content-Transfer-Encoding: 7bit',
17
- 'Mime-Version: 1.0 (1.0)',
18
- 'Subject: Re: Haraka Rocks!',
19
- 'Message-Id: <616DF75E-D799-4F3C-9901-1642B494C45D@gmail.com>',
20
- 'Date: Thu, 31 Mar 2016 15:51:36 -0400',
21
- 'To: The World <world@example.com>',
22
- 'X-Mailer: iPhone Mail (13E233)',
23
- ];
24
-
25
- for (let i=0; i<lines.length; i++) {
26
- lines[i] = `${lines[i] }\n`;
27
- }
28
-
29
- function _set_up (done) {
30
- this.h = new Header()
31
- this.h.parse(lines)
32
- done();
33
- }
34
-
35
- exports.parse = {
36
- setUp: _set_up,
37
- 'get_decoded' (test) {
38
- test.expect(3);
39
- test.equal(this.h.lines().length, 13);
40
- test.equal(
41
- this.h.get_decoded('content-type'),
42
- 'multipart/alternative; boundary=Apple-Mail-F2C5DAD3-7EB3-409D-9FE0-135C9FD43B69'
43
- );
44
- test.equal(this.h.get_decoded('fromUTF8'), 'Kohl’s <Kohls@s.kohls.com>');
45
- test.done();
46
- },
47
- 'content type w/parens' (test) {
48
- test.expect(2);
49
- test.equal(this.h.lines().length, 13);
50
- const ct = this.h.get_decoded('content-type2');
51
- test.equal(ct, 'multipart/mixed; boundary="nqp=nb64=()I9WT8XjoN"');
52
- test.done();
53
- }
54
- }
55
-
56
- exports.add_headers = {
57
- setUp: _set_up,
58
- add_basic (test) {
59
- test.expect(2);
60
- this.h.add('Foo', 'bar');
61
- test.equal(this.h.lines()[0], 'Foo: bar\n');
62
- this.h.add_end('Fizz', 'buzz');
63
- test.equal(this.h.lines()[14], 'Fizz: buzz\n');
64
- test.done();
65
- },
66
- add_utf8 (test) {
67
- test.expect(4);
68
- this.h.add('Foo', 'bøø');
69
- test.equal(this.h.lines()[0], 'Foo: =?UTF-8?Q?b=C3=B8=C3=B8?=\n');
70
- test.equal(this.h.get_decoded('Foo'), 'bøø');
71
- // test wrapping
72
- this.h.add('Bar', 'bøø 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
73
- test.equal(this.h.lines()[0], 'Bar: =?UTF-8?Q?b=C3=B8=C3=B8?= 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n');
74
- test.equal(this.h.get_decoded('Bar'), 'bøø 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');
75
- test.done();
76
- }
77
- }
78
-
79
- exports.continuations = {
80
- setUp: _set_up,
81
- continuations_decoded (test) {
82
- test.expect(1);
83
- test.ok(!/\n/.test(this.h.get_decoded('content-type')));
84
- test.done();
85
- }
86
- }
87
-
88
- exports.remove = {
89
- setUp: _set_up,
90
- 'removes only specified header' (test) {
91
- test.expect(3)
92
- this.h.add('X-Test', 'remove-me')
93
- this.h.add('X-Test-1', 'do-not-remove-me')
94
- this.h.remove('X-Test')
95
- test.equal(this.h.get('X-Test'), '')
96
- test.equal(this.h.get('X-Test-1'), 'do-not-remove-me')
97
- test.ok(this.h.header_list.find(name => name === 'X-Test-1: do-not-remove-me\n'));
98
- test.done()
99
- },
100
- 'removes multiple matching headers' (test) {
101
- test.expect(3)
102
- this.h.add('X-Test', 'remove me')
103
- this.h.add('X-Test', 'and remove me')
104
- this.h.add('X-Test-No', 'leave me')
105
- this.h.remove('X-Test')
106
- test.equal(this.h.get('X-Test'), '')
107
- test.equal(this.h.get('X-Test-No'), 'leave me')
108
- test.ok(this.h.header_list.find(name => name === 'X-Test-No: leave me\n'));
109
- test.done()
110
- }
111
- }
112
-
113
- exports.decode = {
114
- 'multiline 8bit header (#2675)': test => {
115
- test.expect(1);
116
- this.h = new Header();
117
- this.h.parse ([
118
- "Content-Disposition: attachment;\n",
119
- " filename*0*=utf-8''%E8%AC%9B%E6%BC%94%E4%BC%9A%E6;\n",
120
- " filename*1*=%A1%88%E5%86%85%E6%9B%B8%EF%BC%86%E7%94%B3%E8%BE%BC%E6%9B%B8;\n",
121
- " filename*2*=%E6%94%B9%2Etxt\n"
122
- ]);
123
- console.log(this.h.get_decoded('content-disposition'));
124
- test.ok(this.h.get_decoded('content-disposition').includes('講演会案内書&申込書改.txt'));
125
- test.done();
126
- },
127
- 'unfolding (#2702)': test => {
128
- test.expect(1);
129
- this.h = new Header();
130
- this.h.parse ([
131
- "Subject: =?UTF-8?Q?Die_beliebtesten_CAD-_und_AVA-Programme;_die_kl=C3=BCgsten_K?=\n",
132
- " =?UTF-8?Q?=C3=B6pfe_der_Branche;_Abschluss_eines_BIM-Pilotprojekts;_Bauen?=\n",
133
- " =?UTF-8?Q?_in_Zeiten_des_Klimawandels;_u.v.m?=\n"
134
- ]);
135
- test.equal(this.h.get_decoded('subject'), 'Die beliebtesten CAD- und AVA-Programme; die klügsten Köpfe der Branche; Abschluss eines BIM-Pilotprojekts; Bauen in Zeiten des Klimawandels; u.v.m');
136
- test.done();
137
- }
138
- }
@@ -1,34 +0,0 @@
1
-
2
- const stream = require('stream')
3
-
4
- const MessageStream = require('../messagestream')
5
-
6
- function _set_up (done) {
7
- this.ms = new MessageStream({ main: { } }, 'msg', []);
8
- done();
9
- }
10
-
11
- function _tear_down (done) {
12
- done();
13
- }
14
-
15
- exports.messagestream = {
16
- setUp : _set_up,
17
- tearDown : _tear_down,
18
- 'is a Stream' (test) {
19
- test.expect(2);
20
- test.ok(this.ms instanceof MessageStream);
21
- test.ok(this.ms instanceof stream.Stream);
22
- test.done();
23
- },
24
- 'gets message data' (test) {
25
- this.ms.add_line('Header: test\r\n');
26
- this.ms.add_line('\r\n');
27
- this.ms.add_line('I am body text\r\n');
28
- this.ms.add_line_end();
29
- this.ms.get_data((data) => {
30
- test.ok(/^[A-Za-z]+: /.test(data.toString()))
31
- test.done();
32
- })
33
- },
34
- }