Advertisement
SReject

mWebSocket v1.0.0001

Feb 2nd, 2018
222
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
mIRC 36.20 KB | None | 0 0
  1. alias WebSockOpen {
  2.   if ($isid) {
  3.     return
  4.   }
  5.   var %Error, %Sock, %Host, %Ssl, %Port
  6.   if ($0 < 2) {
  7.     %Error = Missing paramters
  8.   }
  9.   elseif ($0 > 3) {
  10.     %Error = Excessive Parameters
  11.   }
  12.   elseif (? isin $1 || * isin $1) {
  13.     %Error = names cannot contain ? or *
  14.   }
  15.   elseif ($1 isnum) {
  16.     %Error = names cannot be a numerical value
  17.   }
  18.   elseif ($sock(WebSocket_ $+ $1)) {
  19.     %Error = specified 'name' in use
  20.   }
  21.   elseif ($0 == 3) && ($3 !isnum 1- || . isin $3 || $3 > 300) {
  22.     %Error = Invalid timeout; must be an integer between 1 and 300
  23.   }
  24.   elseif (!$regex(uri, $2, m ^((?:wss?://)?)([^?&#/\\:]+)((?::\d+)?)((?:(?=[\/\\\?#])[^#]*)?)(?:#.*)?$ i)) {
  25.     %Error = Invalid URL specified
  26.   }
  27.   else {
  28.     %Sock = _WebSocket_ $+ $1
  29.     %Host = $regml(uri, 2)
  30.     if ($hget(%Sock)) {
  31.       ._WebSocket.Cleanup %Sock
  32.     }
  33.     if (wss:// == $regml(uri, 1)) {
  34.       %Ssl = $true
  35.     }
  36.     else {
  37.       %Ssl = $false
  38.     }
  39.     if ($regml(uri, 3)) {
  40.       %Port = $mid($v1, 2-)
  41.       if (%Port !isnum 1-65535 || . isin %port) {
  42.         %Error = Invalid port specified in uri; must be an interger to between 1 and 65,535
  43.         goto error
  44.       }
  45.     }
  46.     elseif (%Ssl) {
  47.       %Port = 443
  48.     }
  49.     else {
  50.       %Port = 80
  51.     }
  52.     hadd -m %Sock SOCK_STATE 1
  53.     hadd %Sock SOCK_SSL %Ssl
  54.     hadd %Sock SOCK_ADDR %Host
  55.     hadd %Sock SOCK_PORT %Port
  56.     hadd %Sock HTTPREQ_URI $2
  57.     hadd %Sock HTTPREQ_RES $iif($left($regml(uri, 4), 1) !== /, /) $+ $regml(uri, 4)
  58.     hadd %Sock HTTPREQ_HOST %Host $+ $iif((%Ssl && %Port !== 443) || (!%Ssl && %Port !== 80), : $+ %Port)
  59.     $+(.timer, _WebSocket_Timeout_, $1) -oi 1 $iif($3, $v1, 300) _WebSocket.ConnectTimeout %Name
  60.     sockopen $iif(%ssl, -e) %sock %host %port
  61.     _WebSocket.Debug -i Connecting> $+ $1 $+ ~Connecting to %host $iif(%ssl, with an SSL connection) on port %port as %sock
  62.   }
  63.   :error
  64.   if ($error || %error) {
  65.     echo $color(info).dd -s * /WebSockOpen: $v1
  66.     _WebSocket.Debug -e /WebSockOpen~ $+ $v1
  67.     reseterror
  68.     halt
  69.   }
  70. }
  71. alias WebSockHeader {
  72.   var %Error, %Name, %Sock
  73.   if ($isid || $event !== signal || !$regex($signal, /^WebSocket_INIT_(?!\d+$)([^?*-][^?*]*)$/i)) {
  74.     return
  75.   }
  76.   else {
  77.     %Name = $regml(name, 1)
  78.     %Sock = _WebSocket_ $+ %Name
  79.     if (!$sock(%Sock)) {
  80.       %Error = WebSocket not in use
  81.     }
  82.     elseif ($0 !== 2) {
  83.       %Error = Missing parameters
  84.     }
  85.     else {
  86.       %Header = $regsubex($1, /(?:^\s)(?:\s*:\s*$)/g, )
  87.       if (!$len(%Header)) {
  88.         %Error = Invalid header name
  89.       }
  90.       else {
  91.         %Index = $calc($hfind(%Sock, ^HTTPREQ_HEADER\d+_, 0, r) + 1)
  92.         hadd -m %Sock $+(HTTPREQ_HEADER, %Index, _, %Header) $2-
  93.       }
  94.     }
  95.   }
  96.   :error
  97.   if ($error || %Error) {
  98.     echo -sg * /WebSockHeader: $v1
  99.     reseterror
  100.     halt
  101.   }
  102. }
  103. alias WebSockMark {
  104.   var %Error, %Switches
  105.   if ($isid) {
  106.     if ($0 !== 2) {
  107.       %Error = Invalid parameters
  108.     }
  109.     elseif (!$regex($1, ^(?!\d+$)[^?*]+$) || !$sock(_WebSocket_ $+ $1)) {
  110.       %Error = WebSocket does not exist
  111.     }
  112.     elseif ($chr(32) isin $2) {
  113.       %Error = Item name cannot contain spaces
  114.     }
  115.     elseif (!$regex($2, /^\d+$/) || $prop === item) {
  116.       return $hget(_WebSocket_ $+ $1, MARK_ $+ $2)
  117.     }
  118.     return $hfind(_WebSocket_ $+ $1, MARK_*, $2, w)
  119.   }
  120.   else {
  121.     if (-* iswm $1) {
  122.       %Switches = $Mid($1, 2-)
  123.       tokenize 32 $2-
  124.     }
  125.     if ($regex(%Switches, ([^nr]))) {
  126.       %Error = Unknown switch specified: $regml(1)
  127.     }
  128.     elseif ($regex(%Switches, ([nr]).*\1)) {
  129.       %Error = Duplicate switch specified: $regml(1)
  130.     }
  131.     elseif ($regex(%Switches, /[nr]/g) > 1) {
  132.       %Error = Conflicting switches specified
  133.     }
  134.     elseif ((r isincs %switches && $0 != 2) || (r !isincs %switches && $0 < 3)) {
  135.       %Error = Invalid parameters
  136.     }
  137.     elseif (!$regex($1, ^(?!\d+$)[^?*]+$) || !$sock(_WebSocket_ $+ $1)) {
  138.       %Error = WebSocket does not exist
  139.     }
  140.     elseif (r isincs %switches) {
  141.       hdel _WebSocket_ $+ $1 MARK_ $+ $2
  142.     }
  143.     elseif (n isincs %switches || &?* !iswm $3 || $0 > 3) {
  144.       hadd -m _WebSocket_ $+ $1 MARK_ $+ $2-
  145.     }
  146.     else {
  147.       hadd -mb _WebSocket_ $+ $1 MARK_ $+ $2-
  148.     }
  149.   }
  150.   :error
  151.   if ($error || %Error) {
  152.     %Error = $v1
  153.     echo $color(info).dd -s * $iif($isid, $, /) $+ WebSockMark: %Error
  154.     _WebSocket.Debug -e $iif($isid, $, /) $+ WebSockMark~ $+ %Error
  155.     reseterror
  156.     if (!$isid) {
  157.       halt
  158.     }
  159.   }
  160. }
  161.  
  162. alias WebSockWrite {
  163.   if ($isid) {
  164.     return
  165.   }
  166.   var %FrameSwitch, %DataSwitch, %Name, %Sock, %Error, %CompFrame = &_WebSocket_CompiledFrame, %Type, %Data, %BUnset, %Size, %Index = 1, %Mask1, %Mask2, %Mask3, %Mask4, %QuadMask
  167.   if ($left($1, 1) isin +-) {
  168.     noop $regex($1, /^((?:-[^+]*)?)((?:\+.*)?)$/))
  169.     %FrameSwitch = $mid($regml(1), 2)
  170.     %DataSwitch = $mid($regml(2), 2)
  171.     tokenize 32 $2-
  172.   }
  173.   %Name = $1
  174.   %Sock = _WebSocket_ $+ $1
  175.   if ($regex(%FrameSwitch, ([^cpPbt]))) {
  176.     %Error = Unknown switch specified: $regml(1)
  177.   }
  178.   elseif ($regex(%FrameSwitch, ([cpPbt]).*?\1)) {
  179.     %Error = Duplicate switch specified: $regml(1)
  180.   }
  181.   elseif ($regex(%FrameSwitch, ([cpPbt]).*?([cpPbt]))) {
  182.     %Error = Conflicting switches: $regml(1) $regml(2)
  183.   }
  184.   elseif ($regex(%DataSwitch, ([^tw]))) {
  185.     %Error = Invalid Data-force switch + $+ $regml(1)
  186.   }
  187.   elseif ($0 < 1) {
  188.     %Error = Missing parameters
  189.   }
  190.   elseif (t !isincs %DataSwitch && $0 == 2 && &?* iswm $2 && $bvar($2, 0) > 4294967295) {
  191.     %Error = Specified bvar exceeds 4gb
  192.   }
  193.   else {
  194.     bunset &_WebSocket_SendBuffer &_WebSocket_FrameData %CompFrame
  195.     if (P isincs %FrameSwitch) {
  196.       bset %CompFrame 1 138
  197.       %Type = PONG
  198.     }
  199.     elseif (p isincs %FrameSwitch) {
  200.       bset %CompFrame 1 137
  201.       %Type = PING
  202.     }
  203.     elseif (c isincs %FrameSwitch) {
  204.       bset %CompFrame 1 136
  205.       %Type = CLOSE
  206.     }
  207.     elseif (b isincs %FrameSwitch) {
  208.       bset %CompFrame 1 130
  209.       %Type = BINARY
  210.     }
  211.     else {
  212.       bset %CompFrame 1 129
  213.       %Type = TEXT
  214.     }
  215.     if (t !isincs %DataSwitch && &?* iswm $2 && $0 == 2) {
  216.       %Data = $2
  217.     }
  218.     else {
  219.       %Data = &_WebSocket_FrameData
  220.       if ($0 > 1) {
  221.         bset -tc %Data 1 $2-
  222.       }
  223.     }
  224.     if ($bvar(%Data, 0)) {
  225.       %Size  = $v1
  226.       if (%Type !isincs TEXT BINARY && %Size > 125) {
  227.         %Error = Control frame data cannot be larger than 125 bytes
  228.         goto error
  229.       }
  230.       elseif (%Size > 4294967295) {
  231.         %Error = Frame data exceeds 4gb limit
  232.         goto error
  233.       }
  234.       elseif (%Size > 65535) {
  235.         bset %CompFrame 2 255 0 0 0 0 $replace($longip(%Size), ., $chr(32))
  236.       }
  237.       elseif (%Size > 125) {
  238.         bset %CompFrame 2 254 $replace($gettok($longip(%Size), 3-, 46), ., $chr(32))
  239.       }
  240.       else {
  241.         bset %CompFrame 2 $calc(128 + %Size)
  242.       }
  243.       %Mask1 = $r(0, 255)
  244.       %Mask2 = $r(0, 255)
  245.       %Mask3 = $r(0, 255)
  246.       %Mask4 = $r(0, 255)
  247.       bset %CompFrame $calc($bvar(%CompFrame, 0) + 1) %Mask1 %Mask2 %Mask3 %Mask4
  248.       %QuadMask = $calc(%Size - (%Size % 4))
  249.       while (%Index < %QuadMask) {
  250.         bset %CompFrame $calc($bvar(%CompFrame,0) +1) $xor($bvar(%Data,%Index),%Mask1) $xor($bvar(%Data,$calc(1+ %Index)),%Mask2) $xor($bvar(%Data,$calc(2+ %Index)),%Mask3) $xor($bvar(%Data,$calc(3+ %Index)),%Mask4)
  251.         inc %Index 4
  252.       }
  253.       if (%Index <= %Size) {
  254.         bset %CompFrame $calc($bvar(%CompFrame,0) +1) $xor($bvar(%Data,%Index),%Mask1)
  255.         inc %index
  256.         if (%Index <= %Size) {
  257.           bset %CompFrame $calc($bvar(%CompFrame,0) +1) $xor($bvar(%Data,%Index),%Mask2)
  258.           inc %index
  259.           if (%Index <= %Size) {
  260.             bset %CompFrame $calc($bvar(%CompFrame,0) +1) $xor($bvar(%Data,%Index),%Mask3)
  261.           }
  262.         }
  263.       }
  264.     }
  265.     else {
  266.       bset %CompFrame 2 0
  267.     }
  268.     if (w isincs %Switches) {
  269.       while ($sock(_WebSocket_ $+ $1, %Index)) {
  270.         %Sock = $v1
  271.         if ($hget(%Sock, SOCK_STATE) == 4 && !$hget(%Sock, CLOSE_PENDING)) {
  272.           if ($hget(%Sock, WSFRAME_Buffer, &_WebSocket_SendBuffer)) {
  273.             bcopy -c &_WebSocket_SendBuffer $calc($bvar(&_WebSocket_SendBuffer, 0) + 1) %CompFrame 1 -1
  274.             hadd -b %Sock WSFRAME_Buffer &_WebSocket_SendBuffer
  275.           }
  276.           else {
  277.             hadd -b %Sock WSFRAME_Buffer %CompFrame
  278.           }
  279.           if (%Type == CLOSE) {
  280.             hadd %Sock CLOSE_PENDING $true
  281.           }
  282.           _WebSocket.Debug -i %Name $+ >FRAME_SEND~ $+ %Type frame queued. Size: $bvar(%CompFrame, 0) -- Head: $bvar(%CompFrame, 1, 2) -- Payload-Len: $calc($bvar(%CompFrame, 2) % 128)
  283.           bunset &_WebSocket_SendBuffer &_WebSocket_FrameData
  284.           _WebSocket.Send %Sock
  285.         }
  286.         inc %Index
  287.       }
  288.       bunset %CompFrame
  289.     }
  290.     elseif (!$regex($1, ^(?!\d+$)[^?*]+$) || !$sock(_WebSocket_ $+ $1)) {
  291.       %Error = WebSocket does not exist
  292.     }
  293.     elseif (!$hget(_WebSocket_ $+ $1) || !$len($hget(_WebSocket_ $+ $1, SOCK_STATE))) {
  294.       hadd -m _WebSocket_ $+ $1 ERROR INTERNAL_ERROR State lost
  295.       _WebSocket.Debug -e $1 $+ >STATE~State lost for $1
  296.       _WebSocket.RaiseError $1 INTERNAL_ERROR sock state lost
  297.     }
  298.     elseif ($hget(_WebSocket_ $+ $1, CLOSE_PENDING)) {
  299.       %Error = Close frame already queued; Cannot queue more
  300.     }
  301.     elseif ($hget(_WebSocket_ $+ $1, SOCK_STATE) isin 0 5) {
  302.       %Error = Connection in closing
  303.     }
  304.     elseif ($hget(_WebSocket_ $+ $1, SOCK_STATE) !== 4) {
  305.       %Error = WebSocket connection not established
  306.     }
  307.     else {
  308.       %Name = $1
  309.       %Sock = _WebSocket_ $+ $1
  310.       if ($hget(%Sock, WSFRAME_Buffer, &_WebSocket_SendBuffer)) {
  311.         bcopy -c &_WebSocket_SendBuffer $calc($bvar(&_WebSocket_SendBuffer, 0) + 1) %CompFrame 1 -1
  312.         hadd -b %Sock WSFRAME_Buffer &_WebSocket_SendBuffer
  313.       }
  314.       else {
  315.         hadd -b %Sock WSFRAME_Buffer %CompFrame
  316.       }
  317.       if (%Type == CLOSE) {
  318.         hadd %Sock CLOSE_PENDING $true
  319.       }
  320.       _WebSocket.Debug -i %Name $+ >FRAME_SEND~ $+ %Type frame queued. Size: $bvar(%CompFrame, 0) -- Head: $bvar(%CompFrame, 1, 2) -- Payload-Len: $calc($bvar(%CompFrame, 2) % 128)
  321.       bunset &_WebSocket_SendBuffer %CompFrame &_WebSocket_FrameData
  322.       _WebSocket.Send %Sock
  323.     }
  324.   }
  325.   :error
  326.   if ($error || %Error) {
  327.     echo $color(info).dd -s * /WebSockWrite: $v1
  328.     _WebSocket.Debug -e /WebSockWrite~ $+ $v1
  329.     reseterror
  330.     halt
  331.   }
  332. }
  333.  
  334. alias WebSockClose {
  335.   var %Switches, %Error, %Name, %Sock, %StatusCode, %Index
  336.   if (-* iswm $1) {
  337.     %Switches = $mid($1, 2)
  338.     tokenize 32 $2-
  339.   }
  340.   if ($regex(%Switches, ([^wfe\d]))) {
  341.     %Error = Unknown switch specified: $regml(1)
  342.   }
  343.   elseif ($regex(%Switches, /([wfe]).*\1/)) {
  344.     %Error = Duplicate switch specified: $regml(1)
  345.   }
  346.   elseif ($regex(%switches, /([fe]).*?([fe])/)) {
  347.     %Error = Conflicting switches specified: $regml(1) $regml(2)
  348.   }
  349.   elseif (e isincs %Switches && !$regex(StatusCode, %Switches, /e(\d{4})/)) {
  350.     %Error = Invalid error code
  351.   }
  352.   elseif (e !isincs %Switches && $regex(%Switches, \d)) {
  353.     %Error = Status Codes can only be specified with the -e switch
  354.   }
  355.   elseif ($0 < 1) {
  356.     %Error = Missing parameters
  357.   }
  358.   else {
  359.     if (f !isincs %Switches) {
  360.       if ($regml(StatusCode, 0)) {
  361.         %StatusCode = $base($regml(StatusCode), 10, 2, 16)
  362.       }
  363.       else {
  364.         %StatusCode = 1000
  365.       }
  366.       bset -c &_WebSocket_SendCloseMsg 1 $base($left(%StatusCode, 8), 2, 10) $base($mid(%StatusCode, 9), 2, 10)
  367.       if ($0 > 1) {
  368.         bset -t &_WebSocket_SendCloseMsg 3 $2-
  369.       }
  370.     }
  371.     if (w !isincs %Switches) {
  372.       %Name = $1
  373.       %Sock = _WebSocket_ $+ %Name
  374.       if (!$regex(%Name, /^(?!\d+$)[^?*-][^?*]*$/)) {
  375.         %Error = Invalid websocket name
  376.       }
  377.       elseif (!$sock(%Sock)) {
  378.         ._WebSocket.Cleanup %Sock
  379.         %Error = WebSocket does not exist
  380.       }
  381.       elseif (f isincs %Switches || $hget(%Sock, SOCK_STATE) isnum 1-3) {
  382.         _WebSocket.Cleanup %Sock
  383.       }
  384.       elseif ($hget(%Sock, SOCK_STATE) == 0 || $v1 == 5) {
  385.         %Error = Connection already closing
  386.       }
  387.       elseif ($hget(%Sock, CLOSE_PENDING)) {
  388.         %Error = CLOSE frame already sent
  389.       }
  390.       else {
  391.         WebSockWrite -c %Name &_WebSocket_SendCloseMsg
  392.         bunset &_WebSocket_SendCloseMsg
  393.       }
  394.     }
  395.     else {
  396.       %Index = 1
  397.       while ($sock(_WebSocket_ $+ $1, %Index)) {
  398.         %Sock = $v1
  399.         if (f isincs %Switches || $hget(%Sock, SOCK_STATE) isnum 1-3) {
  400.           _WebSocket.Cleanup %Sock
  401.           continue
  402.         }
  403.         elseif ($hget(%Sock, SOCK_STATE) == 4 && !$hget(%Sock, CLOSE_PENDING)) {
  404.           WebSockWrite -c $gettok(%Sock, 2-, 95) &_WebSocket_SendCloseMsg
  405.         }
  406.         inc %Index
  407.       }
  408.     }
  409.   }
  410.   :error
  411.   if ($error || %Error) {
  412.     echo $color(info) -sg * /WebSockClose: $v1
  413.     reseterror
  414.     halt
  415.   }
  416. }
  417.  
  418. alias WebSockDebug {
  419.   if ($isid) {
  420.     return $iif($group(#_WebSocket_Debug) == on, $true, $false)
  421.   }
  422.   if ($1 == on || $1 == enable) {
  423.     .enable #_WebSocket_Debug
  424.   }
  425.   elseif ($1 == off || $1 == disable) {
  426.     .disable #_WebSocket_Debug
  427.   }
  428.   elseif (!$0) {
  429.     $iif($group(#_WebSocket_Debug) == on, .disable, .enable) #_WebSocket_Debug
  430.   }
  431.   else {
  432.     echo -gs * /WebSockDebug: Invalid input
  433.     halt
  434.   }
  435.   if ($group(#_WebSocket_Debug) == on && !$window(@WebSocketDebug)) {
  436.     window -nzk0 @WebSocketDebug
  437.   }
  438. }
  439. alias WebSockList {
  440.   var %Index = 1, %Count = $sock(_WebSocket_?*, 0)
  441.   if (!%Count) {
  442.     echo $color(info).dd -age * No open WebSockets
  443.   }
  444.   else {
  445.     echo $color(info).dd -ag -
  446.     echo $color(info).dd -ag * Open WebSockets:
  447.     while (%Index <= %Count) {
  448.       echo -ag * $gettok($sock(_WebSocket_?*, %Index), 2-, 95)
  449.       inc %Index
  450.     }
  451.     echo $color(info).dd -ag -
  452.   }
  453. }
  454. alias WebSock {
  455.   if (!$isid) {
  456.     return
  457.   }
  458.   var %Name, %Sock, %State, %Find, %Index, %Header
  459.   if (!$0) {
  460.     if ($event !== signal || !$regex(NameFromSignal, $signal, /^WebSocket_[a-zA-Z]+_(?!\d+$)([^?*-][^?*]*)$/i)) {
  461.       return
  462.     }
  463.     %Name = $regml(NameFromSignal, 1)
  464.   }
  465.   elseif ($1 == 0) {
  466.     return $iif(!$len($prop), $sock(_WebSocket_?*, 0))
  467.   }
  468.   elseif ($regex(Name, $1, /^(?!\d+$)([^?*-][^?*]*)$/)) {
  469.     %Name = $regml(Name, 1)
  470.   }
  471.   elseif ($0 == 2 && $2 isnum 0- && . !isin $2 && (? isin $1 || * isin $1)) {
  472.     if ($2 == 0) {
  473.       return $sock(_WebSocket_ $+ $1, 0)
  474.     }
  475.     elseif ($sock(_WebSocket_ $+ $1, $2)) {
  476.       %Name = $gettok($v1, 2-, 95)
  477.     }
  478.     else {
  479.       return
  480.     }
  481.   }
  482.   else {
  483.     return
  484.   }
  485.   %Sock = _WebSocket_ $+ %Name
  486.   if (!$sock(%Sock) && !$hget(%sock)) {
  487.     return
  488.   }
  489.   if (!$prop) {
  490.     return %Name
  491.   }
  492.   elseif ($prop == State) {
  493.     return $hget(%Sock, SOCK_STATE)
  494.   }
  495.   elseif ($prop == StateText) {
  496.     %State = $hget(%Sock, SOCK_STATE)
  497.     if (!$len(%State)) {
  498.       return
  499.     }
  500.     elseif (%State == 0) {
  501.       return CLOSING
  502.     }
  503.     elseif (%State == 1) {
  504.       return INITIALIZED
  505.     }
  506.     elseif (%State == 2) {
  507.       return REQUESTING
  508.     }
  509.     elseif (%State == 3) {
  510.       return RESPONSE_PENDING
  511.     }
  512.     elseif (%State == 4) {
  513.       return READY
  514.     }
  515.     elseif (%State == 5) {
  516.       return CLOSING
  517.     }
  518.   }
  519.   elseif ($prop == Ssl) {
  520.     return $iif($sock(%Sock), $sock(%sock).ssl, $hget(%Sock, SOCK_SSL))
  521.   }
  522.   elseif ($prop == Host) {
  523.     return $iif($sock(%Sock).addr, $v1, $hget(%Sock, SOCK_ADDR))
  524.   }
  525.   elseif ($prop == Port) {
  526.     return $iif($sock(%Sock).port, $v1, $hget(%Sock, SOCK_PORT))
  527.   }
  528.   elseif ($prop == Uri) {
  529.     return $hget(%Sock, HTTPREQ_URI))
  530.   }
  531.   elseif ($prop == HttpVersion) {
  532.     return $hget(%Sock, HTTPRESP_HttpVersion)
  533.   }
  534.   elseif ($prop == StatusCode) {
  535.     return $hget(%Sock, HTTPRESP_StatusCode)
  536.   }
  537.   elseif ($prop == StatusText) {
  538.     return $hget(%Sock, HTTPRESP_StatusText)
  539.   }
  540.   elseif ($prop == HttpHeader) {
  541.     if (!$hget(%Sock) || $0 < 2 || !$len($2) || $0 > 3 || ($0 == 3 && (!$len($3) || $3 !isnum 0- || . isin $3))) {
  542.       return
  543.     }
  544.     elseif ($0 == 2 && . !isin $2) {
  545.       if (!$2) {
  546.         return $hfind(%Sock, /^HTTPRESP_HEADER\d+_/, 0, r)
  547.       }
  548.       return $gettok($hfind(%Sock, ^HTTPRESP_HEADER $+ $2 $+ _, 1, r), 3-, 95)
  549.     }
  550.     else {
  551.       %Index = $iif($0 == 3, $3, 1)
  552.       %Header = $hfind(%Sock, /^HTTPRESP_HEADER\d+_\Q $+ $replacecs($2, \E, \Q\\E\E) $+ \E$/, %Index, r)
  553.       if (!%Index) {
  554.         return %Header
  555.       }
  556.       return $hget(%Sock, %Header)
  557.     }
  558.   }
  559. }
  560.  
  561. alias WebSockFrame {
  562.   if (!$isid || $event !== signal || !$regex(event, $signal, /^WebSocket_(?:DATA|CLOSING)_(?!\d*$)([^?*-][^?*-]*)$/i) || $prop) {
  563.     return
  564.   }
  565.   var %Name = $regml(event, 1), %Sock = _WebSocket_ $+ %Name, %Result
  566.   bunset &_WebSocket_EventFrameData
  567.  
  568.   if (!$0 || $1- == text) {
  569.     if ($hget(%Sock, WSFRAME_DATA, &_WebSocket_EventFrameData)) {
  570.       %Result = $bvar(&_WebSocket_EventFrameData, 1, 3800).text
  571.       bunset &_WebSocket_EventFrameData
  572.       return %Result
  573.     }
  574.     return
  575.   }
  576.  
  577.   elseif (&?* iswm $1 && $0 == 1 && $chr(32) !isin $1) {
  578.     if ($hget(%Sock, WSFRAME_DATA, $1)) {
  579.       return $1
  580.     }
  581.     return $null
  582.   }
  583.  
  584.   elseif ($1- == Size) {
  585.     %Result = $hget(%Sock, WSFRAME_DATA, &_WebSocket_EventFrameData)
  586.     %Result = $bvar(&_WebSocket_EventFrameData, 0)
  587.     bunset &_WebSocket_EventFrameData
  588.     return %Result
  589.   }
  590.   elseif ($1- == Type) {
  591.     return $hget(%Sock, WSFRAME_TYPE)
  592.   }
  593.  
  594.   elseif ($1- == TypeText) {
  595.     %Result = $hget(%Sock, WSFRAME_TYPE)
  596.     if (%Result == 1) {
  597.       return TEXT
  598.     }
  599.     elseif (%Result == 2) {
  600.       return BINARY
  601.     }
  602.     elseif (%Result == 8) {
  603.       return CLOSE
  604.     }
  605.     elseif (%Result == 9) {
  606.       return PING
  607.     }
  608.     elseif (%Result == 10) {
  609.       return PONG
  610.     }
  611.     return UNKNOWN
  612.   }
  613. }
  614. alias WebSockSize {
  615.   return $WebSockFrame(size)
  616. }
  617. alias WebSockType {
  618.   return $WebSockFrame(Type)
  619. }
  620. alias WebSockTypeText {
  621.   return $WebSockFrame(TypeText)
  622. }
  623. alias WebSockText {
  624.   return $WebSockFrame(text)
  625. }
  626. alias WebSockData {
  627.   if (&* iswm $1) {
  628.     return $WebSockFrme($1)
  629.   }
  630. }
  631. alias WebSockErr {
  632.   if ($isid && $event == signal && $regex(event, $signal, /^WebSocket_ERROR_(?!\d*$)([^?*-][^?*-]*)$/i)) {
  633.     return $gettok($hget(_WebSocket_ $+ $regml(event, 1), Error), 1, 32)
  634.   }
  635. }
  636. alias WebSockErrMsg {
  637.   if ($isid && $event == signal && $regex(event, $signal, /^WebSocket_ERROR_(?!\d*$)([^?*-][^?*-]*)$/i)) {
  638.     return $gettok($hget(_WebSocket_ $+ $regml(event, 1), Error), 2-, 32)
  639.   }
  640. }
  641. alias -l _WebSocket.ConnectTimeout {
  642.   if ($isid) {
  643.     return
  644.   }
  645.   _WebSocket.Debug -e $1 $+ >TIMEOUT Connection timed out
  646.   _WebSocket.RaiseError $1 SOCK_ERROR Connection timout
  647. }
  648. alias -l _WebSocket.Send {
  649.   bunset &_WebSocket_SendBuffer
  650.   var %Name = $gettok($1, 2-, 95), %Error, %Space, %Size
  651.   if (!$sock($1)) {
  652.     %Error = SOCK_ERROR Connection doesn't exist
  653.   }
  654.   elseif (!$hget($1) || !$len($hget($1, SOCK_STATE))) {
  655.     %Error = INTERNAL_ERROR State lost
  656.   }
  657.   elseif ($hget($1, SOCK_STATE) === 3) {
  658.     %Error = INTERNAL_ERROR State doesn't match data sending
  659.   }
  660.   elseif ($v1 === 2) {
  661.     if (!$hget($1, HTTPREQ_HEAD, &_WebSocket_SendBuffer) && !$sock($1).sq) {
  662.       _WebSocket.Debug -i2 %Name $+ >Head_Sent Finished sending request.
  663.       hadd -m $sockname SOCK_STATE 3
  664.       .signal -n WebSocket_REQSENT_ $+ %Name
  665.     }
  666.     elseif ($bvar(&_WebSocket_SendBuffer, 0) && $sock($1).sq < 16384) {
  667.       %Space = $calc($v2 - $v1)
  668.       %Size = $bvar(&_WebSocket_SendBuffer, 0)
  669.       if (%Size <= %Space) {
  670.         sockwrite $1 &_WebSocket_SendBuffer
  671.         hdel $1 HTTPREQ_HEAD
  672.         _WebSocket.Debug -i %Name $+ >REQ_SEND~Entire head now added to send buffer
  673.       }
  674.       else {
  675.         sockwrite -b $1 %Space &_WebSocket_SendBuffer
  676.         bcopy -c &_WebSocket_SendBuffer 1 &_WebSocket_SendBuffer $calc(%Space +1) -1
  677.         hadd -mb $1 HTTPREQ_HEAD &_WebSocket_SendBuffer
  678.         _WebSocket.Debug -i %Name $+ >REQ_SEND~Added %Space bytes of the head to the send buffer
  679.       }
  680.     }
  681.   }
  682.   elseif ($hget($1, WSFRAME_Buffer, &_WebSocket_SendBuffer) && $sock($1).sq < 16384) {
  683.     %Space = $calc($v2 - $v1)
  684.     %Size = $bvar(&_WebSocket_SendBuffer, 0)
  685.     if (%Size > %Space) {
  686.       sockwrite -b $1 %Space &_WebSocket_SendBuffer
  687.       bcopy -c &_WebSocket_SendBuffer 1 &_WebSocket_SendBuffer $calc(%Space +1) -1
  688.       hadd -b $1 WSFRAME_Buffer &_WebSocket_SendBuffer
  689.       _WebSocket.Debug -i %Name $+ >FRAME_SEND~Added %Space bytes of frame data to send buffer
  690.     }
  691.     else {
  692.       sockwrite $1 &_WebSocket_SendBuffer
  693.       hdel $1 WSFRAME_Buffer
  694.       _WebSocket.Debug -i %Name $+ >FRAME_SEND~All pending frame data now in send buffer
  695.     }
  696.   }
  697.   :error
  698.   if ($error || %Error) {
  699.     %Error = $v1
  700.     reseterror
  701.     _WebSocket.Debug -e %Name $+ >FRAME_SEND~ $+ %Error
  702.     _WebSocket.RaiseError %Name %Error
  703.   }
  704. }
  705. alias -l _WebSocket.Cleanup {
  706.   var %Name = $gettok($1, 2-, 95)
  707.   if ($sock($1)) {
  708.     sockclose $1
  709.   }
  710.   if ($hget($1)) {
  711.     hfree $1
  712.   }
  713.   .timer_WebSocket_Timeout_ $+ %Name off
  714.   if ($show) {
  715.     .signal -n WebSocket_FINISHED_ $+ %Name
  716.   }
  717. }
  718. alias -l _WebSocket.BAdd {
  719.   bset -t $1 $calc($bvar($1, 0) + 1) $2- $+ $crlf
  720. }
  721. alias -l _WebSocket.RaiseError {
  722.   hadd -m $+(_WebSocket_, $1) ERROR $2-
  723.   .signal -n WebSocket_ERROR_ $+ $1
  724.   _WebSocket.Cleanup _WebSocket_ $+ $1
  725. }
  726. #_WebSocket_Debug off
  727. alias -l _WebSocket.Debug {
  728.   if (!$window(@WebSocketDebug)) {
  729.     .disable #_WebSocket_Debug
  730.   }
  731.   else {
  732.     var %Color = 12, %Title = WebSocket, %Msg
  733.     if (-* iswm $1) {
  734.       if ($1 == -e)  %Color = 04
  735.       if ($1 == -w)  %Color = 07
  736.       if ($1 == -i)  %Color = 03
  737.       if ($1 == -i2) %Color = 10
  738.       if ($1 == -s)  %Color = 12
  739.       tokenize 32 $2-
  740.     }
  741.     if (~ !isincs $1-) {
  742.       %Msg = $1-
  743.     }
  744.     elseif (~* iswm $1-) {
  745.       %Msg = $mid($1-, 2-)
  746.     }
  747.     else {
  748.       %Title = $gettok($1-, 1, 126)
  749.       %Msg = $gettok($1-, 2-, 126)
  750.     }
  751.     aline @WebSocketDebug $+($chr(3), %Color, [, %Title, ], $chr(15)) %msg
  752.   }
  753. }
  754. #_WebSocket_Debug end
  755. alias -l _WebSocket.Debug
  756. menu @WebSocketDebug {
  757.   $iif($WebSockDebug, Disable, Enable): WebSocketDebug
  758.   -
  759.   Clear:clear @WebSocketDebug
  760.   -
  761.   Close: .disable #_WebSocket_Debug | close -@ @WebSocketDebug
  762. }
  763. on *:CLOSE:@WebSocketDebug:{
  764.   .disable #_WebSocket_Debug
  765. }
  766. on *:START:{
  767.   if ($WebSockDebug) {
  768.     window -nzk0 @WebSocketDebug
  769.   }
  770. }
  771. on *:UNLOAD:{
  772.   sockclose _WebSocket_*
  773.   hfree -w _WebSocket_
  774.   .timer_WebSocket_Timeout_* off
  775.   if ($Window(@WebSocketDebug)) {
  776.     close -@ @WebSocketDebug
  777.   }
  778. }
  779. on $*:SOCKCLOSE:/^_WebSocket_(?!\d+$)[^-?*][^?*]*$/:{
  780.   var %Error, %Name = $gettok($sockname, 2-, 95)
  781.   if ($sockerr) {
  782.     %Error = SOCK_ERROR $sock($sockname).wsmsg
  783.   }
  784.   elseif (!$hget($sockname)) {
  785.     %Error = INTERNAL_ERROR state lost (hashtable does not exist)
  786.   }
  787.   elseif ($hget($sockname, SOCK_STATE) !== 5) {
  788.     %Error = SOCK_ERROR Connection closed without recieving a CLOSE frame: $hget($sockname, SOCK_STATE)
  789.   }
  790.   :error
  791.   %Error = $iif($error, MIRC_ERROR $v1, %Error)
  792.   if (%Error) {
  793.     reseterror
  794.     _WebSocket.Debug -e %Name $+ >SOCKCLOSE~ $+ %Error
  795.     _WebSocket.RaiseError %Name %Error
  796.   }
  797.   else {
  798.     _WebSocket.Debug -s %Name $+ >SOCKCLOSE~Connection Closed
  799.     .signal -n WebSocket_CLOSE_ $+ %Name
  800.   }
  801.   _WebSocket.Cleanup $sockname
  802. }
  803. on $*:SOCKOPEN:/^_WebSocket_(?!\d+$)[^-?*][^?*]*$/:{
  804.   var %Error, %Name = $gettok($sockname, 2-, 95), %Key, %Index
  805.   _WebSocket.Debug -i2 SockOpen> $+ $sockname $+ ~Connection established
  806.   if ($sockerr) {
  807.     %Error = SOCKOPEN_ERROR $sock($socknamw).wsmsg
  808.   }
  809.   elseif (!$hget($sockname)) {
  810.     %Error = INTERNAL_ERROR socket-state hashtable doesn't exist
  811.   }
  812.   elseif ($hget($sockname, SOCK_STATE) != 1) {
  813.     %Error = INTERNAL_ERROR State doesn't corrospond with connection attempt
  814.   }
  815.   elseif (!$len($hget($sockname, HTTPREQ_HOST))) {
  816.     %Error = INTERNAL_ERROR State table does not contain host name
  817.   }
  818.   elseif (!$len($hget($Sockname, HTTPREQ_RES))) {
  819.     %Error = INTERNAL_ERROR State table does not contain a resource to request
  820.   }
  821.   else {
  822.     _WebSocket.Debug -i SockOpen> $+ %name $+ ~Preparing request head
  823.     bset &_WebSocket_SecWebSocketKey 1 $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255) $r(0,255)
  824.     noop $encode(&_WebSocket_SecWebSocketKey, bm)
  825.     hadd -mb $sockname HTTPREQ_SecWebSocketKey &_WebSocket_SecWebSocketKey
  826.     bunset &_WebSocket_SecWebSocketKey &_WebSocket_HttpReq
  827.     _WebSocket.BAdd &_WebSocket_HttpReq GET $hget($sockname, HTTPREQ_RES) HTTP/1.1
  828.     _WebSocket.BAdd &_WebSocket_HttpReq Host: $hget($sockname, HTTPREQ_HOST)
  829.     _WebSocket.BAdd &_WebSocket_HttpReq Connection: upgrade
  830.     _WebSocket.BAdd &_WebSocket_HttpReq Upgrade: websocket
  831.     _WebSocket.BAdd &_WebSocket_HttpReq Sec-WebSocket-Version: 13
  832.     _WebSocket.BAdd &_WebSocket_HttpReq Sec-WebSocket-Key: $hget($sockname, HTTPREQ_SecWebSocketKey)
  833.     .signal -n WebSocket_INIT_ $+ %Name
  834.     %Index = 1
  835.     while ($hfind($sockname, /^HTTPREQ_HEADER\d+_([^\s]+)$/, %Index, r)) {
  836.       _WebSocket.BAdd &_WebSocket_HttpReq $regml(1) $+ : $hget($sockname, $v1)
  837.       inc %Index
  838.     }
  839.     _WebSocket.BAdd &_WebSocket_HttpReq
  840.     hadd -b $sockname HTTPREQ_HEAD &_WebSocket_HttpReq
  841.     bunset &_WebSocket_HttpReq
  842.     hadd $sockname SOCK_STATE 2
  843.     _WebSocket.Debug -i SockOpen> $+ %Name $+ ~Sending HTTP request
  844.     _WebSocket.Send $sockname
  845.   }
  846.   :error
  847.   %Error = $iif($error, MIRC_ERROR $v1, %Error)
  848.   if (%Error) {
  849.     %Error = $v1
  850.     reseterror
  851.     _WebSocket.Debug -e SockOpen> $+ %Name $+ ~ $+ %Error
  852.     _WebSocket.RaiseError %Name %Error
  853.   }
  854. }
  855. on $*:SOCKREAD:/^_WebSocket_(?!\d+$)[^-?*][^?*]*$/:{
  856.   var %Error, %Name = $gettok($sockname, 2-, 95), %HeadData, %Index, %SecAccept, %HeadSize, %Header, %IsFinal, %RSVBits, %IsControl, %FrameType, %DataSize
  857.   _WebSocket.debug -i2 %Name $+ >SOCKREAD~Sockname: $Sockname -- SockErr: $sockerr -- RecvQueue: $sock($sockname).rq  -- State: $hget($sockname, SOCK_STATE) -- Closing: $hget($sockname, CLOSE_PENDING)
  858.   if ($sockerr) {
  859.     %Error = SOCKREAD_ERROR $sock($sockname).wsmsg
  860.   }
  861.   elseif (!$hget($sockname)) {
  862.     %Error = INTERNAL_ERROR State lost
  863.   }
  864.   elseif ($hget($sockname, SOCK_STATE) == 5) {
  865.     %Error = FRAME_ERROR Frame recieved after a CLOSE frame has been recieved.
  866.   }
  867.   elseif ($hget($sockname, SOCK_STATE) == 3) {
  868.     if (!$hget($sockname, HTTPREQ_SecWebSocketKey)) {
  869.       %Error = INTERNAL_ERROR State lost (Sec-WebSocket-Key Not Found)
  870.     }
  871.     else {
  872.       sockread %HeadData
  873.       while ($sockbr) {
  874.         %HeadData = $regsubex(%HeadData, /(?:^\s+)|(?:\s+$)/g, )
  875.         if (%HeadData) {
  876.           if (!$len($hget($sockname, HTTPRESP_StatusCode))) {
  877.             if ($regex(%HeadData, /^HTTP\/(0\.9|1\.[01]) (\d+)((?:\s.*)?)[\r\n]*$/i)) {
  878.               hadd $sockname HTTPRESP_HttpVersion $regml(1)
  879.               hadd $sockname HTTPRESP_StatusCode $regml(2)
  880.               hadd $sockname HTTPRESP_StatusText $iif($regml(3), $v1, _NONE_)
  881.             }
  882.             else {
  883.               %Error = HTTP_ERROR Status line invalid: %HeadData
  884.             }
  885.           }
  886.           elseif ($regex(header, %HeadData, ^(\S+): (.*)$)) {
  887.             %Index = $calc($hfind($sockname, HTTPRESP_HEADER?*_*, 0, w) + 1)
  888.             hadd $sockname $+(HTTPRESP_HEADER, %Index, _, $regml(header, 1)) $regml(header, 2)
  889.             _WebSocket.Debug -i %Name $+ >HEADER~Header Received: $regml(header, 1) $+ : $regml(header, 2)
  890.           }
  891.           else {
  892.             %Error = HTTP_ERROR Response contained an invalid header
  893.           }
  894.         }
  895.         elseif ($hget($sockname, HTTPRESP_HttpVersion) !== 1.1) {
  896.           %Error = HTTP_ERROR Unacceptable HTTP version: $v1
  897.         }
  898.         elseif ($hget($sockname, HTTPRESP_StatusCode) !== 101) {
  899.           %Error = HTTP_ERROR Response does not wish to upgrade
  900.         }
  901.         elseif ($hfind($sockname, HTTPRESP_Header?*_Connection, 1, w) == $null || $hget($sockname, $v1) !== Upgrade) {
  902.           %Error = HTTP_ERROR Connection header not received or not "Upgrade"
  903.         }
  904.         elseif ($hfind($sockname, HTTPRESP_Header?*_Upgrade, 1, w) == $null || $hget($sockname, $v1) !== websocket) {
  905.           %Error = HTTP_ERROR Upgrade header not received or not "websocket"
  906.         }
  907.         elseif ($hfind($sockname, HTTPRESP_Header?*_Sec-WebSocket-Accept, 1, w) == $null) {
  908.           %Error = HTTP_ERROR Sec-WebSocket-Accept header not received
  909.         }
  910.         else {
  911.           %SecAccept = $hget($sockname, $v1)
  912.           bset -c &_WebSocket_SecWebSockAccept 1 $regsubex($sha1($hget($sockname, HTTPREQ_SecWebSocketKey) $+ 258EAFA5-E914-47DA-95CA-C5AB0DC85B11), /(..)/g, $base(\t, 16, 10) $+ $chr(32))
  913.           noop $encode(&_WebSocket_SecWebSockAccept, mb)
  914.           if (%SecAccept !== $bvar(&_WebSocket_SecWebSockAccept, 1-).text) {
  915.             %Error = HTTP_ERROR Sec-WebSocket-Accept header value does not match digested key
  916.           }
  917.           else {
  918.             $+(.timer, _WebSocket_Timeout_, %Name) off
  919.             hadd $sockname SOCK_STATE 4
  920.             _WebSocket.Debug -s %Name $+ >HANDSHAKE~Handshake complete; ready to send and recieve frames!
  921.             .signal -n WebSocket_READY_ $+ %Name
  922.           }
  923.         }
  924.         if (%Error || $hget($sockname, SOCK_STATE) == 4) {
  925.           break
  926.         }
  927.         sockread %HeadData
  928.       }
  929.     }
  930.   }
  931.   elseif ($hget($sockname, SOCK_STATE) == 4) {
  932.     bunset &_WebSocket_ReadBuffer &_WebSocket_RecvData
  933.     sockread $sock($sockname).rq &_WebSocket_RecvData
  934.     if ($hget($sockname, WSFRAME_PENDING, &_WebSocket_ReadBuffer)) {
  935.       bcopy -c &_WebSocket_ReadBuffer $calc($bvar(&_WebSocket_ReadBuffer, 0) + 1) &_WebSocket_RecvData 1 -1
  936.     }
  937.     else {
  938.       bcopy -c &_WebSocket_ReadBuffer 1 &_WebSocket_RecvData 1 -1
  939.     }
  940.     bunset &_WebSocket_RecvData
  941.     while ($bvar(&_WebSocket_ReadBuffer, 0) >= 2) {
  942.       hdel $sockname WSFRAME_DATA
  943.       hdel $sockname WSFRAME_TYPE
  944.       bunset &_WebSocket_FrameData
  945.       %HeadSize  = 2
  946.       %Header    = $bvar(&_WebSocket_ReadBuffer, 1, 1)
  947.       %IsFinal   = $isbit(%Header, 8)
  948.       %RSVBits   = $calc($isbit(%Header, 7) *4 + $isbit(%Header, 6) *2 + $isbit(%Header, 5))
  949.       %IsControl = $isbit(%header, 4)
  950.       %FrameType = $calc(%Header % 128 % 64 % 32 % 16)
  951.       %DataSize  = $bvar(&_WebSocket_ReadBuffer, 2, 1)
  952.       if (%RSVBits) {
  953.         %Error = FRAME_ERROR Extension reserved bits used without extension negociation
  954.       }
  955.       elseif (%IsControl && !%IsFinal) {
  956.         %Error = FRAME_ERROR Fragmented control frame received
  957.       }
  958.       elseif (%IsControl && %FrameType !isnum 8-10) {
  959.         %Error = FRAME_ERROR Unkown CONTROL frame received( $+ %FrameType $+ )
  960.       }
  961.       elseif (!%IsControl && %FrameType !isnum 0-2) {
  962.         %Error = FRAME_ERROR Unkown DATA frame received( %FrameType )
  963.       }
  964.       elseif ($isbit(%DataSize, 8)) {
  965.         %Error = FRAME_ERROR Masked frame received
  966.       }
  967.       elseif (%IsControl && %DataSize > 125) {
  968.         %Error = FRAME_ERROR Control frame received larger than 127 bytes
  969.       }
  970.       elseif (!%IsControl && $hget($sockname, WSFRAME_FRAGMSG) && %FrameType !== 0) {
  971.         %Error = FRAME_ERROR Frame-Type specified with subsequent frame fragment
  972.       }
  973.       elseif (!$hget($sockname, WSFRAME_FRAGMSG) && %FrameType == 0) {
  974.         %Error = FRAME_ERROR Continuation frame received with no preceeding fragmented frame
  975.       }
  976.       else {
  977.         if (%DataSize == 126) {
  978.           if ($bvar(&_WebSocket_ReadBuffer, 0) < 4) {
  979.             break
  980.           }
  981.           elseif ($bvar(&_WebSocket_ReadBuffer, 3).nword < 126) {
  982.             %Error = FRAME_ERROR Excessive payload size integer recieved from server
  983.             break
  984.           }
  985.           %DataSize = $v1
  986.           %HeadSize = 4
  987.         }
  988.         elseif (%DataSize == 127) {
  989.           if ($bvar(&_WebSocket_ReadBuffer, 0) < 10) {
  990.             break
  991.           }
  992.           elseif ($bvar(&bvar_WebSocket_ReadBuffer, 7).nlong < 4294967296) {
  993.             %Error = FRAME_ERROR Excessive payload size integer recieved from server
  994.             break
  995.           }
  996.           elseif ($bvar(&_WebSocket_ReadBuffer, 3).nlong) {
  997.             %Error = FRAME_ERROR Frame would exceed a 4gb limit
  998.             break
  999.           }
  1000.           %DataSize = $bvar(&_WebSocket_ReadBuffer, 7).nlong
  1001.           %HeadSize = 10
  1002.         }
  1003.         if ($calc(%HeadSize + %DataSize) > $bvar(&_WebSocket_ReadBuffer, 0)) {
  1004.           break
  1005.         }
  1006.         if (%FrameType === 0 && $hget($sockname, WSFRAME_FRAGMSG)) {
  1007.           %FrameType = $hget($sockname, WSFRAME_FRAGMSG_Type)
  1008.           noop $hget($sockname, WSFRAME_FRAGMSG, &_WebSocket_FrameData)
  1009.           hdel $sockname WSFRAME_FRAGMSG_Type
  1010.           hdel $sockname WSFRAME_FRAGMSG_Data
  1011.           hdel $sockname WSFRAME_FRAGMSG
  1012.         }
  1013.         if (%DataSize) {
  1014.           bcopy -c &_WebSocket_FrameData $calc($bvar(&_WebSocket_FrameData,0) + 1) &_WebSocket_ReadBuffer $calc(%HeadSize + 1) %Datasize
  1015.         }
  1016.         if ($calc(%HeadSize + %DataSize) == $bvar(&_WebSocket_ReadBuffer, 0)) {
  1017.           bunset &_WebSocket_ReadBuffer
  1018.         }
  1019.         else {
  1020.           bcopy -c &_WebSocket_ReadBuffer 1 &_WebSocket_ReadBuffer $calc(%HeadSize + %DataSize + 1) -1
  1021.         }
  1022.         if (!%IsFinal) {
  1023.           hadd $sockname WSFRAME_FRAGMSG $true
  1024.           hadd $sockname WSFRAME_FRAGMSG_Type %FrameType
  1025.           hadd -b $sockname WSFRAME_FRAGMSG_Data &_WebSocket_FrameData
  1026.         }
  1027.         else {
  1028.           hadd $sockname WSFRAME_TYPE %FrameType
  1029.           if ($bvar(&_WebSocket_FrameData, 0)) {
  1030.             hadd -b $sockname WSFRAME_DATA &_WebSocket_FrameData
  1031.           }
  1032.           else {
  1033.             hdel $sockname WSFRAME_DATA
  1034.           }
  1035.           if (%FrameType isnum 1-2) {
  1036.             _WebSocket.Debug -i %Name $+ >FRAME_RECV~ $+ $iif(%FrameType == 1, TEXT, BINARY) frame recieved
  1037.             .signal -n WebSocket_DATA_ $+ %Name
  1038.           }
  1039.           elseif (%FrameType == 9) {
  1040.             _WebSocket.Debug -i %Name $+ >FRAME_RECV~PING frame recieved
  1041.             WebSockWrite -P %Name &_WebSocket_FrameData
  1042.             .signal -n WebSocket_DATA_ $+ %Name
  1043.           }
  1044.           elseif (%FrameType == 10) {
  1045.             _WebSocket.Debug -i %Name $+ >FRAME_RECV~PONG frame recieved
  1046.             .signal -n WebSocket_DATA_ $+ %Name
  1047.           }
  1048.           elseif ($bvar(&_WebSocket_ReadBuffer, 0)) {
  1049.             %Error = FRAME_ERROR Data recieved after a CLOSE frame has been recieved.
  1050.             break
  1051.           }
  1052.           elseif (!$hget($sockname, CLOSE_PENDING)) {
  1053.             _WebSocket.Debug -i %Name $+ >FRAME_RECV~CLOSE frame received.
  1054.             hadd $sockname SOCK_STATE 5
  1055.             .signal -n WebSocket_CLOSING_ $+ %Name %Name
  1056.           }
  1057.           else {
  1058.             _WebSocket.Debug -i2 %Name $+ >FRAME_RECV~CLOSE frame reply received; closing connection.
  1059.             .signal -n WebSocket_CLOSE_ $+ %Name
  1060.             _WebSocket.Cleanup $sockname
  1061.             return
  1062.           }
  1063.         }
  1064.       }
  1065.     }
  1066.     if (!%Error) {
  1067.       if ($bvar(&_WebSocket_ReadBuffer, 0)) {
  1068.         hadd -b $sockname WSFRAME_PENDING &_WebSocket_ReadBuffer
  1069.       }
  1070.       elseif ($hget($sockname, WSFRAME_PENDING).item) {
  1071.         hdel $sockname WSFRAME_PENDING
  1072.       }
  1073.     }
  1074.   }
  1075.   elseif ($v1 !== 0) {
  1076.     %Error = INTERNAL_ERROR State variable mixmatch
  1077.   }
  1078.   :error
  1079.   %Error = $iif($error, MIRC_ERROR $v1, %Error)
  1080.   if (%Error) {
  1081.     reseterror
  1082.     _WebSocket.Debug -e SockRead> $+ %Name $+ ~ $+ %Error
  1083.     _WebSocket.RaiseError %Name %Error
  1084.   }
  1085. }
  1086. on $*:SOCKWRITE:/^_WebSocket_(?!\d+$)[^-?*][^?*]*$/:{
  1087.   var %Error, %Name = $gettok($sockname, 2-, 95), %State = $hget($sockname, SOCK_STATE)
  1088.   if ($sockerr) {
  1089.     %Error = SOCK_ERROR Failed to write to connection
  1090.   }
  1091.   elseif (!$hget($sockname) || !$len(%State)) {
  1092.     %Error = INTERNAL_ERROR State lost
  1093.   }
  1094.   elseif (%State !isnum 2-5 && %State !== 3) {
  1095.     %Error = INTERNAL_ERROR State doesn't corrospond with data-send attempt: %State
  1096.   }
  1097.   else {
  1098.     _WebSocket.Send $sockname
  1099.   }
  1100.   :error
  1101.   %Error = $iif($error, MIRC_ERROR $v1, %Error)
  1102.   if (%Error) {
  1103.     reseterror
  1104.     _WebSocket.debug -e %Name $+ >SOCKWRITE~ $+ %Error
  1105.     _WebSocket.RaiseError %Name %Error
  1106.   }
  1107. }
  1108. alias mWebSockVer {
  1109.   return 10000.0001
  1110. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement