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);
}
}