private static void Copy(MemoryPoolIterator head, MemoryPoolIterator tail, ref MemoryPoolIterator writer) { while (!CompareIterators(ref head, ref tail)) { writer.Put((byte)head.Take()); } }
/// <summary> /// Unescape the percent-encodings /// </summary> /// <param name="reader">The iterator point to the first % char</param> /// <param name="writer">The place to write to</param> /// <param name="end">The end of the sequence</param> private static bool DecodeCore(ref MemoryPoolIterator reader, ref MemoryPoolIterator writer, MemoryPoolIterator end) { // preserves the original head. if the percent-encodings cannot be interpreted as sequence of UTF-8 octets, // bytes from this till the last scanned one will be copied to the memory pointed by writer. var byte1 = UnescapePercentEncoding(ref reader, end); if (byte1 == 0) { throw BadHttpRequestException.GetException(RequestRejectionReason.PathContainsNullCharacters); } if (byte1 == -1) { return(false); } if (byte1 <= 0x7F) { // first byte < U+007f, it is a single byte ASCII writer.Put((byte)byte1); return(true); } int byte2 = 0, byte3 = 0, byte4 = 0; // anticipate more bytes var currentDecodeBits = 0; var byteCount = 1; var expectValueMin = 0; if ((byte1 & 0xE0) == 0xC0) { // 110x xxxx, expect one more byte currentDecodeBits = byte1 & 0x1F; byteCount = 2; expectValueMin = 0x80; } else if ((byte1 & 0xF0) == 0xE0) { // 1110 xxxx, expect two more bytes currentDecodeBits = byte1 & 0x0F; byteCount = 3; expectValueMin = 0x800; } else if ((byte1 & 0xF8) == 0xF0) { // 1111 0xxx, expect three more bytes currentDecodeBits = byte1 & 0x07; byteCount = 4; expectValueMin = 0x10000; } else { // invalid first byte return(false); } var remainingBytes = byteCount - 1; while (remainingBytes > 0) { // read following three chars if (CompareIterators(ref reader, ref end)) { return(false); } var nextItr = reader; var nextByte = UnescapePercentEncoding(ref nextItr, end); if (nextByte == -1) { return(false); } if ((nextByte & 0xC0) != 0x80) { // the follow up byte is not in form of 10xx xxxx return(false); } currentDecodeBits = (currentDecodeBits << 6) | (nextByte & 0x3F); remainingBytes--; if (remainingBytes == 1 && currentDecodeBits >= 0x360 && currentDecodeBits <= 0x37F) { // this is going to end up in the range of 0xD800-0xDFFF UTF-16 surrogates that // are not allowed in UTF-8; return(false); } if (remainingBytes == 2 && currentDecodeBits >= 0x110) { // this is going to be out of the upper Unicode bound 0x10FFFF. return(false); } reader = nextItr; if (byteCount - remainingBytes == 2) { byte2 = nextByte; } else if (byteCount - remainingBytes == 3) { byte3 = nextByte; } else if (byteCount - remainingBytes == 4) { byte4 = nextByte; } } if (currentDecodeBits < expectValueMin) { // overlong encoding (e.g. using 2 bytes to encode something that only needed 1). return(false); } // all bytes are verified, write to the output if (byteCount > 0) { writer.Put((byte)byte1); } if (byteCount > 1) { writer.Put((byte)byte2); } if (byteCount > 2) { writer.Put((byte)byte3); } if (byteCount > 3) { writer.Put((byte)byte4); } return(true); }