title: How to fix Websocket Handshake code?
body: <p>This is likely a familiar sob story. But there are so many of them out there, and I'm such a n00b I can't find the answer, so I'd like your help if you can help me.</p>
  
  <p>So, I'm using phpwebsocket by lemmingzshadow (google brings this up pretty easily if you are unfamiliar). As far as I can tell the version he has out has a bug where it doesn't follow the standards that Chrome 20.+ now uses. Its got something to do with the hand shake &amp; security keys but that's where I'm stuck at. I know I need to provide the following based on other questions, hopefully you can help me understand and fix this issue:</p>
  
  <p>The header Chrome receives is (Edited; I apparently posted the message to the server twice.):</p>
  
  <pre><code>HTTP/1.1 101 Switching Protocols
  Upgrade: websocket
  Connection: Upgrade
  Sec-WebSocket-Accept: aWXrpLOnEm15mE8+w1zG05ad01k=
  Sec-WebSocket-Protocol: QuatroDuo
  </code></pre>
  
  <p>The header my server receives is:</p>
  
  <pre><code>Upgrade: websocket
  Connection: Upgrade
  Host: gumonshoe.net:8000
  Origin: http://gumonshoe.net
  Sec-WebSocket-Key: v3+iw0U78qkwZnp+RWTu3A
  Sec-WebSocket-Version: 13
  Sec-WebSocket-Extensions: x-webkit-deflate-frame
  </code></pre>
  
  <p>I don't think the cookies are necessary, correct me if I'm wrong though.</p>
  
  <p>I hate to do this next part, but I figure pasting it all is better than doing nothing and needing to come back later. Here is the portion of code that reads &amp; interprets the handshake and sends the new one.</p>
  
  <p>Help is appreaciated:</p>
  
  <pre><code>&lt;?PHP
  private function handshake($data)
      {   
          $this-&gt;log('Performing handshake\r\n\r\n' . $data);  
          $lines = preg_split("/\r\n/", $data);
  
          // check for valid http-header:
          if(!preg_match('/\AGET (\S+) HTTP\/1.1\z/', $lines[0], $matches)) {
              $this-&gt;log('Invalid request: ' . $lines[0]);
              $this-&gt;sendHttpResponse(400);
              stream_socket_shutdown($this-&gt;socket, STREAM_SHUT_RDWR);
              return false;
          }
  
          // check for valid application:
          $path = $matches[1];
          $this-&gt;application = $this-&gt;server-&gt;getApplication(substr($path, 1));
              if(!$this-&gt;application) {
                  $this-&gt;log('Invalid application: ' . $path);
                  $this-&gt;sendHttpResponse(404);           
                  stream_socket_shutdown($this-&gt;socket, STREAM_SHUT_RDWR);
                  $this-&gt;server-&gt;removeClientOnError($this);
                  return false;
              }
  
          // generate headers array:
          $headers = array();
          foreach($lines as $line)
          {
              $line = chop($line);
              if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
              {
                  $headers[$matches[1]] = $matches[2];
              }
          }
  
          // check for supported websocket version:       
          if(!isset($headers['Sec-WebSocket-Version']) || $headers['Sec-WebSocket-Version'] &lt; 6)
          {
              $this-&gt;log('Unsupported websocket version.');
              $this-&gt;sendHttpResponse(501);
              stream_socket_shutdown($this-&gt;socket, STREAM_SHUT_RDWR);
              $this-&gt;server-&gt;removeClientOnError($this);
              return false;
          }
  
          // check origin:
          if($this-&gt;server-&gt;getCheckOrigin() === true)
          {
              $origin = (isset($headers['Sec-WebSocket-Origin'])) ? $headers['Sec-WebSocket-Origin'] : false;
              $origin = (isset($headers['Origin'])) ? $headers['Origin'] : $origin;
              if($origin === false)
              {
                  $this-&gt;log('No origin provided.');
                  $this-&gt;sendHttpResponse(401);
                  stream_socket_shutdown($this-&gt;socket, STREAM_SHUT_RDWR);
                  $this-&gt;server-&gt;removeClientOnError($this);
                  return false;
              }
  
              if(empty($origin))
              {
                  $this-&gt;log('Empty origin provided.');
                  $this-&gt;sendHttpResponse(401);
                  stream_socket_shutdown($this-&gt;socket, STREAM_SHUT_RDWR);
                  $this-&gt;server-&gt;removeClientOnError($this);
                  return false;
              }
  
              if($this-&gt;server-&gt;checkOrigin($origin) === false)
              {
                  $this-&gt;log('Invalid origin provided. : ' . $origin . ' Legal options were:');
                  $gumk = 0;
                  foreach(array_keys($this-&gt;server-&gt;getAllowedOrigins()) as $lo) {
                      $this-&gt;log( '[' . $gumk++ . '] : ' . $lo);
                  }
                  $this-&gt;sendHttpResponse(401);
                  stream_socket_shutdown($this-&gt;socket, STREAM_SHUT_RDWR);
                  $this-&gt;server-&gt;removeClientOnError($this);
                  return false;
              }
          }       
  
          // do handyshake: (hybi-10)
          $secKey = $headers['Sec-WebSocket-Key'];
          $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
          $response = "HTTP/1.1 101 Switching Protocols\r\n";
          $response.= "Upgrade: websocket\r\n";
          $response.= "Connection: Upgrade\r\n";
          $response.= "Sec-WebSocket-Accept: " . $secAccept . "\r\n";
          $response.= "Sec-WebSocket-Protocol: " . substr($path, 1) . "\r\n\r\n";     
          if(false === ($this-&gt;server-&gt;writeBuffer($this-&gt;socket, $response)))
          {
              return false;
          }
          $this-&gt;handshaked = true;
          $this-&gt;log('Handshake sent');
          $this-&gt;application-&gt;onConnect($this);
  
          // trigger status application:
          if($this-&gt;server-&gt;getApplication('status') !== false)
          {
              $this-&gt;server-&gt;getApplication('status')-&gt;clientConnected($this-&gt;ip, $this-&gt;port);
          }
  
          return true;            
      }
  </code></pre>
  
  <p>Receiving the following error,</p>
  
  <pre><code>Error during WebSocket handshake: Sec-WebSocket-Protocol mismatch
  </code></pre>
  
  <p>As I'm largely inexperienced in this level of server debugging, a more  detailed answer than linking me to documentation/specifications would be appreciated.</p>