示例#1
0
        internal static bool ProcessRangeRequest(HttpContext context,
                                                 string physicalPath,
                                                 long fileLength,
                                                 string rangeHeader,
                                                 string etag,
                                                 DateTime lastModified) {
            HttpRequest request = context.Request;
            HttpResponse response = context.Response;
            bool handled = false;

            // return "416 Requested range not satisfiable" if the file length is zero.
            if (fileLength <= 0) {
                SendRangeNotSatisfiable(response, fileLength);
                handled = true;
                return handled;
            }

            string ifRangeHeader = request.Headers["If-Range"];
            if (ifRangeHeader != null && ifRangeHeader.Length > 1) {
                // Is this an ETag or a Date? We only need to check two 
                // characters; an ETag either begins with W/ or it is quoted.
                if (ifRangeHeader[0] == '"') {
                    // it's a strong ETag
                    if (ifRangeHeader != etag) {
                        // the etags do not match, and we will therefore return the entire response
                        return handled;
                    }
                }
                else if (ifRangeHeader[0] == 'W' && ifRangeHeader[1] == '/') {
                    // it's a weak ETag, and is therefore not usable for sub-range retrieval and
                    // we will return the entire response
                    return handled;
                }
                else {
                    // It's a date. If it is greater than or equal to the last-write time of the file, we can send the range.
                    if (IsOutDated(ifRangeHeader, lastModified)) {
                        return handled;
                    }
                }
            }

            // the expected format is "bytes = <range1>[, <range2>, ...]"
            // where <range> is "<first_byte_pos>-[<last_byte_pos>]" or "-<last_n_bytes>".
            int indexOfEquals = rangeHeader.IndexOf('=');
            if (indexOfEquals == -1 || indexOfEquals == rangeHeader.Length - 1) {
                //invalid syntax
                return handled;
            }
            
            // iterate through the byte ranges and write each satisfiable range to the response
            int startIndex = indexOfEquals + 1;
            bool isRangeHeaderSyntacticallyValid = true;
            long offset;
            long length;
            bool isSatisfiable;
            bool exceededMax = false;
            ByteRange[] byteRanges = null;
            int byteRangesCount = 0;
            long totalBytes = 0;
            while (startIndex < rangeHeader.Length && isRangeHeaderSyntacticallyValid) {
                isRangeHeaderSyntacticallyValid = GetNextRange(rangeHeader, ref startIndex, fileLength, out offset, out length, out isSatisfiable);
                if (!isRangeHeaderSyntacticallyValid) {
                    break;
                }
                if (!isSatisfiable) {
                    continue;
                }
                if (byteRanges == null) {
                    byteRanges = new ByteRange[16];
                }
                if (byteRangesCount >= byteRanges.Length) {
                    // grow byteRanges array
                    ByteRange[] buffer = new ByteRange[byteRanges.Length * 2];
                    int byteCount = byteRanges.Length * Marshal.SizeOf(byteRanges[0]);
                    unsafe {
                        fixed (ByteRange * src = byteRanges, dst = buffer) {
                            StringUtil.memcpyimpl((byte*)src, (byte*)dst, byteCount);
                        }
                    }
                    byteRanges = buffer;
                }
                byteRanges[byteRangesCount].Offset = offset;
                byteRanges[byteRangesCount].Length = length;
                byteRangesCount++;
                // IIS imposes this limitation too, and sends "400 Bad Request" if exceeded
                totalBytes += length;
                if (totalBytes > fileLength * MAX_RANGE_ALLOWED) {
                    exceededMax = true;
                    break;
                }
            }
            
            if (!isRangeHeaderSyntacticallyValid) {
                return handled;
            }

            if (exceededMax) {
                SendBadRequest(response);
                handled = true;
                return handled;
            }

            if (byteRangesCount == 0) {
                // we parsed the Range header and found no satisfiable byte ranges, so return "416 Requested Range Not Satisfiable"
                SendRangeNotSatisfiable(response, fileLength);
                handled = true;
                return handled;
            }

            string contentType = MimeMapping.GetMimeMapping(physicalPath);
            if (byteRangesCount == 1) {
                offset = byteRanges[0].Offset;
                length = byteRanges[0].Length;
                response.ContentType = contentType;
                string contentRange = String.Format(CultureInfo.InvariantCulture, CONTENT_RANGE_FORMAT, offset, offset + length - 1, fileLength);
                response.AppendHeader("Content-Range", contentRange);

                SendFile(physicalPath, offset, length, fileLength, context);
            }
            else {
                response.ContentType = MULTIPART_CONTENT_TYPE;
                string contentRange;
                string partialContentType = "Content-Type: " + contentType + "\r\n";
                for(int i = 0; i < byteRangesCount; i++) {
                    offset = byteRanges[i].Offset;
                    length = byteRanges[i].Length;
                    response.Write(MULTIPART_RANGE_DELIMITER);
                    response.Write(partialContentType);
                    response.Write("Content-Range: ");
                    contentRange = String.Format(CultureInfo.InvariantCulture, CONTENT_RANGE_FORMAT, offset, offset + length - 1, fileLength);
                    response.Write(contentRange);
                    response.Write("\r\n\r\n");
                    SendFile(physicalPath, offset, length, fileLength, context);
                    response.Write("\r\n");
                }
                response.Write(MULTIPART_RANGE_END);
            }

            // if we make it here, we're sending a "206 Partial Content" status
            response.StatusCode = 206;
            response.AppendHeader("Last-Modified", HttpUtility.FormatHttpDateTime(lastModified));
            response.AppendHeader("Accept-Ranges", "bytes");
            response.AppendHeader("ETag", etag);
            response.AppendHeader("Cache-Control", "public");

            handled = true;
            return handled;
        }
示例#2
0
        internal static bool ProcessRangeRequest(HttpContext context,
                                                 string physicalPath,
                                                 long fileLength,
                                                 string rangeHeader,
                                                 string etag,
                                                 DateTime lastModified)
        {
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;
            bool         handled  = false;

            // return "416 Requested range not satisfiable" if the file length is zero.
            if (fileLength <= 0)
            {
                SendRangeNotSatisfiable(response, fileLength);
                handled = true;
                return(handled);
            }

            string ifRangeHeader = request.Headers["If-Range"];

            if (ifRangeHeader != null && ifRangeHeader.Length > 1)
            {
                // Is this an ETag or a Date? We only need to check two
                // characters; an ETag either begins with W/ or it is quoted.
                if (ifRangeHeader[0] == '"')
                {
                    // it's a strong ETag
                    if (ifRangeHeader != etag)
                    {
                        // the etags do not match, and we will therefore return the entire response
                        return(handled);
                    }
                }
                else if (ifRangeHeader[0] == 'W' && ifRangeHeader[1] == '/')
                {
                    // it's a weak ETag, and is therefore not usable for sub-range retrieval and
                    // we will return the entire response
                    return(handled);
                }
                else
                {
                    // It's a date. If it is greater than or equal to the last-write time of the file, we can send the range.
                    if (IsOutDated(ifRangeHeader, lastModified))
                    {
                        return(handled);
                    }
                }
            }

            // the expected format is "bytes = <range1>[, <range2>, ...]"
            // where <range> is "<first_byte_pos>-[<last_byte_pos>]" or "-<last_n_bytes>".
            int indexOfEquals = rangeHeader.IndexOf('=');

            if (indexOfEquals == -1 || indexOfEquals == rangeHeader.Length - 1)
            {
                //invalid syntax
                return(handled);
            }

            // iterate through the byte ranges and write each satisfiable range to the response
            int  startIndex = indexOfEquals + 1;
            bool isRangeHeaderSyntacticallyValid = true;
            long offset;
            long length;
            bool isSatisfiable;
            bool exceededMax = false;

            ByteRange[] byteRanges      = null;
            int         byteRangesCount = 0;
            long        totalBytes      = 0;

            while (startIndex < rangeHeader.Length && isRangeHeaderSyntacticallyValid)
            {
                isRangeHeaderSyntacticallyValid = GetNextRange(rangeHeader, ref startIndex, fileLength, out offset, out length, out isSatisfiable);
                if (!isRangeHeaderSyntacticallyValid)
                {
                    break;
                }
                if (!isSatisfiable)
                {
                    continue;
                }
                if (byteRanges == null)
                {
                    byteRanges = new ByteRange[16];
                }
                if (byteRangesCount >= byteRanges.Length)
                {
                    // grow byteRanges array
                    ByteRange[] buffer    = new ByteRange[byteRanges.Length * 2];
                    int         byteCount = byteRanges.Length * Marshal.SizeOf(byteRanges[0]);
                    unsafe
                    {
                        fixed(ByteRange *src = byteRanges, dst = buffer)
                        {
                            StringUtil.memcpyimpl((byte *)src, (byte *)dst, byteCount);
                        }
                    }
                    byteRanges = buffer;
                }
                byteRanges[byteRangesCount].Offset = offset;
                byteRanges[byteRangesCount].Length = length;
                byteRangesCount++;
                // IIS imposes this limitation too, and sends "400 Bad Request" if exceeded
                totalBytes += length;
                if (totalBytes > fileLength * MAX_RANGE_ALLOWED)
                {
                    exceededMax = true;
                    break;
                }
            }

            if (!isRangeHeaderSyntacticallyValid)
            {
                return(handled);
            }

            if (exceededMax)
            {
                SendBadRequest(response);
                handled = true;
                return(handled);
            }

            if (byteRangesCount == 0)
            {
                // we parsed the Range header and found no satisfiable byte ranges, so return "416 Requested Range Not Satisfiable"
                SendRangeNotSatisfiable(response, fileLength);
                handled = true;
                return(handled);
            }

            string contentType = MimeMapping.GetMimeMapping(physicalPath);

            if (byteRangesCount == 1)
            {
                offset = byteRanges[0].Offset;
                length = byteRanges[0].Length;
                response.ContentType = contentType;
                string contentRange = String.Format(CultureInfo.InvariantCulture, CONTENT_RANGE_FORMAT, offset, offset + length - 1, fileLength);
                response.AppendHeader("Content-Range", contentRange);

                SendFile(physicalPath, offset, length, fileLength, context);
            }
            else
            {
                response.ContentType = MULTIPART_CONTENT_TYPE;
                string contentRange;
                string partialContentType = "Content-Type: " + contentType + "\r\n";
                for (int i = 0; i < byteRangesCount; i++)
                {
                    offset = byteRanges[i].Offset;
                    length = byteRanges[i].Length;
                    response.Write(MULTIPART_RANGE_DELIMITER);
                    response.Write(partialContentType);
                    response.Write("Content-Range: ");
                    contentRange = String.Format(CultureInfo.InvariantCulture, CONTENT_RANGE_FORMAT, offset, offset + length - 1, fileLength);
                    response.Write(contentRange);
                    response.Write("\r\n\r\n");
                    SendFile(physicalPath, offset, length, fileLength, context);
                    response.Write("\r\n");
                }
                response.Write(MULTIPART_RANGE_END);
            }

            // if we make it here, we're sending a "206 Partial Content" status
            response.StatusCode = 206;
            response.AppendHeader("Last-Modified", HttpUtility.FormatHttpDateTime(lastModified));
            response.AppendHeader("Accept-Ranges", "bytes");
            response.AppendHeader("ETag", etag);
            response.AppendHeader("Cache-Control", "public");

            handled = true;
            return(handled);
        }
 internal static unsafe bool ProcessRangeRequest(HttpContext context, string physicalPath, long fileLength, string rangeHeader, string etag, DateTime lastModified)
 {
     long offset;
     long length;
     HttpRequest request = context.Request;
     HttpResponse response = context.Response;
     bool flag = false;
     if (fileLength <= 0L)
     {
         SendRangeNotSatisfiable(response, fileLength);
         return true;
     }
     string ifRangeHeader = request.Headers["If-Range"];
     if ((ifRangeHeader != null) && (ifRangeHeader.Length > 1))
     {
         if (ifRangeHeader[0] == '"')
         {
             if (ifRangeHeader != etag)
             {
                 return flag;
             }
         }
         else
         {
             if ((ifRangeHeader[0] == 'W') && (ifRangeHeader[1] == '/'))
             {
                 return flag;
             }
             if (IsOutDated(ifRangeHeader, lastModified))
             {
                 return flag;
             }
         }
     }
     int index = rangeHeader.IndexOf('=');
     if ((index == -1) || (index == (rangeHeader.Length - 1)))
     {
         return flag;
     }
     int startIndex = index + 1;
     bool flag2 = true;
     bool flag4 = false;
     ByteRange[] rangeArray = null;
     int num5 = 0;
     long num6 = 0L;
     while ((startIndex < rangeHeader.Length) && flag2)
     {
         bool flag3;
         flag2 = GetNextRange(rangeHeader, ref startIndex, fileLength, out offset, out length, out flag3);
         if (!flag2)
         {
             break;
         }
         if (flag3)
         {
             if (rangeArray == null)
             {
                 rangeArray = new ByteRange[0x10];
             }
             if (num5 >= rangeArray.Length)
             {
                 ByteRange[] rangeArray2 = new ByteRange[rangeArray.Length * 2];
                 int len = rangeArray.Length * Marshal.SizeOf(rangeArray[0]);
                 fixed (ByteRange* rangeRef = rangeArray)
                 {
                     fixed (ByteRange* rangeRef2 = rangeArray2)
                     {
                         StringUtil.memcpyimpl((byte*) rangeRef, (byte*) rangeRef2, len);
                     }
                 }
                 rangeArray = rangeArray2;
             }
             rangeArray[num5].Offset = offset;
             rangeArray[num5].Length = length;
             num5++;
             num6 += length;
             if (num6 > (fileLength * 5L))
             {
                 flag4 = true;
                 break;
             }
         }
     }
     if (!flag2)
     {
         return flag;
     }
     if (flag4)
     {
         SendBadRequest(response);
         return true;
     }
     if (num5 == 0)
     {
         SendRangeNotSatisfiable(response, fileLength);
         return true;
     }
     string mimeMapping = MimeMapping.GetMimeMapping(physicalPath);
     if (num5 == 1)
     {
         offset = rangeArray[0].Offset;
         length = rangeArray[0].Length;
         response.ContentType = mimeMapping;
         string str3 = string.Format(CultureInfo.InvariantCulture, "bytes {0}-{1}/{2}", new object[] { offset, (offset + length) - 1L, fileLength });
         response.AppendHeader("Content-Range", str3);
         SendFile(physicalPath, offset, length, fileLength, context);
     }
     else
     {
         response.ContentType = "multipart/byteranges; boundary=<q1w2e3r4t5y6u7i8o9p0zaxscdvfbgnhmjklkl>";
         string s = "Content-Type: " + mimeMapping + "\r\n";
         for (int i = 0; i < num5; i++)
         {
             offset = rangeArray[i].Offset;
             length = rangeArray[i].Length;
             response.Write("--<q1w2e3r4t5y6u7i8o9p0zaxscdvfbgnhmjklkl>\r\n");
             response.Write(s);
             response.Write("Content-Range: ");
             string str4 = string.Format(CultureInfo.InvariantCulture, "bytes {0}-{1}/{2}", new object[] { offset, (offset + length) - 1L, fileLength });
             response.Write(str4);
             response.Write("\r\n\r\n");
             SendFile(physicalPath, offset, length, fileLength, context);
             response.Write("\r\n");
         }
         response.Write("--<q1w2e3r4t5y6u7i8o9p0zaxscdvfbgnhmjklkl>--\r\n\r\n");
     }
     response.StatusCode = 0xce;
     response.AppendHeader("Last-Modified", HttpUtility.FormatHttpDateTime(lastModified));
     response.AppendHeader("Accept-Ranges", "bytes");
     response.AppendHeader("ETag", etag);
     response.AppendHeader("Cache-Control", "public");
     return true;
 }
        internal static unsafe bool ProcessRangeRequest(HttpContext context, string physicalPath, long fileLength, string rangeHeader, string etag, DateTime lastModified)
        {
            long         offset;
            long         length;
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;
            bool         flag     = false;

            if (fileLength <= 0L)
            {
                SendRangeNotSatisfiable(response, fileLength);
                return(true);
            }
            string ifRangeHeader = request.Headers["If-Range"];

            if ((ifRangeHeader != null) && (ifRangeHeader.Length > 1))
            {
                if (ifRangeHeader[0] == '"')
                {
                    if (ifRangeHeader != etag)
                    {
                        return(flag);
                    }
                }
                else
                {
                    if ((ifRangeHeader[0] == 'W') && (ifRangeHeader[1] == '/'))
                    {
                        return(flag);
                    }
                    if (IsOutDated(ifRangeHeader, lastModified))
                    {
                        return(flag);
                    }
                }
            }
            int index = rangeHeader.IndexOf('=');

            if ((index == -1) || (index == (rangeHeader.Length - 1)))
            {
                return(flag);
            }
            int  startIndex = index + 1;
            bool flag2      = true;
            bool flag4      = false;

            ByteRange[] rangeArray = null;
            int         num5       = 0;
            long        num6       = 0L;

            while ((startIndex < rangeHeader.Length) && flag2)
            {
                bool flag3;
                flag2 = GetNextRange(rangeHeader, ref startIndex, fileLength, out offset, out length, out flag3);
                if (!flag2)
                {
                    break;
                }
                if (flag3)
                {
                    if (rangeArray == null)
                    {
                        rangeArray = new ByteRange[0x10];
                    }
                    if (num5 >= rangeArray.Length)
                    {
                        ByteRange[] rangeArray2 = new ByteRange[rangeArray.Length * 2];
                        int         len         = rangeArray.Length * Marshal.SizeOf(rangeArray[0]);
                        fixed(ByteRange *rangeRef = rangeArray)
                        {
                            fixed(ByteRange *rangeRef2 = rangeArray2)
                            {
                                StringUtil.memcpyimpl((byte *)rangeRef, (byte *)rangeRef2, len);
                            }
                        }

                        rangeArray = rangeArray2;
                    }
                    rangeArray[num5].Offset = offset;
                    rangeArray[num5].Length = length;
                    num5++;
                    num6 += length;
                    if (num6 > (fileLength * 5L))
                    {
                        flag4 = true;
                        break;
                    }
                }
            }
            if (!flag2)
            {
                return(flag);
            }
            if (flag4)
            {
                SendBadRequest(response);
                return(true);
            }
            if (num5 == 0)
            {
                SendRangeNotSatisfiable(response, fileLength);
                return(true);
            }
            string mimeMapping = MimeMapping.GetMimeMapping(physicalPath);

            if (num5 == 1)
            {
                offset = rangeArray[0].Offset;
                length = rangeArray[0].Length;
                response.ContentType = mimeMapping;
                string str3 = string.Format(CultureInfo.InvariantCulture, "bytes {0}-{1}/{2}", new object[] { offset, (offset + length) - 1L, fileLength });
                response.AppendHeader("Content-Range", str3);
                SendFile(physicalPath, offset, length, fileLength, context);
            }
            else
            {
                response.ContentType = "multipart/byteranges; boundary=<q1w2e3r4t5y6u7i8o9p0zaxscdvfbgnhmjklkl>";
                string s = "Content-Type: " + mimeMapping + "\r\n";
                for (int i = 0; i < num5; i++)
                {
                    offset = rangeArray[i].Offset;
                    length = rangeArray[i].Length;
                    response.Write("--<q1w2e3r4t5y6u7i8o9p0zaxscdvfbgnhmjklkl>\r\n");
                    response.Write(s);
                    response.Write("Content-Range: ");
                    string str4 = string.Format(CultureInfo.InvariantCulture, "bytes {0}-{1}/{2}", new object[] { offset, (offset + length) - 1L, fileLength });
                    response.Write(str4);
                    response.Write("\r\n\r\n");
                    SendFile(physicalPath, offset, length, fileLength, context);
                    response.Write("\r\n");
                }
                response.Write("--<q1w2e3r4t5y6u7i8o9p0zaxscdvfbgnhmjklkl>--\r\n\r\n");
            }
            response.StatusCode = 0xce;
            response.AppendHeader("Last-Modified", HttpUtility.FormatHttpDateTime(lastModified));
            response.AppendHeader("Accept-Ranges", "bytes");
            response.AppendHeader("ETag", etag);
            response.AppendHeader("Cache-Control", "public");
            return(true);
        }
 private static string WriteMultipartDetails(ByteRange range, string contentType, long fileLength)
 {
     StringBuilder sb = new StringBuilder();
     sb.AppendLine(string.Format("--{0}", RANGE_BOUNDARY));
     sb.AppendLine(string.Format("Content-Type: {0}", contentType));
     sb.AppendLine(string.Format("Content-Range: {0}", string.Format(CultureInfo.InvariantCulture, "bytes {0}-{1}/{2}", range.Offset, range.Length, fileLength)));
     sb.AppendLine();
     return sb.ToString();
 }