private static int findFirst(IDataStream stream, string needle, int offset) { if (needle.Length == 0) { throw new ArgumentOutOfRangeException(); } int endIndex = -1; while (offset < stream.Length) { var len2 = (int)Math.Min(stream.Length - offset, 512); var buff = stream.ReadBytes(offset, len2); var str = ASCIIEncoding.ASCII.GetString(buff); // find end endIndex = (int)str.IndexOf(needle); if (endIndex > -1) { offset += endIndex + needle.Length; return(offset); } offset += len2; } if (endIndex < 0) { throw new PartialChunkException(); } return(-1); }
/// <inheritdoc/> public void Send(IDataStream response) { try { // TODO: improve this socket.SendTo(response.ReadBytes(), remoteEP); OnResponseSent(response); } catch (ObjectDisposedException) { } catch (Exception e) { OnErrorOccured(e); } }
/// <inheritdoc/> public void Send(IDataStream request) { try { // TODO: improve this socket.SendTo(request.ReadBytes(), remoteEP); } catch (ObjectDisposedException) { return; } catch (Exception e) { OnErrorOccured(e); return; } OnRequestSent(request); }
public static void Send(Socket socket, IDataStream stream) { if (stream.Length < socket.SendBufferSize) { socket.Send(stream.ReadBytes()); } else { var buffer = new byte[socket.SendBufferSize]; var remaining = stream.Length; long start = 0; while (remaining > 0) { var read = (int)Math.Min(remaining, buffer.Length); stream.ReadBytesToBuffer(buffer, start, read); start += read; remaining -= read; socket.Send(buffer, read, SocketFlags.None); } } }
/// <summary> /// Creates new ByteArray from a copy of the given stream /// </summary> /// <param name="stream"></param> /// <param name="start"></param> /// <param name="length">length to copy, or -1 to copy from start to the end</param> public ByteArray(IDataStream stream, long start = 0, int length = -1) { if (length == -1) length = (int)Math.Min(int.MaxValue, stream.Length - start); // ReadBytes copies data, so no extra copying is required arr = stream.ReadBytes(start, length); }
public void SetValue(IDataStream s) { // can't really improve this, because the data has to be in memory in order to manipulate them // effectively data.ByteProvider = new Be.Windows.Forms.DynamicByteProvider(s.ReadBytes()); }
/// <summary> /// Parses response/request header /// </summary> /// <param name="s">data to parse, must be long enough to contain at least the start line</param> /// <param name="isResponse"></param> /// <returns>is header parsing finished</returns> /// <exception cref="InvalidHttpHeaderException">Thrown when parsing is unsuccessful</exception> /// <remarks>Max headers size is limited by 512KiB</remarks> public bool Parse(IDataStream s, bool isResponse) { lock (builder) { if (stage == ParsingStage.Finished) { return(true); } if (s.Length <= nextRead) { return(false); } byte[] arr; // max 512KiB int len = (int)Math.Min(s.Length - nextRead, 524288); arr = s.ReadBytes(nextRead, len); var str = ASCIIEncoding.ASCII.GetString(arr); if (stage == ParsingStage.StatusLine) { if (isResponse) { var match = statusLineRegex.Match(str); if (!match.Success && str.Length < s.Length) { throw new InvalidHttpHeaderException(); } builder.IsRequest = false; builder.HttpVersion = match.Groups["Version"].Value; builder.StatusCode = int.Parse(match.Groups["Code"].Value); builder.ReasonPhrase = match.Groups["ReasonPhrase"].Value; nextRead = match.Length; stage = ParsingStage.Headers; str = str.Substring(nextRead); } else { var match = requestLineRegex.Match(str); if (!match.Success && str.Length < s.Length) { throw new InvalidHttpHeaderException(); } var target = match.Groups["Target"].Value; HttpRequestMethod method; if (!Enum.TryParse(match.Groups["Method"].Value, out method)) { throw new InvalidHttpHeaderException(); } builder.IsRequest = true; builder.HttpVersion = match.Groups["Version"].Value; builder.Method = method; builder.RequestTarget = target; nextRead = match.Length; stage = ParsingStage.Headers; str = str.Substring(nextRead); } } if (stage == ParsingStage.Headers) { int read = 0; Match match; while ((match = headerRegex.Match(str, read)).Success) { // Check for end of the string if (str.Length - (match.Length + read) < 2) { nextRead += read; return(false); } var key = match.Groups["Key"].Value; var value = match.Groups["Value"].Value; builder.AddHeader(key, value); read += match.Length; if (str.Substring(read, 2) != "\r\n") { throw new InvalidHttpHeaderException(); } read += 2; } if (str.Length > 0 && read == 0) { throw new InvalidHttpHeaderException(); } str = str.Substring(read); nextRead += read; } if (stage != ParsingStage.Finished && str.Length >= 2 && str.Substring(0, 2) == "\r\n") { stage = ParsingStage.Finished; nextRead += 2; return(true); } return(false); } }
/// <summary> /// Decodes one chunk from stream (chunk must begin at the beggining of the stream) /// </summary> /// <param name="stream"></param> /// <returns></returns> /// <exception cref="ArgumentNullException">stream is null</exception> /// <exception cref="InvalidChunkException">chunk is invalid</exception> /// <exception cref="PartialChunkException">not enough data in the stream to decode the whole chunk</exception> /// <remarks> /// Last chunk info's ChunkLength doesn't include trailer and final CRLF. /// </remarks> public static DecodeOneInfo DecodeOneChunk(IDataStream stream) { if (stream == null) { throw new ArgumentNullException(); } var len = (int)Math.Min(stream.Length, 10); var buff = stream.ReadBytes(0, len); var str = ASCIIEncoding.ASCII.GetString(buff); var match = chunkHeaderRegex.Match(str); if (match.Success) { try { if (!match.Groups["ChunkExt"].Success && !match.Groups["HeaderEnd"].Success) { if (len == stream.Length) { throw new PartialChunkException(); } // chunk size too large else { throw new InvalidChunkException(); } } // parse next chunk size var size = Convert.ToInt32(match.Groups["Size"].Value, 16); if (size < 0) { throw new InvalidChunkException(); } // locate \r\n terminating the chunk header if (match.Groups["HeaderEnd"].Success) { len = match.Length; } else { // \r can already be matched len = findFirst(stream, "\r\n", Math.Max(0, len - 1)); } // len points to the beggining of chunk data long dataStart = len; // last chunk if (size == 0) { return(new DecodeOneInfo(dataStart, 0, len)); } // size > 0 // not enough data if (stream.Length - len < size + 2) { throw new PartialChunkException(); } // check that chunk data is ended with CRLF buff = stream.ReadBytes(len + size, 2); if (buff[0] != 13 || buff[1] != 10) { throw new InvalidChunkException(); } return(new DecodeOneInfo(len, size, len + size + 2)); } catch (ChunkedDecoderException) { throw; } catch { throw new InvalidChunkException(); } } else { // unable to parse chunk size throw new InvalidChunkException(); } }
/// <inheritdoc/> public void Show(IDataStream s) { textBox1.Text = UTF8Encoding.UTF8.GetString(s.ReadBytes()); }