Skip to content

Commit

Permalink
Forward requests in parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany committed May 29, 2024
1 parent 242ec1c commit fa7f4c0
Showing 1 changed file with 68 additions and 11 deletions.
79 changes: 68 additions & 11 deletions ee/desktop/user/universallink/handler_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@ import (
"context"
"fmt"
"log/slog"
"net/http"
"net/url"
"strings"
"sync"
"time"

"github.com/kolide/launcher/ee/gowrapper"
"github.com/kolide/launcher/ee/localserver"
)

const universalLinkPrefix = "/launcher/applinks"
const (
universalLinkPrefix = "/launcher/applinks/"
requestTimeout = 40 * time.Second
)

type universalLinkHandler struct {
urlInput chan string
Expand Down Expand Up @@ -63,27 +72,75 @@ func (u *universalLinkHandler) Interrupt(_ error) {
close(u.urlInput)
}

// handleUniversalLinkRequest receives requests and logs them. In the future,
// it will validate them and forward them to launcher root.
// handleUniversalLinkRequest receives requests, validates them, and forwards them
// to launcher root's localserver.
func (u *universalLinkHandler) handleUniversalLinkRequest(requestUrl string) error {
// Parsing the URL also validates that we got a reasonable URL
parsedUrl, err := url.Parse(requestUrl)
if err != nil {
return fmt.Errorf("parsing universal link request URL: %w", err)
}

origin := parsedUrl.Host
origin := fmt.Sprintf("%s://%s", parsedUrl.Scheme, parsedUrl.Host)
requestPath := strings.TrimPrefix(parsedUrl.Path, universalLinkPrefix)
requestQuery := parsedUrl.RawQuery

u.slogger.Log(context.TODO(), slog.LevelInfo,
"received universal link request",
"origin", origin,
"request_path", requestPath,
"request_query", requestQuery,
)
// Forward the request to each potential launcher root port, in parallel
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
var wg sync.WaitGroup
for _, p := range localserver.PortList {
p := p
wg.Add(1)

gowrapper.Go(ctx, u.slogger, func() {
defer wg.Done()
if err := forwardRequest(ctx, p, requestPath, requestQuery, origin); err != nil {
if strings.Contains(err.Error(), "connection refused") {
// Launcher not running on that port -- no need to log the error
return
}
u.slogger.Log(ctx, slog.LevelWarn,
"could not make universal link request",
"port", p,
"err", err,
)
return
}

// Success!
u.slogger.Log(ctx, slog.LevelDebug,
"successfully forwarded universal link request",
"port", p,
)
},
func(r any) {}, // no special behavior needed after recovering from panic
)
}

// TODO: forward the request to launcher root
wg.Wait()

return nil
}

func forwardRequest(ctx context.Context, port int, requestPath string, requestQuery string, requestOrigin string) error {
// Construct forwarded request, using URL as origin
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("http://localhost:%d/%s?%s", port, requestPath, requestQuery), nil)
if err != nil {
return fmt.Errorf("creating request: %w", err)
}
req.Header.Set("Origin", requestOrigin)

// Forward request
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("forwarding request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

return nil
}

0 comments on commit fa7f4c0

Please sign in to comment.