/// <summary> /// TODO: Implement chunking /// </summary> /// <returns>An enumerable list of chunks</returns> public IEnumerable <HttpResponseDataChunk> ReadChunks(HttpParserConfig config) { if (ConnectRequest) { return(ReadChunksConnect(config)); } else if (HasBody && !Is100Continue && ResponseCode != 304) { if (config.StreamBody) { if (!ChunkedEncoding) { return(ReadChunksStreamedLength(config)); } else { return(ReadChunksStreamedChunked(config)); } } else { return(ReadChunksBuffered(config)); } } else { // No body, then just return the chunk as headers HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = 0; chunk.FinalChunk = true; return(new HttpResponseDataChunk[] { chunk }); } }
private HttpResponseDataChunk CreateChunk(byte[] body, int chunkNumber, bool finalChunk, bool convertToChunked) { HttpResponseDataChunk ret = new HttpResponseDataChunk(this); ret.ChunkNumber = chunkNumber; ret.FinalChunk = finalChunk; ret.Body = body; if (convertToChunked) { ret.ChunkedEncoding = true; List <KeyDataPair <string> > headers = new List <KeyDataPair <string> >(); // Remove any content-length and existing Transfer-Encoding chunked foreach (KeyDataPair <string> pair in ret.Headers) { if (!(pair.Name.Equals("Content-Length", StringComparison.OrdinalIgnoreCase) || (pair.Name.Equals("Transfer-Encoding", StringComparison.OrdinalIgnoreCase) && pair.Value.Equals("chunked", StringComparison.OrdinalIgnoreCase)))) { headers.Add(pair); } } headers.Add(new KeyDataPair <string>("Transfer-Encoding", "chunked")); ret.Headers = headers.ToArray(); } return(ret); }
private IEnumerable <HttpResponseDataChunk> ReadChunksConnect(HttpParserConfig config) { int chunkNumber = 0; while (true) { byte[] data = _reader.ReadBytes(HttpDataChunk.DEFAULT_CHUNK_SIZE, false); if (data.Length == 0) { throw new EndOfStreamException(); } HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = chunkNumber; if (chunkNumber < int.MaxValue) { chunkNumber++; } // Cast to length, really should just ignore any data set greater than a set amount chunk.Body = data; yield return(chunk); } }
private IEnumerable <HttpResponseDataChunk> ReadChunksBuffered(HttpParserConfig config) { HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = 0; chunk.FinalChunk = true; if (!ChunkedEncoding) { if (ReadToEnd) { if (_initialData != null) { List <byte> data = new List <byte>(BinaryEncoding.Instance.GetBytes(_initialData)); if (!_reader.Eof) { data.AddRange(_reader.ReadToEnd()); } chunk.Body = data.ToArray(); } else { chunk.Body = _reader.ReadToEnd(); } } else { long length = ContentLength; if (length > 0) { chunk.Body = _reader.ReadBytes((int)length); } else { chunk.Body = new byte[0]; } } } else { List <byte> body = new List <byte>(); string extension = null; byte[] ret = ReadChunkedEncoding(_reader, out extension); while (ret.Length > 0) { body.AddRange(ret); ret = ReadChunkedEncoding(_reader, out extension); } chunk.ChunkedEncoding = true; chunk.Body = body.ToArray(); } return(new HttpResponseDataChunk[] { chunk }); }
private IEnumerable <HttpResponseDataChunk> ReadChunksStreamedChunked(HttpParserConfig config) { string extension; int chunkNumber = 0; List <KeyDataPair <string> > headers = new List <KeyDataPair <string> >(Headers); if (config.DowngradeChunkedToHttp10) { int i = 0; while (i < headers.Count) { if (headers[i].Name.Equals("transfer-encoding", StringComparison.OrdinalIgnoreCase) && headers[i].Value.Equals("chunked", StringComparison.OrdinalIgnoreCase)) { headers.RemoveAt(i); } else { i++; } } } byte[] ret = ReadChunkedEncoding(_reader, out extension); do { HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = chunkNumber++; chunk.Body = ret; if (config.DowngradeChunkedToHttp10) { chunk.Headers = headers.ToArray(); chunk.Version = HttpVersion.Version10; } else { chunk.ChunkedEncoding = true; } chunk.ChunkExtension = extension; ret = ReadChunkedEncoding(_reader, out extension); chunk.FinalChunk = ret.Length == 0; yield return(chunk); }while (ret.Length > 0); }
private void Write(HttpResponseDataChunk chunk) { // Add proxy specific headers if (chunk.ChunkNumber == 0) { ProcessProxyResponseHeaders(chunk); lock (_requestQueue) { HttpRequestHeader request = _requestQueue.Dequeue(); // Fix up version to match the request if (_server._config.Version10Proxy && !request.Version.IsVersionUnknown) { chunk.Version = HttpVersion.Version10; } else { chunk.Version = request.Version; } if (!chunk.Version.IsVersion11) { // Remove chunked encoding for sending back 1.0 _removeChunked = true; _closeConnection = true; } else { // If not chunk encoding and no content-length then set close of end if (!chunk.ChunkedEncoding) { bool hasContentLength = false; foreach (KeyDataPair<string> header in chunk.Headers) { if (header.Name.Equals("content-length", StringComparison.OrdinalIgnoreCase)) { hasContentLength = true; break; } } if (!hasContentLength) { List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(chunk.Headers); headers.Add(new KeyDataPair<string>("Connection", "close")); chunk.Headers = headers.ToArray(); _closeConnection = true; } } } } } if (_removeChunked) { chunk.ChunkedEncoding = false; } chunk.WriteChunk(_writer); if (chunk.FinalChunk) { if (_closeConnection) { Close(); } } }
private void ReturnResponse(HttpRequestHeader request, int responseCode, string message, string method, HttpVersion version, IEnumerable<KeyDataPair<string>> sendHeaders, DataAdapterToStream stm) { if (request != null) { FlushRequest(request); } HttpResponseDataChunk response = new HttpResponseDataChunk(); if (_config.Version10Proxy && !version.IsVersionUnknown) { response.Version = HttpVersion.Version10; } else { response.Version = version; } response.ResponseCode = responseCode; response.Message = message; response.FinalChunk = true; response.Body = new byte[0]; List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(sendHeaders); headers.Add(new KeyDataPair<string>("X-Proxy-Server", "CANAPE")); if (response.Body.Length > 0) { headers.Add(new KeyDataPair<string>("Content-Type", "text/html")); } response.Headers = headers.ToArray(); if (method.Equals("HEAD", StringComparison.OrdinalIgnoreCase)) { response.HeadResponse = true; } else if (method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase)) { response.ConnectResponse = true; } response.WriteChunk(new DataWriter(stm)); }
private HttpResponseDataChunk BuildError(int error, string message, string method, HttpVersion version) { HttpResponseDataChunk response = new HttpResponseDataChunk(); response.Version = version; response.ResponseCode = error; response.Message = message; response.FinalChunk = true; response.Body = new byte[0]; List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(); headers.Add(new KeyDataPair<string>("X-Proxy-Server", "CANAPE")); response.Headers = headers.ToArray(); if (method.Equals("HEAD", StringComparison.OrdinalIgnoreCase)) { response.HeadResponse = true; } else if (method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase)) { response.ConnectResponse = true; } return response; }
private void ProcessProxyResponseHeaders(HttpResponseDataChunk response) { List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(response.Headers); int i = 0; while (i < headers.Count) { KeyDataPair<string> pair = headers[i]; // We don't send connection headers if (pair.Name.Equals("Connection", StringComparison.OrdinalIgnoreCase) || pair.Name.Equals("Proxy-Connection")) { headers.RemoveAt(i); } else { ++i; } } }
private IEnumerable<HttpResponseDataChunk> ReadChunksStreamedChunked(HttpParserConfig config) { string extension; int chunkNumber = 0; List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(Headers); if (config.DowngradeChunkedToHttp10) { int i = 0; while(i < headers.Count) { if (headers[i].Name.Equals("transfer-encoding", StringComparison.OrdinalIgnoreCase) && headers[i].Value.Equals("chunked", StringComparison.OrdinalIgnoreCase)) { headers.RemoveAt(i); } else { i++; } } } byte[] ret = ReadChunkedEncoding(_reader, out extension); do { HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = chunkNumber++; chunk.Body = ret; if (config.DowngradeChunkedToHttp10) { chunk.Headers = headers.ToArray(); chunk.Version = HttpVersion.Version10; } else { chunk.ChunkedEncoding = true; } chunk.ChunkExtension = extension; ret = ReadChunkedEncoding(_reader, out extension); chunk.FinalChunk = ret.Length == 0; yield return chunk; } while (ret.Length > 0); }
private IEnumerable<HttpResponseDataChunk> ReadChunksConnect(HttpParserConfig config) { int chunkNumber = 0; while (true) { byte[] data = _reader.ReadBytes(HttpDataChunk.DEFAULT_CHUNK_SIZE, false); if (data.Length == 0) { throw new EndOfStreamException(); } HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = chunkNumber; if (chunkNumber < int.MaxValue) { chunkNumber++; } // Cast to length, really should just ignore any data set greater than a set amount chunk.Body = data; yield return chunk; } }
private IEnumerable<HttpResponseDataChunk> ReadChunksBuffered(HttpParserConfig config) { HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = 0; chunk.FinalChunk = true; if (!ChunkedEncoding) { if (ReadToEnd) { if (_initialData != null) { List<byte> data = new List<byte>(BinaryEncoding.Instance.GetBytes(_initialData)); if (!_reader.Eof) { data.AddRange(_reader.ReadToEnd()); } chunk.Body = data.ToArray(); } else { chunk.Body = _reader.ReadToEnd(); } } else { long length = ContentLength; if (length > 0) { chunk.Body = _reader.ReadBytes((int)length); } else { chunk.Body = new byte[0]; } } } else { List<byte> body = new List<byte>(); string extension = null; byte[] ret = ReadChunkedEncoding(_reader, out extension); while (ret.Length > 0) { body.AddRange(ret); ret = ReadChunkedEncoding(_reader, out extension); } chunk.ChunkedEncoding = true; chunk.Body = body.ToArray(); } return new HttpResponseDataChunk[] { chunk }; }
private HttpResponseDataChunk CreateChunk(byte[] body, int chunkNumber, bool finalChunk, bool convertToChunked) { HttpResponseDataChunk ret = new HttpResponseDataChunk(this); ret.ChunkNumber = chunkNumber; ret.FinalChunk = finalChunk; ret.Body = body; if (convertToChunked) { ret.ChunkedEncoding = true; List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(); // Remove any content-length and existing Transfer-Encoding chunked foreach (KeyDataPair<string> pair in ret.Headers) { if (!(pair.Name.Equals("Content-Length", StringComparison.OrdinalIgnoreCase) || (pair.Name.Equals("Transfer-Encoding", StringComparison.OrdinalIgnoreCase) && pair.Value.Equals("chunked", StringComparison.OrdinalIgnoreCase)))) { headers.Add(pair); } } headers.Add(new KeyDataPair<string>("Transfer-Encoding", "chunked")); ret.Headers = headers.ToArray(); } return ret; }
/// <summary> /// TODO: Implement chunking /// </summary> /// <returns>An enumerable list of chunks</returns> public IEnumerable<HttpResponseDataChunk> ReadChunks(HttpParserConfig config) { if (ConnectRequest) { return ReadChunksConnect(config); } else if (HasBody && !Is100Continue && ResponseCode != 304) { if (config.StreamBody) { if (!ChunkedEncoding) { return ReadChunksStreamedLength(config); } else { return ReadChunksStreamedChunked(config); } } else { return ReadChunksBuffered(config); } } else { // No body, then just return the chunk as headers HttpResponseDataChunk chunk = new HttpResponseDataChunk(this); chunk.ChunkNumber = 0; chunk.FinalChunk = true; return new HttpResponseDataChunk[] { chunk }; } }