{"id":111,"date":"2016-07-04T23:12:05","date_gmt":"2016-07-04T22:12:05","guid":{"rendered":"https:\/\/solidt.eu\/blog\/?p=111"},"modified":"2016-07-04T23:12:10","modified_gmt":"2016-07-04T22:12:10","slug":"c-implementing-accept-ranges","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/c-implementing-accept-ranges\/","title":{"rendered":"C# Implementing Accept-Ranges"},"content":{"rendered":"<pre lang=\"c#\" class=\"\">\t\tpublic static bool RequestAcceptsGZip(HttpRequest request)\r\n\t\t{\r\n\t\t\treturn (!String.IsNullOrEmpty(request.Headers[\"Accept-encoding\"]) &amp;&amp; (request.Headers[\"Accept-encoding\"].IndexOf(\"gzip\") != -1));\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBuffered(HttpRequest request, HttpResponse response, Stream s, int bufferSize)\r\n\t\t{\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tif (bufferSize &lt; 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\") &gt; -1)\r\n\t\t\t\t{\r\n\t\t\t\t\ttry\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tresponse.Headers.Remove(\"Content-disposition\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcatch (Exception)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tresponse.AddHeader(\"Accept-Ranges\", \"bytes\");\r\n\r\n\t\t\t\tMemoryStream zippedStream = null;\r\n\t\t\t\tStream zipStream = null;\r\n\r\n\t\t\t\tbool useGZip = false;\r\n\r\n\t\t\t\tstring contentType = response.ContentType.Split(new char[] { ';' })[0].ToLower();\r\n\t\t\t\tif (_contentTypesToGZip.Contains(contentType) &amp;&amp; RequestAcceptsGZip(request))\r\n\t\t\t\t{\r\n\t\t\t\t\tuseGZip = true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (useGZip)\r\n\t\t\t\t{\r\n\t\t\t\t\tResponseAddGZip(response);\r\n\t\t\t\t\tzippedStream = new MemoryStream();\r\n\t\t\t\t\tzipStream = new GZipStream(zippedStream, CompressionMode.Compress, true);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (useGZip)\r\n\t\t\t\t{\r\n\t\t\t\t\t\/\/ with gzip the exact content length is unknown\r\n\t\t\t\t\twhile ((byteCountBuffer = s.Read(buffer, 0, buffer.Length)) &gt; 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tzipStream.Write(buffer, 0, byteCountBuffer);\r\n\t\t\t\t\t\tzipStream.Flush();\r\n\r\n\t\t\t\t\t\tif (response.OutputStream.CanWrite &amp;&amp; response.IsClientConnected)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\twritePosition = zippedStream.Position;\r\n\t\t\t\t\t\t\tzippedStream.Position = readPosition;\r\n\t\t\t\t\t\t\twhile ((byteCountZipped = zippedStream.Read(buffer, 0, buffer.Length)) &gt; 0)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tresponse.OutputStream.Write(buffer, 0, byteCountZipped);\r\n\t\t\t\t\t\t\t\tresponse.OutputStream.Flush();\r\n\t\t\t\t\t\t\t\treadPosition += byteCountZipped;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tzippedStream.Position = writePosition;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tzipStream.Close(); \/\/ Close the zip stream\r\n\t\t\t\t\tzippedStream.Position = readPosition; \/\/ We left the zipped stream OPEN, see new GZipStream(..., true)\r\n\t\t\t\t\twhile ((byteCountZipped = zippedStream.Read(buffer, 0, buffer.Length)) &gt; 0) \/\/ Read the last 11 bytes that indicate the gzip stream is closed\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tresponse.OutputStream.Write(buffer, 0, byteCountZipped);\r\n\t\t\t\t\t\tresponse.OutputStream.Flush();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tbool useRange = false;\r\n\t\t\t\t\tInt64 rangeStart = 0;\r\n\t\t\t\t\tInt64 rangeEnd = s.Length - 1;\r\n\r\n\t\t\t\t\tif (request.Headers[\"Range\"] != null)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tstring rangeHeader = request.Headers[\"Range\"];\r\n\r\n\t\t\t\t\t\t\/\/ multiple byte ranges not supported\r\n\t\t\t\t\t\tif (!rangeHeader.Contains(\",\"))\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\/\/LogHelper.LogInformation(\"ContentRanges\", \"RangeRequest\", request.ServerVariables[\"ALL_RAW\"]);\r\n\t\t\t\t\t\t\tstring[] parts = rangeHeader.Split(new char[] { '=', '-' });\r\n\r\n\t\t\t\t\t\t\tif (parts.Length &gt;= 2)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tInt64.TryParse(parts[1], out rangeStart);\r\n\r\n\t\t\t\t\t\t\t\tif (parts.Length &gt; 2 &amp;&amp; parts[2] != \"\")\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\tInt64.TryParse(parts[2], out rangeEnd);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\trangeEnd = s.Length - 1;\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tif (rangeEnd &gt; rangeStart)\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\tuseRange = true;\r\n\t\t\t\t\t\t\t\t\tresponse.StatusCode = 206; \/\/ Partial request\r\n\r\n\t\t\t\t\t\t\t\t\ttry\r\n\t\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\t\tstring contentRangeHeader = String.Format(\"bytes {0}-{1}\/{2}\", rangeStart, rangeEnd, s.Length);\r\n\t\t\t\t\t\t\t\t\t\tresponse.Headers.Add(\"Content-Range\", contentRangeHeader);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tcatch (Exception e)\r\n\t\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\t\tDCMSEventLogHelper.LogException(CMSContext.CurrentSiteID, \"ContentRanges\", e);\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlong responseLength = 0;\r\n\t\t\t\t\ttry\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tresponseLength = s.Length;\r\n\t\t\t\t\t\tif (useRange)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tresponseLength = (rangeEnd - rangeStart);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcatch (NotSupportedException) { }\r\n\r\n\t\t\t\t\tif (responseLength != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttry\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tresponse.AppendHeader(\"Content-Length\", responseLength.ToString());\r\n\t\t\t\t\t\t\tresponse.AppendHeader(\"Accept-Ranges\", String.Format(\"{0}-{1}\", 0, s.Length - 1));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcatch (HttpException) { }\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (!useRange)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\twhile ((byteCountBuffer = s.Read(buffer, 0, buffer.Length)) &gt; 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif (response.OutputStream.CanWrite &amp;&amp; response.IsClientConnected)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tresponse.OutputStream.Write(buffer, 0, byteCountBuffer);\r\n\t\t\t\t\t\t\t\tresponse.OutputStream.Flush();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ts.Position = rangeStart;\r\n\r\n\t\t\t\t\t\twhile ((byteCountBuffer = s.Read(buffer, 0, buffer.Length)) &gt; 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif (response.OutputStream.CanWrite &amp;&amp; response.IsClientConnected)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tif (s.Position + byteCountBuffer &gt; rangeEnd)\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\tbyteCountBuffer = (int)(buffer.Length + rangeEnd - s.Position);\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tresponse.OutputStream.Write(buffer, 0, byteCountBuffer);\r\n\t\t\t\t\t\t\t\tresponse.OutputStream.Flush();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (s.Position &gt; rangeEnd)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcatch (Exception e)\r\n\t\t\t{\r\n\t\t\t\tif (e is HttpException)\r\n\t\t\t\t{\r\n\t\t\t\t\t\/\/ Ignore\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\t\/\/LogHelper.LogException(CMSContext.CurrentSiteID, \"ContentRanges\", e);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfinally\r\n\t\t\t{\r\n\t\t\t\t\/\/ Make sure the input stream is disposed early\r\n\t\t\t\ts.Dispose();\r\n\r\n\t\t\t\tif (response.IsClientConnected &amp;&amp; response.OutputStream != null)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (response.OutputStream.CanWrite)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tresponse.OutputStream.Flush();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tresponse.OutputStream.Close();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBufferedBytes(HttpRequest request, HttpResponse response, byte[] content)\r\n\t\t{\r\n\t\t\tRespondBufferedBytes(request, response, content, -1);\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBufferedBytes(HttpRequest request, HttpResponse response, byte[] content, int bufferSize)\r\n\t\t{\r\n\t\t\tusing (MemoryStream ms = new MemoryStream(content))\r\n\t\t\t{\r\n\t\t\t\tRespondBuffered(request, response, ms, bufferSize);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBufferedFile(HttpRequest request, HttpResponse response, string fileName)\r\n\t\t{\r\n\t\t\tRespondBufferedFile(request, response, fileName, -1);\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBufferedFile(HttpRequest request, HttpResponse response, string fileName, int bufferSize)\r\n\t\t{\r\n\t\t\tusing (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))\r\n\t\t\t{\r\n\t\t\t\tRespondBuffered(request, response, fs, bufferSize);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBufferedString(HttpRequest request, HttpResponse response, string content)\r\n\t\t{\r\n\t\t\tRespondBufferedString(request, response, content, -1);\r\n\t\t}\r\n\r\n\t\tpublic static void RespondBufferedString(HttpRequest request, HttpResponse response, string content, int bufferSize)\r\n\t\t{\r\n\t\t\tusing (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(content)))\r\n\t\t\t{\r\n\t\t\t\tRespondBuffered(request, response, ms, bufferSize);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic static void ResponseAddGZip(HttpResponse response)\r\n\t\t{\r\n\t\t\tresponse.AppendHeader(\"Content-encoding\", \"gzip\");\r\n\t\t\tresponse.Cache.VaryByHeaders[\"Accept-encoding\"] = true;\r\n\t\t}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>public static bool RequestAcceptsGZip(HttpRequest request) { return (!String.IsNullOrEmpty(request.Headers[&#8220;Accept-encoding&#8221;]) &amp;&amp; (request.Headers[&#8220;Accept-encoding&#8221;].IndexOf(&#8220;gzip&#8221;) != -1)); } public static void RespondBuffered(HttpRequest request, HttpResponse response, Stream s, int bufferSize) { try { if (bufferSize &lt; 1) bufferSize = 1024 * 1024; \/\/ Default buffer size: 1MB byte[] buffer = new byte[bufferSize]; int byteCountBuffer = 0; int byteCountZipped = 0; long [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[6],"tags":[],"class_list":["post-111","post","type-post","status-publish","format-standard","hentry","category-dotnet"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/111","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=111"}],"version-history":[{"count":2,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/111\/revisions"}],"predecessor-version":[{"id":352,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/111\/revisions\/352"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=111"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=111"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=111"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}