<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Tsang</title>
    <description>The latest articles on DEV Community by Alex Tsang (@alxtsg).</description>
    <link>https://dev.to/alxtsg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F156991%2F5c4284c3-1486-4647-b58d-918a0975eee7.png</url>
      <title>DEV Community: Alex Tsang</title>
      <link>https://dev.to/alxtsg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alxtsg"/>
    <language>en</language>
    <item>
      <title>Avoid leaking resources in Deno tests</title>
      <dc:creator>Alex Tsang</dc:creator>
      <pubDate>Sat, 30 May 2020 15:10:48 +0000</pubDate>
      <link>https://dev.to/alxtsg/avoid-leaking-resources-in-deno-tests-10e0</link>
      <guid>https://dev.to/alxtsg/avoid-leaking-resources-in-deno-tests-10e0</guid>
      <description>&lt;p&gt;Recently I have been using &lt;a href="https://deno.land/"&gt;Deno&lt;/a&gt; to implement a simple web API to play with the new TypeScript runtime. In order to test the APIs, today I wrote a test, which is similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;assertStrictEq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std@v0.51.0/testing/asserts.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/x/oak@v5.0.0/mod.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server with a simple middleware&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listenPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://127.0.0.1:8000/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;assertStrictEq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;listenPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The test is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new application.&lt;/li&gt;
&lt;li&gt;Mount a middleware on the application so that the application will respond with "Hello world." when a request arrives.&lt;/li&gt;
&lt;li&gt;Start the application and listen on the specified port (i.e. &lt;code&gt;8000&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Send a request to the application and test whether the response status code is in expected range (&lt;code&gt;response.ok&lt;/code&gt; means the status is in the range 200 - 299).&lt;/li&gt;
&lt;li&gt;Stop the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This test should pass... Except when it didn't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; deno test --allow-net
running 1 tests
test server with a simple middleware ... FAILED (38ms)

failures:

server with a simple middleware
AssertionError: Test case is leaking resources.
Before: {
  "0": "stdin",
  "1": "stdout",
  "2": "stderr"
}
After: {
  "0": "stdin",
  "1": "stdout",
  "2": "stderr",
  "5": "httpBody"
}

Make sure to close all open resource handles returned from Deno APIs before
finishing test case.
    at Object.assert ($deno$/util.ts:33:11)
    at Object.resourceSanitizer [as fn] ($deno$/testing.ts:81:5)
    at async TestApi.[Symbol.asyncIterator] ($deno$/testing.ts:264:11)
    at async Object.runTests ($deno$/testing.ts:346:20)

failures:

        server with a simple middleware

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (42ms)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At first I didn't understand which part of the test was leaking resources. After some experiments, I found that the root cause was that I didn't read the response body obtained from the &lt;code&gt;fetch()&lt;/code&gt; function call.&lt;/p&gt;

&lt;p&gt;After calling &lt;code&gt;await fetch()&lt;/code&gt; to obtain the response, one can call &lt;code&gt;response.text()&lt;/code&gt; (or &lt;code&gt;response.json()&lt;/code&gt;) to read the response stream and parse it as JSON data (or plain text) (see the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods"&gt;document&lt;/a&gt; on MDN for details). Without reading the response stream (which is expected to be read, &lt;em&gt;I guess&lt;/em&gt;), Deno would think the test is leaking resources.&lt;/p&gt;

&lt;p&gt;It is very simple to fix the problem. When using Deno 1.0.3 (the latest version at the time of writing), one can call &lt;code&gt;cancel()&lt;/code&gt; on the response stream to say that the data is not needed anymore. I updated the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;assertStrictEq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/std@v0.51.0/testing/asserts.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/x/oak@v5.0.0/mod.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server with a simple middleware&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listenPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://127.0.0.1:8000/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;assertStrictEq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// The response body is not needed.&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;listenPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that line after checking the response status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(See &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining"&gt;Optional chaining&lt;/a&gt; if you wonder what does &lt;code&gt;?.&lt;/code&gt; mean.)&lt;/p&gt;

&lt;p&gt;Finally the test passed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; deno test --allow-net
running 1 tests
test server with a simple middleware ... ok (89ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (93ms)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you are using Deno 1.0.2 (or previous versions), the &lt;code&gt;cancel()&lt;/code&gt; function is not implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; deno test --allow-net
running 1 tests
test server with a simple middleware ... FAILED (71ms)

failures:

server with a simple middleware
Error: not implemented
    at Object.notImplemented ($deno$/util.ts:64:9)
    at Body.cancel ($deno$/web/fetch.ts:234:12)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can still read the response body and throw it away immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In fact, the same leaking resources problem has been asked and addressed around a month ago, you can see the issue &lt;a href="https://github.com/denoland/deno/issues/4735"&gt;#4735&lt;/a&gt; on Deno's code repository for more details.&lt;/p&gt;

&lt;p&gt;Some useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/cancel"&gt;https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/cancel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://streams.spec.whatwg.org/#rs-cancel"&gt;https://streams.spec.whatwg.org/#rs-cancel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>deno</category>
      <category>oak</category>
      <category>fetch</category>
    </item>
    <item>
      <title>Notes on configuring HAProxy on OpenBSD 6.7 with Mozilla SSL Configuration Generator</title>
      <dc:creator>Alex Tsang</dc:creator>
      <pubDate>Thu, 21 May 2020 17:19:07 +0000</pubDate>
      <link>https://dev.to/alxtsg/notes-on-configuring-haproxy-on-openbsd-6-7-with-mozilla-ssl-configuration-generator-3d9d</link>
      <guid>https://dev.to/alxtsg/notes-on-configuring-haproxy-on-openbsd-6-7-with-mozilla-ssl-configuration-generator-3d9d</guid>
      <description>&lt;p&gt;&lt;em&gt;2021-05-06 update&lt;/em&gt;: At the time of writing this article, I thought the lack of TLSv1.3 support was due to the missing API in LibreSSL, but in fact LibreSSL didn't even support TLSv1.3 on server-side until version 3.2.0 was released (later than OpenBSD 6.7 was released). See the &lt;a href="https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.2.0-relnotes.txt"&gt;release notes&lt;/a&gt; for details. On OpenBSD 6.9, the pre-built HAProxy package supports TLSv1.3.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.openbsd.org/67.html"&gt;OpenBSD 6.7&lt;/a&gt; was released on 2020-05-19. I upgraded one of my servers from OpenBSD 6.6 to OpenBSD 6.7 that night.&lt;/p&gt;

&lt;p&gt;Before the OpenBSD 6.7 was available, I already noticed that the HAProxy package has been upgraded from 1.9 to 2.0 in the ports tree. So after upgrading the OS, I upgraded the installed packages (including HAProxy) by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pkg_add -u
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TLS 1.3
&lt;/h2&gt;

&lt;p&gt;Once I have upgraded the HAProxy installed on my server, I used the &lt;a href="https://ssl-config.mozilla.org/"&gt;Mozilla SSL Configuration Generator&lt;/a&gt; to generate a "Modern" configuration. Part of the generated configuration looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global
  ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
  ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets
  ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
  ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I immediately noticed something "wrong". On OpenBSD 6.7, the pre-built HAProxy says the following TLS versions are supported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# haproxy -vv | grep TLSv
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compared to the pre-built HAProxy on Alpine Linux 3.11:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# haproxy -vv | grep TLSv
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2 TLSv1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output above shows that the pre-built HAProxy on OpenBSD 6.7 does not support TLSv1.3 (while the one on Alpine Linux 3.11 does). So the configuration generated by Mozilla SSL Configuration Generator effectively disables all SSL/ TLS versions. In fact, I tried to apply the configuration and let HAProxy check it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# haproxy -c -f haproxy.cfg.new
...
[ALERT] 140/031748 (28829) : Proxy 'frontend-01': all SSL/TLS versions are disabled for bind ':443' at [/etc/haproxy/haproxy.cfg.new:17].
...
[ALERT] 140/031748 (28829) : Fatal errors found in configuration.
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, the &lt;code&gt;ssl-default-bind-ciphersuites&lt;/code&gt; setting does not work in HAProxy on OpenBSD 6.7. From the HAProxy Documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This setting is only available when support for OpenSSL was built in and OpenSSL 1.1.1 or later was used to build HAProxy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;HAProxy on OpenBSD 6.7 is built with LibreSSL 3.1.1 and the TLS 1.3 API is not available at the moment. From the &lt;a href="https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.1.1-relnotes.txt"&gt;release notes&lt;/a&gt; of LibreSSL 3.1.1:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the OpenSSL TLS 1.3 API is not yet visible/available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hopefully the API will be ready by the time when OpenBSD 6.8 is released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;On OpenBSD 6.6, the pre-built HAProxy does not support compression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# haproxy -vv | grep Compression
Compression algorithms supported : identity("identity")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the HAProxy Documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Identity does not apply any change on data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luckily, on OpenBSD 6.7, the pre-built HAProxy comes with compression support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# haproxy -vv | grep Compression
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means I can enable compression in HAProxy with the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compression algo gzip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also note that &lt;code&gt;reqrep&lt;/code&gt; has been deprecated. From the HAProxy Documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using "reqadd"/"reqdel"/"reqrep" to manipulate request headers is discouraged in newer versions (&amp;gt;= 1.5).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In HAProxy 2.0 (according to the release notes, starting from 2.0-dev4), error message will be printed if the directive is being used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The 'reqrep' directive is deprecated in favor of 'http-request replace-uri', 'http-request replace-path', and 'http-request replace-header' and will be removed in next version.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;For reference, this is the HAProxy's version and build options on OpenBSD 6.6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HA-Proxy version 1.9.15 2020/04/02 - https://haproxy.org/
Build options :
  TARGET  = openbsd
  CPU     = generic
  CC      = cc
  CFLAGS  = -O2 -pipe -fno-strict-aliasing
  OPTIONS = USE_OPENSSL=1 USE_PCRE=1

Default settings :
  maxconn = 2000, bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with OpenSSL version : LibreSSL 3.0.2
Running on OpenSSL version : LibreSSL 3.0.2
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
Built with transparent proxy support using: SO_BINDANY
Built without compression support (neither USE_ZLIB nor USE_SLZ are set).
Compression algorithms supported : identity("identity")
Built with PCRE version : 8.41 2017-07-05
Running on PCRE version : 8.41 2017-07-05
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Encrypted password support via crypt(3): yes
Built with multi-threading support.

Available polling systems :
     kqueue : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use kqueue.

Available multiplexer protocols :
(protocols marked as &amp;lt;default&amp;gt; cannot be specified using 'proto' keyword)
              h2 : mode=HTTP       side=FE
              h2 : mode=HTX        side=FE|BE
       &amp;lt;default&amp;gt; : mode=HTX        side=FE|BE
       &amp;lt;default&amp;gt; : mode=TCP|HTTP   side=FE|BE

Available filters :
        [SPOE] spoe
        [COMP] compression
        [CACHE] cache
        [TRACE] trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On OpenBSD 6.7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HA-Proxy version 2.0.14 2020/04/02 - https://haproxy.org/
Build options :
  TARGET  = openbsd
  CPU     = generic
  CC      = cc
  CFLAGS  = -O2 -pipe -fno-strict-aliasing
  OPTIONS = USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1

Feature list : -EPOLL +KQUEUE -MY_EPOLL -MY_SPLICE -NETFILTER +PCRE -PCRE_JIT -PCRE2 -PCRE2_JIT +POLL -PRIVATE_CACHE +THREAD -PTHREAD_PSHARED -REGPARM -STATIC_PCRE -STATIC_PCRE2 +TPROXY -LINUX_TPROXY -LINUX_SPLICE -LIBCRYPT -CRYPT_H -VSYSCALL -GETADDRINFO +OPENSSL -LUA -FUTEX +ACCEPT4 -MY_ACCEPT4 +ZLIB -SLZ -CPU_AFFINITY -TFO -NS -DL -RT -DEVICEATLAS -51DEGREES -WURFL -SYSTEMD -OBSOLETE_LINKER -PRCTL -THREAD_DUMP -EVPORTS

Default settings :
  bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with multi-threading support (MAX_THREADS=64, default=1).
Built with OpenSSL version : LibreSSL 3.1.1
Running on OpenSSL version : LibreSSL 3.1.1
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
Built with transparent proxy support using: SO_BINDANY
Built with zlib version : 1.2.3
Running on zlib version : 1.2.3
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with PCRE version : 8.41 2017-07-05
Running on PCRE version : 8.41 2017-07-05
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Encrypted password support via crypt(3): yes

Available polling systems :
     kqueue : pref=300,  test result OK
       poll : pref=200,  test result OK
     select : pref=150,  test result OK
Total: 3 (3 usable), will use kqueue.

Available multiplexer protocols :
(protocols marked as &amp;lt;default&amp;gt; cannot be specified using 'proto' keyword)
              h2 : mode=HTTP       side=FE        mux=H2
              h2 : mode=HTX        side=FE|BE     mux=H2
       &amp;lt;default&amp;gt; : mode=HTX        side=FE|BE     mux=H1
       &amp;lt;default&amp;gt; : mode=TCP|HTTP   side=FE|BE     mux=PASS

Available services : none

Available filters :
        [SPOE] spoe
        [COMP] compression
        [CACHE] cache
        [TRACE] trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And some useful links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#3.1-ssl-default-bind-ciphers"&gt;https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#3.1-ssl-default-bind-ciphers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#3.1-ssl-default-bind-ciphersuites"&gt;https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#3.1-ssl-default-bind-ciphersuites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4.2-compression%20algo"&gt;https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4.2-compression%20algo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4.2-http-request"&gt;https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4.2-http-request&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oh, if you also like the work from the OpenBSD developers, please consider &lt;a href="https://www.openbsdfoundation.org/donations.html"&gt;donating&lt;/a&gt; to the OpenBSD Foundation.&lt;/p&gt;

</description>
      <category>openbsd</category>
      <category>haproxy</category>
    </item>
  </channel>
</rss>
