public FakeInput() { Baton = new Baton { Buffer = new ArraySegment<byte>(new byte[1024], 0, 0), }; WaitHandle = new ManualResetEvent(false); Encoding = Encoding.UTF8; }
public bool Consume(Baton baton, Action callback, Action<Exception> fault) { for (; ; ) { switch (_mode) { case Mode.StartLine: if (baton.RemoteIntakeFin) { _mode = Mode.Terminated; return false; } if (!TakeStartLine(baton)) { return false; } _mode = Mode.MessageHeader; break; case Mode.MessageHeader: if (baton.RemoteIntakeFin) { _mode = Mode.Terminated; return false; } var endOfHeaders = false; while (!endOfHeaders) { if (!TakeMessageHeader(baton, out endOfHeaders)) return false; } var resumeBody = HandleExpectContinue(callback); _messageBody = MessageBody.For( _httpVersion, _headers, () => { if (!Consume(baton, resumeBody, fault)) resumeBody.Invoke(); }); _keepAlive = _messageBody.RequestKeepAlive; _mode = Mode.MessageBody; Execute(); return true; case Mode.MessageBody: return _messageBody.Consume(baton, callback, fault); case Mode.Terminated: return false; } } }
public void SkipAdvancesBuffer() { // Arrange var baton = new Baton {Buffer = "xxhello world".ToArraySegment()}; baton.Skip(2); // Act baton.Skip(5); // Assert Assert.Equal(6, baton.Buffer.Count); Assert.Equal(" world", baton.Buffer.ToString(Encoding.Default)); }
public void AvailableBufferBringsOffsetBackToZeroIfOccupiedSegmentIsZeroLength() { // Arrange var baton = new Baton { Buffer = "xxhello worldxx".ToArraySegment() }; baton.Buffer = new ArraySegment<byte>(baton.Buffer.Array, 2, 0); // Act var buffer = baton.Available(0); // Assert Assert.Equal(15, buffer.Count); Assert.Equal("xxhello worldxx", buffer.ToString(Encoding.Default)); }
public void AvailableBufferReturnsAreaThatIsUnused() { // Arrange var baton = new Baton { Buffer = "xxhello worldxx".ToArraySegment() }; baton.Buffer = new ArraySegment<byte>(baton.Buffer.Array, 2, 5); // Act var buffer = baton.Available(0); // Assert Assert.Equal(8, buffer.Count); Assert.Equal(" worldxx", buffer.ToString(Encoding.Default)); }
public void Execute() { _trace.Event(TraceEventType.Start, TraceMessage.Connection); _baton = new Baton { Buffer = new ArraySegment<byte>(new byte[1024], 0, 0) }; _fault = ex => { Debug.WriteLine(ex.Message); }; _socketReceiveAsyncEventArgs = new SocketAsyncEventArgs(); _socketReceiveAsyncEventArgs.SetBuffer(new byte[0], 0, 0); _socketReceiveAsyncEventArgs.Completed += (_, __) => { try { Go(false); } catch (Exception ex) { _fault(ex); } }; _frameConsumeCallback = () => { try { Go(false); } catch (Exception ex) { _fault(ex); } }; try { _socket.Blocking = false; Go(true); } catch (Exception ex) { _fault(ex); } }
public void TakeAdvancesBufferAndReturnsTakenSegment() { // Arrange var baton = new Baton { Buffer = "xxhello world".ToArraySegment() }; baton.Skip(2); // Act var taken = baton.Take(5); // Assert Assert.Equal(6, baton.Buffer.Count); Assert.Equal(" world", baton.Buffer.ToString(Encoding.Default)); Assert.Equal(5, taken.Count); Assert.Equal("hello", taken.ToString(Encoding.Default)); }
public void ExtendCausesArraySegmentToIncludeMoreBytesAtTheEnd() { // Arrange var baton = new Baton { Buffer = "xxhello worldxx".ToArraySegment() }; baton.Buffer = new ArraySegment<byte>(baton.Buffer.Array, 2, 5); // Act var before = baton.Buffer.ToString(Encoding.Default); baton.Extend(5); var after = baton.Buffer.ToString(Encoding.Default); // Assert Assert.Equal("hello", before); Assert.Equal("hello worl", after); Assert.Equal(2, baton.Buffer.Offset); Assert.Equal(10, baton.Buffer.Count); }
public override bool TakeMessageHeader(Baton baton, out bool endOfHeaders) { endOfHeaders = false; var text = Encoding.Default.GetString(baton.Buffer.Array, baton.Buffer.Offset, baton.Buffer.Count); var lines = text.Split(new[] { "\r\n" }, StringSplitOptions.None); foreach (var line in lines) { if (line == "") { endOfHeaders = true; break; } var colonIndex = line.IndexOf(':'); AddRequestHeader(line.Substring(0, colonIndex), line.Substring(colonIndex + 1)); } return false; }
static void Main(string[] args) { var datas = File.ReadAllText("Headers.txt") .Split(new[] { "\r\n\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Select(chunk => Encoding.Default.GetBytes(chunk + "\r\n\r\nAll of the data")) .ToArray(); for (; ; ) { var samples = Enumerable.Range(0, 10); var measures = Strats() .Select(s => new { Strat = s, Stopwatch = samples .Select(x => new Stopwatch()) .ToArray() }).ToArray(); Console.WriteLine("Starting"); foreach (var sample in samples) { foreach (var data in datas) { foreach (var measure in measures) { Action after = () => { }; measure.Stopwatch[sample].Start(); foreach (var loop in Enumerable.Range(0, 10000)) { var strat = measure.Strat(); var baton = new Baton { Buffer = new ArraySegment<byte>(data), RemoteIntakeFin = false, }; var endOfHeaders = false; while (!endOfHeaders) { if (!strat.TakeMessageHeader(baton, out endOfHeaders)) { break; } } if (loop == 0 && sample == 0) { after = () => { Console.WriteLine("{0}", strat.GetType().Name); foreach (var kv in strat.Headers) { Console.WriteLine(" {0}: {1}", kv.Key, kv.Value); } }; } } measure.Stopwatch[sample].Stop(); after(); } } } foreach (var measure in measures) { Console.WriteLine( "{0} {1}\r\n {2}", measure.Strat().GetType().Name, measure.Stopwatch .Aggregate(TimeSpan.Zero, (a, b) => a.Add(b.Elapsed)), measure.Stopwatch .Select(x => x.ElapsedTicks) .OrderBy(x => x) .Aggregate("", (a, b) => a + " " + b)); } Console.WriteLine("Done"); Console.ReadLine(); } }
public abstract bool Consume(Baton baton, Action callback, Action<Exception> fault);
public override bool Consume(Baton baton, Action callback, Action<Exception> fault) { if (baton.RemoteIntakeFin) { LocalIntakeFin = true; _subscriber.Complete(); return false; } var consumed = baton.Take(baton.Buffer.Count); return _subscriber.Next(consumed, callback); }
public override bool Consume(Baton baton, Action callback, Action<Exception> fault) { var consumeLength = Math.Min(_neededLength, baton.Buffer.Count); _neededLength -= consumeLength; var consumed = baton.Take(consumeLength); if (_neededLength != 0) { // TODO: if check baton.Complete==true && neededlength != 0 then remote socket closed early return _subscriber.Next(consumed, callback); } LocalIntakeFin = true; if (consumed.Count != 0) { var delayed = _subscriber.Next( consumed, () => { _subscriber.Complete(); callback(); }); if (delayed) { return true; } _subscriber.Complete(); return false; } _subscriber.Complete(); return false; }
private static bool TakeChunkedLine(Baton baton, ref int chunkSizeOut) { var remaining = baton.Buffer; if (remaining.Count < 2) return false; var ch0 = remaining.Array[remaining.Offset]; var chunkSize = 0; var mode = 0; for (var index = 0; index != remaining.Count - 1; ++index) { var ch1 = remaining.Array[remaining.Offset + index + 1]; if (mode == 0) { if (ch0 >= '0' && ch0 <= '9') { chunkSize = chunkSize * 0x10 + (ch0 - '0'); } else if (ch0 >= 'A' && ch0 <= 'F') { chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10)); } else if (ch0 >= 'a' && ch0 <= 'f') { chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10)); } else { throw new NotImplementedException("INVALID REQUEST FORMAT"); } mode = 1; } else if (mode == 1) { if (ch0 >= '0' && ch0 <= '9') { chunkSize = chunkSize * 0x10 + (ch0 - '0'); } else if (ch0 >= 'A' && ch0 <= 'F') { chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10)); } else if (ch0 >= 'a' && ch0 <= 'f') { chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10)); } else if (ch0 == ';') { mode = 2; } else if (ch0 == '\r' && ch1 == '\n') { baton.Skip(index + 2); chunkSizeOut = chunkSize; return true; } else { throw new NotImplementedException("INVALID REQUEST FORMAT"); } } else if (mode == 2) { if (ch0 == '\r' && ch1 == '\n') { baton.Skip(index + 2); chunkSizeOut = chunkSize; return true; } else { // chunk-extensions not currently parsed } } ch0 = ch1; } return false; }
public override bool Consume(Baton baton, Action callback, Action<Exception> fault) { for (; ; ) { switch (_mode) { case Mode.ChunkSizeLine: var chunkSize = 0; if (!TakeChunkedLine(baton, ref chunkSize)) { return false; } _neededLength = chunkSize; if (chunkSize == 0) { _mode = Mode.Complete; LocalIntakeFin = true; _subscriber.Complete(); return false; } _mode = Mode.ChunkData; break; case Mode.ChunkData: if (_neededLength == 0) { _mode = Mode.ChunkDataCRLF; break; } if (baton.Buffer.Count == 0) { return false; } var consumeLength = Math.Min(_neededLength, baton.Buffer.Count); _neededLength -= consumeLength; var consumed = baton.Take(consumeLength); var paused = _subscriber.Next( consumed, () => { try { if (!Consume(baton, callback, fault)) callback(); } catch (Exception ex) { fault(ex); } }); if (paused) { return true; } break; case Mode.ChunkDataCRLF: if (baton.Buffer.Count < 2) return false; var crlf = baton.Take(2); if (crlf.Array[crlf.Offset] != '\r' || crlf.Array[crlf.Offset + 1] != '\n') { throw new NotImplementedException("INVALID REQUEST FORMAT"); } _mode = Mode.ChunkSizeLine; break; default: throw new NotImplementedException("INVALID REQUEST FORMAT"); } } }
public abstract bool TakeMessageHeader(Baton baton, out bool endOfHeaders);
private bool TakeStartLine(Baton baton) { var remaining = baton.Buffer; if (remaining.Count < 2) return false; var firstSpace = -1; var secondSpace = -1; var questionMark = -1; var ch0 = remaining.Array[remaining.Offset]; for (var index = 0; index != remaining.Count - 1; ++index) { var ch1 = remaining.Array[remaining.Offset + index + 1]; if (ch0 == '\r' && ch1 == '\n') { if (secondSpace == -1) { throw new InvalidOperationException("INVALID REQUEST FORMAT"); } _method = GetString(remaining, 0, firstSpace); _requestUri = GetString(remaining, firstSpace + 1, secondSpace); if (questionMark == -1) { _path = _requestUri; _queryString = string.Empty; } else { _path = GetString(remaining, firstSpace + 1, questionMark); _queryString = GetString(remaining, questionMark + 1, secondSpace); } _httpVersion = GetString(remaining, secondSpace + 1, index); baton.Skip(index + 2); return true; } if (ch0 == ' ' && firstSpace == -1) { firstSpace = index; } else if (ch0 == ' ' && firstSpace != -1 && secondSpace == -1) { secondSpace = index; } else if (ch0 == '?' && firstSpace != -1 && questionMark == -1 && secondSpace == -1) { questionMark = index; } ch0 = ch1; } return false; }
public unsafe override bool TakeMessageHeader(Baton baton, out bool endOfHeaders) { var remaining = baton.Buffer; endOfHeaders = false; if (remaining.Count < 2) return false; var ch0 = remaining.Array[remaining.Offset]; var ch1 = remaining.Array[remaining.Offset + 1]; if (ch0 == '\r' && ch1 == '\n') { endOfHeaders = true; baton.Skip(2); return true; } if (remaining.Count < 3) return false; var wrappedHeaders = false; var colonIndex = -1; var valueStartIndex = -1; var valueEndIndex = -1; var indexEnd = remaining.Count - 2; fixed (byte* pch = remaining.Array) { var scan = pch + remaining.Offset + 2; for (var index = 0; index != indexEnd; ++index) { var ch2 = *scan++; if (ch0 == '\r' && ch1 == '\n' && ch2 != ' ' && ch2 != '\t') { var name = Encoding.Default.GetString(remaining.Array, remaining.Offset, colonIndex); var value = ""; if (valueEndIndex != -1) value = Encoding.Default.GetString(remaining.Array, remaining.Offset + valueStartIndex, valueEndIndex - valueStartIndex); if (wrappedHeaders) value = value.Replace("\r\n", " "); AddRequestHeader(name, value); baton.Skip(index + 2); return true; } if (colonIndex == -1 && ch0 == ':') { colonIndex = index; } else if (colonIndex != -1 && ch0 != ' ' && ch0 != '\t' && ch0 != '\r' && ch0 != '\n') { if (valueStartIndex == -1) valueStartIndex = index; valueEndIndex = index + 1; } else if (!wrappedHeaders && ch0 == '\r' && ch1 == '\n' && (ch2 == ' ' || ch2 == '\t')) { wrappedHeaders = true; } ch0 = ch1; ch1 = ch2; } } return false; }
public override bool TakeMessageHeader(Baton baton, out bool endOfHeaders) { endOfHeaders = false; return false; }