private IEnumerator <object> SendResponseTask(Stream source, int?count) { var length = Math.Min( (int)source.Length, count.GetValueOrDefault(int.MaxValue) ); ContentLength = length; if (!HeadersSent) { HeadersSent = true; yield return(SendHeadersTask()); } ResponseSent = true; const int blockSize = 1024 * 128; var bytesLeft = length; using (var sda = new StreamDataAdapter(source, false)) using (var buffer = BufferPool <byte> .Allocate(blockSize)) while (bytesLeft > 0) { var readSize = Math.Min(blockSize, bytesLeft); var fBlock = sda.Read(buffer.Data, 0, blockSize); yield return(fBlock); bytesLeft -= fBlock.Result; yield return(Adapter.Write(buffer.Data, 0, fBlock.Result)); } }
public Buffer GetBuffer(bool writable) { if (writable) { EnsureList(); } if (_HasList) { return new Buffer { IsTemporary = false, Data = Items.GetBuffer(), Count = Items.Count } } ; else { var alloc = BufferPool <T> .Allocate(4); var buf = alloc.Data; buf[0] = Item1; buf[1] = Item2; buf[2] = Item3; buf[3] = Item4; return(new Buffer { IsTemporary = true, Data = buf, BufferPoolAllocation = alloc, Count = _Count }); } }
public static bool DoPolygonsIntersect(Polygon polygonA, Polygon polygonB) { var offset = ComputeComparisonOffset(polygonA, polygonB); using (var axisBuffer = BufferPool <Vector2> .Allocate(polygonA.Count + polygonB.Count)) { int axisCount = 0; GetPolygonAxes(axisBuffer.Data, ref axisCount, polygonA); GetPolygonAxes(axisBuffer.Data, ref axisCount, polygonB); for (int i = 0; i < axisCount; i++) { var axis = axisBuffer.Data[i]; var intervalA = ProjectOntoAxis(axis, polygonA, offset); var intervalB = ProjectOntoAxis(axis, polygonB, offset); bool intersects = intervalA.Intersects(intervalB, Geometry.IntersectionEpsilon); if (!intersects) { return(false); } } } return(true); }
public LinesForLightSource(LightSource lightSource, DeltaLineWriter lineWriter) { LightSource = lightSource; Buffer = BufferPool <DeltaLine> .Allocate(lineWriter.Lines.Count); lineWriter.CopyTo(Buffer.Data, 0, lineWriter.Lines.Count); Lines = new ArraySegment <DeltaLine>(Buffer.Data, 0, lineWriter.Lines.Count); }
public void Update(bool parallelUpdate) { /* * if (IntersectionTestsLastFrame > 0) * Debug.WriteLine("{0} intersection tests last frame", IntersectionTestsLastFrame); */ IntersectionTestsLastFrame = 0; var options = new ParallelOptions(); if (!parallelUpdate) { options.MaxDegreeOfParallelism = 1; } _ObstructionsByLight.Clear(); #if SDL2 // Parallel is Satan -flibit foreach (LightSource ls in Environment.LightSources) { LineGeneratorContext ctx = new LineGeneratorContext(Environment.Obstructions.Count * 2); GenerateLinesForLightSource(ref ctx, ls); lock (_ObstructionsByLight) { foreach (var kvp in ctx.Queue) { _ObstructionsByLight.Add(kvp.LightSource, kvp.Lines); } } ctx.Dispose(); } #else using (var buffer = BufferPool <LightSource> .Allocate(Environment.LightSources.Count)) { Environment.LightSources.CopyTo(buffer.Data); Parallel.For( 0, Environment.LightSources.Count, options, () => new LineGeneratorContext(Environment.Obstructions.Count * 2), (idx, pls, ctx) => { var ls = buffer.Data[idx]; GenerateLinesForLightSource(ref ctx, ls); return(ctx); }, (ctx) => { lock (_ObstructionsByLight) foreach (var kvp in ctx.Queue) { _ObstructionsByLight.Add(kvp.LightSource, kvp.Lines); } ctx.Dispose(); } ); } #endif }
public void PrepareMany <T> (DenseList <T> batches, Batch.PrepareContext context) where T : IBatch { int totalAdded = 0; const int blockSize = 128; using (var buffer = BufferPool <Task> .Allocate(blockSize)) { var task = new Task(null, context); int j = 0, c = batches.Count; T batch; for (int i = 0; i < c; i++) { batches.GetItem(i, out batch); if (batch == null) { continue; } ValidateBatch(batch, true); task.Batch = batch; if (context.Async) { buffer.Data[j++] = task; totalAdded += 1; if (j == (blockSize - 1)) { Queue.EnqueueMany(new ArraySegment <Task>(buffer.Data, 0, j)); j = 0; } } else { task.Execute(); } } if (context.Async && (j > 0)) { Queue.EnqueueMany(new ArraySegment <Task>(buffer.Data, 0, j)); } } if (context.Async) { Group.NotifyQueuesChanged(); } }
public BufferPool <ItemInfo> .Buffer GetAsBuffer(out int count) { var result = BufferPool <ItemInfo> .Allocate(_Collection.Count); int i = 0; while (MoveNext()) { result.Data[i++] = _Current; } count = i; return(result); }
private void DrawPerformanceStats(ref ImperativeRenderer ir) { const float scale = 1f; var text = PerformanceStats.GetText(this); using (var buffer = BufferPool <BitmapDrawCall> .Allocate(text.Length)) { var layout = Font.LayoutString(text, buffer, scale: scale); var layoutSize = layout.Size; var position = new Vector2(30f, 30f); var dc = layout.DrawCalls; ir.FillRectangle( Bounds.FromPositionAndSize(position, layoutSize), Color.Black ); ir.Layer += 1; ir.DrawMultiple(dc, position); } }
public void DrawString( SpriteFont font, string text, Vector2 position, Color?color = null, float scale = 1, float?sortKey = null, int characterSkipCount = 0, int characterLimit = int.MaxValue, int?layer = null, bool?worldSpace = null, BlendState blendState = null, SamplerState samplerState = null ) { using (var buffer = BufferPool <BitmapDrawCall> .Allocate(text.Length)) { var layout = font.LayoutString( text, new ArraySegment <BitmapDrawCall>(buffer.Data), position, color, scale, sortKey.GetValueOrDefault(NextSortKey), characterSkipCount, characterLimit, alignToPixels: true ); DrawMultiple( layout, layer: layer, worldSpace: worldSpace, blendState: blendState, samplerState: samplerState ); } }
/// <summary> /// Renders all light sources into the target batch container on the specified layer. /// </summary> /// <param name="frame">Necessary for bookkeeping.</param> /// <param name="container">The batch container to render lighting into.</param> /// <param name="layer">The layer to render lighting into.</param> /// <param name="intensityScale">A factor to scale the intensity of all light sources. You can use this to rescale the intensity of light values for HDR.</param> public void RenderLighting(Frame frame, IBatchContainer container, int layer, float intensityScale = 1.0f) { // FIXME var pointLightVertexCount = Environment.LightSources.Count * 4; var pointLightIndexCount = Environment.LightSources.Count * 6; if (PointLightVertices.Length < pointLightVertexCount) { PointLightVertices = new PointLightVertex[1 << (int)Math.Ceiling(Math.Log(pointLightVertexCount, 2))]; } if ((PointLightIndices == null) || (PointLightIndices.Length < pointLightIndexCount)) { PointLightIndices = new short[pointLightIndexCount]; int i = 0, j = 0; while (i < pointLightIndexCount) { PointLightIndices[i++] = (short)(j + 0); PointLightIndices[i++] = (short)(j + 1); PointLightIndices[i++] = (short)(j + 3); PointLightIndices[i++] = (short)(j + 1); PointLightIndices[i++] = (short)(j + 2); PointLightIndices[i++] = (short)(j + 3); j += 4; } } var needStencilClear = true; int vertexOffset = 0, indexOffset = 0; LightSource batchFirstLightSource = null; BatchGroup currentLightGroup = null; int layerIndex = 0; using (var sortedLights = BufferPool <LightSource> .Allocate(Environment.LightSources.Count)) using (var resultGroup = BatchGroup.New(container, layer, before: StoreScissorRect, after: RestoreScissorRect)) { if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(resultGroup, -9999, "Frame {0:0000} : LightingRenderer {1:X4} : Begin", frame.Index, this.GetHashCode()); } int i = 0; var lightCount = Environment.LightSources.Count; foreach (var lightSource in Environment.LightSources) { sortedLights.Data[i++] = lightSource; } Array.Sort(sortedLights.Data, 0, lightCount, LightSourceComparerInstance); int lightGroupIndex = 1; for (i = 0; i < lightCount; i++) { var lightSource = sortedLights.Data[i]; if (lightSource.Opacity <= 0) { continue; } if (batchFirstLightSource != null) { var needFlush = (needStencilClear) || (batchFirstLightSource.ClipRegion.HasValue != lightSource.ClipRegion.HasValue) || (batchFirstLightSource.NeutralColor != lightSource.NeutralColor) || (batchFirstLightSource.Mode != lightSource.Mode) || (batchFirstLightSource.RampMode != lightSource.RampMode) || (batchFirstLightSource.RampTexture != lightSource.RampTexture) || (batchFirstLightSource.RampTextureFilter != lightSource.RampTextureFilter); if (needFlush) { if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(currentLightGroup, layerIndex++, "Frame {0:0000} : LightingRenderer {1:X4} : Point Light Flush ({2} point(s))", frame.Index, this.GetHashCode(), PointLightBatchBuffer.Count); } FlushPointLightBatch(ref currentLightGroup, ref batchFirstLightSource, ref layerIndex); indexOffset = 0; } } if (batchFirstLightSource == null) { batchFirstLightSource = lightSource; } if (currentLightGroup == null) { currentLightGroup = BatchGroup.New(resultGroup, lightGroupIndex++, before: RestoreScissorRect); } var lightBounds = new Bounds(lightSource.Position - new Vector2(lightSource.RampEnd), lightSource.Position + new Vector2(lightSource.RampEnd)); Bounds clippedLightBounds; if (lightSource.ClipRegion.HasValue) { var clipBounds = lightSource.ClipRegion.Value; if (!lightBounds.Intersection(ref lightBounds, ref clipBounds, out clippedLightBounds)) { continue; } } else { clippedLightBounds = lightBounds; } if (needStencilClear) { if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(currentLightGroup, layerIndex++, "Frame {0:0000} : LightingRenderer {1:X4} : Stencil Clear", frame.Index, this.GetHashCode()); } ClearBatch.AddNew(currentLightGroup, layerIndex++, IlluminantMaterials.ClearStencil, clearStencil: StencilFalse); needStencilClear = false; } NativeBatch stencilBatch = null; SpatialCollection <LightObstructionBase> .Sector currentSector; using (var e = Environment.Obstructions.GetSectorsFromBounds(lightBounds)) while (e.GetNext(out currentSector)) { var cachedSector = GetCachedSector(frame, currentSector.Index); if (cachedSector.VertexCount <= 0) { continue; } if (stencilBatch == null) { if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(currentLightGroup, layerIndex++, "Frame {0:0000} : LightingRenderer {1:X4} : Begin Stencil Shadow Batch", frame.Index, this.GetHashCode()); } stencilBatch = NativeBatch.New(currentLightGroup, layerIndex++, IlluminantMaterials.Shadow, ShadowBatchSetup, lightSource); stencilBatch.Dispose(); needStencilClear = true; if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(currentLightGroup, layerIndex++, "Frame {0:0000} : LightingRenderer {1:X4} : End Stencil Shadow Batch", frame.Index, this.GetHashCode()); } } stencilBatch.Add(new NativeDrawCall( PrimitiveType.TriangleList, cachedSector.ObstructionVertexBuffer, 0, cachedSector.ObstructionIndexBuffer, 0, 0, cachedSector.VertexCount, 0, cachedSector.PrimitiveCount )); } PointLightVertex vertex; vertex.LightCenter = lightSource.Position; vertex.Color = lightSource.Color; vertex.Color.W *= (lightSource.Opacity * intensityScale); vertex.Ramp = new Vector2(lightSource.RampStart, lightSource.RampEnd); vertex.Position = clippedLightBounds.TopLeft; PointLightVertices[vertexOffset++] = vertex; vertex.Position = clippedLightBounds.TopRight; PointLightVertices[vertexOffset++] = vertex; vertex.Position = clippedLightBounds.BottomRight; PointLightVertices[vertexOffset++] = vertex; vertex.Position = clippedLightBounds.BottomLeft; PointLightVertices[vertexOffset++] = vertex; var newRecord = new PointLightRecord { VertexOffset = vertexOffset - 4, IndexOffset = indexOffset, VertexCount = 4, IndexCount = 6 }; if (PointLightBatchBuffer.Count > 0) { var oldRecord = PointLightBatchBuffer[PointLightBatchBuffer.Count - 1]; if ( (newRecord.VertexOffset == oldRecord.VertexOffset + oldRecord.VertexCount) && (newRecord.IndexOffset == oldRecord.IndexOffset + oldRecord.IndexCount) ) { oldRecord.VertexCount += newRecord.VertexCount; oldRecord.IndexCount += newRecord.IndexCount; PointLightBatchBuffer[PointLightBatchBuffer.Count - 1] = oldRecord; } else { PointLightBatchBuffer.Add(newRecord); } } else { PointLightBatchBuffer.Add(newRecord); } indexOffset += 6; } if (PointLightBatchBuffer.Count > 0) { if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(currentLightGroup, layerIndex++, "Frame {0:0000} : LightingRenderer {1:X4} : Point Light Flush ({2} point(s))", frame.Index, this.GetHashCode(), PointLightBatchBuffer.Count); } FlushPointLightBatch(ref currentLightGroup, ref batchFirstLightSource, ref layerIndex); } if (Render.Tracing.RenderTrace.EnableTracing) { Render.Tracing.RenderTrace.Marker(resultGroup, 9999, "Frame {0:0000} : LightingRenderer {1:X4} : End", frame.Index, this.GetHashCode()); } } }
private CachedSector GetCachedSector(Frame frame, Pair <int> sectorIndex) { CachedSector result; if (!SectorCache.TryGetValue(sectorIndex, out result)) { SectorCache.Add(sectorIndex, result = new CachedSector { SectorIndex = sectorIndex }); } if (result.FrameIndex == frame.Index) { return(result); } var sector = Environment.Obstructions[sectorIndex]; int lineCount = 0; foreach (var item in sector) { lineCount += item.Item.LineCount; } result.PrimitiveCount = lineCount * 2; result.VertexCount = lineCount * 4; result.IndexCount = lineCount * 6; if ((result.ObstructionVertexBuffer != null) && (result.ObstructionVertexBuffer.VertexCount < result.VertexCount)) { lock (Coordinator.CreateResourceLock) result.ObstructionVertexBuffer.Dispose(); result.ObstructionVertexBuffer = null; } if ((result.ObstructionIndexBuffer != null) && (result.ObstructionIndexBuffer.IndexCount < result.IndexCount)) { lock (Coordinator.CreateResourceLock) result.ObstructionIndexBuffer.Dispose(); result.ObstructionIndexBuffer = null; } if (result.ObstructionVertexBuffer == null) { lock (Coordinator.CreateResourceLock) result.ObstructionVertexBuffer = new DynamicVertexBuffer(frame.RenderManager.DeviceManager.Device, (new ShadowVertex().VertexDeclaration), result.VertexCount, BufferUsage.WriteOnly); } if (result.ObstructionIndexBuffer == null) { lock (Coordinator.CreateResourceLock) result.ObstructionIndexBuffer = new DynamicIndexBuffer(frame.RenderManager.DeviceManager.Device, IndexElementSize.SixteenBits, result.IndexCount, BufferUsage.WriteOnly); } using (var va = BufferPool <ShadowVertex> .Allocate(result.VertexCount)) using (var ia = BufferPool <short> .Allocate(result.IndexCount)) { var vb = va.Data; var ib = ia.Data; ArrayLineWriterInstance.SetOutput(vb, ib); foreach (var itemInfo in sector) { itemInfo.Item.GenerateLines(ArrayLineWriterInstance); } var linesWritten = ArrayLineWriterInstance.Finish(); if (linesWritten != lineCount) { throw new InvalidDataException("GenerateLines didn't generate enough lines based on LineCount"); } lock (Coordinator.UseResourceLock) { result.ObstructionVertexBuffer.SetData(vb, 0, result.VertexCount, SetDataOptions.Discard); result.ObstructionIndexBuffer.SetData(ib, 0, result.IndexCount, SetDataOptions.Discard); } } result.FrameIndex = frame.Index; return(result); }
public static unsafe void WriteImage( byte *data, int dataLength, int width, int height, SurfaceFormat sourceFormat, Stream stream, ImageWriteFormat format = ImageWriteFormat.PNG, int jpegQuality = 75 ) { int numComponents; var bytesPerPixel = Evil.TextureUtils.GetBytesPerPixelAndComponents(sourceFormat, out numComponents); if (dataLength < (bytesPerPixel * width * height)) { throw new ArgumentException("buffer"); } using (var scratch = BufferPool <byte> .Allocate(1024 * 64)) fixed(byte *_pScratch = scratch.Data) { Native.WriteCallback callback = (pScratch, pData, count) => { int offset = 0; while (count > 0) { var copySize = Math.Min(count, scratch.Data.Length); Buffer.MemoryCopy(pData + offset, pScratch, copySize, copySize); stream.Write(scratch.Data, 0, copySize); count -= copySize; offset += copySize; } }; switch (format) { case ImageWriteFormat.HDR: if (bytesPerPixel != 16) { throw new NotImplementedException("Non-vector4"); } Native.API.stbi_write_hdr_to_func(callback, _pScratch, width, height, numComponents, (float *)(void *)data); break; case ImageWriteFormat.PNG: if (bytesPerPixel != 4) { throw new NotImplementedException("Non-rgba32"); } Native.API.stbi_write_png_to_func(callback, _pScratch, width, height, numComponents, data, width * bytesPerPixel); break; case ImageWriteFormat.BMP: if (bytesPerPixel != 4) { throw new NotImplementedException("Non-rgba32"); } Native.API.stbi_write_bmp_to_func(callback, _pScratch, width, height, numComponents, data); break; case ImageWriteFormat.TGA: if (bytesPerPixel != 4) { throw new NotImplementedException("Non-rgba32"); } Native.API.stbi_write_tga_to_func(callback, _pScratch, width, height, numComponents, data); break; case ImageWriteFormat.JPEG: if (bytesPerPixel != 4) { throw new NotImplementedException("Non-rgba32"); } Native.API.stbi_write_jpg_to_func(callback, _pScratch, width, height, numComponents, data, jpegQuality); break; default: throw new ArgumentOutOfRangeException("format"); } } }
protected void BroadcastToSubscribers(object source, string type, object arguments) { EventInfo info = null; EventSubscriberList subscribers; EventFilter filter; EventCategoryToken categoryToken = null; string categoryName = null; IEventSource iSource = source as IEventSource; if (iSource != null) { categoryName = iSource.CategoryName; categoryToken = GetCategory(categoryName); } for (int i = 0; i < 6; i++) { string typeFilter = (i & 1) == 1 ? type : AnyType; object sourceFilter; switch (i) { case 0: case 1: sourceFilter = AnySource; break; case 2: case 3: sourceFilter = categoryToken; break; default: sourceFilter = source; break; } if ((sourceFilter == null) || (typeFilter == null)) { continue; } CreateFilter( sourceFilter, typeFilter, out filter, false ); if (!_Subscribers.TryGetValue(filter, out subscribers)) { continue; } int count = subscribers.Count; if (count <= 0) { continue; } if (info == null) { info = new EventInfo(this, source, categoryToken, categoryName, type, arguments); } using (var b = BufferPool <EventSubscriber> .Allocate(count)) { var temp = b.Data; subscribers.CopyTo(temp); for (int j = count - 1; j >= 0; j--) { temp[j](info); if (info.IsConsumed) { return; } } b.Clear(); } } }
public static ResolvedMotion ResolvePolygonMotion(Polygon polygonA, Polygon polygonB, Vector2 velocityA) { var offset = ComputeComparisonOffset(polygonA, polygonB); var result = new ResolvedMotion(); result.AreIntersecting = true; result.WouldHaveIntersected = true; result.WillBeIntersecting = true; float velocityProjection; var velocityDistance = velocityA.Length(); var velocityAxis = Vector2.Normalize(velocityA); Interval intervalA, intervalB, newIntervalA; float minDistance = float.MaxValue; int bufferSize = polygonA.Count + polygonB.Count + 4; using (var axisBuffer = BufferPool <Vector2> .Allocate(bufferSize)) { int axisCount = 0; if (velocityA.LengthSquared() > 0) { axisCount += 4; axisBuffer.Data[0] = Vector2.Normalize(velocityA); axisBuffer.Data[1] = new Vector2(-axisBuffer.Data[0].X, axisBuffer.Data[0].Y); axisBuffer.Data[2] = new Vector2(axisBuffer.Data[0].X, -axisBuffer.Data[0].Y); axisBuffer.Data[3] = new Vector2(-axisBuffer.Data[0].X, -axisBuffer.Data[0].Y); } GetPolygonAxes(axisBuffer.Data, ref axisCount, polygonA); GetPolygonAxes(axisBuffer.Data, ref axisCount, polygonB); for (int i = 0; i < axisCount; i++) { var axis = axisBuffer.Data[i]; intervalA = ProjectOntoAxis(axis, polygonA, offset); intervalB = ProjectOntoAxis(axis, polygonB, offset); bool intersects = intervalA.Intersects(intervalB, Geometry.IntersectionEpsilon); if (!intersects) { result.AreIntersecting = false; } velocityProjection = axis.Dot(ref velocityA); newIntervalA = intervalA; newIntervalA.Min += velocityProjection; newIntervalA.Max += velocityProjection; var intersectionDistance = newIntervalA.GetDistance(intervalB); intersects = intersectionDistance < 0; if (!intersects) { result.WouldHaveIntersected = false; } if (result.WouldHaveIntersected == false) { result.WillBeIntersecting = false; result.ResultVelocity = velocityA; break; } if ((velocityDistance > 0) && (intersectionDistance < minDistance)) { var minVect = axis * intersectionDistance; var newVelocity = velocityA + minVect; var newLength = Vector2.Dot(velocityAxis, newVelocity); newVelocity = velocityAxis * newLength; if (newVelocity.LengthSquared() > velocityA.LengthSquared()) { continue; } if (Vector2.Dot(velocityA, newVelocity) < 0.0f) { newVelocity = Vector2.Zero; } velocityProjection = axis.Dot(ref newVelocity); newIntervalA.Min = (intervalA.Min + velocityProjection); newIntervalA.Max = (intervalA.Max + velocityProjection); intersectionDistance = newIntervalA.GetDistance(intervalB); if (intersectionDistance < -IntersectionEpsilon) { continue; } result.ResultVelocity = newVelocity; result.WillBeIntersecting = false; minDistance = intersectionDistance; } } } return(result); }
private IEnumerator <object> RequestTask(ListenerContext context, SocketDataAdapter adapter) { var startedWhen = DateTime.UtcNow; bool successful = false; try { const int headerBufferSize = 1024 * 32; const int bodyBufferSize = 1024 * 128; const double requestLineTimeout = 5; // RFC2616: // Words of *TEXT MAY contain characters from character sets other than ISO-8859-1 [22] // only when encoded according to the rules of RFC 2047 [14]. Encoding headerEncoding; try { headerEncoding = Encoding.GetEncoding("ISO-8859-1"); } catch { headerEncoding = Encoding.ASCII; } Request request; RequestBody body; HeaderCollection headers; long bodyBytesRead = 0; long? expectedBodyLength = null; var reader = new AsyncTextReader(adapter, headerEncoding, headerBufferSize, false); string requestLineText; while (true) { var fRequestLine = reader.ReadLine(); var fRequestOrTimeout = Scheduler.Start(new WaitWithTimeout(fRequestLine, requestLineTimeout)); yield return(fRequestOrTimeout); if (fRequestOrTimeout.Failed) { if (!(fRequestOrTimeout.Error is TimeoutException)) { OnRequestError(fRequestOrTimeout.Error); } yield break; } if (fRequestLine.Failed) { if (!(fRequestLine.Error is SocketDisconnectedException)) { OnRequestError(fRequestLine.Error); } yield break; } requestLineText = fRequestLine.Result; // RFC2616: // In the interest of robustness, servers SHOULD ignore any empty line(s) received where a // Request-Line is expected. In other words, if the server is reading the protocol stream // at the beginning of a message and receives a CRLF first, it should ignore the CRLF. if ((requestLineText != null) && (requestLineText.Trim().Length == 0)) { continue; } break; } var requestLineParsed = DateTime.UtcNow; headers = new HeaderCollection(); while (true) { var fHeaderLine = reader.ReadLine(); yield return(fHeaderLine); if (String.IsNullOrWhiteSpace(fHeaderLine.Result)) { break; } headers.Add(new Header(fHeaderLine.Result)); } var headersParsed = DateTime.UtcNow; var expectHeader = (headers.GetValue("Expect") ?? "").ToLowerInvariant(); var expectsContinue = expectHeader.Contains("100-continue"); string hostName; if (headers.Contains("Host")) { hostName = String.Format("http://{0}", headers["Host"].Value); } else { var lep = (IPEndPoint)adapter.Socket.LocalEndPoint; hostName = String.Format("http://{0}:{1}", lep.Address, lep.Port); } var requestLine = new RequestLine(hostName, requestLineText); var remainingBytes = reader.DisposeAndGetRemainingBytes(); bodyBytesRead += remainingBytes.Count; var connectionHeader = (headers.GetValue("Connection") ?? "").ToLowerInvariant(); var shouldKeepAlive = ((requestLine.Version == "1.1") || connectionHeader.Contains("keep-alive")) && !connectionHeader.Contains("close"); if (headers.Contains("Content-Length")) { expectedBodyLength = long.Parse(headers["Content-Length"].Value); } body = new RequestBody(remainingBytes, expectedBodyLength); if (expectsContinue) { yield return(adapter.Write(Continue100, 0, Continue100.Length)); } request = new Request( this, adapter, shouldKeepAlive, requestLine, headers, body ); IncomingRequests.Enqueue(request); var requestEnqueued = DateTime.UtcNow; DateTime?requestBodyRead = null; // FIXME: I think it's technically accepted to send a body without a content-length, but // it seems to be impossible to make that work right. if (expectedBodyLength.HasValue) { using (var bodyBuffer = BufferPool <byte> .Allocate(bodyBufferSize)) while (bodyBytesRead < expectedBodyLength.Value) { long bytesToRead = Math.Min(expectedBodyLength.Value - bodyBytesRead, bodyBufferSize); if (bytesToRead <= 0) { break; } var fBytesRead = adapter.Read(bodyBuffer.Data, 0, (int)bytesToRead); yield return(fBytesRead); if (fBytesRead.Failed) { if (fBytesRead.Error is SocketDisconnectedException) { break; } body.Failed(fBytesRead.Error); OnRequestError(fBytesRead.Error); yield break; } var bytesRead = fBytesRead.Result; bodyBytesRead += bytesRead; body.Append(bodyBuffer.Data, 0, bytesRead); } requestBodyRead = DateTime.UtcNow; } body.Finish(); successful = true; request.Timing = new Request.TimingData { Line = (requestLineParsed - startedWhen), Headers = (headersParsed - requestLineParsed), Queue = (requestEnqueued - headersParsed), Body = (requestBodyRead - requestEnqueued) }; } finally { if (!successful) { adapter.Dispose(); } } }