Advertisement
Guest User

Untitled

a guest
Jul 3rd, 2010
289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 31.90 KB | None | 0 0
  1. using System;
  2. using System.IO;
  3. using System.Web;
  4. using System.Collections;
  5. using System.Data;
  6. using System.Net;
  7. using System.Security.Cryptography;
  8.  
  9.  
  10. public class ResumeDownload : IDisposable
  11. {
  12.     const string MULTIPART_BOUNDARY = "<q1w2e3r4t5y6u7i8o9p0>";
  13.     const string MULTIPART_CONTENTTYPE = "multipart/byteranges; boundary=" + MULTIPART_BOUNDARY;
  14.  
  15.     //Response.AddHeader("Content-Disposition","attachment; filename=" + Path.GetFileName(fUrl));
  16.     const string HTTP_HEADER_Content_Disposition = "Content-Disposition";
  17.  
  18.     const string HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
  19.     const string HTTP_HEADER_ACCEPT_RANGES_BYTES = "bytes";
  20.     const string HTTP_HEADER_CONTENT_TYPE = "Content-Type";
  21.     const string HTTP_HEADER_CONTENT_RANGE = "Content-Range";
  22.     const string HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
  23.     const string HTTP_HEADER_ENTITY_TAG = "ETag";
  24.     const string HTTP_HEADER_LAST_MODIFIED = "Last-Modified";
  25.     const string HTTP_HEADER_RANGE = "Range";
  26.     const string HTTP_HEADER_IF_RANGE = "If-Range";
  27.     const string HTTP_HEADER_IF_MATCH = "If-Match";
  28.     const string HTTP_HEADER_IF_NONE_MATCH = "If-None-Match";
  29.     const string HTTP_HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
  30.     const string HTTP_HEADER_IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
  31.     const string HTTP_HEADER_UNLESS_MODIFIED_SINCE = "Unless-Modified-Since";
  32.  
  33.     const string HTTP_METHOD_GET = "GET";
  34.     const string HTTP_METHOD_HEAD = "HEAD";
  35.  
  36.     private string fContentType = "application/octet-stream";
  37.  
  38.     public string ContentType
  39.     {
  40.         get { return fContentType; }
  41.         set { fContentType = value; }
  42.     }
  43.  
  44.     public void Dispose()
  45.     {
  46.     }
  47.  
  48.     public void ClearResponseData()
  49.     {
  50.         HttpResponse objResponse = HttpContext.Current.Response;
  51.         objResponse.ClearContent();
  52.         objResponse.ClearHeaders();
  53.     }
  54.  
  55.     public DownloadState ProcessDownload(string fileName, string headerFileName, string fileMimeType)
  56.     {
  57.  
  58.         HttpContext objContext = HttpContext.Current;
  59.         // The Response object from the Context
  60.         HttpResponse objResponse = objContext.Response;
  61.         // The Request object from the Context
  62.         HttpRequest objRequest = objContext.Request;
  63.  
  64.         // File information object...
  65.         FileInformation objFile;
  66.  
  67.         // Long Arrays for Range values:
  68.         // ...Begin() contains start positions for each requested Range
  69.         long[] alRequestedRangesBegin = new long[1];
  70.         // ...End() contains end positions for each requested Range
  71.         long[] alRequestedRangesend = new long[1];
  72.  
  73.         // Response Header value: Content Length...
  74.         int iResponseContentLength = 0;
  75.  
  76.         // The Stream we//re using to download the file in chunks...
  77.         System.IO.Stream objStream;
  78.         // Total Bytes to read (per requested range)
  79.         int iBytesToRead;
  80.         // Size of the Buffer for chunk-wise reading
  81.         int iBufferSize = 25000;
  82.         // The Buffer itself
  83.         byte[] bBuffer = new byte[iBufferSize];
  84.         // Amount of Bytes read
  85.         int iLengthOfReadChunk = -1;
  86.  
  87.         // Indicates if the download was interrupted
  88.         bool bDownloadBroken = false;
  89.  
  90.         // Indicates if this is a range request
  91.         bool bIsRangeRequest = false;
  92.         // Indicates if this is a multipart range request
  93.         bool bMultipart = false;
  94.  
  95.         // Loop counter used to iterate through the ranges
  96.         int iLoop;
  97.  
  98.         if (string.IsNullOrEmpty(headerFileName))
  99.             headerFileName = Path.GetFileName(fileName).Replace(' ', '-');
  100.  
  101.         // Content-Disposition value
  102.         string Content_Disposition_File = "attachment; filename=" + headerFileName + "";
  103.  
  104.         // ToDo - your code here (Determine which file is requested)
  105.         // Using objRequest, determine which file is requested to
  106.         // be downloaded, and open objFile with that file:
  107.         // Example:
  108.         // objFile = New Download.FileInformation(<Full path to the requested file>)
  109.         //objFile = new Download.FileInformation(objContext.Server.MapPath("~/download.zip"));
  110.         objFile = new FileInformation(fileName);
  111.         //objFile.ContentType = this.ContentType;
  112.         objFile.ContentType = fileMimeType;
  113.  
  114.         // Clear the current output content from the buffer
  115.         objResponse.Clear();
  116.  
  117.         if (!(objRequest.HttpMethod.Equals(HTTP_METHOD_GET) ||
  118.             objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD)))
  119.             // Currently, only the GET and HEAD methods
  120.             // are supported...
  121.             objResponse.StatusCode = 501;  // Not implemented
  122.  
  123.         else if (!objFile.Exists)
  124.             // The requested file could not be retrieved...
  125.             objResponse.StatusCode = 404;  // Not found
  126.  
  127.         else if (objFile.Length > Int32.MaxValue)
  128.             // The file size is too large...
  129.             objResponse.StatusCode = 413;  // Request Entity Too Large
  130.  
  131.         else if (!ParseRequestHeaderRange(objRequest, ref alRequestedRangesBegin, ref alRequestedRangesend,
  132.             objFile.Length, ref bIsRangeRequest))
  133.             // The Range request contained bad entries
  134.             objResponse.StatusCode = 400;  // Bad Request
  135.  
  136.         else if (!CheckIfModifiedSince(objRequest, objFile))
  137.             // The entity is still unmodified...
  138.             objResponse.StatusCode = 304;  // Not Modified
  139.  
  140.         else if (!CheckIfUnmodifiedSince(objRequest, objFile))
  141.             // The entity was modified since the requested date...
  142.             objResponse.StatusCode = 412;  // Precondition failed
  143.  
  144.         else if (!CheckIfMatch(objRequest, objFile))
  145.             // The entity does not match the request...
  146.             objResponse.StatusCode = 412;  // Precondition failed
  147.  
  148.         else if (!CheckIfNoneMatch(objRequest, objResponse, objFile))
  149.         {
  150.             // The entity does match the none-match request, the response
  151.             // code was set inside the CheckifNoneMatch function
  152.         }
  153.         else
  154.         {
  155.             // Preliminary checks where successful...
  156.  
  157.             if (bIsRangeRequest && CheckIfRange(objRequest, objFile))
  158.             {
  159.                 // This is a Range request...
  160.  
  161.                 // if the Range arrays contain more than one entry,
  162.                 // it even is a multipart range request...
  163.                 bMultipart = (alRequestedRangesBegin.GetUpperBound(0) > 0);
  164.  
  165.                 // Loop through each Range to calculate the entire Response length
  166.                 for (iLoop = alRequestedRangesBegin.GetLowerBound(0); iLoop <= alRequestedRangesBegin.GetUpperBound(0); iLoop++)
  167.                 {
  168.                     // The length of the content (for this range)
  169.                     iResponseContentLength += Convert.ToInt32(alRequestedRangesend[iLoop] - alRequestedRangesBegin[iLoop]) + 1;
  170.  
  171.                     if (bMultipart)
  172.                     {
  173.                         //
  174.                         iResponseContentLength += HTTP_HEADER_Content_Disposition.Length;
  175.                         // if this is a multipart range request, calculate
  176.                         // the length of the intermediate headers to send
  177.                         iResponseContentLength += MULTIPART_BOUNDARY.Length;
  178.                         iResponseContentLength += objFile.ContentType.Length;
  179.                         iResponseContentLength += alRequestedRangesBegin[iLoop].ToString().Length;
  180.                         iResponseContentLength += alRequestedRangesend[iLoop].ToString().Length;
  181.                         iResponseContentLength += objFile.Length.ToString().Length;
  182.                         // 49 is the length of line break and other
  183.                         // needed characters in one multipart header
  184.                         iResponseContentLength += 49;
  185.                     }
  186.  
  187.                 }
  188.  
  189.                 if (bMultipart)
  190.                 {
  191.                     // if this is a multipart range request,  
  192.                     // we must also calculate the length of
  193.                     // the last intermediate header we must send
  194.                     iResponseContentLength += MULTIPART_BOUNDARY.Length;
  195.                     // 8 is the length of dash and line break characters
  196.                     iResponseContentLength += 8;
  197.                 }
  198.                 else
  199.                 {
  200.                     // This is no multipart range request, so
  201.                     // we must indicate the response Range of
  202.                     // in the initial HTTP Header
  203.                     objResponse.AppendHeader(HTTP_HEADER_CONTENT_RANGE, "bytes " +
  204.                         alRequestedRangesBegin[0].ToString() + "-" +
  205.                         alRequestedRangesend[0].ToString() + "/" +
  206.                         objFile.Length.ToString());
  207.                 }
  208.  
  209.                 // Range response
  210.                 objResponse.StatusCode = 206; // Partial Response
  211.  
  212.             }
  213.             else
  214.             {
  215.                 // This is not a Range request, or the requested Range entity ID
  216.                 // does not match the current entity ID, so start a new download
  217.  
  218.                 // Indicate the file//s complete size as content length
  219.                 iResponseContentLength = Convert.ToInt32(objFile.Length);
  220.  
  221.                 // Return a normal OK status...
  222.                 objResponse.StatusCode = 200;
  223.             }
  224.  
  225.  
  226.             // Write file name into the Response
  227.             objResponse.AppendHeader(HTTP_HEADER_Content_Disposition, Content_Disposition_File);
  228.  
  229.             // Write the content length into the Response
  230.             objResponse.AppendHeader(HTTP_HEADER_CONTENT_LENGTH, iResponseContentLength.ToString());
  231.  
  232.             // Write the Last-Modified Date into the Response
  233.             objResponse.AppendHeader(HTTP_HEADER_LAST_MODIFIED, objFile.LastWriteTimeUTC.ToString("r"));
  234.  
  235.             // Tell the client software that we accept Range request
  236.             objResponse.AppendHeader(HTTP_HEADER_ACCEPT_RANGES, HTTP_HEADER_ACCEPT_RANGES_BYTES);
  237.  
  238.             // Write the file//s Entity Tag into the Response (in quotes!)
  239.             objResponse.AppendHeader(HTTP_HEADER_ENTITY_TAG, "\"" + objFile.EntityTag + "\"");
  240.  
  241.  
  242.             // Write the Content Type into the Response
  243.             if (bMultipart)
  244.                 // Multipart messages have this special Type.
  245.                 // In this case, the file//s actual mime type is
  246.                 // written into the Response at a later time...
  247.                 objResponse.ContentType = MULTIPART_CONTENTTYPE;
  248.             else
  249.                 // Single part messages have the files content type...
  250.                 objResponse.ContentType = objFile.ContentType;
  251.  
  252.  
  253.             if (objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD))
  254.             {
  255.                 // Only the HEAD was requested, so we can quit the Response right here...
  256.             }
  257.             else
  258.             {
  259.  
  260.                 // Flush the HEAD information to the client...
  261.                 objResponse.Flush();
  262.  
  263.                 // Download is in progress...
  264.                 objFile.State = DownloadState.fsDownloadInProgress;
  265.  
  266.                 // Open the file as filestream
  267.                 objStream = new FileStream(objFile.FullName, FileMode.Open,
  268.                     FileAccess.Read,
  269.                     FileShare.Read);
  270.                 try
  271.                 {
  272.  
  273.                     //objStream = objFile.DataStream;
  274.  
  275.                     // Now, for each requested range, stream the chunks to the client:
  276.                     for (iLoop = alRequestedRangesBegin.GetLowerBound(0); iLoop <= alRequestedRangesBegin.GetUpperBound(0); iLoop++)
  277.                     {
  278.  
  279.                         // Move the stream to the desired start position...
  280.                         objStream.Seek(alRequestedRangesBegin[iLoop], SeekOrigin.Begin);
  281.  
  282.                         // Calculate the total amount of bytes for this range
  283.                         iBytesToRead = Convert.ToInt32(alRequestedRangesend[iLoop] - alRequestedRangesBegin[iLoop]) + 1;
  284.  
  285.                         if (bMultipart)
  286.                         {
  287.                             // if this is a multipart response, we must add
  288.                             // certain headers before streaming the content:
  289.  
  290.                             // The multipart boundary
  291.                             objResponse.Output.WriteLine("--" + MULTIPART_BOUNDARY);
  292.                             //objResponse.AppendHeader("--",MULTIPART_BOUNDARY);
  293.  
  294.                             // The mime type of this part of the content
  295.                             objResponse.Output.WriteLine(HTTP_HEADER_CONTENT_TYPE + ": " + objFile.ContentType);
  296.                             //objResponse.AppendHeader(HTTP_HEADER_CONTENT_TYPE,objFile.ContentType);
  297.  
  298.                             // The actual range
  299.                             objResponse.Output.WriteLine(HTTP_HEADER_CONTENT_RANGE + ": bytes " +
  300.                                 alRequestedRangesBegin[iLoop].ToString() + "-" +
  301.                                 alRequestedRangesend[iLoop].ToString() + "/" +
  302.                                 objFile.Length.ToString());
  303.  
  304.                             /*objResponse.AppendHeader(HTTP_HEADER_CONTENT_RANGE,": bytes " +
  305.                                 alRequestedRangesBegin[iLoop].ToString() + "-" +
  306.                                 alRequestedRangesend[iLoop].ToString() + "/" +
  307.                                 objFile.Length.ToString());
  308.                             */
  309.                             // Indicating the end of the intermediate headers
  310.                             objResponse.Output.WriteLine();
  311.  
  312.                         }
  313.  
  314.                         // Now stream the range to the client...
  315.                         while (iBytesToRead > 0)
  316.                         {
  317.  
  318.                             if (objResponse.IsClientConnected)
  319.                             {
  320.                                 // Read a chunk of bytes from the stream
  321.                                 iLengthOfReadChunk = objStream.Read(bBuffer, 0, Math.Min(bBuffer.Length, iBytesToRead));
  322.  
  323.                                 // Write the data to the current output stream.
  324.                                 objResponse.OutputStream.Write(bBuffer, 0, iLengthOfReadChunk);
  325.  
  326.                                 // Flush the data to the HTML output.
  327.                                 objResponse.Flush();
  328.  
  329.                                 // Clear the buffer
  330.                                 bBuffer = new byte[iBufferSize];
  331.                                 //ReDim bBuffer(iBufferSize);
  332.  
  333.                                 // Reduce BytesToRead
  334.                                 iBytesToRead -= iLengthOfReadChunk;
  335.                             }
  336.                             else
  337.                             {
  338.                                 // The client was or has disconneceted from the server... stop downstreaming...
  339.                                 iBytesToRead = -1;
  340.                                 bDownloadBroken = true;
  341.  
  342.                             }
  343.                         }
  344.  
  345.                         // In Multipart responses, mark the end of the part
  346.                         if (bMultipart) objResponse.Output.WriteLine();
  347.  
  348.                         // No need to proceed to the next part if the
  349.                         // client was disconnected
  350.                         if (bDownloadBroken) break;
  351.                     }
  352.  
  353.                     // At this point, the response was finished or cancelled...
  354.  
  355.                     if (bDownloadBroken)
  356.                         // Download is broken...
  357.                         objFile.State = DownloadState.fsDownloadBroken;
  358.  
  359.                     else
  360.                     {
  361.                         if (bMultipart)
  362.                         {
  363.                             // In multipart responses, close the response once more with
  364.                             // the boundary and line breaks
  365.                             objResponse.Output.WriteLine("--" + MULTIPART_BOUNDARY + "--");
  366.                             objResponse.Output.WriteLine();
  367.                         }
  368.  
  369.                         // The download was finished
  370.                         objFile.State = DownloadState.fsDownloadFinished;
  371.                     }
  372.                 }
  373.                 finally
  374.                 {
  375.                     objStream.Close();
  376.                 }
  377.             }
  378.         }
  379.         //objResponse.End();
  380.  
  381.         //====== return download state ======
  382.         return objFile.State;
  383.     }
  384.  
  385.  
  386.     bool CheckIfRange(HttpRequest objRequest, FileInformation objFile)
  387.     {
  388.         string sRequestHeaderIfRange;
  389.  
  390.         // Checks the If-Range header if it was sent with the request.
  391.         //
  392.         // returns true if the header value matches the file//s entity tag,
  393.         //              or if no header was sent,
  394.         // returns false if a header was sent, but does not match the file.
  395.  
  396.  
  397.         // Retrieve If-Range Header value from Request (objFile.EntityTag if none is indicated)
  398.         sRequestHeaderIfRange = RetrieveHeader(objRequest, HTTP_HEADER_IF_RANGE, objFile.EntityTag);
  399.  
  400.         // If the requested file entity matches the current
  401.         // file entity, return true
  402.         return sRequestHeaderIfRange.Equals(objFile.EntityTag);
  403.     }
  404.  
  405.     bool CheckIfMatch(HttpRequest objRequest, FileInformation objFile)
  406.     {
  407.         string sRequestHeaderIfMatch;
  408.         string[] sEntityIDs;
  409.         bool breturn = false;
  410.  
  411.         // Checks the If-Match header if it was sent with the request.
  412.         //
  413.         // returns true if one of the header values matches the file//s entity tag,
  414.         //              or if no header was sent,
  415.         // returns false if a header was sent, but does not match the file.
  416.  
  417.  
  418.         // Retrieve If-Match Header value from Request (*, meaning any, if none is indicated)
  419.         sRequestHeaderIfMatch = RetrieveHeader(objRequest, HTTP_HEADER_IF_MATCH, "*");
  420.  
  421.         if (sRequestHeaderIfMatch.Equals("*"))
  422.             // The server may perform the request as if the
  423.             // If-Match header does not exists...
  424.             breturn = true;
  425.  
  426.         else
  427.         {
  428.             // One or more Match IDs where sent by the client software...
  429.             sEntityIDs = sRequestHeaderIfMatch.Replace("bytes=", "").Split(",".ToCharArray());
  430.  
  431.             // Loop through all entity IDs, finding one
  432.             // which matches the current file's ID will
  433.             // be enough to satisfy the If-Match
  434.             for (int iLoop = sEntityIDs.GetLowerBound(0); iLoop <= sEntityIDs.GetUpperBound(0); iLoop++)
  435.             {
  436.                 if (sEntityIDs[iLoop].Trim().Equals(objFile.EntityTag))
  437.                     breturn = true;
  438.             }
  439.         }
  440.         // return the result...
  441.         return breturn;
  442.     }
  443.  
  444.     bool CheckIfNoneMatch(HttpRequest objRequest, HttpResponse objResponse, FileInformation objFile)
  445.     {
  446.         string sRequestHeaderIfNoneMatch;
  447.         string[] sEntityIDs;
  448.         bool breturn = true;
  449.         string sreturn = "";
  450.         // Checks the If-None-Match header if it was sent with the request.
  451.         //
  452.         // returns true if one of the header values matches the file//s entity tag,
  453.         //              or if "*" was sent,
  454.         // returns false if a header was sent, but does not match the file, or
  455.         //               if no header was sent.
  456.  
  457.         // Retrieve If-None-Match Header value from Request (*, meaning any, if none is indicated)
  458.         sRequestHeaderIfNoneMatch = RetrieveHeader(objRequest, HTTP_HEADER_IF_NONE_MATCH, String.Empty);
  459.  
  460.         if (sRequestHeaderIfNoneMatch.Equals(String.Empty))
  461.             // Perform the request normally...
  462.             breturn = true;
  463.         else
  464.         {
  465.             if (sRequestHeaderIfNoneMatch.Equals("*"))
  466.             {
  467.                 // The server must not perform the request
  468.                 objResponse.StatusCode = 412;  // Precondition failed
  469.                 breturn = false;
  470.             }
  471.             else
  472.             {
  473.                 // One or more Match IDs where sent by the client software...
  474.                 sEntityIDs = sRequestHeaderIfNoneMatch.Replace("bytes=", "").Split(",".ToCharArray());
  475.  
  476.                 // Loop through all entity IDs, finding one which
  477.                 // does not match the current file//s ID will be
  478.                 // enough to satisfy the If-None-Match
  479.                 for (int iLoop = sEntityIDs.GetLowerBound(0); iLoop <= sEntityIDs.GetUpperBound(0); iLoop++)
  480.                 {
  481.                     if (sEntityIDs[iLoop].Trim().Equals(objFile.EntityTag))
  482.                     {
  483.                         sreturn = sEntityIDs[iLoop];
  484.                         breturn = false;
  485.                     }
  486.                 }
  487.  
  488.                 if (!breturn)
  489.                 {
  490.                     // One of the requested entities matches the current file//s tag,
  491.                     objResponse.AppendHeader("ETag", sreturn);
  492.                     objResponse.StatusCode = 304; // Not Modified
  493.                 }
  494.             }
  495.         }
  496.         // return the result...
  497.         return breturn;
  498.     }
  499.  
  500.     bool CheckIfModifiedSince(HttpRequest objRequest, FileInformation objFile)
  501.     {
  502.         string sDate;
  503.         DateTime dDate;
  504.         bool breturn;
  505.  
  506.         // Checks the If-Modified header if it was sent with the request.
  507.         //
  508.         // returns true, if the file was modified since the
  509.         //               indicated date (RFC 1123 format), or
  510.         //               if no header was sent,
  511.         // returns false, if the file was not modified since
  512.         //                the indicated date
  513.  
  514.  
  515.         // Retrieve If-Modified-Since Header value from Request (Empty if none is indicated)
  516.         sDate = RetrieveHeader(objRequest, HTTP_HEADER_IF_MODIFIED_SINCE, string.Empty);
  517.  
  518.         if (sDate.Equals(String.Empty))
  519.             // No If-Modified-Since date was indicated,
  520.             // so just give this as true
  521.             breturn = true;
  522.  
  523.         else
  524.         {
  525.             try
  526.             {
  527.                 // ... to parse the indicated sDate to a datetime value
  528.                 dDate = DateTime.Parse(sDate);
  529.                 // return true if the file was modified since or at the indicated date...
  530.                 breturn = (objFile.LastWriteTimeUTC >= DateTime.Parse(sDate));
  531.             }
  532.             catch
  533.             {
  534.                 // Converting the indicated date value failed, return false
  535.                 breturn = false;
  536.             }
  537.         }
  538.         return breturn;
  539.     }
  540.  
  541.     bool CheckIfUnmodifiedSince(HttpRequest objRequest, FileInformation objFile)
  542.     {
  543.         string sDate;
  544.         DateTime dDate;
  545.         bool breturn;
  546.  
  547.  
  548.         // Checks the If-Unmodified or Unless-Modified-Since header, if
  549.         // one of them was sent with the request.
  550.         //
  551.         // returns true, if the file was not modified since the
  552.         //               indicated date (RFC 1123 format), or
  553.         //               if no header was sent,
  554.         // returns false, if the file was modified since the indicated date
  555.  
  556.  
  557.         // Retrieve If-Unmodified-Since Header value from Request (Empty if none is indicated)
  558.         sDate = RetrieveHeader(objRequest, HTTP_HEADER_IF_UNMODIFIED_SINCE, String.Empty);
  559.  
  560.         if (sDate.Equals(String.Empty))
  561.             // If-Unmodified-Since was not sent, check Unless-Modified-Since...
  562.             sDate = RetrieveHeader(objRequest, HTTP_HEADER_UNLESS_MODIFIED_SINCE, String.Empty);
  563.  
  564.  
  565.         if (sDate.Equals(String.Empty))
  566.             // No date was indicated,
  567.             // so just give this as true
  568.             breturn = true;
  569.  
  570.         else
  571.         {
  572.             try
  573.             {
  574.                 // ... to parse the indicated sDate to a datetime value
  575.                 dDate = DateTime.Parse(sDate);
  576.                 // return true if the file was not modified since the indicated date...
  577.                 breturn = objFile.LastWriteTimeUTC < DateTime.Parse(sDate);
  578.             }
  579.             catch
  580.             {
  581.                 // Converting the indicated date value failed, return false
  582.                 breturn = false;
  583.             }
  584.         }
  585.         return breturn;
  586.     }
  587.  
  588.     bool ParseRequestHeaderRange(HttpRequest objRequest, ref long[] lBegin, ref long[] lEnd, long lMax, ref bool bRangeRequest)
  589.     {
  590.         bool bValidRanges;
  591.         string sSource;
  592.         int iLoop;
  593.         string[] sRanges;
  594.  
  595.         // Parses the Range header from the Request (if there is one)
  596.         // returns true, if the Range header was valid, or if there was no
  597.         //               Range header at all (meaning that the whole
  598.         //               file was requested)
  599.         // returns false, if the Range header asked for unsatisfieable
  600.         //                ranges
  601.  
  602.         // Retrieve Range Header value from Request (Empty if none is indicated)
  603.         sSource = RetrieveHeader(objRequest, HTTP_HEADER_RANGE, String.Empty);
  604.  
  605.         if (sSource.Equals(String.Empty))
  606.         {
  607.             // No Range was requested, return the entire file range...
  608.  
  609.             lBegin = new long[1];
  610.             //ReDim lBegin(0);
  611.             lEnd = new long[1];
  612.             //ReDim lEnd(0);
  613.  
  614.             lBegin[0] = 0;
  615.             lEnd[0] = lMax - 1;
  616.  
  617.             // A valid range is returned
  618.             bValidRanges = true;
  619.             // no Range request
  620.             bRangeRequest = false;
  621.         }
  622.         else
  623.         {
  624.             // A Range was requested...
  625.  
  626.             // Preset value...
  627.             bValidRanges = true;
  628.  
  629.             // return true for the bRange parameter, telling the caller
  630.             // that the Request is indeed a Range request...
  631.             bRangeRequest = true;
  632.  
  633.             // Remove "bytes=" from the beginning, and split the remaining
  634.             // string by comma characters
  635.             sRanges = sSource.Replace("bytes=", "").Split(",".ToCharArray());
  636.             lBegin = new long[sRanges.GetUpperBound(0) + 1];
  637.             //ReDim lBegin(sRanges.GetUpperBound(0));
  638.             lEnd = new long[sRanges.GetUpperBound(0) + 1];
  639.             //ReDim lEnd(sRanges.GetUpperBound(0));
  640.  
  641.             // Check each found Range request for consistency
  642.             for (iLoop = sRanges.GetLowerBound(0); iLoop <= sRanges.GetUpperBound(0); iLoop++)
  643.             {
  644.  
  645.                 // Split this range request by the dash character,
  646.                 // sRange(0) contains the requested begin-value,
  647.                 // sRange(1) contains the requested end-value...
  648.                 string[] sRange = sRanges[iLoop].Split("-".ToCharArray());
  649.  
  650.                 // Determine the end of the requested range
  651.                 if (sRange[1].Equals(String.Empty))
  652.                     // No end was specified, take the entire range
  653.                     lEnd[iLoop] = lMax - 1;
  654.                 else
  655.                     // An end was specified...
  656.                     lEnd[iLoop] = long.Parse(sRange[1]);
  657.  
  658.                 // Determine the begin of the requested range
  659.                 if (sRange[0].Equals(String.Empty))
  660.                 {
  661.                     // No begin was specified, which means that
  662.                     // the end value indicated to return the last n
  663.                     // bytes of the file:
  664.  
  665.                     // Calculate the begin
  666.                     lBegin[iLoop] = lMax - 1 - lEnd[iLoop];
  667.                     // ... to the end of the file...
  668.                     lEnd[iLoop] = lMax - 1;
  669.                 }
  670.                 else
  671.                     // A normal begin value was indicated...
  672.                     lBegin[iLoop] = long.Parse(sRange[0]);
  673.  
  674.  
  675.                 // Check if the requested range values are valid,
  676.                 // return false if they are not.
  677.                 //
  678.                 // Note:
  679.                 // Do not clean invalid values up by fitting them into
  680.                 // valid parameters using Math.Min and Math.Max, because
  681.                 // some download clients (like Go!Zilla) might send invalid
  682.                 // (e.g. too large) range requests to determine the file limits!
  683.  
  684.                 // Begin and end must not exceed the file size
  685.                 if ((lBegin[iLoop] > (lMax - 1)) || (lEnd[iLoop] > (lMax - 1)))
  686.                     bValidRanges = false;
  687.  
  688.                 // Begin and end cannot be < 0
  689.                 if ((lBegin[iLoop] < 0) || (lEnd[iLoop] < 0))
  690.                     bValidRanges = false;
  691.  
  692.                 // End must be larger or equal to begin value
  693.                 if (lEnd[iLoop] < lBegin[iLoop])
  694.                     // The requested Range is invalid...
  695.                     bValidRanges = false;
  696.  
  697.             }
  698.  
  699.         }
  700.         return bValidRanges;
  701.     }
  702.  
  703.     string RetrieveHeader(HttpRequest objRequest, string sHeader, string sDefault)
  704.     {
  705.         string sreturn;
  706.  
  707.         // Retrieves the indicated Header//s value from the Request,
  708.         // if the header was not sent, sDefault is returned.
  709.         //
  710.         // If the value contains quote characters, they are removed.
  711.  
  712.         sreturn = objRequest.Headers[sHeader];
  713.  
  714.         if ((sreturn == null) || (sreturn.Equals(string.Empty)))
  715.             // The Header wos not found in the Request,
  716.             // return the indicated default value...
  717.             return sDefault;
  718.  
  719.         else
  720.             // return the found header value, stripped of any quote characters...
  721.             return sreturn.Replace("\"", "");
  722.  
  723.     }
  724.  
  725.  
  726.     string GenerateHash(System.IO.Stream objStream, long lBegin, long lEnd)
  727.     {
  728.         byte[] bByte = new byte[Convert.ToInt32(lEnd)];
  729.  
  730.         objStream.Read(bByte, Convert.ToInt32(lBegin), Convert.ToInt32(lEnd - lBegin) + 1);
  731.  
  732.         //Instantiate an MD5 Provider object
  733.         MD5CryptoServiceProvider Md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
  734.  
  735.         //Compute the hash value from the source
  736.         byte[] ByteHash = Md5.ComputeHash(bByte);
  737.  
  738.         //And convert it to String format for return
  739.         return Convert.ToBase64String(ByteHash);
  740.     }
  741.  
  742. }
  743.  
  744. public class FileInformation
  745. {
  746.     DownloadState m_nState;
  747.     DateTime fCreatTime;
  748.     string fFileName = "";
  749.     string m_ContentType = "application/octet-stream";
  750.     long? fileLength = null;
  751.  
  752.     public FileInformation(string fileName)
  753.     {
  754.         fFileName = fileName;
  755.         fCreatTime = DateTime.Now;
  756.     }
  757.  
  758.     public bool Exists
  759.     {
  760.         get
  761.         {
  762.             return File.Exists(fFileName);
  763.         }
  764.     }
  765.  
  766.     public string FullName
  767.     {
  768.         get { return fFileName;/*m_objFile.FullName;*/}
  769.     }
  770.  
  771.     public DateTime LastWriteTimeUTC
  772.     {
  773.         get { return fCreatTime.ToUniversalTime(); }
  774.     }
  775.     public long Length
  776.     {
  777.         get
  778.         {
  779.             if (fileLength.HasValue == false)
  780.             {
  781.                 FileInfo info = new FileInfo(fFileName);
  782.                 fileLength = info.Length;
  783.             }
  784.             return fileLength.Value;
  785.  
  786.         }
  787.     }
  788.  
  789.     public string ContentType
  790.     {
  791.         get
  792.         {
  793.             return m_ContentType;
  794.         }
  795.         set
  796.         {
  797.             m_ContentType = value;
  798.         }
  799.     }
  800.     public string EntityTag
  801.     {
  802.         get
  803.         {
  804.             return fFileName.GetHashCode().ToString();//"MyExampleFileID";
  805.         }
  806.     }
  807.     public virtual DownloadState State
  808.     {
  809.         get
  810.         {
  811.             return m_nState;
  812.         }
  813.         set
  814.         {
  815.             m_nState = value;
  816.         }
  817.     }
  818. }
  819.  
  820.  
  821. public enum DownloadState
  822. {
  823.     /// Clear: No download in progress,
  824.     /// the file can be manipulated
  825.     fsClear = 1,
  826.  
  827.     /// Locked: A dynamically created file must
  828.     /// not be changed
  829.     fsLocked = 2,
  830.  
  831.     /// In Progress: File is locked, and download
  832.     /// is currently in progress
  833.     fsDownloadInProgress = 6,
  834.  
  835.     /// Broken: File is locked, download was in
  836.     /// progress, but was cancelled
  837.     fsDownloadBroken = 10,
  838.  
  839.     /// Finished: File is locked, download
  840.     /// was completed
  841.     fsDownloadFinished = 18
  842. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement