Advertisement
Guest User

Untitled

a guest
Nov 30th, 2012
197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.31 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //                                                                            //
  3. //  @title    Torque Webserver                                                //
  4. //  @author   Truce                                                           //
  5. //  @version  3.0 - Era of the WebSocket                                      //
  6. //                                                                            //
  7. //  Dynamically writes pages created by the user by parsing raw Torquescript  //
  8. //  located between the <?tqs and ?> tags and supports standard web protocol  //
  9. //                                                                            //
  10. ////////////////////////////////////////////////////////////////////////////////
  11.  
  12. if(!isObject(Webserver))
  13. {
  14.     new ScriptGroup(WebSockets);
  15.     new TCPObject(Webserver)
  16.     {
  17.         port      = 80;
  18.         debug     = false;
  19.         localOnly = false;
  20.         blockIPs  = "78.69.143.58";
  21.         timeout   = 1000;
  22.         accounts  = "config/accounts.dat";
  23.         folder    = "config/pages";
  24.         index     = "/index.tqs";
  25.         tagPrefix = "<?tqs ";
  26.         tagSuffix = " ?>";
  27.     };
  28.    
  29.     Webserver.listen(Webserver.port);
  30.    
  31.     WebSockets.server = Webserver.getID();
  32.     Webserver.sockets = WebSockets.getID();
  33. }
  34.  
  35. ////////////////////////////////////////
  36. //  Webserver Methods                 //
  37. ////////////////////////////////////////
  38.  
  39. function Webserver::debug(%this,%line)
  40. {
  41.     if(%this.debug)
  42.         echo("[Webserver] " @ %line);
  43. }
  44.  
  45. function Webserver::onConnectRequest(%this,%address,%id)
  46. {
  47.     %address       = getWord(strReplace(%address,":"," "),1);
  48.     %client        = new TCPObject(Webclient,%id).getID();
  49.     %client.ip     = %address;
  50.     %client.server = %this;
  51.    
  52.     %this.debug("Connect request from IP " @ %address @ " (" @ %client @ ")");
  53.    
  54.     if(%this.localOnly && !isLANAddress(%address))
  55.     {
  56.         %this.debug("> Client is not local and will be disconnected.");
  57.         %client.disconnectClean();
  58.        
  59.         return;
  60.     }
  61.    
  62.     %blockIPs = %this.blockIPs;
  63.     %count    = getWordCount(%blockIPs);
  64.    
  65.     for(%i = 0; %i < %count; %i++)
  66.     {
  67.         %blockIP = getWord(%blockIPs,%i);
  68.        
  69.         if(strPos(%address,%blockIP) == 0)
  70.         {
  71.             %this.debug("> Client is on blacklist and will be disconnected.");
  72.             %client.disconnectClean();
  73.            
  74.             return;
  75.         }
  76.     }
  77.    
  78.     %timeout        = %this.timeout;
  79.     %client.timeout = %client.schedule(%timeout,timeout);
  80.    
  81.     %this.debug("> Client timeout in " @ %timeout @ " milliseconds.");
  82. }
  83.  
  84. function Webclient::timeout(%this)
  85. {
  86.     %this.server.debug("Client " @ %this @ " timed out after some time.");
  87.     %this.disconnectClean();
  88. }
  89.  
  90. function Webclient::onLine(%this,%line)
  91. {
  92.     cancel(%this.timeout);
  93.    
  94.     %server       = %this.server;
  95.     %this.timeout = %this.schedule(%server.timeout,finish);
  96.     %this.packet  = %this.packet @ %line @ "\n";
  97.     %length       = %this._SERVER["HTTP_CONTENT_LENGTH"];
  98.    
  99.     if(!%this.lineCount)
  100.     {
  101.         %this.command = getWord(%line,0);
  102.         %this.page    = getWord(%line,1);
  103.         %this.version = getWord(%line,2);
  104.     }
  105.     else if(%line $= "" && %length !$= "")
  106.     {
  107.         %this.binarySize = %length;
  108.         %this.setBinary(1);
  109.     }
  110.     else
  111.     {
  112.         %args  = strReplace(%line,": ","\t");
  113.         %name  = "HTTP_" @ strReplace(getField(%args,0),"-","_");
  114.         %value = getField(%args,1);
  115.        
  116.         %this._SERVER[%name] = %value;
  117.     }
  118.    
  119.     %this.lineCount++;
  120. }
  121.  
  122. function Webclient::onBinChunk(%this,%chunk)
  123. {
  124.     %server = %this.server;
  125.    
  126.     if(%this.websocket)
  127.     {
  128.         %server.debug(%chunk @ " bytes of WebSocket data received.");
  129.         %this.chunk = %chunk;
  130.        
  131.         %this.saveBufferToFile("config/temp_websocket");
  132.         %this.setBinarySize(1);
  133.         %this.decodeFrame();
  134.        
  135.         return;
  136.     }
  137.    
  138.     if(%chunk >= %this.binarySize)
  139.         %this.saveBufferToFile("config/temp");
  140.    
  141.     cancel(%this.timeout);
  142.     %this.timeout = %this.schedule(%server.timeout,finish);
  143. }
  144.  
  145. function Webclient::finish(%this)
  146. {
  147.     %server  = %this.server;
  148.     %packet  = %this.packet;
  149.     %request = getRecord(%packet,0);
  150.    
  151.     if(isFile("config/temp"))
  152.     {
  153.         %file = new FileObject();
  154.         %file.openForRead("config/temp");
  155.        
  156.         while(!%file.isEOF())
  157.             %packet = %packet @ %file.readLine() @ "\n";
  158.        
  159.         %file.close();
  160.         %file.delete();
  161.        
  162.         fileDelete("config/temp");
  163.     }
  164.    
  165.     %server.debug("Packet terminated from client " @ %this @ ".");
  166.    
  167.     %command = getWord(%request,0);
  168.     %page    = getWord(%request,1);
  169.     %version = getWord(%request,2);
  170.    
  171.     %server.debug("> First line is " @ %command SPC %page SPC %version);
  172.    
  173.     if(%version !$= "HTTP/1.1")
  174.     {
  175.         %server.debug("> Client using old HTTP and will be disconnected.");
  176.         %this.disconnectClean();
  177.        
  178.         return;
  179.     }
  180.    
  181.     deleteVariables("$_GET*");
  182.     deleteVariables("$_POST*");
  183.     deleteVariables("$_SERVER*");
  184.    
  185.     $_SERVER["REMOTE_ADDR"] = %this.ip;
  186.    
  187.     if((%pos = strPos(%page,"?")) != -1)
  188.     {
  189.         %args = getSubStr(%page,%pos + 1,strLen(%page));
  190.         %page = getSubStr(%page,0,%pos);
  191.        
  192.         %server.debug("Parsing client " @ %this @ "'s GET args: " @ %args);
  193.        
  194.         %args = strReplace(%args,"&","\t");
  195.         %num  = getFieldCount(%args);
  196.        
  197.         if(!%num)
  198.             %server.debug("> No GET args found to parse!");
  199.        
  200.         for(%i = 0; %i < %num; %i++)
  201.         {
  202.             %arg = getField(%args,%i);
  203.             %arg = strReplace(%arg,"=","\t");
  204.            
  205.             %name  = getField(%arg,0);
  206.             %value = getField(%arg,1);
  207.            
  208.             $_GET[%name] = %value;
  209.             %server.debug("> Assigning " @ %value @ " to " @ %name @ ".");
  210.         }
  211.     }
  212.    
  213.     %header = getRecords(%packet,1);
  214.     %count  = getRecordCount(%header);
  215.    
  216.     %server.debug("Parsing client " @ %this @ "'s header: " @ %header);
  217.    
  218.     for(%i = 0; %i < %count; %i++)
  219.     {
  220.         %record = getRecord(%header,%i);
  221.        
  222.         if(%record $= "")
  223.         {
  224.             %args = getRecord(%header,%i + 1);
  225.            
  226.             %server.debug("Parsing client " @ %this @ "'s POST args: " @ %args);
  227.            
  228.             %args = strReplace(%args,"&","\t");
  229.             %num  = getFieldCount(%args);
  230.            
  231.             if(!%num)
  232.                 %server.debug("> No POST args found to parse!");
  233.            
  234.             for(%i = 0; %i < %num; %i++)
  235.             {
  236.                 %arg = getField(%args,%i);
  237.                 %arg = strReplace(%arg,"=","\t");
  238.                
  239.                 %name  = getField(%arg,0);
  240.                 %value = getField(%arg,1);
  241.                
  242.                 $_POST[%name] = %value;
  243.                 %server.debug("> Assigning " @ %value @ " to " @ %name @ ".");
  244.             }
  245.            
  246.             break;
  247.         }
  248.        
  249.         %record = strReplace(%record,": ","\t");
  250.         %name   = "HTTP_" @ strReplace(getField(%record,0),"-","_");
  251.         %value  = getField(%record,1);
  252.        
  253.         $_SERVER[%name] = %value;
  254.         %server.debug("> Assigning " @ %value @ " to " @ %name @ ".");
  255.     }
  256.    
  257.     if($_SERVER["HTTP_UPGRADE"] $= "websocket")
  258.     {
  259.         %server.debug("Upgrading client connection to websocket.");
  260.        
  261.         if(%page !$= $WebSocketPassword)
  262.         {
  263.             %server.debug("> Client unauthorized and will be disconnected.");
  264.             %this.disconnectClean();
  265.            
  266.             return;
  267.         }
  268.        
  269.         %magic   = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  270.         %key_in  = $_SERVER["HTTP_SEC_WEBSOCKET_KEY"];
  271.         %key_out = convertWebkey(%key_in @ %magic);
  272.        
  273.         %server.debug("> Client provided the websocket key " @ %key_in);
  274.         %server.debug("> Server returned the websocket key " @ %key_out);
  275.        
  276.         %this.send("HTTP/1.1 101 Switching Protocols\r\n");
  277.         %this.send("Upgrade: websocket\r\n");
  278.         %this.send("Connection: Upgrade\r\n");
  279.         %this.send("Sec-WebSocket-Accept: " @ %key_out @ "\r\n");
  280.         %this.send("\r\n");
  281.        
  282.         %this.websocket = true;
  283.         %this.setBinary(1);
  284.        
  285.         WebSockets.add(%this);
  286.         return;
  287.     }
  288.    
  289.     if(%page $= "/")
  290.         %page = %server.index;
  291.    
  292.     %server.debug("Deploying file: " @ %page);
  293.    
  294.     if(fileExt(%server.folder @ %page) $= ".tqss")
  295.     {
  296.         if(!isFile(%server.accounts))
  297.         {
  298.             %server.debug("> Requested secured page, but no accounts file exists.");
  299.             %this.disconnectClean();
  300.            
  301.             return;
  302.         }
  303.        
  304.         if($_SERVER["HTTP_AUTHORIZATION"] $= "")
  305.         {
  306.             %server.debug("> Requested secured page, prompting for authentication.");
  307.            
  308.             %this.send("HTTP/1.1 401 Authorization Required\r\n");
  309.             %this.send("WWW-Authenticate: Basic realm=\"TQS Webserver\"\r\n");
  310.             %this.send("\r\n");
  311.            
  312.             %this.disconnectClean();
  313.             return;
  314.         }
  315.        
  316.         %auth = getWord($_SERVER["HTTP_AUTHORIZATION"],1);
  317.         %auth = base64Decode(%auth);
  318.        
  319.         %file = new FileObject();
  320.         %file.openForRead(%server.accounts);
  321.        
  322.         while(!%file.isEOF())
  323.         {
  324.             %line = %file.readLine();
  325.             %pos  = strPos(%line,"#");
  326.            
  327.             if(%pos != -1)
  328.                 %line = getSubStr(%line,0,%pos);
  329.            
  330.             %line = trim(%line);
  331.            
  332.             if(%line !$= "" && %line $= %auth)
  333.             {
  334.                 %authed = true;
  335.                 break;
  336.             }
  337.         }
  338.        
  339.         %file.close();
  340.         %file.delete();
  341.        
  342.         if(!%authed)
  343.         {
  344.             %server.debug("> Client provided invalid credentials, access denied.");
  345.            
  346.             %this.send("HTTP/1.1 401 Authorization Required\r\n");
  347.             %this.send("WWW-Authenticate: Basic realm=\"TQS Webserver\"\r\n");
  348.             %this.send("\r\n");
  349.            
  350.             %this.disconnectClean();
  351.             return;
  352.         }
  353.        
  354.         %server.debug("> Client provided proper credentials, access granted.");
  355.     }
  356.    
  357.     if(striPos(%page,"http://") != -1)
  358.     {
  359.         %server.debug("> Client tempting security and will be disconnected.");
  360.         %this.disconnectClean();
  361.        
  362.         return;
  363.     }
  364.    
  365.     if(isFile(%server.folder @ %page))
  366.     {
  367.         %server.debug("> File found! Including all its contents.");
  368.        
  369.         $Webkey = -1;
  370.         %body   = input(%page);
  371.        
  372.         %this.send("HTTP/1.1 200 OK\r\n");
  373.         %this.send("Content-Length: " @ strLen(%body) @ "\r\n");
  374.         %this.send("Content-Type: text/html; charset=UTF-8\r\n");
  375.         %this.send("Connection: close\r\n");
  376.         %this.send("\r\n");
  377.         %this.send(%body @ "\r\n");
  378.     }
  379.     else
  380.     {
  381.         %server.debug("> File not found! Deploying 404 instead.");
  382.        
  383.         %this.send("HTTP/1.1 404 Not Found\r\n");
  384.         %this.send("Connection: close\r\n");
  385.         %this.send("\r\n");
  386.     }
  387.    
  388.     %this.disconnectClean();
  389. }
  390.  
  391. function Webclient::disconnectClean(%this)
  392. {
  393.     %this.disconnect();
  394.     %this.schedule(0,delete);
  395.    
  396.     %this.server.debug("Client " @ %this @ " has been disconnected.");
  397. }
  398.  
  399. ////////////////////////////////////////
  400. //  Inline Scripting                  //
  401. ////////////////////////////////////////
  402.  
  403. function parse(%_body)
  404. {
  405.     %_pre  = Webserver.tagPrefix;
  406.     %_suf  = Webserver.tagSuffix;
  407.     %_pos  = striPos(%_body,%_pre);
  408.     %_rest = getSubStr(%_body,%_pos + strLen(%_pre),strLen(%_body));
  409.     %_body = getSubStr(%_body,0,%_pos);
  410.     %_pos  = striPos(%_rest,%_suf);
  411.     %_eval = getSubStr(%_rest,0,%_pos);
  412.     %_rest = getSubStr(%_rest,%_pos + strLen(%_suf),strLen(%_rest));
  413.    
  414.     $Webcache[$Webkey] = "";
  415.     eval(%_eval);
  416.    
  417.     return %_body @ $Webcache[$Webkey] @ %_rest;
  418. }
  419.  
  420. function input(%path)
  421. {
  422.     %path = Webserver.folder @ %path;
  423.    
  424.     if(!isFile(%path))
  425.         return;
  426.    
  427.     %file = new FileObject();
  428.     %file.openForRead(%path);
  429.    
  430.     while(!%file.isEOF())
  431.         %body = %body @ strReplace(%file.readLine(),"\t","    ") @ " \n ";
  432.    
  433.     %file.close();
  434.     %file.delete();
  435.    
  436.     %body = getSubStr(%body,0,strLen(%body) - 3);
  437.     %pre  = Webserver.tagPrefix;
  438.     $Webkey++;
  439.    
  440.     while(striPos(%body,%pre) != -1)
  441.         %body = parse(%body);
  442.    
  443.     $Webkey--;
  444.     return %body;
  445. }
  446.  
  447. function include(%path)
  448. {
  449.     print(input(%path));
  450. }
  451.  
  452. function print(%str)
  453. {
  454.     $Webcache[$Webkey] = $Webcache[$Webkey] @ %str;
  455. }
  456.  
  457. function puts(%str)
  458. {
  459.     print(%str @ "\n");
  460. }
  461.  
  462. ////////////////////////////////////////
  463. //  Basetype Conversion               //
  464. ////////////////////////////////////////
  465.  
  466. $Basetype[  2] = "01";
  467. $Basetype[ 10] = "0123456789";
  468. $Basetype[ 16] = "0123456789ABCDEF";
  469. $Basetype[ 64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  470. $Basetype[256] =     "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" @
  471.                  "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" @
  472.                  "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F" @
  473.                  "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F" @
  474.                  "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F" @
  475.                  "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F" @
  476.                  "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F" @
  477.                  "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F" @
  478.                  "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" @
  479.                  "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" @
  480.                  "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" @
  481.                  "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF" @
  482.                  "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF" @
  483.                  "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF" @
  484.                  "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF" @
  485.                  "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
  486.  
  487. function convertBase(%val,%atype,%btype)
  488. {
  489.     %vlen = strLen(%val);
  490.     %alen = strLen(%atype);
  491.     %blen = strLen(%btype);
  492.    
  493.     for(%i = 0; %i < %vlen; %i++)
  494.         %sum += striPos(%atype,getSubStr(%val,%i,1)) * mPow(%alen,%vlen - %i - 1);
  495.    
  496.     while(1)
  497.     {
  498.         %rem = %sum % %blen;
  499.         %new = getSubStr(%btype,%rem,1) @ %new;
  500.         %sum = mFloor(%sum / %blen);
  501.        
  502.         if(!%sum)
  503.             break;
  504.     }
  505.    
  506.     return %new;
  507. }
  508.  
  509. function base64Encode(%str)
  510. {
  511.     %len = strLen(%str);
  512.    
  513.     for(%i = 0; %i < %len; %i++)
  514.     {
  515.         %chr   = getSubStr(%str,%i,1);
  516.         %ascii = strPos($Basetype[256],%chr) + 32;
  517.         %bin   = convertBase(%ascii,$Basetype[10],$Basetype[2]);
  518.         %bin   = padBase(%bin,$Basetype[2],8);
  519.         %all   = %all @ %bin;
  520.     }
  521.    
  522.     %len = strLen(%all);
  523.    
  524.     for(%i = 0; %i < %len; %i += 6)
  525.     {
  526.         %pack = getSubStr(%all,%i,6);
  527.        
  528.         while(strLen(%pack) < 6)
  529.             %pack = %pack @ "0";
  530.        
  531.         %dec = convertBase(%pack,$Basetype[2],$Basetype[10]);
  532.         %new = %new @ getSubStr($Basetype[64],%dec,1);
  533.     }
  534.    
  535.     while(strLen(%new) % 4 > 0)
  536.         %new = %new @ "=";
  537.    
  538.     return %new;
  539. }
  540.  
  541. function base64Encode_Nulls(%str)
  542. {
  543.     %len = getWordCount(%str);
  544.    
  545.     for(%i = 0; %i < %len; %i++)
  546.     {
  547.         %dec = getWord(%str,%i);
  548.         %bin = convertBase(%dec,$Basetype[10],$Basetype[2]);
  549.         %bin = padBase(%bin,$Basetype[2],8);
  550.         %all = %all @ %bin;
  551.     }
  552.    
  553.     %len = strLen(%all);
  554.    
  555.     for(%i = 0; %i < %len; %i += 6)
  556.     {
  557.         %pack = getSubStr(%all,%i,6);
  558.        
  559.         while(strLen(%pack) < 6)
  560.             %pack = %pack @ "0";
  561.        
  562.         %dec = convertBase(%pack,$Basetype[2],$Basetype[10]);
  563.         %new = %new @ getSubStr($Basetype[64],%dec,1);
  564.     }
  565.    
  566.     while(strLen(%new) % 4 > 0)
  567.         %new = %new @ "=";
  568.    
  569.     return %new;
  570. }
  571.  
  572. function base64Decode(%str)
  573. {
  574.     while(getSubStr(%str,strLen(%str) - 1,1) $= "=")
  575.         %str = getSubStr(%str,0,strLen(%str) - 1);
  576.    
  577.     %len = strLen(%str);
  578.    
  579.     for(%i = 0; %i < %len; %i++)
  580.     {
  581.         %chr = getSubStr(%str,%i,1);
  582.         %pos = strPos($Basetype[64],%chr);
  583.         %bin = convertBase(%pos,$Basetype[10],$Basetype[2]);
  584.         %bin = padBase(%bin,$Basetype[2],6);
  585.         %all = %all @ %bin;
  586.     }
  587.    
  588.     while(strLen(%all) % 8 > 0)
  589.         %all = getSubStr(%all,0,strLen(%all) - 1);
  590.    
  591.     %len = strLen(%all);
  592.    
  593.     for(%i = 0; %i < %len; %i += 8)
  594.     {
  595.         %bin = getSubStr(%all,%i,8);
  596.         %dec = convertBase(%bin,$Basetype[2],$Basetype[10]) - 32;
  597.         %chr = getSubStr($Basetype[256],%dec,1);
  598.        
  599.         %new = %new @ %chr;
  600.     }
  601.    
  602.     return %new;
  603. }
  604.  
  605. function padBase(%val,%type,%len)
  606. {
  607.     while(strLen(%val) < %len)
  608.         %val = getSubStr(%type,0,1) @ %val;
  609.    
  610.     return %val;
  611. }
  612.  
  613. ////////////////////////////////////////
  614. //  WebSocket Methods                 //
  615. ////////////////////////////////////////
  616.  
  617. function Webclient::encodeFrame(%this,%opcode,%data)
  618. {
  619.     if(%data $= "")
  620.         %data = "\x01";
  621.    
  622.     %fin  = 1;
  623.     %rsv1 = 0;
  624.     %rsv2 = 0;
  625.     %rsv3 = 0;
  626.     %mask = 0;
  627.     %len  = strLen(%data);
  628.    
  629.     %opcode  = padBase(convertBase(%opcode,$Basetype[10],$Basetype[2]),$Basetype[2],4);
  630.     %length  = padBase(convertBase(%len,   $Basetype[10],$Basetype[2]),$Basetype[2],7);
  631.    
  632.     %byte[0] = %fin  @ %rsv1 @ %rsv2 @ %rsv3 @ %opcode;
  633.     %byte[1] = %mask @ %length;
  634.    
  635.     %byte[0] = getSubStr($Basetype[256],convertBase(%byte[0],$Basetype[2],$Basetype[10]) - 1,1);
  636.     %byte[1] = getSubStr($Basetype[256],convertBase(%byte[1],$Basetype[2],$Basetype[10]) - 1,1);
  637.    
  638.     for(%i = 0; %i < %len; %i++)
  639.         %frame = %frame @ getSubStr(%data,%i,1);
  640.    
  641.     %this.send(%byte[0] @ %byte[1] @ %frame);
  642. }
  643.  
  644. function Webclient::decodeFrame(%this)
  645. {
  646.     %server = %this.server;
  647.     %server.debug("Decoding the current WebSocket frame.");
  648.    
  649.     %file = new FileObject();
  650.     %file.openForRead("config/temp_websocket");
  651.    
  652.     %str = %file.readLine();
  653.     %len = strLen(%str);
  654.    
  655.     %file.delete();
  656.     fileDelete("config/temp_websocket");
  657.    
  658.     for(%i = 0; %i < %len; %i++)
  659.     {
  660.         %chr  = strPos($Basetype[256],getSubStr(%str,%i,1)) + 1;
  661.         %bits = convertBase(%chr,$Basetype[10],$Basetype[2]);
  662.         %pad  = padBase(%bits,$Basetype[2],8);
  663.        
  664.         %byte[%i] = %pad;
  665.     }
  666.    
  667.     %fin    = getSubStr(%byte[0],0,1);
  668.     %rsv1   = getSubStr(%byte[0],1,1);
  669.     %rsv2   = getSubStr(%byte[0],2,1);
  670.     %rsv3   = getSubStr(%byte[0],3,1);
  671.     %opcode = getSubStr(%byte[0],4,4);
  672.     %ismask = getSubStr(%byte[1],0,1);
  673.     %length = getSubStr(%byte[1],1,7);
  674.    
  675.     %opcode = convertBase(%opcode,$Basetype[2],$Basetype[10]);
  676.     %length = convertBase(%length,$Basetype[2],$Basetype[10]);
  677.     %pos    = 2;
  678.    
  679.     if(%len != %this.chunk)
  680.     {
  681.         %server.debug("> The data does not have the expected length.");
  682.        
  683.         switch(%opcode)
  684.         {
  685.             case 1:
  686.                 %server.debug("> Requesting a text frame resend.");
  687.                 %this.encodeFrame(1,"\x02");
  688.            
  689.             case 10:
  690.                 %server.debug("> Requesting a pong frame resend.");
  691.                 %this.encodeFrame(9,%this.ping);
  692.         }
  693.        
  694.         return;
  695.     }
  696.    
  697.     if(%ismask)
  698.     {
  699.         for(%i = %pos; %i < %pos + 4; %i++)
  700.             %mask = %mask @ %byte[%i];
  701.        
  702.         %pos += 4;
  703.     }
  704.    
  705.     for(%i = %pos; %i < %len; %i++)
  706.         %data = %data @ %byte[%i];
  707.    
  708.     for(%i = 0; %i < %len - %pos; %i++)
  709.     {
  710.         %data = %byte[%pos + %i];
  711.        
  712.         if(%ismask)
  713.         {
  714.             %mask = %byte[2 + %i % 4];
  715.             %data = manualXor(%data,%mask);
  716.         }
  717.        
  718.         %dec   = convertBase(%data,$Basetype[2],$Basetype[10]);
  719.         %val   = getSubStr($Basetype[256],%dec - 1,1);
  720.         %value = %value @ %val;
  721.     }
  722.    
  723.     switch(%opcode)
  724.     {
  725.         case 1:
  726.             %server.debug("> The frame is a text frame.");
  727.             %server.debug("> The result was: " @ %value);
  728.            
  729.             %this.onWebSocketLine(%value);
  730.        
  731.         case 8:
  732.             %server.debug("> The frame is a connection close.");
  733.             %this.disconnectClean();
  734.        
  735.         case 9:
  736.             %server.debug("> The frame is a ping frame.");
  737.             %server.debug("> The result was: " @ %value);
  738.        
  739.         case 10:
  740.             %server.debug("> The frame is a pong frame.");
  741.             %server.debug("> The result was: " @ %value);
  742.            
  743.             %ping = %this.ping;
  744.            
  745.             if(%ping $= "")
  746.                 return;
  747.            
  748.             if(%value !$= %ping)
  749.             {
  750.                 %server.debug("> Client " @ %this @ " failed ping and will be disconnected.");
  751.                 %this.disconnectClean();
  752.                
  753.                 return;
  754.             }
  755.            
  756.             %this.ping = "";
  757.             cancel(%this.timeout);
  758.     }
  759. }
  760.  
  761. function Webclient::onWebSocketLine(%this,%line)
  762. {
  763.     %server  = %this.server;
  764.     %sockets = %server.sockets;
  765.     %count   = %sockets.getCount();
  766.    
  767.     %line = strReplace(%line,"<","&lt;");
  768.     %line = strReplace(%line,">","&gt;");
  769.     %line = %this.ip SPC %line;
  770.    
  771.     echo(%line);
  772.     %this.encodeFrame(1,"\x03");
  773.    
  774.     for(%i = 0; %i < %count; %i++)
  775.         %sockets.getObject(%i).encodeFrame(1,%line);
  776.    
  777.     %sockets.pingAll();
  778. }
  779.  
  780. function WebSockets::pingAll(%this)
  781. {
  782.     %time  = %this.server.timeout;
  783.     %count = %this.getCount();
  784.    
  785.     for(%i = 0; %i < %count; %i++)
  786.     {
  787.         %sock = %this.getObject(%i);
  788.        
  789.         if(%sock.ping !$= "")
  790.             continue;
  791.        
  792.         %ping = mFloor($Sim::Time);
  793.         %sock.encodeFrame(9,%ping);
  794.        
  795.         %sock.ping    = %ping;
  796.         %sock.timeout = %sock.schedule(%time,pingTimeout);
  797.     }
  798. }
  799.  
  800. function Webclient::pingTimeout(%this)
  801. {
  802.     %this.server.debug("Client " @ %this @ " failed ping and will be disconnected.");
  803.     %this.disconnectClean();
  804. }
  805.  
  806. ////////////////////////////////////////
  807. //  WebSocket Support                 //
  808. ////////////////////////////////////////
  809.  
  810. function convertWebkey(%key)
  811. {
  812.     %sha = sha1(%key);
  813.     %len = strLen(%sha);
  814.    
  815.     for(%i = 0; %i < %len; %i += 2)
  816.         %str = %str SPC convertBase(getSubStr(%sha,%i,2),$Basetype[16],$Basetype[10]);
  817.    
  818.     %str = trim(%str);
  819.     %b64 = base64Encode_Nulls(%str);
  820.    
  821.     return %b64;
  822. }
  823.  
  824. function manualXor(%a,%b)
  825. {
  826.     %len = strLen(%a);
  827.    
  828.     for(%i = 0; %i < %len; %i++)
  829.         %xor = %xor @ (getSubStr(%a,%i,1) ^ getSubStr(%b,%i,1));
  830.    
  831.     return %xor;
  832. }
  833.  
  834. function manualAbsSub(%a)
  835. {
  836.     %a   = getSubStr(%a,1,strLen(%a));
  837.     %len = strLen(%a);
  838.     %dec = 1;
  839.    
  840.     for(%i = %len - 1; %i >= 0; %i--)
  841.     {
  842.         %int = getSubStr(%a,%i,1);
  843.        
  844.         if(%dec)
  845.         {
  846.             if(%int-- < 0) %int = 0;
  847.             else           %dec = 0;
  848.         }
  849.        
  850.         %val = %int @ %val;
  851.     }
  852.    
  853.     return %val;
  854. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement