private Return ( Stream stream, Socket socket, bool forceFlush ) : bool | ||
stream | Stream | |
socket | Socket | |
forceFlush | bool | |
return | bool |
internal bool Return(Stream stream, Socket socket, bool forceFlush)
{
var offset = offsetInOutput;
int responseCode = (int)ResponseStatus;
var http = HttpResponse[responseCode - 100];
Buffer.BlockCopy(http, 0, OutputTemp, offset, http.Length);
offset += http.Length;
if (ResponseIsJson)
{
Buffer.BlockCopy(JsonContentType, 0, OutputTemp, offset, JsonContentType.Length);
offset += JsonContentType.Length;
}
else if (ResponseContentType != null)
{
offset = AddContentType(ResponseContentType, offset);
}
for (int x = 0; x < ResponseHeadersLength; x++)
{
var kv = ResponseHeaders[x];
var val = kv.Key;
for (int i = 0; i < val.Length; i++)
OutputTemp[offset + i] = (byte)val[i];
offset += val.Length;
OutputTemp[offset++] = 58;
OutputTemp[offset++] = 32;
val = kv.Value;
for (int i = 0; i < val.Length; i++)
OutputTemp[offset + i] = (byte)val[i];
offset += val.Length;
OutputTemp[offset++] = 13;
OutputTemp[offset++] = 10;
}
bool keepAlive;
if (IsHttp10)
{
if (responseCode < 400 && "keep-alive".Equals(GetRequestHeader("connection"), StringComparison.OrdinalIgnoreCase))
{
keepAlive = true;
Buffer.BlockCopy(ConnectionKeepAlive, 0, OutputTemp, offset, ConnectionKeepAlive.Length);
offset += ConnectionKeepAlive.Length;
}
else
{
keepAlive = false;
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, false);
Buffer.BlockCopy(ConnectionClose, 0, OutputTemp, offset, ConnectionClose.Length);
offset += ConnectionClose.Length;
}
}
else
{
if (responseCode >= 400 || "close".Equals(GetRequestHeader("connection"), StringComparison.OrdinalIgnoreCase))
{
keepAlive = false;
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, false);
Buffer.BlockCopy(ConnectionClose, 0, OutputTemp, offset, ConnectionClose.Length);
offset += ConnectionClose.Length;
}
else keepAlive = true;
}
offset = AddServerAndDate(offset);
var cms = stream as ChunkedMemoryStream;
var mustFlushResponse = forceFlush || !keepAlive || !Pipeline;
if (cms != null)
{
offset = AddContentLength(cms.Length, offset);
var len = offset + cms.Length;
if (len < 4096)
{
cms.CopyTo(OutputTemp, offset);
if (mustFlushResponse || len > 1024)
{
offsetInOutput = 0;
socket.Send(OutputTemp, (int)len, SocketFlags.None);
}
else offsetInOutput = (int)len;
}
else
{
socket.Send(OutputTemp, offset, SocketFlags.Partial);
cms.Send(socket);
offsetInOutput = 0;
}
cms.Dispose();
}
else if (stream != null)
{
try
{
long len;
if (ResponseLength != null)
len = ResponseLength.Value;
else if (stream.CanSeek)
len = stream.Length;
else
throw new NotSupportedException("Chunked stream not implemented");
offset = AddContentLength(len, offset);
if (len + offset < OutputTemp.Length)
{
int pos = 0;
int size = (int)len;
do
{
pos += stream.Read(OutputTemp, pos + offset, size - pos);
} while (pos < len);
offset += size;
if (mustFlushResponse)
{
socket.Send(OutputTemp, offset, SocketFlags.None);
offsetInOutput = 0;
}
else offsetInOutput = offset;
}
else
{
int pos = 0;
int size = (int)len;
socket.Send(OutputTemp, offset, SocketFlags.Partial);
do
{
pos = stream.Read(OutputTemp, 0, OutputTemp.Length);
socket.Send(OutputTemp, pos, SocketFlags.None);
} while (pos != 0);
offsetInOutput = 0;
}
}
finally
{
stream.Dispose();
}
}
else
{
Buffer.BlockCopy(ZeroContentLength, 0, OutputTemp, offset, ZeroContentLength.Length);
offset += ZeroContentLength.Length;
if (mustFlushResponse)
{
socket.Send(OutputTemp, offset, SocketFlags.None);
offsetInOutput = 0;
}
else offsetInOutput = offset;
}
return keepAlive;
}
private void ProcessAllMessages(RequestInfo request, HttpSocketContext ctx, IPrincipal principal, ManualResetEvent resetEvent, bool canReschedule) { RouteMatch? routeMatch; RouteHandler route; var socket = request.Socket; while (ctx.Parse(socket, out routeMatch, out route)) { var match = routeMatch.Value; var auth = Authentication.TryAuthorize(ctx.GetRequestHeader("authorization"), ctx.RawUrl, route); if (auth.Principal != null) { if (canReschedule && route.IsAsync) { resetEvent.Reset(); ThreadPool.QueueUserWorkItem(ProcessInThread, new ThreadArgs(request, ctx, resetEvent, auth, route, match)); Thread.Yield(); resetEvent.WaitOne(); return; } else { ctx.ForRouteWithAuth(match, auth.Principal); if (principal != auth.Principal) { Thread.CurrentPrincipal = principal = auth.Principal; } using (var stream = route.Handle(match.OrderedArgs, ctx, ctx, ctx.InputStream, ctx.OutputStream)) { var keepAlive = ctx.Return(stream, socket, !canReschedule); if (keepAlive) { if (ctx.Pipeline) { continue; } else if (socket.Connected && Requests.TryAdd(request.Processed())) { return; } } socket.Close(); return; } } } else { CheckAuth(socket, auth, ctx); return; } } }