From e70cf898cdd60b75f44f7b0dd83e67b5838571f6 Mon Sep 17 00:00:00 2001 From: merlin Date: Sat, 17 Jun 2023 16:51:12 +0300 Subject: [PATCH 1/5] fix depguard linter config --- .golangci.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.golangci.yaml b/.golangci.yaml index d2c16fd..1d29f06 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -80,6 +80,13 @@ linters-settings: # - net/context packages-with-error-messages: # - context: "context instead" + rules: + Main: + deny: + - pkg: golang.org/x/net/context + msg: "use context instead" + - pkg: github.com/pkg/errors + msg: "use errors instead" dogsled: max-blank-identifiers: 2 From 86f5ff9492d5fd80772b11334d8a8f58a3406cff Mon Sep 17 00:00:00 2001 From: merlin Date: Sat, 17 Jun 2023 16:55:03 +0300 Subject: [PATCH 2/5] fix linter issues --- gemax/internal/bufreader/bufreader.go | 4 +- gemax/internal/bufwriter/bufwriter.go | 1 + gemax/request.go | 1 - gemax/response.go | 6 +- gemax/server_test.go | 1 + torture_report.txt | 223 ++++++++++++++++++++++++++ 6 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 torture_report.txt diff --git a/gemax/internal/bufreader/bufreader.go b/gemax/internal/bufreader/bufreader.go index 80d669b..12c0ad3 100644 --- a/gemax/internal/bufreader/bufreader.go +++ b/gemax/internal/bufreader/bufreader.go @@ -14,7 +14,9 @@ type ( *buf } - buf = bufio.Reader + //nolint:unused // used as embedded field + buf = bufio.Reader + //nolint:unused // used as embedded field closer = io.Closer ) diff --git a/gemax/internal/bufwriter/bufwriter.go b/gemax/internal/bufwriter/bufwriter.go index 60725ff..fa561a5 100644 --- a/gemax/internal/bufwriter/bufwriter.go +++ b/gemax/internal/bufwriter/bufwriter.go @@ -31,6 +31,7 @@ func New(w io.WriteCloser, bufSize int) *Writer { } } +//nolint:unused // used as embedded field type writer = bufio.Writer // Reset buffer and sets new write target. diff --git a/gemax/request.go b/gemax/request.go index 0c4ed4e..92be17c 100644 --- a/gemax/request.go +++ b/gemax/request.go @@ -77,7 +77,6 @@ func ParseIncomingRequest(re io.Reader, remoteAddr string) (IncomingRequest, err } func isValidPath(path string) bool { - path = strings.TrimPrefix(path, "/") path = strings.TrimSuffix(path, "/") diff --git a/gemax/response.go b/gemax/response.go index 988177c..3c73515 100644 --- a/gemax/response.go +++ b/gemax/response.go @@ -87,7 +87,11 @@ var bufioWriterPool = &sync.Pool{ } func newBufferedWriter(wr io.WriteCloser) *bufwriter.Writer { - var bwr = bufioWriterPool.Get().(*bufwriter.Writer) + var bwr, _ = bufioWriterPool.Get().(*bufwriter.Writer) + if bwr == nil { + bwr = bufwriter.New(nil, writeBufferSize) + } + bwr.Reset(wr) return bwr } diff --git a/gemax/server_test.go b/gemax/server_test.go index 47f6ee9..12d9dc7 100644 --- a/gemax/server_test.go +++ b/gemax/server_test.go @@ -326,6 +326,7 @@ func runTask(t *testing.T, task func()) { }) } +//nolint:unparam // it's ok for tests func dialAndWrite(t *testing.T, ctx context.Context, dialer *memnet.Listener, format string, args ...any) string { t.Helper() diff --git a/torture_report.txt b/torture_report.txt new file mode 100644 index 0000000..d8a1d45 --- /dev/null +++ b/torture_report.txt @@ -0,0 +1,223 @@ +Running server diagnostics check against localhost:1986 +... + +[IPv4Address] Establish a connection over an IPv4 address +Looking up IPv4 address for 'localhost' + ✓ '127.0.0.1' +Attempting to connect to 127.0.0.1:1986 + ✓ Successfully established connection + +[IPv6Address] Establish a connection over an IPv6 address +Looking up IPv6 address for 'localhost' + ✓ '::1' +Attempting to connect to [::1]:1986 + x [Errno 111] Connection refused + +[TLSVersion] Server must negotiate at least TLS v1.2, ideally TLS v1.3 +Checking client library + 'OpenSSL 3.0.8 7 Feb 2023' +Determining highest supported TLS version + ✓ Negotiated TLSv1.3 + +[TLSClaims] Certificate claims must be valid +Checking "Not Valid Before" timestamp + ✓ 2021-03-16 14:04:02 UTC +Checking "Not Valid After" timestamp + ✓ 2031-03-14 14:04:02 UTC +Checking subject claim matches server hostname + {'subject': ((),), 'subjectAltName': (('DNS', 'localhost'),)} + ✓ Hostname 'localhost' matches claim + +[TLSVerified] Certificate should be self-signed or have a trusted issuer +Connecting over verified SSL socket + ✓ Self-signed TLS certificate detected + +[TLSCloseNotify] Server should send a close_notify alert before closing the connection +Checking for close_notify TLS signal +Request URL + 'gemini://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' + ✓ TLS close_notify signal was received successfully + +[TLSRequired] Non-TLS requests should be refused +Sending non-TLS request + ✓ Connection closed by server + +[ConcurrentConnections] Server should support concurrent connections +Attempting to establish two connections + Opening socket 1 + Opening socket 2 + Closing socket 2 + Closing socket 1 + ✓ Concurrent connections supported + +[ResponseFormat] Validate the response header and body for the root URL +Request URL + 'gemini://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a success code (20 SUCCESS) + ✓ Received status of '20' +There should be a single space between and + ✓ '0 t' +Mime type should be "text/gemini" + ✓ 'text/gemini' +Header should end with "\r\n" + ✓ '\r\n' +Body should be non-empty + ✓ '```\n __..._ _...__\n_..-" `Y` "-._\n' +Body should use consistent line endings + ✓ All lines end with \n + +[HomepageNoRedirect] The root URL should return the same resource with or without the trailing slash. +Request URL + 'gemini://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a success code (20 SUCCESS) + ✓ Received status of '20' + +[PageNotFound] Request a gemini URL that does not exist +Request URL + 'gemini://localhost:1986/09pdsakjo73hjn12id78\r\n' +Response header + '51 NOT FOUND: /09pdsakjo73hjn12id78\r\n' +Status should return code 51 (NOT FOUND) + ✓ '51' +Header should end with "\r\n" + ✓ '\r\n' +Body should be empty + ✓ '' + +[RequestMissingCR] A request without a should timeout +Request URL + 'gemini://localhost:1986/\n' +Response header + '20 text/gemini\r\n' +No response should be received + x '20' + +[URLIncludePort] Send the URL with the port explicitly defined +Request URL + 'gemini://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a success code (20 SUCCESS) + ✓ Received status of '20' + +[URLSchemeMissing] A URL without a scheme should result in a 59 Bad Request +Request URL + '//localhost:1986/\r\n' +Response header + '50 50 PERMANENT FAILURE\r\n' +Status should return a failure code (59 BAD REQUEST) + x Received status of '50' + +[URLByIPAddress] Send the URL using the IPv4 address +Request URL + 'gemini://127.0.0.1:1986/\r\n' +Response header + '20 text/gemini\r\n' +Verify that the status matches your desired behavior + ✓ '20' + +[URLInvalidUTF8Byte] Send a URL containing a non-UTF8 byte sequence +Request URL + 'gemini://localhost:1986/\udcdc\r\n' +Response header + '50 50 PERMANENT FAILURE\r\n' +Connection should either drop, or return 59 (BAD REQUEST) + x Received status of '50' + +[URLMaxSize] Send a 1024 byte URL, the maximum allowed size +Request URL + 'gemini://localhost:1986/0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\r\n' +Response header + '51 NOT FOUND: /0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\r\n' +Status should return code 51 (NOT FOUND) + ✓ '51' + +[URLAboveMaxSize] Send a 1025 byte URL, above the maximum allowed size +Request URL + 'gemini://localhost:1986/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\r\n' +Response header + '59 59 BAD REQUEST\r\n' +Connection should either drop, or return 59 (BAD REQUEST) + ✓ Received status of '59' + +[URLWrongPort] A URL with an incorrect port number should be rejected +Request URL + 'gemini://localhost:443/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a failure code (53 PROXY REQUEST REFUSED) + x Received status of '20' + +[URLWrongHost] A URL with a foreign hostname should be rejected +Request URL + 'gemini://wikipedia.org/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a failure code (53 PROXY REQUEST REFUSED) + x Received status of '20' + +[URLSchemeHTTP] Send a URL with an HTTP scheme +Request URL + 'http://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a failure code (53 PROXY REQUEST REFUSED) + x Received status of '20' + +[URLSchemeHTTPS] Send a URL with an HTTPS scheme +Request URL + 'https://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a failure code (53 PROXY REQUEST REFUSED) + x Received status of '20' + +[URLSchemeGopher] Send a URL with a Gopher scheme +Request URL + 'gopher://localhost:1986/\r\n' +Response header + '20 text/gemini\r\n' +Status should return a failure code (53 PROXY REQUEST REFUSED) + x Received status of '20' + +[URLEmpty] Empty URLs should not be accepted by the server +Request URL + '\r\n' +Response header + '59 59 BAD REQUEST\r\n' +Status should return a failure code (59 BAD REQUEST) + ✓ Received status of '59' + +[URLRelative] Relative URLs should not be accepted by the server +Request URL + '/\r\n' +Response header + '50 host not found\r\n' +Status should return a failure code (59 BAD REQUEST) + x Received status of '50' + +[URLInvalid] Random text should not be accepted by the server +Request URL + 'Hello Gemini!\r\n' +Response header + '59 59 BAD REQUEST\r\n' +Status should return a failure code (59 BAD REQUEST) + ✓ Received status of '59' + +[URLDotEscape] A URL should not be able to escape the root using dot notation +Request URL + 'gemini://localhost:1986/../../\r\n' +Response header + '50 50 PERMANENT FAILURE\r\n' +Status should return a failure code (5X PERMANENT FAILURE) + ✓ Received status of '50' + +Done! +Failed 10 checks: IPv6Address, RequestMissingCR, URLSchemeMissing, URLInvalidUTF8Byte, URLWrongPort, URLWrongHost, URLSchemeHTTP, URLSchemeHTTPS, URLSchemeGopher, URLRelative +1 check returned None: URLByIPAddress From a1034dd84e4d65fc167721af3855c6bafbb6c5f8 Mon Sep 17 00:00:00 2001 From: merlin Date: Sat, 17 Jun 2023 20:36:58 +0300 Subject: [PATCH 3/5] fix TestURLDotEscape --- gemax/server_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemax/server_test.go b/gemax/server_test.go index 12d9dc7..59a8a08 100644 --- a/gemax/server_test.go +++ b/gemax/server_test.go @@ -238,7 +238,7 @@ func TestURLDotEscape(test *testing.T) { var resp = dialAndWrite(test, ctx, listener, "gemini://example.com/./\r\n") - expectResponse(test, strings.NewReader(resp), "50 50 PERMANENT FAILURE\r\n") + expectResponse(test, strings.NewReader(resp), "59 59 PERMANENT FAILURE\r\n") } // emulates michael-lazar/gemini-diagnostics localhost 9999 --checks='PageNotFound' From 940c3823db030e3b219f222b3f284ced3454f2eb Mon Sep 17 00:00:00 2001 From: merlin Date: Sat, 17 Jun 2023 20:38:10 +0300 Subject: [PATCH 4/5] fix TestURLDotEscape --- gemax/server_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemax/server_test.go b/gemax/server_test.go index 59a8a08..5fbead5 100644 --- a/gemax/server_test.go +++ b/gemax/server_test.go @@ -238,7 +238,7 @@ func TestURLDotEscape(test *testing.T) { var resp = dialAndWrite(test, ctx, listener, "gemini://example.com/./\r\n") - expectResponse(test, strings.NewReader(resp), "59 59 PERMANENT FAILURE\r\n") + expectResponse(test, strings.NewReader(resp), "59 59 BAD REQUEST\r\n") } // emulates michael-lazar/gemini-diagnostics localhost 9999 --checks='PageNotFound' From 02833ebfd09d206b07dd265f199fd3dba2c7a5ff Mon Sep 17 00:00:00 2001 From: merlin Date: Sat, 17 Jun 2023 20:40:35 +0300 Subject: [PATCH 5/5] bump go version --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d06760..5991e4e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ jobs: test: strategy: matrix: - go-version: [1.19.*] + go-version: [1.20.*] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -25,7 +25,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.19.x + go-version: 1.20.x - name: Checkout code uses: actions/checkout@v2 - name: Test