Exemplo n.º 1
0
        private bool BinaryHeaderReceived(byte[] Data, int Offset, int NrRead)
        {
            string Header = null;
            int    i, c;
            byte   b;

            c = Offset + NrRead;

            for (i = Offset; i < c; i++)
            {
                b = Data[i];

                if (this.b1 == CR && this.b2 == LF && this.b3 == CR && b == LF)                 // RFC 2616, §2.2
                {
                    if (this.headerStream is null)
                    {
                        Header = InternetContent.ISO_8859_1.GetString(Data, Offset, i - Offset - 3);
                    }
                    else
                    {
                        this.headerStream.Write(Data, Offset, i - Offset - 3);

                        Header            = InternetContent.ISO_8859_1.GetString(this.headerStream.ToArray(), 0, (int)this.headerStream.Position);
                        this.headerStream = null;
                    }
                }
                else if (this.b3 == LF && b == LF)                  // RFC 2616, §19.3
                {
                    if (this.headerStream is null)
                    {
                        Header = InternetContent.ISO_8859_1.GetString(Data, Offset, i - Offset - 1);
                    }
                    else
                    {
                        this.headerStream.Write(Data, Offset, i - Offset - 1);
                        Header            = InternetContent.ISO_8859_1.GetString(this.headerStream.ToArray(), 0, (int)this.headerStream.Position);
                        this.headerStream = null;
                    }
                }
                else
                {
                    this.b1 = this.b2;
                    this.b2 = this.b3;
                    this.b3 = b;
                    continue;
                }

                this.ReceiveText(Header);
                this.header       = new HttpRequestHeader(Header, this.encrypted ? "https" : "http");
                this.lastResource = this.header.Resource;

                if (this.header.HttpVersion < 1)
                {
                    this.SendResponse(null, 505, "HTTP Version Not Supported", true);
                    return(false);
                }
                else if (this.header.ContentLength != null && (this.header.ContentLength.ContentLength > MaxEntitySize))
                {
                    this.SendResponse(null, 413, "Request Entity Too Large", true);
                    return(false);
                }
                else if (i + 1 < NrRead)
                {
                    return(this.BinaryDataReceived(Data, i + 1, NrRead - i - 1));
                }
                else if (!this.header.HasMessageBody)
                {
                    return(this.RequestReceived());
                }
                else
                {
                    return(true);
                }
            }

            if (this.headerStream is null)
            {
                this.headerStream = new MemoryStream();
            }

            this.headerStream.Write(Data, Offset, NrRead);

            if (this.headerStream.Position < MaxHeaderSize)
            {
                return(true);
            }
            else
            {
                if (this.HasSniffers)
                {
                    int    d     = (int)this.headerStream.Position;
                    byte[] Data2 = new byte[d];
                    this.headerStream.Position = 0;
                    this.headerStream.Read(Data2, 0, d);
                    this.ReceiveBinary(Data2);
                }

                this.SendResponse(null, 431, "Request Header Fields Too Large", true);
                return(false);
            }
        }
Exemplo n.º 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 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();
            }
        }
Exemplo n.º 3
0
        private Stream CheckAcceptable(HttpRequest Request, HttpResponse Response, ref string ContentType, out bool Dynamic,
                                       string FullPath, string ResourceName)
        {
            HttpRequestHeader Header = Request.Header;

            Dynamic = false;

            if (Header.Accept != null)
            {
                bool Acceptable = Header.Accept.IsAcceptable(ContentType, out double Quality, out ContentTypeAcceptance TypeAcceptance, null);

                if ((!Acceptable || TypeAcceptance == ContentTypeAcceptance.Wildcard) && (this.allowTypeConversionFrom == null ||
                                                                                          (this.allowTypeConversionFrom.TryGetValue(ContentType, out bool Allowed) && Allowed)))
                {
                    IContentConverter Converter      = null;
                    string            NewContentType = null;

                    foreach (AcceptRecord AcceptRecord in Header.Accept.Records)
                    {
                        NewContentType = AcceptRecord.Item;
                        if (NewContentType.EndsWith("/*"))
                        {
                            continue;
                        }

                        if (InternetContent.CanConvert(ContentType, NewContentType, out Converter))
                        {
                            Acceptable = true;
                            break;
                        }
                    }

                    if (Acceptable && Converter != null)
                    {
                        Stream f2 = null;
                        Stream f  = File.OpenRead(FullPath);
                        bool   Ok = false;

                        try
                        {
                            f2 = f.Length < HttpClientConnection.MaxInmemoryMessageSize ? (Stream) new MemoryStream() : new TemporaryFile();

                            if (Request.Session != null)
                            {
                                Request.Session["Request"]  = Request;
                                Request.Session["Response"] = Response;
                            }

                            if (Converter.Convert(ContentType, f, FullPath, ResourceName, Request.Header.GetURL(false, false),
                                                  NewContentType, f2, Request.Session))
                            {
                                Dynamic = true;
                            }

                            ContentType = NewContentType;
                            Ok          = true;
                        }
                        finally
                        {
                            if (f2 == null)
                            {
                                f.Dispose();
                            }
                            else if (!Ok)
                            {
                                f2.Dispose();
                                f.Dispose();
                            }
                            else
                            {
                                f.Dispose();
                                f          = f2;
                                f2         = null;
                                f.Position = 0;
                            }
                        }

                        return(f);
                    }
                }

                if (!Acceptable)
                {
                    throw new NotAcceptableException();
                }
            }

            return(null);
        }
Exemplo n.º 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 void GET(HttpRequest Request, HttpResponse Response, ByteRangeInterval FirstInterval)
        {
            string FullPath = this.GetFullPath(Request);

            if (!File.Exists(FullPath))
            {
                throw new NotFoundException();
            }

            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;
                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;

            ReadProgress Progress = new ReadProgress()
            {
                Response = Response,
                f        = f ?? File.OpenRead(FullPath)
            };

            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 == 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)
            {
                Response.SendResponse();
                Progress.Dispose();
            }
            else
            {
                if (FirstInterval.Next != null)
                {
                    Response.WriteLine();
                    Response.WriteLine("--" + Progress.Boundary);
                    Response.WriteLine("Content-Type: " + Progress.ContentType);
                    Response.WriteLine("Content-Range: " + ContentByteRangeInterval.ContentRangeToString(First, First + Progress.BytesLeft - 1, Progress.TotalLength));
                    Response.WriteLine();
                }

                Task T = Progress.BeginRead();
            }
        }
Exemplo n.º 5
0
        private Stream CheckAcceptable(HttpRequest Request, HttpResponse Response, ref string ContentType, out bool Dynamic,
                                       string FullPath, string ResourceName)
        {
            HttpRequestHeader Header = Request.Header;

            Dynamic = false;

            if (Header.Accept != null)
            {
                bool Acceptable = Header.Accept.IsAcceptable(ContentType, out double Quality, out AcceptanceLevel TypeAcceptance, null);

                if ((!Acceptable || TypeAcceptance == AcceptanceLevel.Wildcard) && (this.allowTypeConversionFrom is null ||
                                                                                    (this.allowTypeConversionFrom.TryGetValue(ContentType, out bool Allowed) && Allowed)))
                {
                    IContentConverter Converter      = null;
                    string            NewContentType = null;

                    foreach (AcceptRecord AcceptRecord in Header.Accept.Records)
                    {
                        NewContentType = AcceptRecord.Item;
                        if (NewContentType.EndsWith("/*"))
                        {
                            NewContentType = null;
                            continue;
                        }

                        if (InternetContent.CanConvert(ContentType, NewContentType, out Converter))
                        {
                            Acceptable = true;
                            break;
                        }
                    }

                    if (Converter is null)
                    {
                        IContentConverter[] Converters = InternetContent.GetConverters(ContentType);

                        if (!(Converters is null))
                        {
                            string            BestContentType = null;
                            double            BestQuality     = 0;
                            IContentConverter Best            = null;
                            bool Found;

                            foreach (IContentConverter Converter2 in InternetContent.Converters)
                            {
                                Found = false;

                                foreach (string FromContentType in Converter2.FromContentTypes)
                                {
                                    if (ContentType == FromContentType)
                                    {
                                        Found = true;
                                        break;
                                    }
                                }

                                if (!Found)
                                {
                                    continue;
                                }

                                foreach (string ToContentType in Converter2.ToContentTypes)
                                {
                                    if (Header.Accept.IsAcceptable(ToContentType, out double Quality2) && Quality > BestQuality)
                                    {
                                        BestContentType = ToContentType;
                                        BestQuality     = Quality;
                                        Best            = Converter2;
                                    }
                                }
                            }

                            if (Best != null && (!Acceptable || BestQuality >= Quality))
                            {
                                Acceptable     = true;
                                Converter      = Best;
                                NewContentType = BestContentType;
                            }
                        }
                    }

                    if (Acceptable && Converter != null)
                    {
                        Stream f2 = null;
                        Stream f  = File.Open(FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                        bool   Ok = false;

                        try
                        {
                            f2 = f.Length < HttpClientConnection.MaxInmemoryMessageSize ? (Stream) new MemoryStream() : new TemporaryFile();

                            if (Request.Session != null)
                            {
                                Request.Session["Request"]  = Request;
                                Request.Session["Response"] = Response;
                            }

                            List <string> Alternatives = null;
                            string[]      Range        = Converter.ToContentTypes;

                            foreach (AcceptRecord AcceptRecord in Header.Accept.Records)
                            {
                                if (AcceptRecord.Item.EndsWith("/*") || AcceptRecord.Item == NewContentType)
                                {
                                    continue;
                                }

                                if (Array.IndexOf <string>(Range, AcceptRecord.Item) >= 0)
                                {
                                    if (Alternatives is null)
                                    {
                                        Alternatives = new List <string>();
                                    }

                                    Alternatives.Add(AcceptRecord.Item);
                                }
                            }

                            if (Converter.Convert(ContentType, f, FullPath, ResourceName, Request.Header.GetURL(false, false),
                                                  ref NewContentType, f2, Request.Session, Alternatives?.ToArray()))
                            {
                                Dynamic = true;
                            }

                            ContentType = NewContentType;
                            Ok          = true;
                        }
                        finally
                        {
                            if (f2 is null)
                            {
                                f.Dispose();
                            }
                            else if (!Ok)
                            {
                                f2.Dispose();
                                f.Dispose();
                            }
                            else
                            {
                                f.Dispose();
                                f          = f2;
                                f.Position = 0;
                            }
                        }

                        return(f);
                    }
                }

                if (!Acceptable)
                {
                    throw new NotAcceptableException();
                }
            }

            return(null);
        }