Пример #1
0
        private static void SendResponse(Stream f, string FullPath, string ContentType, bool IsDynamic, string ETag, DateTime LastModified,
                                         HttpResponse Response)
        {
            ReadProgress Progress = new ReadProgress()
            {
                Response    = Response,
                f           = f ?? File.OpenRead(FullPath),
                Next        = null,
                Boundary    = null,
                ContentType = null
            };

            Progress.BytesLeft = Progress.TotalLength = Progress.f.Length;
            Progress.BlockSize = (int)Math.Min(BufferSize, Progress.BytesLeft);
            Progress.Buffer    = new byte[Progress.BlockSize];

            Response.ContentType   = ContentType;
            Response.ContentLength = Progress.TotalLength;

            if (!IsDynamic)
            {
                Response.SetHeader("ETag", ETag);
                Response.SetHeader("Last-Modified", CommonTypes.EncodeRfc822(LastModified));
            }

            if (Response.OnlyHeader || Progress.TotalLength == 0)
            {
                Response.SendResponse();
                Progress.Dispose();
            }
            else
            {
                Task T = Progress.BeginRead();
            }
        }
Пример #2
0
        /// <summary>
        /// Executes a method on the resource. The default behaviour is to call the corresponding execution methods defined in the specialized
        /// interfaces <see cref="IHttpGetMethod"/>, <see cref="IHttpPostMethod"/>, <see cref="IHttpPutMethod"/> and <see cref="IHttpDeleteMethod"/>
        /// if they are defined for the resource.
        /// </summary>
        /// <param name="Server">HTTP Server</param>
        /// <param name="Request">HTTP Request</param>
        /// <param name="Response">HTTP Response</param>
        /// <exception cref="HttpException">If an error occurred when processing the method.</exception>
        public virtual async Task Execute(HttpServer Server, HttpRequest Request, HttpResponse Response)
        {
            HttpRequestHeader Header = Request.Header;
            string            Method = Request.Header.Method;

            if (this.UserSessions && Request.Session is null)
            {
                HttpFieldCookie Cookie;
                string          HttpSessionID;

                if ((Cookie = Request.Header.Cookie) is null || string.IsNullOrEmpty(HttpSessionID = Cookie["HttpSessionID"]))
                {
                    HttpSessionID = Convert.ToBase64String(Hashes.ComputeSHA512Hash(Guid.NewGuid().ToByteArray()));
                    Response.SetCookie(new Cookie("HttpSessionID", HttpSessionID, null, "/", null, false, true));
                }

                Request.Session = Server.GetSession(HttpSessionID);
            }

            switch (Method)
            {
            case "GET":
            case "HEAD":
                if (!(this.getRanges is null))
                {
                    Response.SetHeader("Accept-Ranges", "bytes");

                    if (Header.Range != null)
                    {
                        ByteRangeInterval FirstInterval = Header.Range.FirstInterval;
                        if (FirstInterval is null)
                        {
                            throw new RangeNotSatisfiableException();
                        }
                        else
                        {
                            Response.OnlyHeader    = Method == "HEAD";
                            Response.StatusCode    = 206;
                            Response.StatusMessage = "Partial Content";

                            await this.getRanges.GET(Request, Response, FirstInterval);
                        }
                    }
                    else
                    {
                        Response.OnlyHeader = Method == "HEAD";

                        if (!(this.get is null))
                        {
                            await this.get.GET(Request, Response);
                        }
        /// <summary>
        /// Executes the GET method on the resource.
        /// </summary>
        /// <param name="Request">HTTP Request</param>
        /// <param name="Response">HTTP Response</param>
        /// <exception cref="HttpException">If an error occurred when processing the method.</exception>
        public async Task GET(HttpRequest Request, HttpResponse Response)
        {
            using (Stream f = this.assembly.GetManifestResourceStream(this.embeddedResourceName))
            {
                if (f is null)
                {
                    throw new NotFoundException("Resource not found: " + this.embeddedResourceName);
                }

                if (this.etag is null)
                {
                    this.etag = this.ComputeETag(f);
                }

                if (Request.Header.IfNoneMatch != null && Request.Header.IfNoneMatch.Value == this.etag)
                {
                    throw new NotModifiedException();
                }

                Response.SetHeader("ETag", "\"" + this.etag + "\"");

                long   l      = f.Length;
                long   Pos    = 0;
                int    Size   = (int)Math.Min(BufferSize, l);
                byte[] Buffer = new byte[Size];
                int    i;

                Response.ContentType   = this.contentType;
                Response.ContentLength = l;

                if (!Response.OnlyHeader)
                {
                    while (Pos < l)
                    {
                        i = f.Read(Buffer, 0, Size);
                        if (i <= 0)
                        {
                            throw new Exception("Unexpected end of stream.");
                        }

                        await Response.Write(Buffer, 0, i);

                        Pos += i;
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Executes the ranged GET method on the resource.
        /// </summary>
        /// <param name="Request">HTTP Request</param>
        /// <param name="Response">HTTP Response</param>
        /// <param name="FirstInterval">First byte range interval.</param>
        /// <exception cref="HttpException">If an error occurred when processing the method.</exception>
        public async Task GET(HttpRequest Request, HttpResponse Response, ByteRangeInterval FirstInterval)
        {
            string FullPath = this.GetFullPath(Request);

            if (File.Exists(FullPath))
            {
                HttpRequestHeader Header       = Request.Header;
                DateTime          LastModified = File.GetLastWriteTime(FullPath).ToUniversalTime();
                DateTimeOffset?   Limit;
                CacheRec          Rec;

                if (Header.IfRange != null && (Limit = Header.IfRange.Timestamp).HasValue &&
                    !LessOrEqual(LastModified, Limit.Value.ToUniversalTime()))
                {
                    Response.StatusCode = 200;
                    await this.GET(Request, Response);                        // No ranged request.

                    return;
                }

                Rec = this.CheckCacheHeaders(FullPath, LastModified, Request);

                string ContentType = InternetContent.GetContentType(Path.GetExtension(FullPath));
                Stream f           = CheckAcceptable(Request, Response, ref ContentType, out bool Dynamic, FullPath, Request.Header.Resource);
                Rec.IsDynamic = Dynamic;

                if (Response.ResponseSent)
                {
                    return;
                }

                ReadProgress Progress = new ReadProgress()
                {
                    Response = Response,
                    Request  = Request,
                    f        = f ?? File.Open(FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
                };

                ByteRangeInterval Interval = FirstInterval;
                Progress.TotalLength = Progress.f.Length;

                long i = 0;
                long j;
                long First;

                if (FirstInterval.First.HasValue)
                {
                    First = FirstInterval.First.Value;
                }
                else
                {
                    First = Progress.TotalLength - FirstInterval.Last.Value;
                }

                Progress.f.Position = First;
                Progress.BytesLeft  = Interval.GetIntervalLength(Progress.TotalLength);
                Progress.Next       = Interval.Next;

                while (Interval != null)
                {
                    j = Interval.GetIntervalLength(Progress.TotalLength);
                    if (j > i)
                    {
                        i = j;
                    }

                    Interval = Interval.Next;
                }

                Progress.BlockSize = (int)Math.Min(BufferSize, i);
                Progress.Buffer    = new byte[Progress.BlockSize];

                if (FirstInterval.Next is null)
                {
                    Progress.Boundary    = null;
                    Progress.ContentType = null;

                    Response.ContentType   = ContentType;
                    Response.ContentLength = FirstInterval.GetIntervalLength(Progress.f.Length);
                    Response.SetHeader("Content-Range", ContentByteRangeInterval.ContentRangeToString(First, First + Progress.BytesLeft - 1, Progress.TotalLength));
                }
                else
                {
                    Progress.Boundary    = Guid.NewGuid().ToString().Replace("-", string.Empty);
                    Progress.ContentType = ContentType;

                    Response.ContentType = "multipart/byteranges; boundary=" + Progress.Boundary;
                    // chunked transfer encoding will be used
                }

                if (!Rec.IsDynamic)
                {
                    Response.SetHeader("ETag", Rec.ETag);
                    Response.SetHeader("Last-Modified", CommonTypes.EncodeRfc822(LastModified));
                }

                if (Response.OnlyHeader || Progress.BytesLeft == 0)
                {
                    await Response.SendResponse();

                    await Progress.Dispose();
                }
                else
                {
                    if (FirstInterval.Next != null)
                    {
                        await Response.WriteLine();

                        await Response.WriteLine("--" + Progress.Boundary);

                        await Response.WriteLine("Content-Type: " + Progress.ContentType);

                        await Response.WriteLine("Content-Range: " + ContentByteRangeInterval.ContentRangeToString(First, First + Progress.BytesLeft - 1, Progress.TotalLength));

                        await Response.WriteLine();
                    }

                    Task _ = Progress.BeginRead();
                }
            }
            else
            {
                await this.RaiseFileNotFound(FullPath, Request, Response);
            }
        }
Пример #5
0
        /// <summary>
        /// Executes a method on the resource. The default behaviour is to call the corresponding execution methods defined in the specialized
        /// interfaces <see cref="IHttpGetMethod"/>, <see cref="IHttpPostMethod"/>, <see cref="IHttpPutMethod"/> and <see cref="IHttpDeleteMethod"/>
        /// if they are defined for the resource.
        /// </summary>
        /// <param name="Server">HTTP Server</param>
        /// <param name="Request">HTTP Request</param>
        /// <param name="Response">HTTP Response</param>
        /// <exception cref="HttpException">If an error occurred when processing the method.</exception>
        public virtual void Execute(HttpServer Server, HttpRequest Request, HttpResponse Response)
        {
            HttpRequestHeader Header = Request.Header;
            string            Method = Request.Header.Method;

            if (this.UserSessions)
            {
                HttpFieldCookie Cookie;
                string          HttpSessionID;

                if ((Cookie = Request.Header.Cookie) is null || string.IsNullOrEmpty(HttpSessionID = Cookie["HttpSessionID"]))
                {
                    HttpSessionID = System.Convert.ToBase64String(Hashes.ComputeSHA512Hash(Guid.NewGuid().ToByteArray()));
                    Response.SetCookie(new HTTP.Cookie("HttpSessionID", HttpSessionID, null, "/", null, false, true));
                }

                Request.Session = Server.GetSession(HttpSessionID);
            }

            switch (Method)
            {
            case "GET":
            case "HEAD":
                if (this.getRanges != null)
                {
                    Response.SetHeader("Accept-Ranges", "bytes");

                    if (Header.Range != null)
                    {
                        ByteRangeInterval FirstInterval = Header.Range.FirstInterval;
                        if (FirstInterval is null)
                        {
                            throw new RangeNotSatisfiableException();
                        }
                        else
                        {
                            Response.OnlyHeader    = Method == "HEAD";
                            Response.StatusCode    = 206;
                            Response.StatusMessage = "Partial Content";

                            this.getRanges.GET(Request, Response, FirstInterval);
                        }
                    }
                    else
                    {
                        Response.OnlyHeader = Method == "HEAD";

                        if (this.get != null)
                        {
                            this.get.GET(Request, Response);
                        }
                        else
                        {
                            this.getRanges.GET(Request, Response, new ByteRangeInterval(0, null));
                        }
                    }
                }
                else if (this.get != null)
                {
                    Response.OnlyHeader = Method == "HEAD";
                    this.get.GET(Request, Response);
                }
                else
                {
                    throw new MethodNotAllowedException(this.allowedMethods);
                }
                break;

            case "POST":
                if (this.postRanges != null)
                {
                    if (Header.ContentRange != null)
                    {
                        ContentByteRangeInterval Interval = Header.ContentRange.Interval;
                        if (Interval is null)
                        {
                            throw new RangeNotSatisfiableException();
                        }
                        else
                        {
                            this.postRanges.POST(Request, Response, Interval);
                        }
                    }
                    else
                    {
                        if (this.post != null)
                        {
                            this.post.POST(Request, Response);
                        }
                        else
                        {
                            long Total;

                            if (Header.ContentLength != null)
                            {
                                Total = Header.ContentLength.ContentLength;
                            }
                            else if (Request.DataStream != null)
                            {
                                Total = Request.DataStream.Position;
                            }
                            else
                            {
                                Total = 0;
                            }

                            this.postRanges.POST(Request, Response, new ContentByteRangeInterval(0, Total - 1, Total));
                        }
                    }
                }
                else if (this.post != null)
                {
                    this.post.POST(Request, Response);
                }
                else
                {
                    throw new MethodNotAllowedException(this.allowedMethods);
                }
                break;

            case "PUT":
                if (this.putRanges != null)
                {
                    if (Header.ContentRange != null)
                    {
                        ContentByteRangeInterval Interval = Header.ContentRange.Interval;
                        if (Interval is null)
                        {
                            throw new RangeNotSatisfiableException();
                        }
                        else
                        {
                            this.putRanges.PUT(Request, Response, Interval);
                        }
                    }
                    else
                    {
                        if (this.put != null)
                        {
                            this.put.PUT(Request, Response);
                        }
                        else
                        {
                            long Total;

                            if (Header.ContentLength != null)
                            {
                                Total = Header.ContentLength.ContentLength;
                            }
                            else if (Request.DataStream != null)
                            {
                                Total = Request.DataStream.Position;
                            }
                            else
                            {
                                Total = 0;
                            }

                            this.putRanges.PUT(Request, Response, new ContentByteRangeInterval(0, Total - 1, Total));
                        }
                    }
                }
                else if (this.put != null)
                {
                    this.put.PUT(Request, Response);
                }
                else
                {
                    throw new MethodNotAllowedException(this.allowedMethods);
                }
                break;

            case "DELETE":
                if (this.delete is null)
                {
                    throw new MethodNotAllowedException(this.allowedMethods);
                }
                else
                {
                    this.delete.DELETE(Request, Response);
                }
                break;

            case "OPTIONS":
                if (this.options is null)
                {
                    throw new MethodNotAllowedException(this.allowedMethods);
                }
                else
                {
                    this.options.OPTIONS(Request, Response);
                }
                break;

            case "TRACE":
                if (this.trace is null)
                {
                    throw new MethodNotAllowedException(this.allowedMethods);
                }
                else
                {
                    this.trace.TRACE(Request, Response);
                }
                break;

            default:
                throw new MethodNotAllowedException(this.allowedMethods);
            }

            if (this.Synchronous)
            {
                Response.SendResponse();
                Response.Dispose();
            }
        }