context: // **********************************************************************
  //
  // Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
  //
  // This copy of Ice is licensed to you under the terms described in the
  // ICE_LICENSE file included in this distribution.
  //
  // **********************************************************************
  
  namespace IceInternal
  {
      using System.Diagnostics;
      using System.Collections.Generic;
      using System.Text;
  
      internal sealed class WebSocketException : System.Exception
      {
          internal WebSocketException() :
              base("", null)
          {
          }
  
          internal WebSocketException(string message) :
              base(message, null)
          {
          }
  
          internal WebSocketException(string message, System.Exception cause) :
              base(message, cause)
          {
          }
  
          internal WebSocketException(System.Exception cause) :
              base("", cause)
          {
          }
      }
  
      internal sealed class HttpParser
      {
          internal HttpParser()
          {
              _type = Type.Unknown;
              _versionMajor = 0;
              _versionMinor = 0;
              _status = 0;
              _state = State.Init;
          }
  
          internal enum Type
          {
              Unknown,
              Request,
              Response
          };
  
          internal int isCompleteMessage(ByteBuffer buf, int begin, int end)
          {
              byte[] raw = buf.rawBytes();
              int p = begin;
  
              //
              // Skip any leading CR-LF characters.
              //
              while(p < end)
              {
                  byte ch = raw[p];
                  if(ch != (byte)'\r' && ch != (byte)'\n')
                  {
                      break;
                  }
                  ++p;
              }
  
              //
              // Look for adjacent CR-LF/CR-LF or LF/LF.
              //
              bool seenFirst = false;
              while(p < end)
              {
                  byte ch = raw[p++];
                  if(ch == (byte)'\n')
                  {
                      if(seenFirst)
                      {
                          return p;
                      }
                      else
                      {
                          seenFirst = true;
                      }
                  }
                  else if(ch != (byte)'\r')
                  {
                      seenFirst = false;
                  }
              }
  
              return -1;
          }
  
          internal bool parse(ByteBuffer buf, int begin, int end)
          {
              byte[] raw = buf.rawBytes();
              int p = begin;
              int start = 0;
              const char CR = '\r';
              const char LF = '\n';
  
              if(_state == State.Complete)
              {
                  _state = State.Init;
              }
  
              while(p != end && _state != State.Complete)
              {
                  char c = (char)raw[p];
  
                  switch(_state)
                  {
                  case State.Init:
                  {
                      _method = new StringBuilder();
                      _uri = new StringBuilder();
                      _versionMajor = -1;
                      _versionMinor = -1;
                      _status = -1;
                      _reason = "";
                      _headers.Clear();
                      _state = State.Type;
                      continue;
                  }
                  case State.Type:
                  {
                      if(c == CR || c == LF)
                      {
                          break;
                      }
                      else if(c == 'H')
                      {
                          //
                          // Could be the start of "HTTP/1.1" or "HEAD".
                          //
                          _state = State.TypeCheck;
                          break;
                      }
                      else
                      {
                          _state = State.Request;
                          continue;
                      }
                  }
                  case State.TypeCheck:
                  {
                      if(c == 'T') // Continuing "H_T_TP/1.1"
                      {
                          _state = State.Response;
                      }
                      else if(c == 'E') // Expecting "HEAD"
                      {
                          _state = State.Request;
                          _method.Append('H');
                          _method.Append('E');
                      }
                      else
                      {
                          throw new WebSocketException("malformed request or response");
                      }
                      break;
                  }
                  case State.Request:
                  {
                      _type = Type.Request;
                      _state = State.RequestMethod;
                      continue;
                  }
                  case State.RequestMethod:
                  {
                      if(c == ' ' || c == CR || c == LF)
                      {
                          _state = State.RequestMethodSP;
                          continue;
                      }
                      _method.Append(c);
                      break;
                  }
                  case State.RequestMethodSP:
                  {
                      if(c == ' ')
                      {
                          break;
                      }
                      else if(c == CR || c == LF)
                      {
                          throw new WebSocketException("malformed request");
                      }
                      _state = State.RequestURI;
                      continue;
                  }
                  case State.RequestURI:
                  {
                      if(c == ' ' || c == CR || c == LF)
                      {
                          _state = State.RequestURISP;
                          continue;
                      }
                      _uri.Append(c);
                      break;
                  }
                  case State.RequestURISP:
                  {
                      if(c == ' ')
                      {
                          break;
                      }
                      else if(c == CR || c == LF)
                      {
                          throw new WebSocketException("malformed request");
                      }
                      _state = State.Version;
                      continue;
                  }
                  case State.RequestLF:
                  {
                      if(c != LF)
                      {
                          throw new WebSocketException("malformed request");
                      }
                      _state = State.HeaderFieldStart;
                      break;
                  }
                  case State.HeaderFieldStart:
                  {
                      //
                      // We've already seen a LF to reach this state.
                      //
                      // Another CR or LF indicates the end of the header fields.
                      //
                      if(c == CR)
                      {
                          _state = State.HeaderFieldEndLF;
                          break;
                      }
                      else if(c == LF)
                      {
                          _state = State.Complete;
                          break;
                      }
                      else if(c == ' ')
                      {
                          //
                          // Could be a continuation line.
                          //
                          _state = State.HeaderFieldContStart;
                          break;
                      }
  
                      _state = State.HeaderFieldNameStart;
                      continue;
                  }
                  case State.HeaderFieldContStart:
                  {
                      if(c == ' ')
                      {
                          break;
                      }
  
                      _state = State.HeaderFieldCont;
                      start = p;
                      continue;
                  }
                  case State.HeaderFieldCont:
                  {
                      if(c == CR || c == LF)
                      {
                          if(p > start)
                          {
                              if(_headerName.Length == 0)
                              {
                                  throw new WebSocketException("malformed header");
                              }
                              Debug.Assert(_headers.ContainsKey(_headerName));
                              string s = _headers[_headerName];
                              StringBuilder newValue = new StringBuilder(s);
                              newValue.Append(' ');
                              for(int i = start; i < p; ++i)
                              {
                                  newValue.Append((char)raw[i]);
                              }
                              _headers[_headerName] = newValue.ToString();
                              _state = c == CR ? State.HeaderFieldLF : State.HeaderFieldStart;
                          }
                          else
                          {
                              //
                              // Could mark the end of the header fields.
                              //
                              _state = c == CR ? State.HeaderFieldEndLF : State.Complete;
                          }
                      }
  
                      break;
                  }
                  case State.HeaderFieldNameStart:
                  {
                      Debug.Assert(c != ' ');
                      start = p;
                      _headerName = "";
                      _state = State.HeaderFieldName;
                      continue;
                  }
                  case State.HeaderFieldName:
                  {
                      if(c == ' ' || c == ':')
                      {
                          _state = State.HeaderFieldNameEnd;
                          continue;
                      }
                      else if(c == CR || c == LF)
                      {
                          throw new WebSocketException("malformed header");
                      }
                      break;
                  }
                  case State.HeaderFieldNameEnd:
                  {
                      if(_headerName.Length == 0)
                      {
                          StringBuilder str = new StringBuilder();
                          for(int i = start; i < p; ++i)
                          {
                              str.Append((char)raw[i]);
                          }
                          _headerName = str.ToString().ToLower();
                          //
                          // Add a placeholder entry if necessary.
                          //
                          if(!_headers.ContainsKey(_headerName))
                          {
                              _headers[_headerName] = "";
                              _headerNames[_headerName] = str.ToString();
                          }
                      }
  
                      if(c == ' ')
                      {
                          break;
                      }
                      else if(c != ':' || p == start)
                      {
                          throw new WebSocketException("malformed header");
                      }
  
                      _state = State.HeaderFieldValueStart;
                      break;
                  }
                  case State.HeaderFieldValueStart:
                  {
                      if(c == ' ')
                      {
                          break;
                      }
  
                      //
                      // Check for "Name:\r\n"
                      //
                      if(c == CR)
                      {
                          _state = State.HeaderFieldLF;
                          break;
                      }
                      else if(c == LF)
                      {
                          _state = State.HeaderFieldStart;
                          break;
                      }
  
                      start = p;
                      _state = State.HeaderFieldValue;
                      continue;
                  }
                  case State.HeaderFieldValue:
                  {
                      if(c == CR || c == LF)
                      {
                          _state = State.HeaderFieldValueEnd;
                          continue;
                      }
                      break;
                  }
                  case State.HeaderFieldValueEnd:
                  {
                      Debug.Assert(c == CR || c == LF);
                      if(p > start)
                      {
                          StringBuilder str = new StringBuilder();
                          for(int i = start; i < p; ++i)
                          {
                              str.Append((char)raw[i]);
                          }
                          string s = null;
                          if(!_headers.TryGetValue(_headerName, out s) || s.Length == 0)
                          {
                              _headers[_headerName] = str.ToString();
                          }
                          else
                          {
                              _headers[_headerName] = s + ", " + str.ToString();
                          }
                      }
  
                      if(c == CR)
                      {
                          _state = State.HeaderFieldLF;
                      }
                      else
                      {
                          _state = State.HeaderFieldStart;
                      }
                      break;
                  }
                  case State.HeaderFieldLF:
                  {
                      if(c != LF)
                      {
                          throw new WebSocketException("malformed header");
                      }
                      _state = State.HeaderFieldStart;
                      break;
                  }
                  case State.HeaderFieldEndLF:
                  {
  
gt:                     if(c != LF)