// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// VMOptions=
// VMOptions=--short_socket_read
// VMOptions=--short_socket_write
// VMOptions=--short_socket_read --short_socket_write
// OtherResources=certificates/server_chain.pem
// OtherResources=certificates/server_key.pem

library dart._http;

import "dart:async";
import "dart:io";
import "dart:math";
import "dart:typed_data";

import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";

part "../../../sdk/lib/_http/crypto.dart";

const String webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
const String CERT_NAME = 'localhost_cert';
const String HOST_NAME = 'localhost';

String localFile(path) => Platform.script.resolve(path).toFilePath();

SecurityContext serverContext = new SecurityContext()
  ..useCertificateChain(localFile('certificates/server_chain.pem'))
  ..usePrivateKey(localFile('certificates/server_key.pem'),
      password: 'dartdart');

SecurityContext clientContext = new SecurityContext()
  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));

/**
 * A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
 */
class SecurityConfiguration {
  final bool secure;

  SecurityConfiguration({required bool this.secure});

  Future<HttpServer> createServer({int backlog: 0}) => secure
      ? HttpServer.bindSecure(HOST_NAME, 0, serverContext, backlog: backlog)
      : HttpServer.bind(HOST_NAME, 0, backlog: backlog);

  Future<WebSocket> createClient(int port) =>
      WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/',
          customClient: secure ? HttpClient(context: clientContext) : null);

  void testForceCloseServerEnd(int totalConnections) {
    createServer().then((server) {
      server.listen((request) {
        var response = request.response;
        response.statusCode = HttpStatus.switchingProtocols;
        response.headers.set(HttpHeaders.connectionHeader, "upgrade");
        response.headers.set(HttpHeaders.upgradeHeader, "websocket");
        String? key = request.headers.value("Sec-WebSocket-Key");
        _SHA1 sha1 = new _SHA1();
        sha1.add("$key$webSocketGUID".codeUnits);
        String accept = _CryptoUtils.bytesToBase64(sha1.close());
        response.headers.add("Sec-WebSocket-Accept", accept);
        response.headers.contentLength = 0;
        response.detachSocket().then((socket) {
          socket.destroy();
        });
      });

      int closeCount = 0;
      for (int i = 0; i < totalConnections; i++) {
        createClient(server.port).then((webSocket) {
          webSocket.add("Hello, world!");
          webSocket.listen((message) {
            Expect.fail("unexpected message");
          }, onDone: () {
            closeCount++;
            if (closeCount == totalConnections) {
              server.close();
            }
          });
        });
      }
    });
  }

  void runTests() {
    testForceCloseServerEnd(10);
  }
}

main() {
  asyncStart();
  new SecurityConfiguration(secure: false).runTests();
  new SecurityConfiguration(secure: true).runTests();
  asyncEnd();
}
