Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

websocket is not connecting #329

Open
AwaisKhan74 opened this issue Feb 26, 2024 · 0 comments
Open

websocket is not connecting #329

AwaisKhan74 opened this issue Feb 26, 2024 · 0 comments

Comments

@AwaisKhan74
Copy link

I am getting this error:
Bad response 'Sec-WebSocket-Accept' header

Here is my code snippet WebSocketChannel.connect(Uri.parse(wsUrl));
upoun debging websocket_impl.dart I found these values

nonce="cKPAQxX7w6REzh3smWpAYA=="
accept="Kfh9QIsMVZcl6xEPYxPHzW8SZ8w="

Expected results
It should compare accept and nonce and return true. As it is connecting to socket while connecting from postman or JS.

Actual results
The fluter say bad request sec-websocket header. The List for expectedAccept and orignalAccept differ but thy shouldn't.

Code sample:
WebSocketChannel.connect(Uri.parse(wsUrl));
values in headers are
nonce="cKPAQxX7w6REzh3smWpAYA=="
accept="Kfh9QIsMVZcl6xEPYxPHzW8SZ8w="
code from flutter to run is
static Future connect(
String url, Iterable? protocols, Map<String, dynamic>? headers,
{CompressionOptions compression = CompressionOptions.compressionDefault,
HttpClient? customClient}) {
Uri uri = Uri.parse(url);
if (!uri.isScheme("ws") && !uri.isScheme("wss")) {
throw WebSocketException("Unsupported URL scheme '${uri.scheme}'");
}

Random random = Random();
// Generate 16 random bytes.
Uint8List nonceData = Uint8List(16);
for (int i = 0; i < 16; i++) {
  nonceData[i] = random.nextInt(256);
}
String nonce = base64Encode(nonceData);

final callerStackTrace = StackTrace.current;

uri = Uri(
    scheme: uri.isScheme("wss") ? "https" : "http",
    userInfo: uri.userInfo,
    host: uri.host,
    port: uri.port,
    path: uri.path,
    query: uri.query,
    fragment: uri.fragment);
return (customClient ?? _httpClient).openUrl("GET", uri).then((request) {
  if (uri.userInfo != null && uri.userInfo.isNotEmpty) {
    // If the URL contains user information use that for basic
    // authorization.
    String auth = base64Encode(utf8.encode(uri.userInfo));
    request.headers.set(HttpHeaders.authorizationHeader, "Basic $auth");
  }
  if (headers != null) {
    headers.forEach((field, value) => request.headers.add(field, value));
  }
  // Setup the initial handshake.
  request.headers
    ..set(HttpHeaders.connectionHeader, "Upgrade")
    ..set(HttpHeaders.upgradeHeader, "websocket")
    ..set("Sec-WebSocket-Key", nonce)
    ..set("Cache-Control", "no-cache")
    ..set("Sec-WebSocket-Version", "13");
  if (protocols != null) {
    request.headers.add("Sec-WebSocket-Protocol", protocols.toList());
  }

  if (compression.enabled) {
    request.headers
        .add("Sec-WebSocket-Extensions", compression._createHeader());
  }

  return request.close();
}).then((response) {
  Future<WebSocket> error(String message) {
    // Flush data.
    response.detachSocket().then((socket) {
      socket.destroy();
    });
    return Future<WebSocket>.error(
        WebSocketException(message), callerStackTrace);
  }

  var connectionHeader = response.headers[HttpHeaders.connectionHeader];
  if (response.statusCode != HttpStatus.switchingProtocols ||
      connectionHeader == null ||
      !connectionHeader.any((value) => value.toLowerCase() == "upgrade") ||
      response.headers.value(HttpHeaders.upgradeHeader)!.toLowerCase() !=
          "websocket") {
    return error("Connection to '$uri' was not upgraded to websocket");
  }
  String? accept = response.headers.value("Sec-WebSocket-Accept");
  if (accept == null) {
    return error(
        "Response did not contain a 'Sec-WebSocket-Accept' header");
  }
  _SHA1 sha1 = _SHA1();
  sha1.add("$nonce$_webSocketGUID".codeUnits);
  List<int> expectedAccept = sha1.close();
  List<int> receivedAccept = base64Decode(accept);
  if (expectedAccept.length != receivedAccept.length) {
    return error(
        "Response header 'Sec-WebSocket-Accept' is the wrong length");
  }
  for (int i = 0; i < expectedAccept.length; i++) {
    if (expectedAccept[i] != receivedAccept[i]) {
      return error("Bad response 'Sec-WebSocket-Accept' header");
    }
  }
  var protocol = response.headers.value('Sec-WebSocket-Protocol');

  _WebSocketPerMessageDeflate? deflate =
      negotiateClientCompression(response, compression);

  return response.detachSocket().then<WebSocket>((socket) =>
      _WebSocketImpl._fromSocket(
          socket, protocol, compression, false, deflate));
});

}

static _WebSocketPerMessageDeflate? negotiateClientCompression(
HttpClientResponse response, CompressionOptions compression) {
String extensionHeader =
response.headers.value('Sec-WebSocket-Extensions') ?? "";

var hv = HeaderValue.parse(extensionHeader, valueSeparator: ',');

if (compression.enabled && hv.value == PER_MESSAGE_DEFLATE) {
  var serverNoContextTakeover =
      hv.parameters.containsKey(_serverNoContextTakeover);
  var clientNoContextTakeover =
      hv.parameters.containsKey(_clientNoContextTakeover);

  int getWindowBits(String type) {
    var o = hv.parameters[type];
    if (o == null) {
      return DEFAULT_WINDOW_BITS;
    }

    return int.tryParse(o) ?? DEFAULT_WINDOW_BITS;
  }

  return _WebSocketPerMessageDeflate(
      clientMaxWindowBits: getWindowBits(_clientMaxWindowBits),
      serverMaxWindowBits: getWindowBits(_serverMaxWindowBits),
      clientNoContextTakeover: clientNoContextTakeover,
      serverNoContextTakeover: serverNoContextTakeover);
}

return null;

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant