private const int MaxBufferSize = 1 << 20; // Max ArrayPool<byte>.Shared buffer size. public static void GetHashFinal(this HashAlgorithm alg, ByteSpan hash) { var data = new byte[0]; alg.TransformFinalBlock(data, 0, 0); alg.Hash.CopyTo(hash); }
public static bool TryParseRequestUri(ByteSpan buffer, out Utf8Span requestUri, out int parsedBytes) { var uriSpan = HttpReader.SliceTo(buffer, HttpReader.s_SP, out parsedBytes); requestUri = new Utf8Span(uriSpan); return(parsedBytes != 0); }
public static bool TryParseHttpVersion(ByteSpan buffer, out Utf8Span httpVersion, out int parsedBytes) { var versionSpan = HttpReader.SliceTo(buffer, HttpReader.s_CR, HttpReader.s_LF, out parsedBytes); httpVersion = new Utf8Span(versionSpan); return(parsedBytes != 0); }
public override bool TryDecode(string hex, ByteSpan bytes) { if (hex.Length % 2 == 1) { throw new ArgumentException("Invalid hex bytes string.", nameof(hex)); } if (hex.Length != bytes.Length * 2) { throw new ArgumentException("Length mismatch.", nameof(bytes)); } for (int i = 0, j = bytes.Length; i < hex.Length;) { var a = CharToNibble(hex[i++]); var b = CharToNibble(hex[i++]); if (a == -1 || b == -1) { return(false); } bytes[--j] = (byte)((a << 4) | b); } return(true); }
public static bool TryParseMethod(ByteSpan buffer, out HttpMethod method, out int parsedBytes) { if (buffer.StartsWith(s_Get.Bytes)) { method = HttpMethod.Get; parsedBytes = s_Get.Length; return(true); } if (buffer.StartsWith(s_Post.Bytes)) { method = HttpMethod.Post; parsedBytes = s_Post.Length; return(true); } if (buffer.StartsWith(s_Put.Bytes)) { method = HttpMethod.Put; parsedBytes = s_Put.Length; return(true); } if (buffer.StartsWith(s_Delete.Bytes)) { method = HttpMethod.Delete; parsedBytes = s_Delete.Length; return(true); } method = HttpMethod.Unknown; parsedBytes = 0; return(false); }
void pack_roundtrip_check <T>(BitSize bitcount) where T : unmanaged { var src = Random.BitString(bitcount); Claim.eq(bitcount, src.Length); var x = src.ToBits(); Claim.eq(bitcount, x.Length); var y = Bits.pack(x); var sizeT = size <T>(); var q = Math.DivRem(bitcount, 8, out int r); var bytes = q + (r == 0 ? 0 : 1); Claim.eq(bytes, y.Length); var bulk = ByteSpan.ReadValues <T>(y, out Span <byte> rem); var merged = rem.Length != 0 ? bulk.Extend(bulk.Length + 1) : bulk; if (merged.Length != bulk.Length) { merged[merged.Length - 1] = rem.TakeScalar <T>(); } var bsOutput = merged.ToBitString().Truncate(bitcount); Claim.eq(src, bsOutput); Claim.eq((src & ~bsOutput).PopCount(), 0); }
void OnReadWindows(UVBuffer.Windows buffer, IntPtr bytesAvaliable) { // TODO: all branches need to release buffer, I think long bytesRead = bytesAvaliable.ToInt64(); if (bytesRead == 0) { buffer.Dispose(); return; } else if (bytesRead < 0) { var error = UVException.ErrorCodeToError((int)bytesRead); if (error == UVError.EOF) { OnEndOfStream(); Dispose(); buffer.Dispose(); } else { Dispose(); buffer.Dispose(); throw new UVException((int)bytesRead); } } else { var readSlice = new ByteSpan((byte *)buffer.Buffer, (int)bytesRead); OnReadCompleted(readSlice); buffer.Dispose(); } }
void OnReadCompleted(ByteSpan bytesRead) { if (ReadCompleted != null) { ReadCompleted(bytesRead); } }
// Write a 32-bit integer in big-endian format to output[0..4) public static void WriteBigEndian32(this ByteSpan output, uint value, int offset) { output[offset + 0] = (byte)(value >> 24); output[offset + 1] = (byte)(value >> 16); output[offset + 2] = (byte)(value >> 8); output[offset + 3] = (byte)(value >> 0); }
public unsafe void ByteSpanEqualsTestsTwoDifferentInstancesOfBuffersWithSameValues() { const int bufferLength = 128; byte[] buffer1 = new byte[bufferLength]; byte[] buffer2 = new byte[bufferLength]; for (int i = 0; i < bufferLength; i++) { buffer1[i] = (byte)(bufferLength + 1 - i); buffer2[i] = (byte)(bufferLength + 1 - i); } fixed(byte *buffer1pinned = buffer1) fixed(byte *buffer2pinned = buffer2) { ByteSpan b1 = new ByteSpan(buffer1pinned, bufferLength); ByteSpan b2 = new ByteSpan(buffer2pinned, bufferLength); for (int i = 0; i < bufferLength; i++) { Assert.True(b1.Slice(i).Equals(b2.Slice(i))); } } }
/// <summary> /// Validates the authentication tag against the provided additional /// data, then decrypts the cipher text returning the original /// plaintext. /// </summary> /// <param name="nonce"> /// The unique value used to seal this message /// </param> /// <param name="ciphertext"> /// Combined ciphertext and authentication tag /// </param> /// <param name="associatedData"> /// Additional data used to authenticate the message /// </param> /// <param name="output"> /// On successful validation and decryprion, Open writes the original /// plaintext to output. Must contain enough space to hold /// `ciphertext.Length - CiphertextOverhead` bytes. /// </param> /// <returns> /// True if the data was validated and successfully decrypted. /// Otherwise, false. /// </returns> public bool Open(ByteSpan output, ByteSpan nonce, ByteSpan ciphertext, ByteSpan associatedData) { if (nonce.Length != NonceSize) { throw new ArgumentException("Invalid nonce size", nameof(nonce)); } if (ciphertext.Length < CiphertextOverhead) { throw new ArgumentException("Invalid ciphertext size", nameof(ciphertext)); } else if (output.Length < ciphertext.Length - CiphertextOverhead) { throw new ArgumentException("Invalid output size", nameof(output)); } // Split ciphertext into actual ciphertext and authentication // tag components. ByteSpan authenticationTag = ciphertext.Slice(ciphertext.Length - TagSize); ciphertext = ciphertext.Slice(0, ciphertext.Length - TagSize); // Create the initial counter block nonce.CopyTo(this.blockJ_); // Verify the tags match GenerateAuthenticationTag(this.blockScratch_, ciphertext, associatedData); if (0 == Const.ConstantCompareSpans(this.blockScratch_, authenticationTag)) { return(false); } // Decrypt the cipher text to output GCTR(output, this.blockJ_, 2, ciphertext); return(true); }
/// <inheritdoc /> public void EncodeServerKeyExchangeMessage(ByteSpan output, object privateKey) { RSA rsaPrivateKey = privateKey as RSA; if (rsaPrivateKey == null) { throw new ArgumentException("Invalid private key", nameof(privateKey)); } output[0] = (byte)ECCurveType.NamedCurve; output.WriteBigEndian16((ushort)NamedCurve.x25519, 1); output[3] = (byte)X25519.KeySize; X25519.Func(output.Slice(4, X25519.KeySize), this.privateAgreementKey); // Hash the key parameters byte[] paramterDigest = this.sha256.ComputeHash(output.GetUnderlyingArray(), output.Offset, 4 + X25519.KeySize); // Sign the paramter digest RSAPKCS1SignatureFormatter signer = new RSAPKCS1SignatureFormatter(rsaPrivateKey); signer.SetHashAlgorithm("SHA256"); ByteSpan signature = signer.CreateSignature(paramterDigest); Debug.Assert(signature.Length == rsaPrivateKey.KeySize / 8); output[4 + X25519.KeySize] = (byte)HashAlgorithm.Sha256; output[5 + X25519.KeySize] = (byte)SignatureAlgorithm.RSA; output.Slice(6 + X25519.KeySize).WriteBigEndian16((ushort)signature.Length); signature.CopyTo(output.Slice(8 + X25519.KeySize)); }
/// <summary> /// Flush any queued application data packets /// </summary> private void FlushQueuedApplicationData() { foreach (ByteSpan queuedSpan in this.queuedApplicationData) { Record outgoingRecord = new Record(); outgoingRecord.ContentType = ContentType.ApplicationData; outgoingRecord.Epoch = this.epoch; outgoingRecord.SequenceNumber = this.currentEpoch.NextOutgoingSequence; outgoingRecord.Length = (ushort)this.currentEpoch.RecordProtection.GetEncryptedSize(queuedSpan.Length); ++this.currentEpoch.NextOutgoingSequence; // Encode the record to wire format ByteSpan packet = new byte[Record.Size + outgoingRecord.Length]; ByteSpan writer = packet; outgoingRecord.Encode(writer); writer = writer.Slice(Record.Size); queuedSpan.CopyTo(writer); // Protect the record this.currentEpoch.RecordProtection.EncryptClientPlaintext( packet.Slice(Record.Size, outgoingRecord.Length) , packet.Slice(Record.Size, queuedSpan.Length) , ref outgoingRecord ); base.WriteBytesToConnection(packet.GetUnderlyingArray(), packet.Length); } this.queuedApplicationData.Clear(); }
public Utf8String(ByteSpan buffer) { _buffer = buffer; _bytes = null; _index = 0; _length = 0; }
/// <summary> /// Parse a Handshake HelloVerifyRequest payload from wire /// format /// </summary> /// <returns> /// True if we successfully decode the HelloVerifyRequest /// message. Otherwise false. /// </returns> public static bool Parse(out HelloVerifyRequest result, ByteSpan span) { result = new HelloVerifyRequest(); if (span.Length < 3) { return(false); } ProtocolVersion serverVersion = (ProtocolVersion)span.ReadBigEndian16(0); if (serverVersion != ProtocolVersion.DTLS1_2) { return(false); } byte cookieSize = span[2]; span = span.Slice(3); if (span.Length < cookieSize) { return(false); } result.Cookie = span; return(true); }
/// <summary> /// Expand a secret key /// </summary> /// <param name="output">Output span. Length determines how much data to generate</param> /// <param name="key">Original key to expand</param> /// <param name="label">Label (treated as a salt)</param> /// <param name="initialSeed">Seed for expansion (treated as a salt)</param> public static void ExpandSecret(ByteSpan output, ByteSpan key, ByteSpan label, ByteSpan initialSeed) { ByteSpan writer = output; byte[] roundSeed = new byte[label.Length + initialSeed.Length]; label.CopyTo(roundSeed); initialSeed.CopyTo(roundSeed, label.Length); byte[] hashA = roundSeed; using (HMACSHA256 hmac = new HMACSHA256(key.ToArray())) { byte[] input = new byte[hmac.OutputBlockSize + roundSeed.Length]; new ByteSpan(roundSeed).CopyTo(input, hmac.OutputBlockSize); while (writer.Length > 0) { // Update hashA hashA = hmac.ComputeHash(hashA); // generate hash input new ByteSpan(hashA).CopyTo(input); ByteSpan roundOutput = hmac.ComputeHash(input); if (roundOutput.Length > writer.Length) { roundOutput = roundOutput.Slice(0, writer.Length); } roundOutput.CopyTo(writer); writer = writer.Slice(roundOutput.Length); } } }
/// <summary> /// Parse a Handshake ServerHello payload from wire format /// </summary> /// <returns> /// True if we successfully decode the ServerHello /// message. Otherwise false. /// </returns> public static bool Parse(out ServerHello result, ByteSpan span) { result = new ServerHello(); if (span.Length < Size) { return(false); } ProtocolVersion serverVersion = (ProtocolVersion)span.ReadBigEndian16(); span = span.Slice(2); result.Random = span.Slice(0, Dtls.Random.Size); span = span.Slice(Dtls.Random.Size); byte sessionKeySize = span[0]; span = span.Slice(1 + sessionKeySize); result.CipherSuite = (CipherSuite)span.ReadBigEndian16(); span = span.Slice(2); CompressionMethod compressionMethod = (CompressionMethod)span[0]; if (compressionMethod != CompressionMethod.Null) { return(false); } return(true); }
public static bool TryDecodeCodePoint(ByteSpan buffer, out UnicodeCodePoint codePoint, out int encodedBytes) { if (buffer.Length == 0) { codePoint = default(UnicodeCodePoint); encodedBytes = default(int); return false; } byte first = buffer[0]; if (!TryGetFirstByteCodePointValue(first, out codePoint, out encodedBytes)) return false; if (buffer.Length < encodedBytes) return false; // TODO: Should we manually inline this for values 1-4 or will compiler do this for us? for (int i = 1; i < encodedBytes; i++) { if (!TryReadCodePointByte(buffer[i], ref codePoint)) return false; } return true; }
public unsafe void ByteSpanEqualsTestsTwoDifferentInstancesOfBuffersWithOneValueDifferent() { const int bufferLength = 128; byte[] buffer1 = new byte[bufferLength]; byte[] buffer2 = new byte[bufferLength]; for (int i = 0; i < bufferLength; i++) { buffer1[i] = (byte)(bufferLength + 1 - i); buffer2[i] = (byte)(bufferLength + 1 - i); } fixed(byte *buffer1pinned = buffer1) fixed(byte *buffer2pinned = buffer2) { ByteSpan b1 = new ByteSpan(buffer1pinned, bufferLength); ByteSpan b2 = new ByteSpan(buffer2pinned, bufferLength); for (int i = 0; i < bufferLength; i++) { for (int diffPosition = i; diffPosition < bufferLength; diffPosition++) { buffer1[diffPosition] = unchecked ((byte)(buffer1[diffPosition] + 1)); Assert.False(b1.Slice(i).Equals(b2.Slice(i))); } } } }
internal static bool TryParseHttpVersion(ByteSpan buffer, out Utf8String httpVersion, out int parsedBytes) { var versionSpan = buffer.SliceTo(HttpRequestReader.s_CR, HttpRequestReader.s_LF, out parsedBytes); httpVersion = new Utf8String(versionSpan); return(parsedBytes != 0); }
internal static bool TryParseRequestUri(ByteSpan buffer, out Utf8String requestUri, out int parsedBytes) { var uriSpan = buffer.SliceTo(HttpRequestReader.s_SP, out parsedBytes); requestUri = new Utf8String(uriSpan); return(parsedBytes != 0); }
internal static bool TryParseRequestLine(ByteSpan buffer, out HttpRequestLine requestLine, out int totalParsedBytes) { requestLine = new HttpRequestLine(); totalParsedBytes = 0; var reader = new HttpRequestReader(); reader.Buffer = buffer; requestLine.Method = reader.ReadMethod(); if (requestLine.Method == HttpMethod.Unknown) { return(false); } requestLine.RequestUri = reader.ReadRequestUri(); if (requestLine.RequestUri.Length == 0) { return(false); } requestLine.Version = reader.ReadHttpVersion(); if (requestLine.Version == HttpVersion.Unknown) { return(false); } totalParsedBytes = buffer.Length - reader.Buffer.Length; return(true); }
/// <summary> /// Clear a span's contents to zero /// </summary> public static void SecureClear(this ByteSpan span) { if (span.Length > 0) { Array.Clear(span.GetUnderlyingArray(), span.Offset, span.Length); } }
public Utf8Span ReadHeader() { int parsedBytes; var header = SliceTo(Buffer, s_CR, s_LF, out parsedBytes); Buffer = Buffer.Slice(parsedBytes); return new Utf8Span(header); }
/// <summary> /// Creates a new instance of an AEAD_AES128_GCM cipher /// </summary> /// <param name="key">Symmetric key</param> public Aes128Gcm(ByteSpan key) { if (key.Length != KeySize) { throw new ArgumentException("Invalid key length", nameof(key)); } // Create the AES block cipher using (Aes aes = Aes.Create()) { aes.KeySize = 128; aes.KeySize = 128; aes.BlockSize = 128; aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.Zeros; aes.Key = key.ToArray(); this.encryptor_ = aes.CreateEncryptor(); } // Allocate scratch space ByteSpan scratchSpace = new byte[96]; this.hashSubkey_ = scratchSpace.Slice(0, 16); this.blockJ_ = scratchSpace.Slice(16, 16); this.blockS_ = scratchSpace.Slice(32, 16); this.blockZ_ = scratchSpace.Slice(48, 16); this.blockV_ = scratchSpace.Slice(64, 16); this.blockScratch_ = scratchSpace.Slice(80, 16); // Create the GHASH subkey by encrypting the 0-block this.encryptor_.TransformBlock(this.hashSubkey_.GetUnderlyingArray(), this.hashSubkey_.Offset, this.hashSubkey_.Length, this.hashSubkey_.GetUnderlyingArray(), this.hashSubkey_.Offset); }
/// <summary> /// Encode Handshake ClientHello payload to wire format /// </summary> public void Encode(ByteSpan span) { span.WriteBigEndian16((ushort)ProtocolVersion.DTLS1_2); span = span.Slice(2); Debug.Assert(this.Random.Length == Dtls.Random.Size); this.Random.CopyTo(span); span = span.Slice(Dtls.Random.Size); // Do not encode session ids span[0] = (byte)0; span = span.Slice(1); span[0] = (byte)this.Cookie.Length; this.Cookie.CopyTo(span.Slice(1)); span = span.Slice(1 + this.Cookie.Length); span.WriteBigEndian16((ushort)this.CipherSuites.Length); this.CipherSuites.CopyTo(span.Slice(2)); span = span.Slice(2 + this.CipherSuites.Length); span[0] = 1; span[1] = (byte)CompressionMethod.Null; span = span.Slice(2); // Extensions size span.WriteBigEndian16((ushort)(6 + this.SupportedCurves.Length)); span = span.Slice(2); // Supported curves extension span.WriteBigEndian16((ushort)ExtensionType.EllipticCurves); span.WriteBigEndian16((ushort)(2 + this.SupportedCurves.Length), 2); span.WriteBigEndian16((ushort)this.SupportedCurves.Length, 4); this.SupportedCurves.CopyTo(span.Slice(6)); }
// Run the GHASH function void GHASH(ByteSpan output, ByteSpan data, int numBlocks) { ///TODO(mendsley): See Ref[6] for opitmizations of GHASH on both hardware and software /// ///[6] D. McGrew, J. Viega, The Galois/Counter Mode of Operation (GCM), Natl. Inst. Stand. ///Technol. [Web page], http://www.csrc.nist.gov/groups/ST/toolkit/BCM/documents/ ///proposedmodes / gcm / gcm - revised - spec.pdf, May 31, 2005. Debug.Assert(output.Length == 16); Debug.Assert(data.Length >= numBlocks * 16); int readIndex = 0; for (int ii = 0; ii != numBlocks; ++ii) { for (int jj = 0; jj != 16; ++jj, ++readIndex) { // Y[ii-1] xor X[ii] output[jj] ^= data[readIndex]; } // Y[ii] = (Y[ii-1] xor X[ii]) · H MultiplyGF128Elements(output, this.hashSubkey_, this.blockZ_, this.blockV_); } }
// Set the contents of a span to all zero static void SetSpanToZeros(ByteSpan span) { for (int ii = 0, nn = span.Length; ii != nn; ++ii) { span[ii] = 0; } }
public bool TryCopyTo(ref ByteSpan span) { if (IsRaw) { var len = (int)Length; if (len > span.Length) { goto fail; } Operand.Data.Sequence.CopyTo(span.Slice(0, len)); span = span.Slice(len); } else { if (!Operand.TryCopyTo(ref span)) { goto fail; } } return(true); fail: return(false); }
// Run the GCTR cipher void GCTR(ByteSpan output, ByteSpan counterBlock, uint counter, ByteSpan data) { Debug.Assert(counterBlock.Length == 16); Debug.Assert(output.Length >= data.Length); // Loop through plaintext blocks int writeIndex = 0; int numBlocks = (data.Length + 15) / 16; for (int ii = 0; ii != numBlocks; ++ii) { // Encode counter into block // CB[1] = J0 // CB[i] = inc[32](CB[i-1]) counterBlock.WriteBigEndian32(counter, 12); ++counter; // CIPH[k](CB[i]) this.encryptor_.EncryptBlock(counterBlock.Slice(0, 16), this.blockScratch_); // Y[i] = X[i] xor CIPH[k](CB[i]) for (int jj = 0; jj != 16 && writeIndex < data.Length; ++jj, ++writeIndex) { output[writeIndex] = (byte)(data[writeIndex] ^ this.blockScratch_[jj]); } } }
protected virtual void QueueRawData(ByteSpan span, IPEndPoint remoteEndPoint) { this.sendQueue.TryAdd(new SendMessageInfo() { Span = span, Recipient = remoteEndPoint }); }
public static bool TryEncodeCodePoint(UnicodeCodePoint codePoint, ByteSpan buffer, out int encodedBytes) { encodedBytes = GetNumberOfEncodedBytes(codePoint); if (encodedBytes > buffer.Length) return false; switch (encodedBytes) { case 1: buffer[0] = (byte)(mask_0111_1111 & codePoint.Value); return true; case 2: buffer[0] = (byte)(((codePoint.Value >> 6) & mask_0001_1111) | mask_1100_0000); buffer[1] = (byte)(((codePoint.Value >> 0) & mask_0011_1111) | mask_1000_0000); return true; case 3: buffer[0] = (byte)(((codePoint.Value >> 12) & mask_0000_1111) | mask_1110_0000); buffer[1] = (byte)(((codePoint.Value >> 6) & mask_0011_1111) | mask_1000_0000); buffer[2] = (byte)(((codePoint.Value >> 0) & mask_0011_1111) | mask_1000_0000); return true; case 4: buffer[0] = (byte)(((codePoint.Value >> 18) & mask_0000_0111) | mask_1111_0000); buffer[1] = (byte)(((codePoint.Value >> 12) & mask_0011_1111) | mask_1000_0000); buffer[2] = (byte)(((codePoint.Value >> 6) & mask_0011_1111) | mask_1000_0000); buffer[3] = (byte)(((codePoint.Value >> 0) & mask_0011_1111) | mask_1000_0000); return true; default: return false; } }
/// <summary> /// Create a new instance of the AES128_GCM record protection /// </summary> /// <param name="masterSecret">Shared secret</param> /// <param name="serverRandom">Server random data</param> /// <param name="clientRandom">Client random data</param> public Aes128GcmRecordProtection(ByteSpan masterSecret, ByteSpan serverRandom, ByteSpan clientRandom) { ByteSpan combinedRandom = new byte[serverRandom.Length + clientRandom.Length]; serverRandom.CopyTo(combinedRandom); clientRandom.CopyTo(combinedRandom.Slice(serverRandom.Length)); // Expand master_secret to encryption keys const int ExpandedSize = 0 + 0 // mac_key_length + 0 // mac_key_length + Aes128Gcm.KeySize // enc_key_length + Aes128Gcm.KeySize // enc_key_length + ImplicitNonceSize // fixed_iv_length + ImplicitNonceSize // fixed_iv_length ; ByteSpan expandedKey = new byte[ExpandedSize]; PrfSha256.ExpandSecret(expandedKey, masterSecret, PrfLabel.KEY_EXPANSION, combinedRandom); ByteSpan clientWriteKey = expandedKey.Slice(0, Aes128Gcm.KeySize); ByteSpan serverWriteKey = expandedKey.Slice(Aes128Gcm.KeySize, Aes128Gcm.KeySize); this.clientWriteIV = expandedKey.Slice(2 * Aes128Gcm.KeySize, ImplicitNonceSize); this.serverWriteIV = expandedKey.Slice(2 * Aes128Gcm.KeySize + ImplicitNonceSize, ImplicitNonceSize); this.serverWriteCipher = new Aes128Gcm(serverWriteKey); this.clientWriteCipher = new Aes128Gcm(clientWriteKey); }
public int BufferIndexFromSpanAddress(ref ByteSpan span) { var buffer = (ulong)span._data; var firstBuffer = (ulong)_memory; var offset = buffer - firstBuffer; var index = offset / (ulong)_bufferSizeInBytes; return (int)index; }
public void Return(ref ByteSpan span) { int spanIndex = BufferIndexFromSpanAddress(ref span); span._data = null; if (Interlocked.CompareExchange(ref _freeList[spanIndex], 0, 1) != 1) { throw new InvalidOperationException("this span has been already returned"); } if (spanIndex < _nextFree) { _nextFree = spanIndex; } }
public unsafe void ParseUtf8UInt32() { byte[] textBuffer = Encoding.UTF8.GetBytes("1258"); fixed(byte * ptextBuffer = textBuffer) { uint value; int bytesConsumed; ByteSpan text = new ByteSpan(ptextBuffer, textBuffer.Length); Assert.True(InvariantParser.TryParse(text, FormattingData.Encoding.Utf8, out value, out bytesConsumed)); Assert.Equal(1258U, value); Assert.Equal(textBuffer.Length, bytesConsumed); } }
public static bool TryParse(ByteSpan text, FormattingData.Encoding encoding, out uint value, out int bytesConsumed) { Precondition.Require(text.Length > 0); Precondition.Require(encoding == FormattingData.Encoding.Utf8 || text.Length > 1); value = 0; bytesConsumed = 0; if (text[0] == '0') { bytesConsumed = 1; if (encoding == FormattingData.Encoding.Utf16) { return text[1] == 0; } return true; } for (int byteIndex = 0; byteIndex < text.Length; byteIndex++) { byte nextByte = text[byteIndex]; if (nextByte < '0' || nextByte > '9') { if (bytesConsumed == 0) { value = default(uint); return false; } else { return true; } } uint candidate = value * 10; candidate += (uint)nextByte - '0'; if (candidate > value) { value = candidate; } else { return true; } bytesConsumed++; if (encoding == FormattingData.Encoding.Utf16) { byteIndex++; if(byteIndex >= text.Length || text[byteIndex] != 0) { return false; } bytesConsumed++; } } return true; }
public unsafe Utf8EncodedCodePoint(char highSurrogate, char lowSurrogate) : this() { UnicodeCodePoint codePoint = (UnicodeCodePoint)(uint)char.ConvertToUtf32(highSurrogate, lowSurrogate); fixed (byte* encodedData = &_byte0) { ByteSpan buffer = new ByteSpan(encodedData, 4); if (!Utf8Encoder.TryEncodeCodePoint(codePoint, buffer, out _length)) { // TODO: Change exception type throw new Exception("Internal error: this should never happen as codePoint should be within acceptable range"); } } }
public void Return(ByteSpan buffer) { int spanIndex = BufferIndexFromSpanAddress(ref buffer); if (spanIndex < 0 || spanIndex > _freeList.Length) { throw new InvalidOperationException("This buffer is not from this pool."); } if (Interlocked.CompareExchange(ref _freeList[spanIndex], 0, 1) != 1) { throw new InvalidOperationException("this buffer has been already returned."); } if (spanIndex < _nextFree) { _nextFree = spanIndex; } }
internal static bool TryParse(string text, int index, int count, out uint value, out int charsConsumed) { Precondition.Require(count > 0); Precondition.Require(text.Length >= index + count); unsafe { fixed(char* pText = text) { char* pSubstring = pText + index; var span = new ByteSpan((byte*)pSubstring, count << 1); int bytesConsumed; var result = TryParse(span, FormattingData.Encoding.Utf16, out value, out bytesConsumed); charsConsumed = bytesConsumed << 1; return result; } } }
// TODO: Validate constructors if we decide to keep this class public unsafe Utf8EncodedCodePoint(char character) : this() { if (char.IsSurrogate(character)) { throw new ArgumentOutOfRangeException("character", "Surrogate characters are not allowed"); } UnicodeCodePoint codePoint = (UnicodeCodePoint)(uint)character; fixed (byte* encodedData = &_byte0) { ByteSpan buffer = new ByteSpan(encodedData, 4); if (!Utf8Encoder.TryEncodeCodePoint(codePoint, buffer, out _length)) { // TODO: Change exception type throw new Exception("Internal error: this should never happen as codePoint is within acceptable range and is not surrogate"); } } }
public static bool TryParseRequestLine(ByteSpan buffer, out HttpRequestLine requestLine) { int parsedBytes; return TryParseRequestLine(buffer, out requestLine, out parsedBytes); }
public static bool TryParseRequestLine(ByteSpan buffer, out HttpRequestLine requestLine, out int totalParsedBytes) { requestLine = new HttpRequestLine(); totalParsedBytes = 0; var reader = new HttpRequestReader(); reader.Buffer = buffer; requestLine.Method = reader.ReadMethod(); if(requestLine.Method == HttpMethod.Unknown) { return false; } requestLine.RequestUri = reader.ReadRequestUri(); if(requestLine.RequestUri.Length == 0) { return false; } requestLine.Version = reader.ReadHttpVersion(); if (requestLine.Version == HttpVersion.Unknown) { return false; } totalParsedBytes = buffer.Length - reader.Buffer.Length; return true; }
public static bool TryParseHttpVersion(ByteSpan buffer, out Utf8Span httpVersion, out int parsedBytes) { var versionSpan = HttpRequestReader.SliceTo(buffer, HttpRequestReader.s_CR, HttpRequestReader.s_LF, out parsedBytes); httpVersion = new Utf8Span(versionSpan); return parsedBytes != 0; }
public static bool TryParseMethod(ByteSpan buffer, out HttpMethod method, out int parsedBytes) { if(buffer.StartsWith(s_Get.Bytes)) { method = HttpMethod.Get; parsedBytes = s_Get.Length; return true; } if (buffer.StartsWith(s_Post.Bytes)) { method = HttpMethod.Post; parsedBytes = s_Post.Length; return true; } if (buffer.StartsWith(s_Put.Bytes)) { method = HttpMethod.Put; parsedBytes = s_Put.Length; return true; } if (buffer.StartsWith(s_Delete.Bytes)) { method = HttpMethod.Delete; parsedBytes = s_Delete.Length; return true; } method = HttpMethod.Unknown; parsedBytes = 0; return false; }
protected abstract HttpServerBuffer CreateResponse(HttpRequestLine requestLine, ByteSpan headersAndBody);
public Utf8Span(ByteSpan bytes) { _bytes = bytes; }
public Utf8Span ReadRequestUri() { Utf8Span requestUri; int parsedBytes; if (!HttpRequestParser.TryParseRequestUri(Buffer, out requestUri, out parsedBytes)) { return Utf8Span.Empty; } Buffer = Buffer.Slice(parsedBytes); return requestUri; }
public HttpVersion ReadHttpVersion() { ByteSpan oldBuffer = Buffer; Utf8Span version = ReadHttpVersionAsUtf8String(); if (version.Equals(s_Http1_1)) { return HttpVersion.V1_1; } else if (version.Equals(s_Http2_0)) { return HttpVersion.V2_0; } else if (version.Equals(s_Http1_0)) { return HttpVersion.V1_0; } else { Buffer = oldBuffer; return HttpVersion.Unknown; } }
void OnReadWindows(UVBuffer.Windows buffer, IntPtr bytesAvaliable) { // TODO: all branches need to release buffer, I think long bytesRead = bytesAvaliable.ToInt64(); if (bytesRead == 0) { buffer.Dispose(); return; } else if (bytesRead < 0) { var error = UVException.ErrorCodeToError((int)bytesRead); if (error == UVError.EOF) { OnEndOfStream(); Dispose(); buffer.Dispose(); } else if(error == UVError.ECONNRESET) { Debug.Assert(buffer.Buffer == IntPtr.Zero && buffer.Length == 0); // no need to dispose // TODO: what should we do here? } else { Dispose(); buffer.Dispose(); throw new UVException((int)bytesRead); } } else { var readSlice = new ByteSpan((byte*)buffer.Buffer, (int)bytesRead); OnReadCompleted(readSlice); buffer.Dispose(); } }
void OnReadUnix(UVBuffer.Unix buffer, IntPtr bytesAvaliable) { long bytesRead = bytesAvaliable.ToInt64(); if (bytesRead == 0) { return; } else if (bytesRead < 0) { var error = UVException.ErrorCodeToError((int)bytesRead); if (error == UVError.EOF) { OnEndOfStream(); Dispose(); } else { Dispose(); throw new UVException((int)bytesRead); } } else { var readSlice = new ByteSpan((byte*)buffer.Buffer, (int)bytesRead); OnReadCompleted(readSlice); buffer.Dispose(); } }
void LogRestOfRequest(ByteSpan buffer) { HttpRequestReader reader = new HttpRequestReader(); reader.Buffer = buffer; while (true) { var header = reader.ReadHeader(); if (header.Length == 0) break; Log.LogMessage(Log.Level.Verbose, "\tHeader: {0}", header.ToString()); } var messageBody = reader.Buffer; Log.LogMessage(Log.Level.Verbose, "\tBody bytecount: {0}", messageBody.Length); }
// Not Found protected virtual HttpServerBuffer CreateResponseFor404(HttpRequestLine requestLine, ByteSpan headersAndBody) { Log.LogMessage(Log.Level.Warning, "Request {0}, Response: 404 Not Found", requestLine); BufferFormatter formatter = new BufferFormatter(1024, FormattingData.InvariantUtf8); WriteCommonHeaders(formatter, @"HTTP/1.1 404 Not Found"); formatter.Append(HttpNewline); return new HttpServerBuffer(formatter.Buffer, formatter.CommitedByteCount, BufferPool.Shared); }
// Bad Request protected virtual HttpServerBuffer CreateResponseFor400(ByteSpan receivedBytes) { BufferFormatter formatter = new BufferFormatter(1024, FormattingData.InvariantUtf8); WriteCommonHeaders(formatter, @"HTTP/1.1 400 Bad Request"); formatter.Append(HttpNewline); return new HttpServerBuffer(formatter.Buffer, formatter.CommitedByteCount, BufferPool.Shared); }
public static bool TryParseRequestUri(ByteSpan buffer, out Utf8Span requestUri, out int parsedBytes) { var uriSpan = HttpRequestReader.SliceTo(buffer, HttpRequestReader.s_SP, out parsedBytes); requestUri = new Utf8Span(uriSpan); return parsedBytes != 0; }
internal static ByteSpan SliceTo(ByteSpan buffer, byte terminatorFirst, byte terminatorSecond, out int consumedBytes) { int index = 0; while (index < buffer.Length) { if (buffer[index] == terminatorFirst && buffer.Length > index + 1 && buffer[index + 1] == terminatorSecond) { consumedBytes = index + 2; return buffer.Slice(0, index); } index++; } consumedBytes = 0; unsafe { return new ByteSpan(null, 0); // TODO: Empty instance should be used } }
Utf8Span ReadHttpVersionAsUtf8String() { Utf8Span httpVersion; int parsedBytes; if (!HttpRequestParser.TryParseHttpVersion(Buffer, out httpVersion, out parsedBytes)) { return Utf8Span.Empty; } Buffer = Buffer.Slice(parsedBytes); return httpVersion; }
public HttpMethod ReadMethod() { HttpMethod method; int parsedBytes; if (!HttpRequestParser.TryParseMethod(Buffer, out method, out parsedBytes)) { return HttpMethod.Unknown; } Buffer = Buffer.Slice(parsedBytes); return method; }
public unsafe void TryWrite(ByteSpan data) { EnsureNotDisposed(); IntPtr ptrData = (IntPtr)data.UnsafeBuffer; if (IsUnix) { var buffer = new UVBuffer.Unix(ptrData, (uint)data.Length); UVException.ThrowIfError(UVInterop.uv_try_write(Handle, &buffer, 1)); } else { var buffer = new UVBuffer.Windows(ptrData, (uint)data.Length); UVException.ThrowIfError(UVInterop.uv_try_write(Handle, &buffer, 1)); } }