| 186 | } |
| 187 | |
| 188 | func handshakeRequest(ctx context.Context, urls string, opts *DialOptions, copts *compressionOptions, secWebSocketKey string) (*http.Response, error) { |
| 189 | u, err := url.Parse(urls) |
| 190 | if err != nil { |
| 191 | return nil, fmt.Errorf("failed to parse url: %w", err) |
| 192 | } |
| 193 | |
| 194 | switch u.Scheme { |
| 195 | case "ws": |
| 196 | u.Scheme = "http" |
| 197 | case "wss": |
| 198 | u.Scheme = "https" |
| 199 | case "http", "https": |
| 200 | default: |
| 201 | return nil, fmt.Errorf("unexpected url scheme: %q", u.Scheme) |
| 202 | } |
| 203 | |
| 204 | req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil) |
| 205 | if err != nil { |
| 206 | return nil, fmt.Errorf("failed to create new http request: %w", err) |
| 207 | } |
| 208 | if len(opts.Host) > 0 { |
| 209 | req.Host = opts.Host |
| 210 | } |
| 211 | req.Header = opts.HTTPHeader.Clone() |
| 212 | req.Header.Set("Connection", "Upgrade") |
| 213 | req.Header.Set("Upgrade", "websocket") |
| 214 | req.Header.Set("Sec-WebSocket-Version", "13") |
| 215 | req.Header.Set("Sec-WebSocket-Key", secWebSocketKey) |
| 216 | if len(opts.Subprotocols) > 0 { |
| 217 | req.Header.Set("Sec-WebSocket-Protocol", strings.Join(opts.Subprotocols, ",")) |
| 218 | } |
| 219 | if copts != nil { |
| 220 | req.Header.Set("Sec-WebSocket-Extensions", copts.String()) |
| 221 | } |
| 222 | |
| 223 | resp, err := opts.HTTPClient.Do(req) |
| 224 | if err != nil { |
| 225 | return nil, fmt.Errorf("failed to send handshake request: %w", err) |
| 226 | } |
| 227 | return resp, nil |
| 228 | } |
| 229 | |
| 230 | func secWebSocketKey(rr io.Reader) (string, error) { |
| 231 | if rr == nil { |