public ServerUploadToken RequestUploadToken(string node)
        {
            ServerUploadToken token;

            lock (activeTokenList)
            {
                //Create token
                if (recycledList.Count > 0)
                {
                    token = recycledList.Dequeue();
                }
                else
                {
                    token = new ServerUploadToken();
                }

                activeTokenList.Add(token);
                token.RemoteEndPoint = node;

                int totalUploads = activeTokenList.Where(t => t.GlobalQueuePosition == 0).Count();
                //If we have reached the global uploads then pause the download
                if (totalUploads > model.MaxUploads)
                {
                    //Record queue position
                    token.GlobalQueuePosition = activeTokenList.Where(t => t.GlobalQueuePosition != 0).Count() + 1;
                }
                else
                {
                    token.GlobalQueuePosition = 0;
                }
            }
            return(token);
        }
        public void FreeToken(ServerUploadToken itoken)
        {
            lock (activeTokenList)
            {
                //Recycle token
                itoken.RemoteEndPoint      = null;
                itoken.GlobalQueuePosition = 0;
                recycledList.Enqueue(itoken);
                activeTokenList.Remove(itoken);

                //Start next item
                List <ServerUploadToken> list =
                    activeTokenList.Where(t => t.GlobalQueuePosition > 0).OrderBy(t => t.GlobalQueuePosition).ToList();
                if (list.Count > 0)
                {
                    list[0].GlobalQueuePosition = 0;
                }
                for (int i = 1; i < list.Count; i++)
                {
                    list[i].GlobalQueuePosition = i;
                }
            }
        }
Exemplo n.º 3
0
        public void DoUpload(IHttpContext context, Stream stream, string user, string url)
        {
            ResumePoint = 0;
            length      = stream.Length;
            IHeader rangeHeader =
                context.Request.Headers.Where(n => n.Name.ToLowerInvariant() == "range").FirstOrDefault();
            ServerUploadToken token = null;

            try
            {
                //Check for range header
                if (null != rangeHeader)
                {
                    //Partial request
                    //Try to parse header
                    long start = 0;
                    long end   = 0;

                    if (rangeHeader.HeaderValue.StartsWith("bytes="))
                    {
                        string header   = rangeHeader.HeaderValue.Substring(6).Trim();
                        string starttxt = string.Empty;
                        string endtxt   = string.Empty;

                        if (header.Contains('-'))
                        {
                            starttxt = header.Substring(0, header.IndexOf("-"));
                            endtxt   = header.Substring(header.IndexOf("-") + 1, header.Length - (header.IndexOf("-") + 1));
                        }
                        else
                        {
                            starttxt = header;
                        }

                        if (!string.IsNullOrEmpty(starttxt))
                        {
                            start = long.Parse(starttxt);
                        }
                        if (!string.IsNullOrEmpty(endtxt))
                        {
                            end = long.Parse(endtxt);
                        }
                        if (start != 0)
                        {
                            if (start > stream.Length)
                            {
                                start = stream.Length;
                            }
                            stream.Seek(start, SeekOrigin.Begin);
                            position    = start;
                            ResumePoint = start;
                        }
                        //TODO: Implement this
                        if (end != 0)
                        {
                            throw new Exception("End range not supported");
                        }
                    }
                }

                //Send HTTP Headers
                SendChunkedHeaders(context);

                if (stream.Length - stream.Position > Model.FREE_FILE_LIMIT)
                {
                    //File isnt free leech, acquire a token before we send the file
                    token = uploadLimiter.RequestUploadToken(context.RemoteEndPoint.Address.ToString());
                    while (token.GlobalQueuePosition > 0)
                    {
                        int QueuePosition = token.GlobalQueuePosition;
                        if (QueuePosition > 0)
                        {
                            status = string.Format("{0} - {1} - {2} - Queue Position {3}", user, Path.GetFileName(url),
                                                   Utility.FormatBytes(stream.Length), QueuePosition);
                            SendChunkedData(context, Encoding.ASCII.GetBytes(QueuePosition.ToString() + '|'));
                            token.WaitTimeout();
                        }
                    }
                }

                TransferStart = DateTime.Now;
                //Zero queue flag, data follows
                SendChunkedData(context, Encoding.ASCII.GetBytes("0|"));
                status = string.Format("{0} - {1} - {2}", user, Path.GetFileName(url),
                                       Utility.FormatBytes(stream.Length));

                //Send data
                MemoryBuffer buffer = bufferService.GetBuffer();
                try
                {
                    //Unfortunatly the microsoft http client implementation uses an int32 for chunk sizes which limits them to 2047mb.
                    //so sigh, send it smaller chunks.  Use a limit to 1.86gb for as it is more clean..

                    for (long i = 0; i < stream.Length; i += CHUNK_SIZE_LIMIT)
                    {
                        int chunkSize = 0;
                        if (stream.Length - position > CHUNK_SIZE_LIMIT)
                        {
                            chunkSize = CHUNK_SIZE_LIMIT;
                        }
                        else
                        {
                            chunkSize = (int)(stream.Length - position);
                        }

                        //Send chunk length
                        byte[] hexbytes = Encoding.ASCII.GetBytes(chunkSize.ToString("X"));
                        context.Stream.Write(hexbytes, 0, hexbytes.Length);
                        context.Stream.Write(CRLF, 0, CRLF.Length);
                        //Send data
                        long dataSent  = 0;
                        int  bytesRead = 0;
                        while (dataSent < chunkSize)
                        {
                            context.LastAction = DateTime.Now;
                            int toRead = buffer.Data.Length;
                            //Less that one buffer to send, ensure we dont send too much data just incase the file size has increased.
                            if (chunkSize - dataSent < toRead)
                            {
                                toRead = (int)(chunkSize - dataSent);
                            }
                            bytesRead = stream.Read(buffer.Data, 0, toRead);
                            context.Stream.Write(buffer.Data, 0, bytesRead);
                            nsm.PutData(bytesRead);
                            dataSent += bytesRead;
                            position += bytesRead;
                        }
                        //End data chunk
                        context.Stream.Write(CRLF, 0, CRLF.Length);
                    }
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("faplog").Trace("Failed write file to http stream", err);
                }
                finally
                {
                    bufferService.FreeBuffer(buffer);
                }
                //Send empty chunk, to flag stream end
                SendChunkedData(context, new byte[0]);
            }
            finally
            {
                status = string.Format("{0} - {1} - Complete", user, Path.GetFileName(url));
                if (null != token)
                {
                    uploadLimiter.FreeToken(token);
                }
                isComplete = true;
                position   = length;
            }
        }
Exemplo n.º 4
0
        public void DoUpload(IHttpContext context, Stream stream, string user, string url)
        {
            length      = stream.Length;
            ResumePoint = 0;
            IHeader rangeHeader =
                context.Request.Headers.Where(n => n.Name.ToLowerInvariant() == "range").FirstOrDefault();
            ServerUploadToken token = null;

            try
            {
                if (stream.Length > Model.FREE_FILE_LIMIT)
                {
                    //File isnt free leech, acquire a token before we send the file
                    token = uploadLimiter.RequestUploadToken(context.RemoteEndPoint.Address.ToString());
                    while (token.GlobalQueuePosition > 0)
                    {
                        context.LastAction = DateTime.Now;
                        status             = string.Format("HTTP ({0}) queued upload in slot {1}", user, token.GlobalQueuePosition);
                        token.WaitTimeout();
                    }
                }

                status = string.Format("HTTP ({0}) Sending {1}", user, url);
                try
                {
                    if (null != rangeHeader)
                    {
                        //Partial request
                        //Try to parse header - if we fail just send a 200 ok from zero
                        long start = 0;
                        long end   = 0;

                        if (rangeHeader.HeaderValue.StartsWith("bytes="))
                        {
                            string header   = rangeHeader.HeaderValue.Substring(6).Trim();
                            string starttxt = string.Empty;
                            string endtxt   = string.Empty;

                            if (header.Contains('-'))
                            {
                                starttxt = header.Substring(0, header.IndexOf("-"));
                                endtxt   = header.Substring(header.IndexOf("-") + 1,
                                                            header.Length - (header.IndexOf("-") + 1));
                            }
                            else
                            {
                                starttxt = header;
                            }

                            if (!string.IsNullOrEmpty(starttxt))
                            {
                                start = long.Parse(starttxt);
                            }
                            if (!string.IsNullOrEmpty(endtxt))
                            {
                                end = long.Parse(endtxt);
                            }
                            //Only allow a partial request start.  May implement this at some point but its beyond the scope of this atm.
                            if (start != 0 && end == 0)
                            {
                                if (start > stream.Length)
                                {
                                    start = stream.Length;
                                }
                                stream.Seek(start, SeekOrigin.Begin);
                                position = start;

                                ResumePoint = start;
                            }
                            context.Response.Status = HttpStatusCode.PartialContent;
                        }
                    }
                }
                catch
                {
                }

                TransferStart = DateTime.Now;
                //Send headers
                context.Response.ContentLength.Value = stream.Length - stream.Position;
                var generator = new ResponseWriter();
                generator.SendHeaders(context, context.Response);
                //Send data
                MemoryBuffer buffer = bufferService.GetBuffer();
                try
                {
                    int bytesRead = stream.Read(buffer.Data, 0, buffer.Data.Length);
                    while (bytesRead > 0)
                    {
                        context.LastAction = DateTime.Now;
                        context.Stream.Write(buffer.Data, 0, bytesRead);
                        position += bytesRead;
                        nsm.PutData(bytesRead);
                        bytesRead = stream.Read(buffer.Data, 0, buffer.Data.Length);
                    }
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("faplog").Trace("Failed to send body through context stream.", err);
                }
                finally
                {
                    bufferService.FreeBuffer(buffer);
                }
            }
            finally
            {
                status = string.Format("HTTP ({0}) Upload complete", user);
                if (null != token)
                {
                    uploadLimiter.FreeToken(token);
                }
                isComplete = true;
                position   = length;
            }
        }