C# Implementing Accept-Ranges

Date: 2016-07-04
		public static bool RequestAcceptsGZip(HttpRequest request)
		{
			return (!String.IsNullOrEmpty(request.Headers["Accept-encoding"]) && (request.Headers["Accept-encoding"].IndexOf("gzip") != -1));
		}

		public static void RespondBuffered(HttpRequest request, HttpResponse response, Stream s, int bufferSize)
		{
			try
			{
				if (bufferSize < 1) bufferSize = 1024 * 1024; // Default buffer size: 1MB byte[] buffer = new byte[bufferSize]; int byteCountBuffer = 0; int byteCountZipped = 0; long readPosition = 0; long writePosition = 0; response.Buffer = false; response.BufferOutput = false; if (response.ContentType.IndexOf("video") > -1)
				{
					try
					{
						response.Headers.Remove("Content-disposition");
					}
					catch (Exception)
					{
					}
				}

				response.AddHeader("Accept-Ranges", "bytes");

				MemoryStream zippedStream = null;
				Stream zipStream = null;

				bool useGZip = false;

				string contentType = response.ContentType.Split(new char[] { ';' })[0].ToLower();
				if (_contentTypesToGZip.Contains(contentType) && RequestAcceptsGZip(request))
				{
					useGZip = true;
				}

				if (useGZip)
				{
					ResponseAddGZip(response);
					zippedStream = new MemoryStream();
					zipStream = new GZipStream(zippedStream, CompressionMode.Compress, true);
				}

				if (useGZip)
				{
					// with gzip the exact content length is unknown
					while ((byteCountBuffer = s.Read(buffer, 0, buffer.Length)) > 0)
					{
						zipStream.Write(buffer, 0, byteCountBuffer);
						zipStream.Flush();

						if (response.OutputStream.CanWrite && response.IsClientConnected)
						{
							writePosition = zippedStream.Position;
							zippedStream.Position = readPosition;
							while ((byteCountZipped = zippedStream.Read(buffer, 0, buffer.Length)) > 0)
							{
								response.OutputStream.Write(buffer, 0, byteCountZipped);
								response.OutputStream.Flush();
								readPosition += byteCountZipped;
							}
							zippedStream.Position = writePosition;
						}
						else
						{
							break;
						}
					}
					zipStream.Close(); // Close the zip stream
					zippedStream.Position = readPosition; // We left the zipped stream OPEN, see new GZipStream(..., true)
					while ((byteCountZipped = zippedStream.Read(buffer, 0, buffer.Length)) > 0) // Read the last 11 bytes that indicate the gzip stream is closed
					{
						response.OutputStream.Write(buffer, 0, byteCountZipped);
						response.OutputStream.Flush();
					}
				}
				else
				{
					bool useRange = false;
					Int64 rangeStart = 0;
					Int64 rangeEnd = s.Length - 1;

					if (request.Headers["Range"] != null)
					{
						string rangeHeader = request.Headers["Range"];

						// multiple byte ranges not supported
						if (!rangeHeader.Contains(","))
						{
							//LogHelper.LogInformation("ContentRanges", "RangeRequest", request.ServerVariables["ALL_RAW"]);
							string[] parts = rangeHeader.Split(new char[] { '=', '-' });

							if (parts.Length >= 2)
							{
								Int64.TryParse(parts[1], out rangeStart);

								if (parts.Length > 2 && parts[2] != "")
								{
									Int64.TryParse(parts[2], out rangeEnd);
								}
								else
								{
									rangeEnd = s.Length - 1;
								}

								if (rangeEnd > rangeStart)
								{
									useRange = true;
									response.StatusCode = 206; // Partial request

									try
									{
										string contentRangeHeader = String.Format("bytes {0}-{1}/{2}", rangeStart, rangeEnd, s.Length);
										response.Headers.Add("Content-Range", contentRangeHeader);
									}
									catch (Exception e)
									{
										DCMSEventLogHelper.LogException(CMSContext.CurrentSiteID, "ContentRanges", e);
									}
								}
							}
						}
					}

					long responseLength = 0;
					try
					{
						responseLength = s.Length;
						if (useRange)
						{
							responseLength = (rangeEnd - rangeStart);
						}
					}
					catch (NotSupportedException) { }

					if (responseLength != 0)
					{
						try
						{
							response.AppendHeader("Content-Length", responseLength.ToString());
							response.AppendHeader("Accept-Ranges", String.Format("{0}-{1}", 0, s.Length - 1));
						}
						catch (HttpException) { }
					}

					if (!useRange)
					{
						while ((byteCountBuffer = s.Read(buffer, 0, buffer.Length)) > 0)
						{
							if (response.OutputStream.CanWrite && response.IsClientConnected)
							{
								response.OutputStream.Write(buffer, 0, byteCountBuffer);
								response.OutputStream.Flush();
							}
							else
							{
								break;
							}
						}
					}
					else
					{
						s.Position = rangeStart;

						while ((byteCountBuffer = s.Read(buffer, 0, buffer.Length)) > 0)
						{
							if (response.OutputStream.CanWrite && response.IsClientConnected)
							{
								if (s.Position + byteCountBuffer > rangeEnd)
								{
									byteCountBuffer = (int)(buffer.Length + rangeEnd - s.Position);
								}

								response.OutputStream.Write(buffer, 0, byteCountBuffer);
								response.OutputStream.Flush();
							}
							else
							{
								break;
							}

							if (s.Position > rangeEnd)
							{
								break;
							}
						}
					}
				}
			}
			catch (Exception e)
			{
				if (e is HttpException)
				{
					// Ignore
				}
				else
				{
					//LogHelper.LogException(CMSContext.CurrentSiteID, "ContentRanges", e);
				}
			}
			finally
			{
				// Make sure the input stream is disposed early
				s.Dispose();

				if (response.IsClientConnected && response.OutputStream != null)
				{
					if (response.OutputStream.CanWrite)
					{
						response.OutputStream.Flush();
					}
					response.OutputStream.Close();
				}
			}
		}

		public static void RespondBufferedBytes(HttpRequest request, HttpResponse response, byte[] content)
		{
			RespondBufferedBytes(request, response, content, -1);
		}

		public static void RespondBufferedBytes(HttpRequest request, HttpResponse response, byte[] content, int bufferSize)
		{
			using (MemoryStream ms = new MemoryStream(content))
			{
				RespondBuffered(request, response, ms, bufferSize);
			}
		}

		public static void RespondBufferedFile(HttpRequest request, HttpResponse response, string fileName)
		{
			RespondBufferedFile(request, response, fileName, -1);
		}

		public static void RespondBufferedFile(HttpRequest request, HttpResponse response, string fileName, int bufferSize)
		{
			using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
			{
				RespondBuffered(request, response, fs, bufferSize);
			}
		}

		public static void RespondBufferedString(HttpRequest request, HttpResponse response, string content)
		{
			RespondBufferedString(request, response, content, -1);
		}

		public static void RespondBufferedString(HttpRequest request, HttpResponse response, string content, int bufferSize)
		{
			using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(content)))
			{
				RespondBuffered(request, response, ms, bufferSize);
			}
		}

		public static void ResponseAddGZip(HttpResponse response)
		{
			response.AppendHeader("Content-encoding", "gzip");
			response.Cache.VaryByHeaders["Accept-encoding"] = true;
		}
1110cookie-checkC# Implementing Accept-Ranges