| 321 | } |
| 322 | |
| 323 | func (runCtx *runContext) connectToRunServer(ctx context.Context) (*http.Response, net.Conn, error) { |
| 324 | if runCtx.attachURL == "" { |
| 325 | return nil, nil, errors.New(ctx, "no attach URL to connect to") |
| 326 | } |
| 327 | |
| 328 | url, err := url.Parse(runCtx.attachURL) |
| 329 | if err != nil { |
| 330 | return nil, nil, errors.Wrap(ctx, err, "parse URL") |
| 331 | } |
| 332 | |
| 333 | // Establish an initial TCP connection |
| 334 | conn, err := net.Dial("tcp", url.Host) |
| 335 | if err != nil { |
| 336 | return nil, nil, errors.Wrap(ctx, err, "establish initial TCP connection") |
| 337 | } |
| 338 | |
| 339 | // Wrap with TLS if using HTTPS |
| 340 | if url.Scheme == "https" { |
| 341 | tlsConfig := config.TLSConfig.Clone() |
| 342 | tlsConfig.ServerName = url.Hostname() |
| 343 | conn = tls.Client(conn, tlsConfig) |
| 344 | } |
| 345 | |
| 346 | req, err := http.NewRequest("CONNECT", runCtx.attachURL, nil) |
| 347 | if err != nil { |
| 348 | return nil, nil, errors.Wrap(ctx, err, "create request") |
| 349 | } |
| 350 | |
| 351 | token, err := runCtx.scalingoClient.GetAccessToken(ctx) |
| 352 | if err != nil { |
| 353 | return nil, nil, errors.Wrap(ctx, err, "get access token") |
| 354 | } |
| 355 | req.SetBasicAuth("", token) |
| 356 | |
| 357 | // Write the HTTP request directly to the connection |
| 358 | err = req.Write(conn) |
| 359 | if err != nil { |
| 360 | return nil, nil, errors.Wrap(ctx, err, "write request") |
| 361 | } |
| 362 | |
| 363 | resp, err := http.ReadResponse(bufio.NewReader(conn), req) |
| 364 | if err != nil { |
| 365 | if err, ok := err.(*net.OpError); ok { |
| 366 | if err.Err.Error() == "record overflow" { |
| 367 | return nil, nil, errors.New(ctx, fmt.Sprintf( |
| 368 | "secure connection error to Scalingo server\n"+ |
| 369 | "The encountered error is: %v (ID: CLI-1001)\n"+ |
| 370 | "Your firewall or proxy may block the connection to %s", |
| 371 | err, url.Host, |
| 372 | )) |
| 373 | } |
| 374 | } |
| 375 | return nil, nil, errors.Wrap(ctx, err, "read response") |
| 376 | } |
| 377 | |
| 378 | if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { |
| 379 | return resp, nil, errors.Newf(ctx, "invalid status code: %s", resp.Status) |
| 380 | } |