Skip to content

Commit

Permalink
Merge pull request #39 from ninedraft/fix-request-parsing
Browse files Browse the repository at this point in the history
Fix CI and linter issues
  • Loading branch information
ninedraft committed Jun 17, 2023
2 parents 0f98247 + 02833eb commit 2fe9c69
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 6 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion gemax/internal/bufreader/bufreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down
1 change: 1 addition & 0 deletions gemax/internal/bufwriter/bufwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 0 additions & 1 deletion gemax/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, "/")

Expand Down
6 changes: 5 additions & 1 deletion gemax/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion gemax/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 BAD REQUEST\r\n")
}

// emulates michael-lazar/gemini-diagnostics localhost 9999 --checks='PageNotFound'
Expand Down Expand Up @@ -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()

Expand Down
223 changes: 223 additions & 0 deletions torture_report.txt
Original file line number Diff line number Diff line change
@@ -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 <STATUS> and <META>
✓ '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 <CR> 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

0 comments on commit 2fe9c69

Please sign in to comment.