mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-07-13 21:18:50 +00:00
tests: minioClient web proxy (#13340)
follow-up to #13306 ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests for Go changes - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I ran... - [x] `make pr-go` before pushing ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [ ] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. *The decision if the pull request will be shown in the release notes is up to the mergers / release team.* The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/13340 Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
This commit is contained in:
parent
9947e07037
commit
7dd5bb8527
1 changed files with 105 additions and 0 deletions
|
|
@ -5,9 +5,14 @@ package storage
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -257,3 +262,103 @@ func TestNewMinioStorageInitializationTimeout(t *testing.T) {
|
|||
require.ErrorIs(t, err, context.DeadlineExceeded, "err must be a context deadline exceeded error, but was %v", err)
|
||||
assert.Nil(t, storage)
|
||||
}
|
||||
|
||||
// newProxyServer starts an HTTP proxy server that implements CONNECT tunneling.
|
||||
// It sets proxied to true whenever any request is received.
|
||||
func newProxyServer(t *testing.T, proxied *atomic.Bool) *httptest.Server {
|
||||
t.Helper()
|
||||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
proxied.Store(true)
|
||||
if r.Method != http.MethodConnect {
|
||||
http.Error(w, "only CONNECT is supported", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
targetConn, err := net.Dial("tcp", r.Host)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
defer targetConn.Close()
|
||||
clientConn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer clientConn.Close()
|
||||
_, _ = clientConn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
|
||||
go io.Copy(targetConn, clientConn)
|
||||
io.Copy(clientConn, targetConn)
|
||||
}))
|
||||
}
|
||||
|
||||
func TestMinioStorageProxy(t *testing.T) {
|
||||
// Start a fake TLS S3-compatible server.
|
||||
// `UseSSL: true` triggers CONNECT-style proxying.
|
||||
// `InsecureSkipVerify: true` accepts the self-signed cert.
|
||||
// `BucketLookup: path` forces path-style URLs so the fake server stays simple.
|
||||
s3Server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
fmt.Fprint(w, `<?xml version="1.0" encoding="UTF-8"?><VersioningConfiguration xmlns="http://test/"></VersioningConfiguration>`)
|
||||
case http.MethodHead:
|
||||
w.WriteHeader(http.StatusOK)
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}))
|
||||
defer s3Server.Close()
|
||||
|
||||
minioStorageCfg := func() *setting.Storage {
|
||||
return &setting.Storage{
|
||||
MinioConfig: setting.MinioStorageConfig{
|
||||
Endpoint: s3Server.Listener.Addr().String(),
|
||||
AccessKeyID: "123456",
|
||||
SecretAccessKey: "12345678",
|
||||
Bucket: "bucket",
|
||||
Location: "us-east-1",
|
||||
UseSSL: true,
|
||||
InsecureSkipVerify: true,
|
||||
BucketLookup: "path",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("ProxyIsUsed", func(t *testing.T) {
|
||||
var proxied atomic.Bool
|
||||
proxyServer := newProxyServer(t, &proxied)
|
||||
defer proxyServer.Close()
|
||||
|
||||
proxyURL, err := url.Parse(proxyServer.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer test.MockVariableValue(&setting.Proxy.Enabled, true)()
|
||||
defer test.MockVariableValue(&setting.Proxy.ProxyURL, proxyServer.URL)()
|
||||
defer test.MockVariableValue(&setting.Proxy.ProxyURLFixed, proxyURL)()
|
||||
defer test.MockVariableValue(&setting.Proxy.ProxyHosts, []string{"*"})()
|
||||
|
||||
storage, err := NewMinioStorage(t.Context(), minioStorageCfg())
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, storage)
|
||||
assert.True(t, proxied.Load(), "expected minio client to connect through the proxy")
|
||||
})
|
||||
|
||||
t.Run("ProxyIsNotUsed", func(t *testing.T) {
|
||||
var proxied atomic.Bool
|
||||
proxyServer := newProxyServer(t, &proxied)
|
||||
defer proxyServer.Close()
|
||||
|
||||
proxyURL, err := url.Parse(proxyServer.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Proxy is fully configured but disabled; minioClient should connect directly to s3Server.
|
||||
defer test.MockVariableValue(&setting.Proxy.Enabled, false)()
|
||||
defer test.MockVariableValue(&setting.Proxy.ProxyURL, proxyServer.URL)()
|
||||
defer test.MockVariableValue(&setting.Proxy.ProxyURLFixed, proxyURL)()
|
||||
defer test.MockVariableValue(&setting.Proxy.ProxyHosts, []string{"*"})()
|
||||
|
||||
storage, err := NewMinioStorage(t.Context(), minioStorageCfg())
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, storage)
|
||||
assert.False(t, proxied.Load(), "expected minio client to bypass the proxy when proxy is disabled")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue