GetPool() public method

public GetPool ( ) : Server
return Server
Example #1
0
        private void DoHmux(HttpContext context)
        {
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;

            String sessionId;

            if (!_isStickySessions)
            {
                sessionId = null;
            }
            else
            {
                sessionId = GetRequestedSessionId(request);
            }

            TempBuffer tempBuf = TempBuffer.Allocate();

            byte[] buf = tempBuf.GetBuffer();

            try {
                Stream is_ = request.InputStream;
                int    len = is_.Read(buf, 0, buf.Length);
                bool   isComplete;

                if (len < 0)
                {
                    isComplete = true;
                }
                else if (len < buf.Length)
                {
                    int sublen = is_.Read(buf, len, 1);

                    if (sublen == 0) //.NET return 0 for Stream.EOF
                    {
                        isComplete = true;
                    }
                    else
                    {
                        len       += sublen;
                        isComplete = false;
                    }
                }
                else
                {
                    isComplete = false;
                }

                Server client = null;
                int    result = OK | EXIT;

                HmuxConnection channel = _loadBalancer.OpenServer(sessionId, null);

                // If everything fails, return an error
                if (channel == null)
                {
                    SendNotAvailable(response);

                    return;
                }

                client = channel.GetPool();

                BufferedStream rs = channel.GetSocketStream();
                BufferedStream ws = channel.GetSocketStream();
                result = FAIL | EXIT;
                long requestStartTime = Utils.CurrentTimeMillis();

                try {
                    result = HandleRequest(context, request, response, channel, rs, ws,
                                           buf, len, isComplete, isComplete);

                    if ((result & STATUS_MASK) == OK)
                    {
                        client.ClearBusy();

                        return;
                    }
                    else if ((result & STATUS_MASK) == BUSY)
                    {
                        client.Busy();
                    }
                    else
                    {
                        client.FailSocket();
                    }
                } catch (ClientDisconnectException) {
                    _log.Info("Client disconnect detected for '{0}'", channel.GetTraceId());

                    return;
                } catch (IOException e) {
                    client.FailSocket();
                    _log.Error("IOException '{0}': '{1}' {2}", channel.GetTraceId(), e.Message, e.StackTrace);
                } finally {
                    if ((result & EXIT_MASK) == QUIT)
                    {
                        channel.Free(requestStartTime);
                    }
                    else
                    {
                        channel.Close();
                    }
                }

                // server/2675
                if (isComplete && (result & STATUS_MASK) == BUSY ||
                    "GET".Equals(request.HttpMethod))
                {
                    channel = _loadBalancer.OpenServer(sessionId, client);

                    // If everything fails, return an error
                    if (channel == null)
                    {
                        _log.Info("load-balance failed" + (client != null ? (" for " + client.GetDebugId()) : ""));

                        SendNotAvailable(response);

                        return;
                    }

                    Server client2 = channel.GetPool();

                    if (_log.IsLoggable(EventLogEntryType.Information))
                    {
                        _log.Info("load-balance failing over"
                                  + (client != null ? (" from " + client.GetDebugId()) : "")
                                  + " to " + client2.GetDebugId());
                    }

                    rs = channel.GetSocketStream();
                    ws = channel.GetSocketStream();

                    result           = FAIL | EXIT;
                    requestStartTime = Utils.CurrentTimeMillis();

                    try {
                        result = HandleRequest(context, request, response, channel, rs, ws,
                                               buf, len, isComplete, false);

                        if ((result & STATUS_MASK) == OK)
                        {
                            client2.ClearBusy();

                            return;
                        }
                        else if ((result & STATUS_MASK) == BUSY)
                        {
                            client2.Busy();
                        }
                        else
                        {
                            client2.FailSocket();
                        }
                    } catch (IOException e) {
                        client2.FailSocket();

                        _log.Info("Failover to '{0}' did not succeed '{1}', {2} ", client2.GetDebugId(), e.Message, e.StackTrace);
                    } finally {
                        if ((result & EXIT_MASK) == QUIT)
                        {
                            channel.Free(requestStartTime);
                        }
                        else
                        {
                            channel.Close();
                        }
                    }
                }

                SendNotAvailable(response);
            } finally {
                TempBuffer.Free(tempBuf);
                tempBuf = null;
            }
        }
Example #2
0
        private int HandleRequest(HttpContext context,
                                  HttpRequest request,
                                  HttpResponse response,
                                  HmuxConnection hmuxChannel,
                                  BufferedStream rs,
                                  BufferedStream ws,
                                  byte[] buf, int length, bool isComplete,
                                  bool allowBusy)
        {
            Trace.TraceInformation("Handle request: length: {0}, complete: {1}, allowBusy {2}", length, isComplete, allowBusy);
            String traceId = hmuxChannel.GetTraceId();

            StringBuilder cb = new StringBuilder();

            bool isDebugFiner = true;

            String uri = request.Path;

            uri = Uri.EscapeUriString(uri);

            Trace.TraceInformation("Hmux[{0}] >>U:uri {1}->{2}", traceId, request.RawUrl, uri);
            WriteRequestString(ws, HmuxConnection.HMUX_URI, uri, traceId);

            String rawUri   = request.RawUrl;
            int    queryIdx = rawUri.IndexOf('?');

            if (queryIdx > -1 && queryIdx + 1 < rawUri.Length)
            {
                String query = rawUri.Substring(queryIdx + 1);
                Trace.TraceInformation("Hmux[{0}] >>U:query {1}", traceId, query);
                WriteRequestString(ws, HmuxConnection.CSE_QUERY_STRING, query, traceId);
            }

            Trace.TraceInformation("Hmux[{0}] >>m:method {1}", traceId, request.HttpMethod);
            WriteRequestString(ws, HmuxConnection.HMUX_METHOD, request.HttpMethod, traceId);

            Trace.TraceInformation("Hmux[{0}] >>u:server type {1}", traceId, "IIS");
            WriteRequestString(ws, HmuxConnection.CSE_SERVER_TYPE, "IIS", traceId);

            NameValueCollection serverVariables = request.ServerVariables;

            String serverPort = serverVariables.Get("SERVER_PORT");
            String serverName = serverVariables.Get("SERVER_NAME") + ':' + serverPort;

            Trace.TraceInformation("Hmux[{0}] >>v:server name {1}", traceId, serverName);
            WriteRequestString(ws, HmuxConnection.HMUX_SERVER_NAME, serverName, traceId);

            Trace.TraceInformation("Hmux[{0}] >>g:server port {1}", traceId, serverPort);
            WriteRequestString(ws, HmuxConnection.CSE_SERVER_PORT, serverPort, traceId);

            String remoteAddr = serverVariables.Get("REMOTE_ADDR");

            Trace.TraceInformation("Hmux[{0}] >>i:remote address {1}", traceId, remoteAddr);
            WriteRequestString(ws, HmuxConnection.CSE_REMOTE_ADDR, remoteAddr, traceId);

            String remoteHost = serverVariables.Get("REMOTE_HOST");

            if (remoteHost == null)
            {
                remoteHost = remoteAddr;
            }

            Trace.TraceInformation("Hmux[{0}] >>h:remote host {1}", traceId, remoteHost);
            WriteRequestString(ws, HmuxConnection.CSE_REMOTE_HOST, remoteHost, traceId);

            String protocol = serverVariables.Get("HTTP_VERSION");

            Trace.TraceInformation("Hmux[{0}] >>c:protocol {1}", traceId, protocol);
            WriteRequestString(ws, HmuxConnection.CSE_PROTOCOL, protocol, traceId);

            HttpClientCertificate clientCertificate = request.ClientCertificate;

            if (request.IsSecureConnection)
            {
                Trace.TraceInformation("Hmux[{0}] >>r:secure", traceId);
                WriteRequestString(ws, HmuxConnection.CSE_IS_SECURE, "", traceId);

                WriteRequestHeader(ws, "HTTPS", "on", traceId);
                WriteRequestHeader(ws, "SSL_SECRETKEYSIZE", clientCertificate.KeySize.ToString(), traceId);
            }

            if (clientCertificate.IsPresent)
            {
                Trace.TraceInformation("Hmux[{0}] >>r:certificate ({1})", traceId, clientCertificate.Certificate.Length);
                ws.WriteByte(HmuxConnection.CSE_CLIENT_CERT);
                WriteHmuxLength(ws, clientCertificate.Certificate.Length);
                ws.Write(clientCertificate.Certificate, 0, clientCertificate.Certificate.Length);
            }

            if (request.IsAuthenticated)
            {
                /*
                 * String remoteUser = request.LogonUserIdentity.Name;
                 */
                String remoteUser = context.Current.User.Identity.Name;
                WriteRequestString(ws, HmuxConnection.CSE_REMOTE_USER, remoteUser, traceId);
            }

            NameValueCollection headers = request.Headers;

            foreach (String key in headers.AllKeys)
            {
                if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                String[] values = headers.GetValues(key);
                foreach (String value in values)
                {
                    WriteRequestHeader(ws, key, value, traceId);
                }
            }

            if (_isDebug)
            {
                WriteRequestHeader(ws, "X-Resin-Debug", traceId, traceId);
            }

            Stream requestStream  = request.InputStream;
            Stream responseStream = null;

            bool hasHeader = true;
            bool hasStatus = false;


            if (length > 0)
            {
                Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
                WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, length, traceId);
            }

            int len;

            int code;

            while (!isComplete && (len = requestStream.Read(buf, 0, buf.Length)) > 0)
            {
                Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
                WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, len, traceId);

                Trace.TraceInformation("Hmux[{0}] >>Y: (yield)", traceId);
                ws.WriteByte(HmuxConnection.HMUX_YIELD);
                ws.Flush();

                while (true)
                {
                    code = rs.ReadByte();

                    if (code < 0)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<w: end of file", traceId);

                        if (hasStatus)
                        {
                            return(OK | EXIT);
                        }
                        else
                        {
                            // Trace.TraceInformation("Hmux[{0}] <<w: unexpected end of file", traceId);

                            return(FAIL | EXIT);
                        }
                    }
                    else if (code == HmuxConnection.HMUX_QUIT)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);

                        if (hasStatus)
                        {
                            return(OK | QUIT);
                        }
                        else
                        {
                            Trace.TraceInformation("Hmux[{0}] <<Q: unexpected quit file", traceId);

                            return(FAIL | QUIT);
                        }
                    }
                    else if (code == HmuxConnection.HMUX_EXIT)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

                        if (hasStatus)
                        {
                            return(OK | EXIT);
                        }
                        else
                        {
                            Trace.TraceInformation("Hmux[{0}] <<X: unexpected exit", traceId);

                            return(FAIL | EXIT);
                        }
                    }
                    else if (code == HmuxConnection.HMUX_YIELD)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

                        continue;
                    }

                    int sublen = ReadHmuxLength(rs);

                    if (code == HmuxConnection.HMUX_ACK)
                    {
                        if (isDebugFiner)
                        {
                            Trace.TraceInformation("Hmux[{0}] <<A: (ack) ({1})", traceId, sublen);
                        }

                        break;
                    }
                    else if (code == HmuxConnection.HMUX_CHANNEL)
                    {
                        int channel = sublen;
                        Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
                    }
                    else if (code == HmuxConnection.HMUX_STATUS && hasHeader)
                    {
                        String status = ReadHmuxString(rs, sublen);
                        Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);
                        int statusCode = 0;
                        for (int i = 0; i < 3; i++)
                        {
                            statusCode = 10 * statusCode + status[i] - '0';
                        }

                        if (statusCode != 200)
                        {
                            response.StatusCode = statusCode;
                        }

                        hasStatus = true;
                    }
                    else if (code == HmuxConnection.HMUX_HEADER && hasHeader)
                    {
                        String name = ReadHmuxString(rs, sublen);
                        rs.ReadByte();
                        sublen = ReadHmuxLength(rs);
                        String value = ReadHmuxString(rs, sublen);

                        Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

                        RelayResponseHeader(response, name, value);
                    }
                    else if (code == HmuxConnection.HMUX_DATA)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

                        if (responseStream == null)
                        {
                            responseStream = response.OutputStream;
                        }

                        RelayResponseData(rs, responseStream, sublen);
                    }
                    else if (code == HmuxConnection.HMUX_META_HEADER)
                    {
                        String name = ReadHmuxString(rs, sublen);
                        rs.ReadByte();
                        sublen = ReadHmuxLength(rs);
                        String value = ReadHmuxString(rs, sublen);

                        Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

                        if ("cpu-load".Equals(name))
                        {
                            double loadAvg = 0.001 * long.Parse(value);

                            hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
                        }
                    }
                    else
                    {
                        Skip(rs, sublen);
                    }
                }
            }

            ws.WriteByte(HmuxConnection.HMUX_QUIT);
            ws.Flush();

            code = rs.ReadByte();

            // #2369 - A slow modem can cause the app-tier and web-tier times
            // to get out of sync, with the app-tier thinking it's completed
            // (and starts the keepalive timeout) 30s before the web-tier reads
            // its data.
            // As a temporary measure, we start the idle time at the first data
            // read (later we might mark the time it takes to read an app-tier
            // packet.  If it's short, e.g. 250ms, don't update the time.)
            hmuxChannel.SetIdleStartTime(Utils.CurrentTimeMillis());

            bool isBusy = false;

            for (; code >= 0; code = rs.ReadByte())
            {
                if (code == HmuxConnection.HMUX_QUIT)
                {
                    if (isDebugFiner)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);
                    }

                    return(isBusy ? BUSY | QUIT : OK | QUIT);
                }
                else if (code == HmuxConnection.HMUX_EXIT)
                {
                    Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

                    return((isBusy || !hasStatus) ? BUSY | EXIT : OK | EXIT);
                }
                else if (code == HmuxConnection.HMUX_YIELD)
                {
                    Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

                    continue;
                }

                int sublen = (rs.ReadByte() << 8) + rs.ReadByte();

                if (code == HmuxConnection.HMUX_DATA)
                {
                    if (responseStream == null)
                    {
                        responseStream = response.OutputStream;
                    }

                    Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

                    if (!isBusy)
                    {
                        RelayResponseData(rs, responseStream, sublen);
                    }
                    else
                    {
                        Skip(rs, sublen);
                    }
                }
                else if (code == HmuxConnection.HMUX_STATUS && hasHeader)
                {
                    hasStatus = true;
                    String status = ReadHmuxString(rs, sublen);
                    Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);

                    int statusCode = 0;
                    for (int i = 0; i < 3; i++)
                    {
                        statusCode = 10 * statusCode + status[i] - '0';
                    }

                    if (statusCode == 503 && allowBusy)
                    {
                        isBusy = true;
                    }
                    else if (statusCode != 200)
                    {
                        response.StatusCode = statusCode;
                    }
                }
                else if (code == HmuxConnection.HMUX_HEADER && hasHeader)
                {
                    String name = ReadHmuxString(rs, sublen);
                    rs.ReadByte();
                    sublen = ReadHmuxLength(rs);
                    String value = ReadHmuxString(rs, sublen);

                    Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

                    if (!isBusy)
                    {
                        RelayResponseHeader(response, name, value);
                    }
                }
                else if (code == HmuxConnection.HMUX_META_HEADER)
                {
                    String name = ReadHmuxString(rs, sublen);
                    rs.ReadByte();
                    sublen = ReadHmuxLength(rs);
                    String value = ReadHmuxString(rs, sublen);

                    Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

                    if ("cpu-load".Equals(name))
                    {
                        double loadAvg = 0.001 * long.Parse(value);

                        hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
                    }
                }
                else if (code == HmuxConnection.HMUX_CHANNEL)
                {
                    int channel = sublen;
                    Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
                }
                else if (code == HmuxConnection.CSE_SEND_HEADER)
                {
                    Trace.TraceInformation("Hmux[{0}] <<G: send headers", traceId);
                    Skip(rs, sublen);
                }
                else if (code == 0)
                {
                    Trace.TraceInformation("Hmux[{0}] <<0: unknown code (0)", traceId);

                    return(FAIL | EXIT);
                }
                else
                {
                    Trace.TraceInformation("Hmux[{0}] <<?: unknown code ({1})", traceId, code);
                    Skip(rs, sublen);
                }
            }
            Trace.TraceInformation("Hmux[{0}] end of file", traceId);

            // server/269q
            if (hasStatus)
            {
                return(isBusy ? BUSY | EXIT : OK | EXIT);
            }
            else
            {
                // Trace.TraceInformation("Hmux[{0}] unexpected end of file", traceId, code);
                return(FAIL | EXIT);
            }
        }
Example #3
0
        private int HandleRequest(HttpRequest request,
            HttpResponse response,
            HmuxConnection hmuxChannel,
            BufferedStream rs,
            BufferedStream ws,
            byte[] buf, int length, bool isComplete,
            bool allowBusy)
        {
            Trace.TraceInformation("Handle request: length: {0}, complete: {1}, allowBusy {2}", length, isComplete, allowBusy);
              String traceId = hmuxChannel.GetTraceId();

              StringBuilder cb = new StringBuilder();

              bool isDebugFiner = true;

              String uri = request.Path;
              uri = Uri.EscapeUriString(uri);

              Trace.TraceInformation("Hmux[{0}] >>U:uri {1}->{2}", traceId, request.RawUrl, uri);
              WriteRequestString(ws, HmuxConnection.HMUX_URI, uri, traceId);

              String rawUri = request.RawUrl;
              int queryIdx = rawUri.IndexOf('?');
              if (queryIdx > -1 && queryIdx + 1 < rawUri.Length) {
            String query = rawUri.Substring(queryIdx + 1);
            Trace.TraceInformation("Hmux[{0}] >>U:query {1}", traceId, query);
            WriteRequestString(ws, HmuxConnection.CSE_QUERY_STRING, query, traceId);
              }

              Trace.TraceInformation("Hmux[{0}] >>m:method {1}", traceId, request.HttpMethod);
              WriteRequestString(ws, HmuxConnection.HMUX_METHOD, request.HttpMethod, traceId);

              Trace.TraceInformation("Hmux[{0}] >>u:server type {1}", traceId, "IIS");
              WriteRequestString(ws, HmuxConnection.CSE_SERVER_TYPE, "IIS", traceId);

              NameValueCollection serverVariables = request.ServerVariables;

              String serverPort = serverVariables.Get("SERVER_PORT");
              String serverName = serverVariables.Get("SERVER_NAME") + ':' + serverPort;
              Trace.TraceInformation("Hmux[{0}] >>v:server name {1}", traceId, serverName);
              WriteRequestString(ws, HmuxConnection.HMUX_SERVER_NAME, serverName, traceId);

              Trace.TraceInformation("Hmux[{0}] >>g:server port {1}", traceId, serverPort);
              WriteRequestString(ws, HmuxConnection.CSE_SERVER_PORT, serverPort, traceId);

              String remoteAddr = serverVariables.Get("REMOTE_ADDR");
              Trace.TraceInformation("Hmux[{0}] >>i:remote address {1}", traceId, remoteAddr);
              WriteRequestString(ws, HmuxConnection.CSE_REMOTE_ADDR, remoteAddr, traceId);

              String remoteHost = serverVariables.Get("REMOTE_HOST");
              if (remoteHost == null)
            remoteHost = remoteAddr;

              Trace.TraceInformation("Hmux[{0}] >>h:remote host {1}", traceId, remoteHost);
              WriteRequestString(ws, HmuxConnection.CSE_REMOTE_HOST, remoteHost, traceId);

              String protocol = serverVariables.Get("HTTP_VERSION");
              Trace.TraceInformation("Hmux[{0}] >>c:protocol {1}", traceId, protocol);
              WriteRequestString(ws, HmuxConnection.CSE_PROTOCOL, protocol, traceId);

              HttpClientCertificate clientCertificate = request.ClientCertificate;
              if (request.IsSecureConnection) {
            Trace.TraceInformation("Hmux[{0}] >>r:secure", traceId);
            WriteRequestString(ws, HmuxConnection.CSE_IS_SECURE, "", traceId);

            WriteRequestHeader(ws, "HTTPS", "on", traceId);
            WriteRequestHeader(ws, "SSL_SECRETKEYSIZE", clientCertificate.KeySize.ToString(), traceId);
              }

              if (clientCertificate.IsPresent) {
            Trace.TraceInformation("Hmux[{0}] >>r:certificate ({1})", traceId, clientCertificate.Certificate.Length);
            ws.WriteByte(HmuxConnection.CSE_CLIENT_CERT);
            WriteHmuxLength(ws, clientCertificate.Certificate.Length);
            ws.Write(clientCertificate.Certificate, 0, clientCertificate.Certificate.Length);
              }

              NameValueCollection headers = request.Headers;
              foreach (String key in headers.AllKeys) {
            if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase))
              continue;

            String[] values = headers.GetValues(key);
            foreach (String value in values) {
              WriteRequestHeader(ws, key, value, traceId);
            }
              }

              if (_isDebug) {
            WriteRequestHeader(ws, "X-Resin-Debug", traceId, traceId);
              }

              Stream requestStream = request.InputStream;
              Stream responseStream = null;

              bool hasHeader = true;
              bool hasStatus = false;

              if (length > 0) {
            Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
            WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, length, traceId);
              }

              int len;

              int code;

              while (!isComplete && (len = requestStream.Read(buf, 0, buf.Length)) > 0) {
            Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
            WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, len, traceId);

            Trace.TraceInformation("Hmux[{0}] >>Y: (yield)", traceId);
            ws.WriteByte(HmuxConnection.HMUX_YIELD);
            ws.Flush();

            while (true) {
              code = rs.ReadByte();

              if (code < 0) {
            Trace.TraceInformation("Hmux[{0}] <<w: end of file", traceId);

            if (hasStatus)
              return OK | EXIT;
            else {
              Trace.TraceInformation("Hmux[{0}] <<w: unexpected end of file", traceId);

              return FAIL | EXIT;
            }
              } else if (code == HmuxConnection.HMUX_QUIT) {
            Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);

            if (hasStatus)
              return OK | QUIT;
            else {
              Trace.TraceInformation("Hmux[{0}] <<Q: unexpected quit file", traceId);

              return FAIL | QUIT;
            }
              } else if (code == HmuxConnection.HMUX_EXIT) {
            Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

            if (hasStatus) {
              return OK | EXIT;
            } else {
              Trace.TraceInformation("Hmux[{0}] <<X: unexpected exit", traceId);

              return FAIL | EXIT;
            }
              } else if (code == HmuxConnection.HMUX_YIELD) {
            Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

            continue;
              }

              int sublen = ReadHmuxLength(rs);

              if (code == HmuxConnection.HMUX_ACK) {
            if (isDebugFiner)
              Trace.TraceInformation("Hmux[{0}] <<A: (ack) ({1})", traceId, sublen);

            break;
              } else if (code == HmuxConnection.HMUX_CHANNEL) {
            int channel = sublen;
            Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
              } else if (code == HmuxConnection.HMUX_STATUS && hasHeader) {
            String status = ReadHmuxString(rs, sublen);
            Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);
            int statusCode = 0;
            for (int i = 0; i < 3; i++)
              statusCode = 10 * statusCode + status[i] - '0';

            if (statusCode != 200)
              response.StatusCode = statusCode;

            hasStatus = true;
              } else if (code == HmuxConnection.HMUX_HEADER && hasHeader) {
            String name = ReadHmuxString(rs, sublen);
            rs.ReadByte();
            sublen = ReadHmuxLength(rs);
            String value = ReadHmuxString(rs, sublen);

            Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

            RelayResponseHeader(response, name, value);
              } else if (code == HmuxConnection.HMUX_DATA) {
            Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

            if (responseStream == null)
              responseStream = response.OutputStream;

            RelayResponseData(rs, responseStream, sublen);
              } else if (code == HmuxConnection.HMUX_META_HEADER) {
            String name = ReadHmuxString(rs, sublen);
            rs.ReadByte();
            sublen = ReadHmuxLength(rs);
            String value = ReadHmuxString(rs, sublen);

            Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

            if ("cpu-load".Equals(name)) {
              double loadAvg = 0.001 * long.Parse(value);

              hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
            }
              } else {
            Skip(rs, sublen);
              }
            }
              }

              ws.WriteByte(HmuxConnection.HMUX_QUIT);
              ws.Flush();

              code = rs.ReadByte();

              // #2369 - A slow modem can cause the app-tier and web-tier times
              // to get out of sync, with the app-tier thinking it's completed
              // (and starts the keepalive timeout) 30s before the web-tier reads
              // its data.
              // As a temporary measure, we start the idle time at the first data
              // read (later we might mark the time it takes to read an app-tier
              // packet.  If it's short, e.g. 250ms, don't update the time.)
              hmuxChannel.SetIdleStartTime(Utils.CurrentTimeMillis());

              bool isBusy = false;
              for (; code >= 0; code = rs.ReadByte()) {
            if (code == HmuxConnection.HMUX_QUIT) {
              if (isDebugFiner)
            Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);

              return isBusy ? BUSY | QUIT : OK | QUIT;
            } else if (code == HmuxConnection.HMUX_EXIT) {

              Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

              return (isBusy || !hasStatus) ? BUSY | EXIT : OK | EXIT;
            } else if (code == HmuxConnection.HMUX_YIELD) {
              Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

              continue;
            }

            int sublen = (rs.ReadByte() << 8) + rs.ReadByte();

            if (code == HmuxConnection.HMUX_DATA) {
              if (responseStream == null)
            responseStream = response.OutputStream;

              Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

              if (!isBusy)
            RelayResponseData(rs, responseStream, sublen);
              else
            Skip(rs, sublen);
            } else if (code == HmuxConnection.HMUX_STATUS && hasHeader) {
              hasStatus = true;
              String status = ReadHmuxString(rs, sublen);
              Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);

              int statusCode = 0;
              for (int i = 0; i < 3; i++)
            statusCode = 10 * statusCode + status[i] - '0';

              if (statusCode == 503 && allowBusy) {
            isBusy = true;
              } else if (statusCode != 200) {
            response.StatusCode = statusCode;
              }
            } else if (code == HmuxConnection.HMUX_HEADER && hasHeader) {
              String name = ReadHmuxString(rs, sublen);
              rs.ReadByte();
              sublen = ReadHmuxLength(rs);
              String value = ReadHmuxString(rs, sublen);

              Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

              if (!isBusy)
            RelayResponseHeader(response, name, value);
            } else if (code == HmuxConnection.HMUX_META_HEADER) {
              String name = ReadHmuxString(rs, sublen);
              rs.ReadByte();
              sublen = ReadHmuxLength(rs);
              String value = ReadHmuxString(rs, sublen);

              Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

              if ("cpu-load".Equals(name)) {
            double loadAvg = 0.001 * long.Parse(value);

            hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
              }
            } else if (code == HmuxConnection.HMUX_CHANNEL) {
              int channel = sublen;
              Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
            } else if (code == 0) {
              Trace.TraceInformation("Hmux[{0}] <<0: unknown code (0)", traceId);

              return FAIL | EXIT;
            } else {
              Trace.TraceInformation("Hmux[{0}] <<?: unknown code ({1})", traceId, code);
              Skip(rs, sublen);
            }
              }
              Trace.TraceInformation("Hmux[{0}] end of file", traceId);

              // server/269q
              if (hasStatus)
            return isBusy ? BUSY | EXIT : OK | EXIT;
              else {
            Trace.TraceInformation("Hmux[{0}] unexpected end of file", traceId, code);
            return FAIL | EXIT;
              }
        }