Esempio n. 1
0
 public async Task OnCompleted(HttpTransfer transfer)
 {
     await this.notifications.Send(
         "Transfer Complete",
         $"{transfer.Identifier} complete"
         );
 }
Esempio n. 2
0
 public async Task OnError(HttpTransfer transfer, Exception ex)
 {
     await this.notifications.Send(
         "Transfer Error",
         $"{transfer.Identifier} errored - SORRY!"
         );
 }
 public Task OnCompleted(HttpTransfer transfer)
 {
     return(Task.Run(() =>
     {
         Xamarin.Forms.MessagingCenter.Send(this, "UPLOAD_DONE", transfer);
     }));
 }
Esempio n. 4
0
 public async Task <Screenshot> GetAppScreenShotAsync(Guid appGuid, AppScreenshotType appScreenshotType, AppScreenshotSize appScreenshotSize, int screenShotIndex)
 {
     return(await HttpTransfer.GetAppScreenshotAsync(
                appGuid,
                appScreenshotType,
                appScreenshotSize,
                screenShotIndex));
 }
 public Task OnError(HttpTransfer transfer, Exception ex)
 {
     return(Task.Run(() =>
     {
         System.Diagnostics.Debug.WriteLine(ex.Message);
         MessagingCenter.Send(this, "UPLOAD_FAILED", ex);
     }));
 }
        async Task TryUpdate(HttpTransfer transfer)
        {
            var result = await repository.Remove <SyncItem>(transfer.Identifier);

            if (result && this.syncManager.ShowBadgeCount)
            {
                this.notificationManager.Badge = this.notificationManager.Badge - 1;
            }
        }
Esempio n. 7
0
 static void ToViewModel(HttpTransferViewModel viewModel, HttpTransfer transfer)
 {
     // => Math.Round(this.transfer.BytesPerSecond.Bytes().Kilobytes, 2) + " Kb/s";
     //public string EstimateMinsRemaining => Math.Round(this.transfer.EstimatedCompletionTime.TotalMinutes, 1) + " min(s)";
     //viewModel.EstimateMinsRemaining =
     viewModel.PercentComplete     = transfer.PercentComplete;
     viewModel.PercentCompleteText = $"{transfer.PercentComplete * 100}%";
     viewModel.Status = transfer.Status.ToString();
 }
Esempio n. 8
0
 static MetricHolder Get(HttpTransfer transfer, Dictionary <string, MetricHolder> metrics)
 {
     if (!metrics.ContainsKey(transfer.Identifier))
     {
         metrics.Add(transfer.Identifier, new MetricHolder(transfer.Identifier)
         {
             LastBytesTransferred = transfer.BytesTransferred,
             LastPing             = DateTime.UtcNow
         });
     }
     return(metrics[transfer.Identifier]);
 }
Esempio n. 9
0
        static HttpTransferMetric Calculate(HttpTransfer transfer, IDictionary <string, MetricHolder> metrics)
        {
            var holder       = metrics[transfer.Identifier];
            var elapsed      = DateTime.UtcNow - holder.LastPing;
            var totalSeconds = (long)elapsed.TotalSeconds;

            var xferDiff       = transfer.BytesTransferred - holder.LastBytesTransferred;
            var bytesPerSecond = xferDiff / totalSeconds;
            var rawEta         = (transfer.FileSize - transfer.BytesTransferred) / bytesPerSecond;
            var metric         = new HttpTransferMetric(transfer, bytesPerSecond, TimeSpan.FromSeconds(rawEta));

            holder.LastPing             = DateTime.UtcNow;
            holder.LastBytesTransferred = transfer.BytesTransferred;

            return(metric);
        }
        /// <summary>
        /// This method is called by <see cref="MediaServerDevice.WebServer_OnPacketReceiveSink"/>
        /// and handles the HTTP-GET or HTTP-GET message requests and provides
        /// the appropriate response. In either case, the handler is intended
        /// to handle requests for resource URIs that have been mapped to local
        /// files using the <see cref="MediaResource.AUTOMAPFILE"/> convention.
        /// <para>
        /// If a resource cannot be mapped to a local file, 
        /// then the method will ask upper-layer application logic 
        /// for a stream object to send in response to the request.
        /// This is used primarily in scenarios where the application intentionally
        /// specified a contentUri value for a resource that uses the 
        /// <see cref="MediaResource.AUTOMAPFILE"/> convention but doesn't
        /// actually map to a local file. This gives the upper application layer
        /// to provide transcoded stream objects or some specialized file stream
        /// that is not stored on the local file system.
        /// </para>
        /// <para>
        /// Upper application layers can always opt to leave the stream object
        /// blank, effectively indicating that the HTTP-GET or head request 
        /// cannot be handled because such a file does not exist.
        /// </para>
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="session"></param>
        private void HandleGetOrHeadRequest(HTTPMessage msg, HTTPSession session)
        {
            // Format of DirectiveObj will be
            // "/[res.m_ResourceID]/[item.ID]/[item.Title].[ext]"
            // We want the
            bool is404 = true;
            Exception problem = null;

            string resourceID = null;
            string objectID = null;

            try
            {
                DText DirectiveParser = new DText();
                DirectiveParser.ATTRMARK = "/";

                DirectiveParser[0] = msg.DirectiveObj;
                resourceID = DirectiveParser[2];
                objectID = DirectiveParser[3];
                IDvResource res = this.GetResource(objectID, resourceID);

                if (res == null)
                {
                    throw new Error_GetRequestError(msg.DirectiveObj, null);
                }
                else
                {
                    // attempt to figure otu the local file path and the mime type
                    string f = MediaResource.AUTOMAPFILE;
                    string fileName = res.ContentUri.Substring(f.Length);
                    string type = res.ProtocolInfo.MimeType;

                    if ((type == null) || (type == "") || (type == "*"))
                    {
                        //content-type not known, programmer
                        //that built content-hierarchy didn't provide one

                        throw new Error_GetRequestError(msg.DirectiveObj, res);
                    }
                    else
                    {
                        // must be a get or head request

                        // check if the file actually exists
                        if (Directory.Exists(fileName))
                        {
                            throw new Error_GetRequestError(msg.DirectiveObj, res);
                        }

                        FileNotMapped mapping = new FileNotMapped();
                        mapping.RequestedResource = res;
                        mapping.LocalInterface = session.Source.ToString();
                        mapping.RedirectedStream = null;
                        if (File.Exists(fileName))
                        {
                            // the file exists, so go ahead and send it
                            mapping.RedirectedStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                        }
                        else
                        {
                            try
                            {
                                // the file doesn't exist but the owner of this
                                // server specified some kind of locally mapped file
                                // so perhaps they may want to route a stream object themselves
                                if (this.OnFileNotMapped != null)
                                {
                                    this.OnFileNotMapped (this, mapping);
                                }
                            }
                            catch (Exception ofnm)
                            {
                                mapping.RedirectedStream = null;
                            }
                        }

                        // if the RedirectedStream is blank, then it means
                        // no stream can be sent in response to the request

                        if (mapping.RedirectedStream != null)
                        {
                            lock (session)
                            {
                                // get the intended length, if known
                                long expectedLength = -1;
                                if (mapping.OverrideRedirectedStreamLength)
                                {
                                    expectedLength = mapping.ExpectedStreamLength;
                                }
                                else
                                {
                                    expectedLength = mapping.RedirectedStream.Length;
                                }

                                if (String.Compare(msg.Directive, "HEAD", true) == 0)
                                {
                                    // must be a head request - reply with 200/OK, content type, content length
                                    HTTPMessage head = new HTTPMessage();
                                    head.StatusCode = 200;
                                    head.StatusData = "OK";
                                    head.ContentType = type;
                                    if (expectedLength >= 0)
                                    {
                                        // if we can calculate the length,
                                        // then we provide a content-length and
                                        // also indicate that range requests can be
                                        // handled.

                                        head.OverrideContentLength = true;

                                        string rangeStr = msg.GetTag("RANGE");
                                        if ((rangeStr == null) || (rangeStr == ""))
                                        {
                                            head.AddTag("CONTENT-LENGTH", expectedLength.ToString());
                                            head.AddTag("ACCEPT-RANGES", "bytes");
                                        }
                                        else
                                        {
                                            ArrayList rangeSets = new ArrayList();
                                            head.StatusCode = 206;
                                            AddRangeSets(rangeSets, rangeStr.Trim().ToLower(), expectedLength);
                                            if (rangeSets.Count == 1)
                                            {
                                                head.AddTag("Content-Range", "bytes " + ((HTTPSession.Range)(rangeSets[0])).Position.ToString() + "-" + ((int)(((HTTPSession.Range)(rangeSets[0])).Position+((HTTPSession.Range)(rangeSets[0])).Length-1)).ToString() + "/" + expectedLength.ToString());
                                                head.AddTag("Content-Length", ((HTTPSession.Range)(rangeSets[0])).Length.ToString());
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // can't calculate length => can't do range
                                        head.AddTag("ACCEPT-RANGES", "none");
                                    }
                                    session.Send(head);
                                    is404 = false;
                                }
                                else
                                {
                                    ArrayList rangeSets = new ArrayList();
                                    string rangeStr = msg.GetTag("RANGE");

                                    // Only allow range requests for content where we have the
                                    // entire length and also only for requests that have
                                    // also provided an allowed range.
                                    if ((rangeStr == null) || (rangeStr != ""))
                                    {
                                        if (expectedLength >= 0)
                                        {
                                            // validate the requested ranges; if invalid range
                                            // found, send the entire document...
                                            AddRangeSets(rangeSets, rangeStr.Trim().ToLower(), expectedLength);
                                        }
                                    }

                                    // must be a get request
                                    // create an outgoing transfer that is not visible to UPNP
                                    // GetTransferProgress method, and add the transfer
                                    HttpTransfer transferInfo = new HttpTransfer(false, false, session, res, mapping.RedirectedStream, expectedLength);
                                    this.AddTransfer(session, transferInfo);

                                    if (rangeSets.Count > 0)
                                    {
                                        session.SendStreamObject(mapping.RedirectedStream, (HTTPSession.Range[])rangeSets.ToArray(typeof(HTTPSession.Range)), type);
                                    }
                                    else
                                    {
                                        //start from the beginning
                                        mapping.RedirectedStream.Seek(0, SeekOrigin.Begin);
                                        if (expectedLength >= 0)
                                        {
                                            session.SendStreamObject(mapping.RedirectedStream, expectedLength, type);
                                        }
                                        else
                                        {
                                            session.SendStreamObject(mapping.RedirectedStream, type);
                                        }
                                    }
                                    is404 = false;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception error)
            {
                problem = error;
            }

            if (is404)
            {
                StringBuilder sb = new StringBuilder();

                sb.Append("File not found.");
                sb.AppendFormat("\r\n\tRequested: \"{0}\"", msg.DirectiveObj);

                if (objectID != null)
                {
                    sb.AppendFormat("\r\n\tObjectID=\"{0}\"", objectID);
                }

                if (resourceID != null)
                {
                    sb.AppendFormat("\r\n\tResourceID=\"{0}\"", resourceID);
                }

                Error_GetRequestError getHeadError = problem as Error_GetRequestError;

                if (getHeadError != null)
                {
                    sb.Append("\r\n");

                    IUPnPMedia mobj = this._GetEntry(objectID);

                    if (mobj == null)
                    {
                        sb.AppendFormat("\r\n\tCould not find object with ID=\"{0}\"", objectID);
                    }
                    else
                    {
                        sb.AppendFormat("\r\n\tFound object with ID=\"{0}\"", objectID);
                        sb.Append("\r\n---Metadata---\r\n");
                        sb.Append(mobj.ToDidl());
                    }

                    sb.Append("\r\n");

                    if (getHeadError.Resource == null)
                    {
                        sb.Append("\r\n\tResource is null.");
                    }
                    else
                    {
                        sb.Append("\r\n\tResource is not null.");

                        string uri = getHeadError.Resource.ContentUri;
                        if (uri== null)
                        {
                            sb.Append("\r\n\t\tContentUri of resource is null.");
                        }
                        else if (uri == "")
                        {
                            sb.Append("\r\n\t\tContentUri of resource is empty.");
                        }
                        else
                        {
                            sb.AppendFormat("\r\n\t\tContentUri of resource is \"{0}\"", uri);
                        }
                    }
                }

                if (problem != null)
                {
                    sb.Append("\r\n");

                    Exception e = problem;
                    sb.Append("\r\n!!! Exception information !!!");

                    while (e != null)
                    {
                        sb.AppendFormat("\r\nMessage=\"{0}\".\r\nStackTrace=\"{1}\"", e.Message, e.StackTrace);

                        e = e.InnerException;
                        if (e != null)
                        {
                            sb.Append("\r\n---InnerException---");
                        }
                    }
                }

                // file has not been found so return a valid HTTP 404 error message
                HTTPMessage error = new HTTPMessage();
                error.StatusCode = 404;
                error.StatusData = "File not found";
                error.StringBuffer = sb.ToString();
                session.Send(error);
            }
        }
        /// <summary>
        /// Method executes when a control point invokes the ContentDirectory.ImportResource action.
        /// The method first checks to see if the local URI actually maps to an automapped file
        /// and that the remote URI is an HTTP resource.
        /// The method then asks upper software layers to accept or reject the request to
        /// import a resource from a remote URI to a local URI. Upper software layers reject the request by throwing an exception,
        /// preferably a UPnPCustomException. If the request was approved by upper layers,
        /// then we do a bunch of stuff that results in the file getting transferred over HTTP.
        /// </summary>
        /// <param name="SourceURI">the URI where the binary should be obtained</param>
        /// <param name="DestinationURI">the URI (that can map to a local file) where the binary should be stored</param>
        /// <param name="TransferID">Returns ID for the file transfer.</param>
        private void SinkCd_ImportResource(System.Uri SourceURI, System.Uri DestinationURI, out System.UInt32 TransferID)
        {
            string objectID, resourceID;

            // Parse the media and resource IDs from the destination uri.
            this.GetObjectResourceIDS(DestinationURI, out objectID, out resourceID);

            if ((objectID == "") || (resourceID == ""))
            {
                throw new Error_NoSuchResource(DestinationURI.ToString());
            }
            else
            {
                // TODO: Might consider throwing ane xception in the
                // rare case that stupid ass control point says to
                // download to a different media server.
            }

            // ensure that we're doing http
            if (SourceURI.Scheme.ToLower().StartsWith("http") == false)
            {
                throw new Error_NonHttpImport(DestinationURI.ToString());
            }

            // get the resource object associated with the destination uri
            IDvResource res = this.GetResource(objectID, resourceID);

            // request application logic to approve the binary transfer;
            // Application logic should throw an exception to rject the request.
            if (this.OnRequestSaveBinary != null)
            {
                this.OnRequestSaveBinary(this, res);
            }
            else
            {
                throw new Error_InvalidServerConfiguration("ImportResource() cannot be supported until the vendor configures the server correctly.");
            }

            //
            // Grab the file through http-get
            //

            IPAddress addr = null;
            IPHostEntry ihe = null;
            IPEndPoint dest = null;

            // Attempt to get a routeable IP address for the request

            try
            {
                if(SourceURI.HostNameType == UriHostNameType.Dns)
                {
                    ihe = Dns.GetHostByName(SourceURI.Host);
                    addr = new IPAddress(ihe.AddressList[0].Address);
                }
                else
                {
                    addr = IPAddress.Parse(SourceURI.Host);
                }
            }
            catch
            {
                throw new Error_ConnectionProblem("Could parse or resolve the SourceURI IP address represented by" +SourceURI.ToString());
            }

            dest = new IPEndPoint(addr, SourceURI.Port);

            // Open a socket and connect to the remote IP address and port

            System.Net.Sockets.Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                s.Connect(dest);
            }
            catch
            {
                throw new Error_ConnectionProblem("Could not connect to the remote URI " + DestinationURI.ToString());
            }

            // Do a check to make sure we're not dumping to a directory.

            string filename = res.ContentUri.Substring(MediaResource.AUTOMAPFILE.Length);
            if (Directory.Exists(filename))
            {
                throw new Error_ImportError("System error. Resource has been mapped incorrectly. Cannot overwrite a directory with a binary.");
            }

            // Create an HTTP session for this socket.
            // Set things up so that the HTTP-GET will automatically dump
            // the body of the message into a binary file that has
            // been automatically mapped.

            HTTPSession session = new HTTPSession(s, null, null);
            this.SetupSessionForTransfer(session);
            session.OnHeader += new HTTPSession.ReceiveHeaderHandler(this.GetRequest_OnHeaderReceiveSink);
            try
            {
                session.UserStream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
            }
            catch
            {
                throw new Error_ImportError("System busy. Could not open file from local system for writing.");
            }

            if (session.UserStream == null)
            {
                throw new Error_ImportError("System error. Cannot write to a null stream.");
            }

            SessionData sd = (SessionData) session.StateObject;
            sd.HttpVer1_1 = false;

            // Create the HTTP message that will request the binary.

            HTTPMessage msg = new HTTPMessage();
            msg.Directive = "GET";
            msg.DirectiveObj = HTTPMessage.UnEscapeString(SourceURI.PathAndQuery);
            msg.AddTag("HOST", dest.ToString());
            msg.Version = "1.0";

            // Create an HttpTransfer object that will represent the progress
            // of this file transfer and add it to the media server's current
            // transfers list.

            long expectedLength = 0;
            HttpTransfer transferInfo = new HttpTransfer(true, true, session, res, session.UserStream, expectedLength);
            this.AddTransfer(session, transferInfo);
            TransferID = transferInfo.m_TransferId;

            // Go make the request for the file.
            session.Send(msg);

            this.m_Stats.ImportResource++;
            this.FireStatsChange();
        }
Esempio n. 12
0
 public async Task <BitmapImage> GetAppBackgroundImageAsync(Guid appGuid)
 {
     return(await HttpTransfer.GetAppBackgroundImageAsync(appGuid));
 }
Esempio n. 13
0
        async Task <HttpTransfer> Download(HttpTransferStore request, CancellationToken ct)
        {
            HttpTransfer lastTransfer     = default;
            var          status           = HttpTransferState.Pending;
            var          file             = new FileInfo(request.LocalFile);
            var          message          = this.Build(request);
            var          fileSize         = 0L;
            var          bytesTransferred = file.Exists ? file.Length : 0;
            var          fileMode         = file.Exists ? FileMode.Append : FileMode.Create;
            Exception?   exception        = null;

            using (var fs = file.Open(fileMode, FileAccess.Write, FileShare.Write))
            {
                while (!status.IsCompleted() && !ct.IsCancellationRequested)
                {
                    try
                    {
                        if (fs.Length > 0)
                        {
                            var resumeOffset = fs.Length + 1;
                            message.Headers.Range = new RangeHeaderValue(resumeOffset, null);
                        }

                        var buffer   = new byte[65535];
                        var response = await this.httpClient
                                       .SendAsync(
                            message,
                            HttpCompletionOption.ResponseHeadersRead,
                            ct
                            )
                                       .ConfigureAwait(false);


                        response.EnsureSuccessStatusCode();

                        var inputStream = await response
                                          .Content
                                          .ReadAsStreamAsync()
                                          .ConfigureAwait(false);

                        var read = inputStream.Read(buffer, 0, buffer.Length);

                        // status code 206 means restart
                        if (response.Headers.AcceptRanges == null && fs.Length > 0)
                        {
                            // resume not supported, starting over
                            fs.SetLength(0);
                            fs.Flush();
                            bytesTransferred = 0;
                        }

                        var i = 0;
                        while (read > 0 && !ct.IsCancellationRequested)
                        {
                            fileSize = response.Content?.Headers?.ContentRange?.Length ?? response.Content?.Headers?.ContentLength ?? 0;
                            //this.RemoteFileName = response.Content?.Headers?.ContentDisposition?.FileName ?? String.Empty;
                            ////pr.FileSize = response.Content?.Headers?.ContentLength ?? 0; // this will change on resume
                            bytesTransferred += read;

                            fs.Write(buffer, 0, read);
                            fs.Flush();

                            i++;
                            if (i % 4 == 0)
                            {
                                lastTransfer = new HttpTransfer(
                                    request.Id,
                                    request.Uri,
                                    request.LocalFile,
                                    false,
                                    request.UseMeteredConnection,
                                    null,
                                    fileSize,
                                    bytesTransferred,
                                    HttpTransferState.InProgress
                                    );
                                this.messageBus.Publish(lastTransfer);
                            }
                            read = inputStream.Read(buffer, 0, buffer.Length);
                        }
                        status = HttpTransferState.Completed;
                    }
                    catch (TaskCanceledException)
                    {
                        status = ct.IsCancellationRequested
                            ? HttpTransferState.Canceled
                            : HttpTransferState.Retrying;
                    }
                    catch (IOException ex)
                    {
                        if (ex.InnerException is WebException)
                        {
                            status = HttpTransferState.Retrying;
                        }
                        else
                        {
                            exception = ex;
                            status    = HttpTransferState.Error;
                        }
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                        status    = HttpTransferState.Error;
                    }
                    lastTransfer = new HttpTransfer(
                        request.Id,
                        request.Uri,
                        request.LocalFile,
                        true,
                        request.UseMeteredConnection,
                        exception,
                        fileSize,
                        bytesTransferred,
                        status
                        );
                    this.messageBus.Publish(lastTransfer);
                }
            }
            return(lastTransfer);
        }
 public void OnError(HttpTransfer transfer, Exception ex)
 {
 }
        /// <summary>
        /// Lock the set of existing transfers for the entire server.
        /// Add the new transfer to the session's state object, for future reference.
        /// Obtain a unique transfer ID
        /// Add the new transfer to the set of existing transfers for the entire server.
        /// Unlock the set of existing transfers.
        /// </summary>
        /// <param name="session"></param>
        /// <param name="transferInfo"></param>
        private void AddTransfer(HTTPSession session, HttpTransfer transferInfo)
        {
            this.m_LockHttpTransfers.AcquireWriterLock(-1);

            SessionData sd = (SessionData) session.StateObject;
            sd.Transfers.Enqueue(transferInfo);
            sd.Requested++;

            // obtain unique transfer id
            UInt32 id = (uint) session.GetHashCode();
            while (this.m_HttpTransfers.ContainsKey(id))
            {
                id++;
            }

            this.m_HttpTransfers.Add(id, transferInfo);
            transferInfo.m_TransferId = id;

            this.m_LockHttpTransfers.ReleaseWriterLock();
            this.FireHttpTransfersChange();
        }
 public Task OnCompleted(HttpTransfer transfer)
 => this.TryUpdate(transfer);
 public Task OnError(HttpTransfer transfer, Exception ex)
 {
     // TODO: file error with delegate?
     return(this.TryUpdate(transfer));
 }
 public void OnCompleted(HttpTransfer transfer)
 {
 }
        /// <summary>
        /// Handles the code for when a client attempts to post a binary
        /// to the server. The method attempts to find a resource object
        /// that maps to the specified uri and will then ask upper application
        /// logic for permission to save the binary. Application logic
        /// can reject the request by throwing an exception.
        /// <para>
        /// As an aside, piplelining is really easy for POST messages
        /// because the bodies of POST messages will contain the actual
        /// binary that's getting transfered to the server. Standard pipelining
        /// rules dictate that the next POST message must follow an already 
        /// complete HTTP message. Regardless of whether the request was
        /// GET, POST, or HEAD - setting the WebSession's UserSTream property
        /// should always work.
        /// </para>
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="WebSession"></param>
        private void HandlePostedFileToServer(HTTPMessage msg, HTTPSession WebSession)
        {
            // Format of DirectiveObj will be
            // "/[res.m_ResourceID]/[res.m_Owner.ID]/"
            //
            DText DirectiveParser = new DText();
            DirectiveParser.ATTRMARK = "/";

            DirectiveParser[0] = msg.DirectiveObj;
            string resourceID = DirectiveParser[2];
            string objectID = DirectiveParser[3];

            IDvResource res = this.GetResource(objectID, resourceID);
            WebSession.UserStream = null;

            if (res != null)
            {
                // only receive files that are allow overwriting
                if (res.AllowImport)
                {
                    if (this.OnRequestSaveBinary != null)
                    {
                        // If application has not requested notifications for
                        // when something post data, tnen automatically approve
                        // the POST.
                    }
                    else
                    {
                        // Allow the application to approve or reject the POST.
                        // If the application logic throws an exception,
                        // then the WebSession.UserStream field remains null.
                        // The message of the exception is used in the HTTP
                        // error response to the POST-sender.
                        this.OnRequestSaveBinary(this, res);
                    }

                    // Set the session to write to the following local file.
                    //
                    string path = res.ContentUri.Substring(MediaResource.AUTOMAPFILE.Length);

                    // attempt to figure out the intended file extension by
                    // examining the sender's post request for a content-type.
                    // if so, append the extension as appropriately.
                    string mime = msg.ContentType;
                    string ext = MimeTypes.MimeToExtension(mime);

                    if (path.EndsWith(ext) == false)
                    {
                        path += ext;
                    }

                    // attempt to figure ot the intended file's length by
                    // examining the sender's post request
                    long expectedLength = 0;
                    try
                    {
                        expectedLength = this.ExtractContentLength(msg);
                    }
                    catch
                    {
                    }

                    // Create a stream for the file incoming data,
                    // wire up session to dump the incoming data to the stream,
                    // create a transfer info block indicating information about
                    // the transfer, and formally add the transfer.
                    FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 4*1024);
                    WebSession.UserStream = fs;
                    HttpTransfer transferInfo = new HttpTransfer(true, true, WebSession, res, WebSession.UserStream, expectedLength);
                    this.AddTransfer(WebSession, transferInfo);
                }
            }
        }
Esempio n. 20
0
        async Task <HttpTransfer> Upload(HttpTransferStore request, CancellationToken ct)
        {
            var          file             = new FileInfo(request.LocalFile);
            var          status           = HttpTransferState.Pending;
            var          bytesTransferred = 0L;
            Exception?   exception        = null;
            HttpTransfer lastTransfer     = default;

            // and not cancelled or error
            while (!status.IsCompleted() && !ct.IsCancellationRequested)
            {
                try
                {
                    var content = new MultipartFormDataContent();
                    if (!request.PostData.IsEmpty())
                    {
                        content.Add(new StringContent(request.PostData));
                    }

                    content.Add(
                        new ProgressStreamContent(
                            file.OpenRead(),
                            8192,
                            sent =>
                    {
                        status            = HttpTransferState.InProgress;
                        bytesTransferred += sent;
                        lastTransfer      = new HttpTransfer(
                            request.Id,
                            request.Uri,
                            request.LocalFile,
                            true,
                            request.UseMeteredConnection,
                            null,
                            file.Length,
                            bytesTransferred,
                            status
                            );
                        this.messageBus.Publish(lastTransfer);
                    }
                            ),
                        "blob",
                        file.Name
                        );
                    var message = this.Build(request);
                    message.Content = content;

                    var response = await this.httpClient
                                   .SendAsync(message, ct)
                                   .ConfigureAwait(false);

                    response.EnsureSuccessStatusCode();

                    status = HttpTransferState.Completed;
                }
                catch (TimeoutException)
                {
                    status = HttpTransferState.Retrying;
                }
                catch (IOException ex)
                {
                    if (ex.InnerException is WebException)
                    {
                        status = HttpTransferState.Retrying;
                    }
                    else
                    {
                        exception = ex;
                        status    = HttpTransferState.Error;
                    }
                }
                catch (WebException ex)
                {
                    switch (ex.Status)
                    {
                    case WebExceptionStatus.ConnectFailure:
                    case WebExceptionStatus.Timeout:
                        status = HttpTransferState.Retrying;
                        break;

                    default:
                        status    = HttpTransferState.Error;
                        exception = ex;
                        break;
                    }
                }
                catch (TaskCanceledException)
                {
                    status = ct.IsCancellationRequested
                        ? HttpTransferState.Canceled
                        : HttpTransferState.Retrying;
                }
                catch (Exception ex)
                {
                    exception = ex;
                    status    = HttpTransferState.Error;
                }
                lastTransfer = new HttpTransfer(
                    request.Id,
                    request.Uri,
                    request.LocalFile,
                    true,
                    request.UseMeteredConnection,
                    exception,
                    file.Length,
                    bytesTransferred,
                    status
                    );
                this.messageBus.Publish(lastTransfer);
            }
            return(lastTransfer);
        }
        /// <summary>
        /// Method actually removes an <see cref="HttpTransfer"/>
        /// object from the mediaserver's list of active transfers.
        /// The method is executed after the LifeTimeMonitor
        /// notes that the prerequisite 30 seconds has passed since
        /// the actual transfer was completed.
        /// Method is called by <see cref="MediaServerDevice.Sink_OnExpired"/>.
        /// </summary>
        /// <param name="transferInfo"></param>
        private void RemoveTransfer(HttpTransfer transferInfo)
        {
            UInt32 id = transferInfo.m_TransferId;
            this.m_LockHttpTransfers.AcquireWriterLock(-1);

            bool error = false;
            if (this.m_HttpTransfers.ContainsKey(id))
            {
                HttpTransfer transferInfo2 = (HttpTransfer) this.m_HttpTransfers[id];
                if (transferInfo2 == transferInfo)
                {
                    this.m_HttpTransfers.Remove(id);
                }
                else
                {
                    error = true;
                }
            }
            else
            {
                error = true;
            }
            this.m_LockHttpTransfers.ReleaseWriterLock();

            if (error)
            {
                throw new Error_TransferProblem(id, transferInfo);
            }

            this.FireHttpTransfersChange();
        }
Esempio n. 22
0
 static void ToViewModel(HttpTransferViewModel viewModel, HttpTransfer transfer)
 {
     viewModel.PercentComplete     = transfer.PercentComplete;
     viewModel.PercentCompleteText = $"{transfer.PercentComplete * 100}%";
     viewModel.Status = transfer.Status.ToString();
 }
        /// <summary>
        /// Method executes when a control point invokes the ContentDirectory.ExportResource action.
        /// This method effectively causes the MediaServer to send a local binary to 
        /// an URI that expects an HTTP-POST method of transfer. The method will report
        /// error messages if the specified local URI does not map to a URI that is 
        /// automapped using <see cref="MediaResource.AUTOMAPFILE"/>.
        /// </summary>
        /// <param name="SourceURI"></param>
        /// <param name="DestinationURI"></param>
        /// <param name="TransferID"></param>
        private void SinkCd_ExportResource(System.Uri SourceURI, System.Uri DestinationURI, out System.UInt32 TransferID)
        {
            TransferID = 0;
            Uri dest = DestinationURI;
            string resourceID, objectID;

            // find media and resource IDs given a URI that should map to something
            // served on this server
            this.GetObjectResourceIDS(SourceURI, out objectID, out resourceID);

            if ((objectID == "") || (resourceID == ""))
            {
                throw new Error_NoSuchResource(SourceURI.ToString());
            }

            IDvResource res = this.GetResource(objectID, resourceID);

            if (res != null)
            {
                //TODO: Might actually want to throw an exception here if the IP address
                //of the requested resource doesn't match an IP address of the server.
                //This may be more trouble than its worth though,a s it means
                //we have to figure out all of the IP addresses that apply to this
                //object and do a match, etc. What happens if the IP address
                //of the server changes spontaneously? Ignore the problem for now.

                //
                // create a socket that will connect to remote host
                //

                Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPEndPoint remoteIPE = null;
                if (dest.HostNameType == System.UriHostNameType.Dns)
                {
                    remoteIPE = new IPEndPoint(Dns.GetHostByName(dest.Host).AddressList[0], dest.Port);
                }
                else
                {
                    remoteIPE = new IPEndPoint(IPAddress.Parse(dest.Host), dest.Port);
                }

                if (remoteIPE != null)
                {
                    // check if the file actually exists
                    string fileName = res.ContentUri.Substring(MediaResource.AUTOMAPFILE.Length);
                    if (Directory.Exists(fileName))
                    {
                        throw new Error_NoSuchResource("The binary could not be found on the system.");
                    }

                    FileNotMapped mapping = new FileNotMapped();
                    StringBuilder li = new StringBuilder();
                    li.AppendFormat("{0}:{1}", SourceURI.Host, SourceURI.Port);
                    mapping.LocalInterface = li.ToString();
                    mapping.RequestedResource = res;
                    mapping.RedirectedStream = null;
                    if (File.Exists(fileName))
                    {
                        // the file exists, so go ahead and send it
                        mapping.RedirectedStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                    }
                    else
                    {
                        try
                        {
                            if (this.OnFileNotMapped != null)
                            {
                                this.OnFileNotMapped(this, mapping);
                            }
                        }
                        catch (Exception ofnme)
                        {
                            mapping.RedirectedStream = null;
                        }
                    }

                    if (mapping.RedirectedStream == null)
                    {
                        throw new Error_NoSuchResource("The binary could not be found on the system.");
                    }
                    else
                    {
                        try
                        {
                            s.Connect(remoteIPE);
                        }
                        catch
                        {
                            throw new UPnPCustomException(800, "Could not connect to the remote address of " +remoteIPE.ToString()+":"+remoteIPE.Port.ToString());
                        }

                        // Create a session that will post the file

                        HTTPSession session = null;
                        SessionData sd;

                        this.SetupSessionForTransfer(session);
                        sd = (SessionData) session.StateObject;
                        sd.HttpVer1_1 = true;

                        HttpTransfer transferInfo = new HttpTransfer(false, true, session, res, mapping.RedirectedStream, mapping.RedirectedStream.Length);
                        this.AddTransfer(session, transferInfo);

                        session.PostStreamObject(mapping.RedirectedStream, dest.PathAndQuery, res.ProtocolInfo.MimeType);

                        TransferID = transferInfo.m_TransferId;
                    }
                }
                else
                {
                    throw new UPnPCustomException(800, "Could not connect to the socket.");
                }
            }
            else
            {
                throw new Error_NoSuchResource("");
            }

            this.m_Stats.ExportResource++;
            this.FireStatsChange();
        }