mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: allow ports in wildcard url configuration (#11657)
* fix: allow ports in wildcard url configuration This just forwards the port to the ui that generates urls. Our existing parsing + regex already supported ports for subdomain app requests.
This commit is contained in:
@@ -3,7 +3,6 @@ package agentapi
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -108,19 +107,14 @@ func (a *ManifestAPI) GetManifest(ctx context.Context, _ *agentproto.GetManifest
|
||||
return nil, xerrors.Errorf("fetching workspace agent data: %w", err)
|
||||
}
|
||||
|
||||
appHost := appurl.ApplicationURL{
|
||||
appSlug := appurl.ApplicationURL{
|
||||
AppSlugOrPort: "{{port}}",
|
||||
AgentName: workspaceAgent.Name,
|
||||
WorkspaceName: workspace.Name,
|
||||
Username: owner.Username,
|
||||
}
|
||||
vscodeProxyURI := a.AccessURL.Scheme + "://" + strings.ReplaceAll(a.AppHostname, "*", appHost.String())
|
||||
if a.AppHostname == "" {
|
||||
vscodeProxyURI += a.AccessURL.Hostname()
|
||||
}
|
||||
if a.AccessURL.Port() != "" {
|
||||
vscodeProxyURI += fmt.Sprintf(":%s", a.AccessURL.Port())
|
||||
}
|
||||
|
||||
vscodeProxyURI := vscodeProxyURI(appSlug, a.AccessURL, a.AppHostname)
|
||||
|
||||
var gitAuthConfigs uint32
|
||||
for _, cfg := range a.ExternalAuthConfigs {
|
||||
@@ -155,6 +149,17 @@ func (a *ManifestAPI) GetManifest(ctx context.Context, _ *agentproto.GetManifest
|
||||
}, nil
|
||||
}
|
||||
|
||||
func vscodeProxyURI(app appurl.ApplicationURL, accessURL *url.URL, appHost string) string {
|
||||
// This will handle the ports from the accessURL or appHost.
|
||||
appHost = appurl.SubdomainAppHost(appHost, accessURL)
|
||||
// If there is no appHost, then we want to use the access url as the proxy uri.
|
||||
if appHost == "" {
|
||||
appHost = accessURL.Host
|
||||
}
|
||||
// Return the url with a scheme and any wildcards replaced with the app slug.
|
||||
return accessURL.Scheme + "://" + strings.ReplaceAll(appHost, "*", app.String())
|
||||
}
|
||||
|
||||
func dbAgentMetadataToProtoDescription(metadata []database.WorkspaceAgentMetadatum) []*agentproto.WorkspaceAgentMetadata_Description {
|
||||
ret := make([]*agentproto.WorkspaceAgentMetadata_Description, len(metadata))
|
||||
for i, metadatum := range metadata {
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package agentapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
|
||||
)
|
||||
|
||||
func Test_vscodeProxyURI(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
coderAccessURL, err := url.Parse("https://coder.com")
|
||||
require.NoError(t, err)
|
||||
|
||||
accessURLWithPort, err := url.Parse("https://coder.com:8080")
|
||||
require.NoError(t, err)
|
||||
|
||||
basicApp := appurl.ApplicationURL{
|
||||
Prefix: "prefix",
|
||||
AppSlugOrPort: "slug",
|
||||
AgentName: "agent",
|
||||
WorkspaceName: "workspace",
|
||||
Username: "user",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
Name string
|
||||
App appurl.ApplicationURL
|
||||
AccessURL *url.URL
|
||||
AppHostname string
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
// No hostname proxies through the access url.
|
||||
Name: "NoHostname",
|
||||
AccessURL: coderAccessURL,
|
||||
AppHostname: "",
|
||||
App: basicApp,
|
||||
Expected: coderAccessURL.String(),
|
||||
},
|
||||
{
|
||||
Name: "NoHostnameAccessURLPort",
|
||||
AccessURL: accessURLWithPort,
|
||||
AppHostname: "",
|
||||
App: basicApp,
|
||||
Expected: accessURLWithPort.String(),
|
||||
},
|
||||
{
|
||||
Name: "Hostname",
|
||||
AccessURL: coderAccessURL,
|
||||
AppHostname: "*.apps.coder.com",
|
||||
App: basicApp,
|
||||
Expected: fmt.Sprintf("https://%s.apps.coder.com", basicApp.String()),
|
||||
},
|
||||
{
|
||||
Name: "HostnameWithAccessURLPort",
|
||||
AccessURL: accessURLWithPort,
|
||||
AppHostname: "*.apps.coder.com",
|
||||
App: basicApp,
|
||||
Expected: fmt.Sprintf("https://%s.apps.coder.com:%s", basicApp.String(), accessURLWithPort.Port()),
|
||||
},
|
||||
{
|
||||
Name: "HostnameWithPort",
|
||||
AccessURL: coderAccessURL,
|
||||
AppHostname: "*.apps.coder.com:4444",
|
||||
App: basicApp,
|
||||
Expected: fmt.Sprintf("https://%s.apps.coder.com:%s", basicApp.String(), "4444"),
|
||||
},
|
||||
{
|
||||
// Port from hostname takes precedence over access url port.
|
||||
Name: "HostnameWithPortAccessURLWithPort",
|
||||
AccessURL: accessURLWithPort,
|
||||
AppHostname: "*.apps.coder.com:4444",
|
||||
App: basicApp,
|
||||
Expected: fmt.Sprintf("https://%s.apps.coder.com:%s", basicApp.String(), "4444"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require.NotNilf(t, c.AccessURL, "AccessURL is required")
|
||||
|
||||
output := vscodeProxyURI(c.App, c.AccessURL, c.AppHostname)
|
||||
require.Equal(t, c.Expected, output)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user