예제 #1
0
        bool CheckIfNoneMatch(HttpRequest objRequest, HttpResponse objResponse, UrlInformation objFile)
        {
            string sRequestHeaderIfNoneMatch;

            string[] sEntityIDs;
            bool     breturn = true;
            string   sreturn = "";

            // Checks the If-None-Match header if it was sent with the request.
            //
            // returns true if one of the header values matches the file//s entity tag,
            //              or if "*" was sent,
            // returns false if a header was sent, but does not match the file, or
            //               if no header was sent.

            // Retrieve If-None-Match Header value from Request (*, meaning any, if none is indicated)
            sRequestHeaderIfNoneMatch = RetrieveHeader(objRequest, HTTP_HEADER_IF_NONE_MATCH, String.Empty);

            if (sRequestHeaderIfNoneMatch.Equals(String.Empty))
            {
                // Perform the request normally...
                breturn = true;
            }
            else
            {
                if (sRequestHeaderIfNoneMatch.Equals("*"))
                {
                    // The server must not perform the request
                    objResponse.StatusCode = 412;                      // Precondition failed
                    breturn = false;
                }
                else
                {
                    // One or more Match IDs where sent by the client software...
                    sEntityIDs = sRequestHeaderIfNoneMatch.Replace("bytes=", "").Split(",".ToCharArray());

                    // Loop through all entity IDs, finding one which
                    // does not match the current file//s ID will be
                    // enough to satisfy the If-None-Match
                    for (int iLoop = sEntityIDs.GetLowerBound(0); iLoop <= sEntityIDs.GetUpperBound(0); iLoop++)
                    {
                        if (sEntityIDs[iLoop].Trim().Equals(objFile.EntityTag))
                        {
                            sreturn = sEntityIDs[iLoop];
                            breturn = false;
                        }
                    }

                    if (!breturn)
                    {
                        // One of the requested entities matches the current file//s tag,
                        objResponse.AppendHeader("ETag", sreturn);
                        objResponse.StatusCode = 304;                          // Not Modified
                    }
                }
            }
            // return the result...
            return(breturn);
        }
예제 #2
0
        bool CheckIfUnmodifiedSince(HttpRequest objRequest, UrlInformation objFile)
        {
            string   sDate;
            DateTime dDate;
            bool     breturn;


            // Checks the If-Unmodified or Unless-Modified-Since header, if
            // one of them was sent with the request.
            //
            // returns true, if the file was not modified since the
            //               indicated date (RFC 1123 format), or
            //               if no header was sent,
            // returns false, if the file was modified since the indicated date


            // Retrieve If-Unmodified-Since Header value from Request (Empty if none is indicated)
            sDate = RetrieveHeader(objRequest, HTTP_HEADER_IF_UNMODIFIED_SINCE, String.Empty);

            if (sDate.Equals(String.Empty))
            {
                // If-Unmodified-Since was not sent, check Unless-Modified-Since...
                sDate = RetrieveHeader(objRequest, HTTP_HEADER_UNLESS_MODIFIED_SINCE, String.Empty);
            }


            if (sDate.Equals(String.Empty))
            {
                // No date was indicated,
                // so just give this as true
                breturn = true;
            }

            else
            {
                try
                {
                    // ... to parse the indicated sDate to a datetime value
                    dDate = DateTime.Parse(sDate);
                    // return true if the file was not modified since the indicated date...
                    breturn = objFile.LastWriteTimeUTC < DateTime.Parse(sDate);
                }
                catch (Exception)
                {
                    // Converting the indicated date value failed, return false
                    breturn = false;
                }
            }
            return(breturn);
        }
예제 #3
0
        bool CheckIfRange(HttpRequest objRequest, UrlInformation objFile)
        {
            string sRequestHeaderIfRange;

            // Checks the If-Range header if it was sent with the request.
            //
            // returns true if the header value matches the file//s entity tag,
            //              or if no header was sent,
            // returns false if a header was sent, but does not match the file.


            // Retrieve If-Range Header value from Request (objFile.EntityTag if none is indicated)
            sRequestHeaderIfRange = RetrieveHeader(objRequest, HTTP_HEADER_IF_RANGE, objFile.EntityTag);

            // If the requested file entity matches the current
            // file entity, return true
            return(sRequestHeaderIfRange.Equals(objFile.EntityTag));
        }
예제 #4
0
        bool CheckIfMatch(HttpRequest objRequest, UrlInformation objFile)
        {
            string sRequestHeaderIfMatch;

            string[] sEntityIDs;
            bool     breturn = false;

            // Checks the If-Match header if it was sent with the request.
            //
            // returns true if one of the header values matches the file//s entity tag,
            //              or if no header was sent,
            // returns false if a header was sent, but does not match the file.


            // Retrieve If-Match Header value from Request (*, meaning any, if none is indicated)
            sRequestHeaderIfMatch = RetrieveHeader(objRequest, HTTP_HEADER_IF_MATCH, "*");

            if (sRequestHeaderIfMatch.Equals("*"))
            {
                // The server may perform the request as if the
                // If-Match header does not exists...
                breturn = true;
            }

            else
            {
                // One or more Match IDs where sent by the client software...
                sEntityIDs = sRequestHeaderIfMatch.Replace("bytes=", "").Split(",".ToCharArray());

                // Loop through all entity IDs, finding one
                // which matches the current file's ID will
                // be enough to satisfy the If-Match
                for (int iLoop = sEntityIDs.GetLowerBound(0); iLoop <= sEntityIDs.GetUpperBound(0); iLoop++)
                {
                    if (sEntityIDs[iLoop].Trim().Equals(objFile.EntityTag))
                    {
                        breturn = true;
                    }
                }
            }
            // return the result...
            return(breturn);
        }
예제 #5
0
        bool CheckIfModifiedSince(HttpRequest objRequest, UrlInformation objFile)
        {
            string   sDate;
            DateTime dDate;
            bool     breturn;

            // Checks the If-Modified header if it was sent with the request.
            //
            // returns true, if the file was modified since the
            //               indicated date (RFC 1123 format), or
            //               if no header was sent,
            // returns false, if the file was not modified since
            //                the indicated date


            // Retrieve If-Modified-Since Header value from Request (Empty if none is indicated)
            sDate = RetrieveHeader(objRequest, HTTP_HEADER_IF_MODIFIED_SINCE, string.Empty);

            if (sDate.Equals(String.Empty))
            {
                // No If-Modified-Since date was indicated,
                // so just give this as true
                breturn = true;
            }

            else
            {
                try
                {
                    // ... to parse the indicated sDate to a datetime value
                    dDate = DateTime.Parse(sDate);
                    // return true if the file was modified since or at the indicated date...
                    breturn = (objFile.LastWriteTimeUTC >= DateTime.Parse(sDate));
                }
                catch
                {
                    // Converting the indicated date value failed, return false
                    breturn = false;
                }
            }
            return(breturn);
        }
예제 #6
0
        public DownloadState ProcessDownload(byte[] pageData, string UrlAddress, string filename)
        {
            HttpContext objContext = HttpContext.Current;
            // The Response object from the Context
            HttpResponse objResponse = objContext.Response;
            // The Request object from the Context
            HttpRequest objRequest = objContext.Request;

            // File information object...
            UrlInformation objFile;

            // Long Arrays for Range values:
            // ...Begin() contains start positions for each requested Range
            long[] alRequestedRangesBegin = new long[1];
            // ...End() contains end positions for each requested Range
            long[] alRequestedRangesend = new long[1];

            // Response Header value: Content Length...
            int iResponseContentLength = 0;

            // The Stream we//re using to download the file in chunks...
            System.IO.Stream objStream;
            // Total Bytes to read (per requested range)
            int iBytesToRead;
            // Size of the Buffer for chunk-wise reading
            int iBufferSize = 25000;

            // The Buffer itself
            byte[] bBuffer = new byte[iBufferSize];
            // Amount of Bytes read
            int iLengthOfReadChunk = -1;

            // Indicates if the download was interrupted
            bool bDownloadBroken = false;

            // Indicates if this is a range request
            bool bIsRangeRequest = false;
            // Indicates if this is a multipart range request
            bool bMultipart = false;

            // Loop counter used to iterate through the ranges
            int iLoop;

            filename = filename.Replace(' ', '-');
            // Content-Disposition value
            string Content_Disposition_File = "attachment; filename=" + filename + "";

            // ToDo - your code here (Determine which file is requested)
            // Using objRequest, determine which file is requested to
            // be downloaded, and open objFile with that file:
            // Example:
            // objFile = New Download.FileInformation(<Full path to the requested file>)
            //objFile = new Download.FileInformation(objContext.Server.MapPath("~/download.zip"));
            objFile             = new UrlInformation(pageData, UrlAddress);
            objFile.ContentType = this.ContentType;

            // Clear the current output content from the buffer
            //objResponse.Clear();

            if (!(objRequest.HttpMethod.Equals(HTTP_METHOD_GET) ||
                  objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD)))
            {
                // Currently, only the GET and HEAD methods
                // are supported...
                objResponse.StatusCode = 501;                  // Not implemented
            }
            else if (!objFile.Exists)
            {
                // The requested file could not be retrieved...
                objResponse.StatusCode = 404;                  // Not found
            }
            else if (objFile.Length > Int32.MaxValue)
            {
                // The file size is too large...
                objResponse.StatusCode = 413;                  // Request Entity Too Large
            }
            else if (!ParseRequestHeaderRange(objRequest, ref alRequestedRangesBegin, ref alRequestedRangesend,
                                              objFile.Length, ref bIsRangeRequest))
            {
                // The Range request contained bad entries
                objResponse.StatusCode = 400;                  // Bad Request
            }
            else if (!CheckIfModifiedSince(objRequest, objFile))
            {
                // The entity is still unmodified...
                objResponse.StatusCode = 304;                  // Not Modified
            }
            else if (!CheckIfUnmodifiedSince(objRequest, objFile))
            {
                // The entity was modified since the requested date...
                objResponse.StatusCode = 412;                  // Precondition failed
            }
            else if (!CheckIfMatch(objRequest, objFile))
            {
                // The entity does not match the request...
                objResponse.StatusCode = 412;                  // Precondition failed
            }
            else if (!CheckIfNoneMatch(objRequest, objResponse, objFile))
            {
                // The entity does match the none-match request, the response
                // code was set inside the CheckifNoneMatch function
            }
            else
            {
                // Preliminary checks where successful...

                if (bIsRangeRequest && CheckIfRange(objRequest, objFile))
                {
                    // This is a Range request...

                    // if the Range arrays contain more than one entry,
                    // it even is a multipart range request...
                    bMultipart = (alRequestedRangesBegin.GetUpperBound(0) > 0);

                    // Loop through each Range to calculate the entire Response length
                    for (iLoop = alRequestedRangesBegin.GetLowerBound(0); iLoop <= alRequestedRangesBegin.GetUpperBound(0); iLoop++)
                    {
                        // The length of the content (for this range)
                        iResponseContentLength += Convert.ToInt32(alRequestedRangesend[iLoop] - alRequestedRangesBegin[iLoop]) + 1;

                        if (bMultipart)
                        {
                            //
                            iResponseContentLength += HTTP_HEADER_Content_Disposition.Length;
                            // if this is a multipart range request, calculate
                            // the length of the intermediate headers to send
                            iResponseContentLength += MULTIPART_BOUNDARY.Length;
                            iResponseContentLength += objFile.ContentType.Length;
                            iResponseContentLength += alRequestedRangesBegin[iLoop].ToString().Length;
                            iResponseContentLength += alRequestedRangesend[iLoop].ToString().Length;
                            iResponseContentLength += objFile.Length.ToString().Length;
                            // 49 is the length of line break and other
                            // needed characters in one multipart header
                            iResponseContentLength += 49;
                        }
                    }

                    if (bMultipart)
                    {
                        // if this is a multipart range request,
                        // we must also calculate the length of
                        // the last intermediate header we must send
                        iResponseContentLength += MULTIPART_BOUNDARY.Length;
                        // 8 is the length of dash and line break characters
                        iResponseContentLength += 8;
                    }
                    else
                    {
                        // This is no multipart range request, so
                        // we must indicate the response Range of
                        // in the initial HTTP Header
                        objResponse.AppendHeader(HTTP_HEADER_CONTENT_RANGE, "bytes " +
                                                 alRequestedRangesBegin[0].ToString() + "-" +
                                                 alRequestedRangesend[0].ToString() + "/" +
                                                 objFile.Length.ToString());
                    }

                    // Range response
                    objResponse.StatusCode = 206;                     // Partial Response
                }
                else
                {
                    // This is not a Range request, or the requested Range entity ID
                    // does not match the current entity ID, so start a new download

                    // Indicate the file//s complete size as content length
                    iResponseContentLength = Convert.ToInt32(objFile.Length);

                    // Return a normal OK status...
                    objResponse.StatusCode = 200;
                }


                // Write file name into the Response
                objResponse.AppendHeader(HTTP_HEADER_Content_Disposition, Content_Disposition_File);

                // Write the content length into the Response
                objResponse.AppendHeader(HTTP_HEADER_CONTENT_LENGTH, iResponseContentLength.ToString());

                // Write the Last-Modified Date into the Response
                objResponse.AppendHeader(HTTP_HEADER_LAST_MODIFIED, objFile.LastWriteTimeUTC.ToString("r"));

                // Tell the client software that we accept Range request
                objResponse.AppendHeader(HTTP_HEADER_ACCEPT_RANGES, HTTP_HEADER_ACCEPT_RANGES_BYTES);

                // Write the file//s Entity Tag into the Response (in quotes!)
                objResponse.AppendHeader(HTTP_HEADER_ENTITY_TAG, "\"" + objFile.EntityTag + "\"");


                // Write the Content Type into the Response
                if (bMultipart)
                {
                    // Multipart messages have this special Type.
                    // In this case, the file//s actual mime type is
                    // written into the Response at a later time...
                    objResponse.ContentType = MULTIPART_CONTENTTYPE;
                }
                else
                {
                    // Single part messages have the files content type...
                    objResponse.ContentType = objFile.ContentType;
                }


                if (objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD))
                {
                    // Only the HEAD was requested, so we can quit the Response right here...
                }
                else
                {
                    // Flush the HEAD information to the client...
                    objResponse.Flush();

                    // Download is in progress...
                    objFile.State = DownloadState.fsDownloadInProgress;

                    // Open the file as filestream

                    /*objStream = new FileStream(objFile.FullName, FileMode.Open,
                     *      FileAccess.Read,
                     *      FileShare.Read);*/
                    objStream = objFile.DataStream;

                    // Now, for each requested range, stream the chunks to the client:
                    for (iLoop = alRequestedRangesBegin.GetLowerBound(0); iLoop <= alRequestedRangesBegin.GetUpperBound(0); iLoop++)
                    {
                        // Move the stream to the desired start position...
                        objStream.Seek(alRequestedRangesBegin[iLoop], SeekOrigin.Begin);

                        // Calculate the total amount of bytes for this range
                        iBytesToRead = Convert.ToInt32(alRequestedRangesend[iLoop] - alRequestedRangesBegin[iLoop]) + 1;

                        if (bMultipart)
                        {
                            // if this is a multipart response, we must add
                            // certain headers before streaming the content:

                            // The multipart boundary
                            objResponse.Output.WriteLine("--" + MULTIPART_BOUNDARY);
                            //objResponse.AppendHeader("--",MULTIPART_BOUNDARY);

                            // The mime type of this part of the content
                            objResponse.Output.WriteLine(HTTP_HEADER_CONTENT_TYPE + ": " + objFile.ContentType);
                            //objResponse.AppendHeader(HTTP_HEADER_CONTENT_TYPE,objFile.ContentType);

                            // The actual range
                            objResponse.Output.WriteLine(HTTP_HEADER_CONTENT_RANGE + ": bytes " +
                                                         alRequestedRangesBegin[iLoop].ToString() + "-" +
                                                         alRequestedRangesend[iLoop].ToString() + "/" +
                                                         objFile.Length.ToString());

                            /*objResponse.AppendHeader(HTTP_HEADER_CONTENT_RANGE,": bytes " +
                             *      alRequestedRangesBegin[iLoop].ToString() + "-" +
                             *      alRequestedRangesend[iLoop].ToString() + "/" +
                             *      objFile.Length.ToString());
                             */
                            // Indicating the end of the intermediate headers
                            objResponse.Output.WriteLine();
                        }

                        // Now stream the range to the client...
                        while (iBytesToRead > 0)
                        {
                            if (objResponse.IsClientConnected)
                            {
                                // Read a chunk of bytes from the stream
                                iLengthOfReadChunk = objStream.Read(bBuffer, 0, Math.Min(bBuffer.Length, iBytesToRead));

                                // Write the data to the current output stream.
                                objResponse.OutputStream.Write(bBuffer, 0, iLengthOfReadChunk);

                                // Flush the data to the HTML output.
                                objResponse.Flush();

                                // Clear the buffer
                                //bBuffer=new byte[iBufferSize];

                                // Reduce BytesToRead
                                iBytesToRead -= iLengthOfReadChunk;
                            }
                            else
                            {
                                // The client was or has disconneceted from the server... stop downstreaming...
                                iBytesToRead    = -1;
                                bDownloadBroken = true;
                            }
                        }

                        // In Multipart responses, mark the end of the part
                        if (bMultipart)
                        {
                            objResponse.Output.WriteLine();
                        }

                        // No need to proceed to the next part if the
                        // client was disconnected
                        if (bDownloadBroken)
                        {
                            break;
                        }
                    }

                    // At this point, the response was finished or cancelled...

                    if (bDownloadBroken)
                    {
                        // Download is broken...
                        objFile.State = DownloadState.fsDownloadBroken;
                    }

                    else
                    {
                        if (bMultipart)
                        {
                            // In multipart responses, close the response once more with
                            // the boundary and line breaks
                            objResponse.Output.WriteLine("--" + MULTIPART_BOUNDARY + "--");
                            objResponse.Output.WriteLine();
                        }

                        // The download was finished
                        objFile.State = DownloadState.fsDownloadFinished;
                    }
                    objStream.Close();
                }
            }
            //objResponse.End();

            //====== return download state ======
            return(objFile.State);
        }