private void SendResponse() { var statusCode = response.Status; var responseBody = ProcessRanges(response, ref statusCode); var responseStream = new ConcatenatedStream(); try { var headerBlock = new StringBuilder(); headerBlock.AppendFormat( "HTTP/1.1 {0} {1}\r\n", (uint)statusCode, HttpPhrases.Phrases[statusCode] ); headerBlock.Append(response.Headers.HeaderBlock); headerBlock.Append(CRLF); var headerStream = new MemoryStream( Encoding.ASCII.GetBytes(headerBlock.ToString())); responseStream.AddStream(headerStream); if (Method != "HEAD" && responseBody != null) { responseStream.AddStream(responseBody); responseBody = null; } DebugFormat("{0} - {1} response for {2}", this, (uint)statusCode, Path); state = HttpStates.Writing; var sp = new StreamPump(responseStream, stream, BUFFER_SIZE); sp.Pump((pump, result) => { pump.Input.Close(); pump.Input.Dispose(); if (result == StreamPumpResult.Delivered) { DebugFormat("{0} - Done writing response", this); string conn; if (Headers.TryGetValue("connection", out conn) && conn.ToUpperInvariant() == "KEEP-ALIVE") { ReadNext(); return; } } else { DebugFormat("{0} - Client aborted connection", this); } Close(); }); } catch (Exception) { responseStream.Dispose(); throw; } finally { responseBody?.Dispose(); } }
private void SendResponse() { var responseBody = response.Body; var st = response.Status; var contentLength = GetContentLengthFromStream(responseBody); string ar; if (st == HttpCodes.OK && contentLength > 0 && headers.TryGetValue("Range", out ar)) { try { var m = bytes.Match(ar); if (!m.Success) { throw new InvalidDataException("Not parsed!"); } var totalLength = contentLength; var start = 0L; var end = totalLength - 1; if (!long.TryParse(m.Groups[1].Value, out start) || start < 0) { throw new InvalidDataException("Not parsed"); } if (m.Groups.Count != 3 || !long.TryParse(m.Groups[2].Value, out end) || end <= start || end >= totalLength) { end = totalLength - 1; } if (start >= end) { responseBody.Close(); response = Error416.HandleRequest(this); SendResponse(); return; } if (start > 0) { responseBody.Seek(start, SeekOrigin.Current); } contentLength = end - start + 1; response.Headers["Content-Length"] = contentLength.ToString(); response.Headers.Add("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, totalLength)); st = HttpCodes.PARTIAL; } catch (Exception ex) { Warn(String.Format("{0} - Failed to process range request!", this), ex); } } var hb = new StringBuilder(); hb.AppendFormat("HTTP/1.1 {0} {1}\r\n", (uint)st, HttpPhrases.Phrases[st]); hb.Append(response.Headers.HeaderBlock); hb.Append("\r\n"); var rs = new ConcatenatedStream(); try { var headerStream = new MemoryStream(Encoding.ASCII.GetBytes(hb.ToString())); rs.AddStream(headerStream); if (method != "HEAD" && responseBody != null) { rs.AddStream(responseBody); } InfoFormat("{0} - {1} response for {2}", this, (uint)st, path); state = HttpStates.WRITING; new StreamPump(rs, stream, (pump, result) => { pump.Input.Close(); pump.Input.Dispose(); if (result == StreamPumpResult.Delivered) { DebugFormat("{0} - Done writing response", this); string conn; if (headers.TryGetValue("connection", out conn) && conn.ToLower() == "keep-alive") { ReadNext(); return; } } Close(); }, BUFFER_SIZE); } catch (Exception) { rs.Dispose(); throw; } }