HandshakeProtocol.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. import { TextMessageFormat } from "./TextMessageFormat";
  4. import { isArrayBuffer } from "./Utils";
  5. /** @private */
  6. export interface HandshakeRequestMessage {
  7. readonly protocol: string;
  8. readonly version: number;
  9. }
  10. /** @private */
  11. export interface HandshakeResponseMessage {
  12. readonly error: string;
  13. readonly minorVersion: number;
  14. }
  15. /** @private */
  16. export class HandshakeProtocol {
  17. // Handshake request is always JSON
  18. public writeHandshakeRequest(handshakeRequest: HandshakeRequestMessage): string {
  19. return TextMessageFormat.write(JSON.stringify(handshakeRequest));
  20. }
  21. public parseHandshakeResponse(data: any): [any, HandshakeResponseMessage] {
  22. let messageData: string;
  23. let remainingData: any;
  24. if (isArrayBuffer(data)) {
  25. // Format is binary but still need to read JSON text from handshake response
  26. const binaryData = new Uint8Array(data);
  27. const separatorIndex = binaryData.indexOf(TextMessageFormat.RecordSeparatorCode);
  28. if (separatorIndex === -1) {
  29. throw new Error("Message is incomplete.");
  30. }
  31. // content before separator is handshake response
  32. // optional content after is additional messages
  33. const responseLength = separatorIndex + 1;
  34. messageData = String.fromCharCode.apply(null, Array.prototype.slice.call(binaryData.slice(0, responseLength)));
  35. remainingData = (binaryData.byteLength > responseLength) ? binaryData.slice(responseLength).buffer : null;
  36. } else {
  37. const textData: string = data;
  38. const separatorIndex = textData.indexOf(TextMessageFormat.RecordSeparator);
  39. if (separatorIndex === -1) {
  40. throw new Error("Message is incomplete.");
  41. }
  42. // content before separator is handshake response
  43. // optional content after is additional messages
  44. const responseLength = separatorIndex + 1;
  45. messageData = textData.substring(0, responseLength);
  46. remainingData = (textData.length > responseLength) ? textData.substring(responseLength) : null;
  47. }
  48. // At this point we should have just the single handshake message
  49. const messages = TextMessageFormat.parse(messageData);
  50. const response = JSON.parse(messages[0]);
  51. if (response.type) {
  52. throw new Error("Expected a handshake response from the server.");
  53. }
  54. const responseMessage: HandshakeResponseMessage = response;
  55. // multiple messages could have arrived with handshake
  56. // return additional data to be parsed as usual, or null if all parsed
  57. return [remainingData, responseMessage];
  58. }
  59. }