public async Task <WebFetchResponse> FetchAsync(string url, WebFetchOptions options = null)
        {
            try
            {
                var response = new WebFetchResponse();
                var(serviceMd, parsedPath) = await WebFetchHelper(url);

                var path = CreateFinalPath(parsedPath);
                var file = await TryDifferentPaths(serviceMd, path);

                var fileData = await ReadContentFromFile(serviceMd, file, options);

                response.Data     = fileData.Item1.ToArray();
                response.MimeType = file.MimeType;
                response.Headers.Add("Content-Type", file.MimeType);
                if (options == null)
                {
                    return(response);
                }

                response.Headers.Add("Content-Range", $"bytes {fileData.Item2}-{fileData.Item3}/{fileData.Item4}");
                response.Headers.Add("Content-Length", $"{fileData.Item4}");
                return(response);
            }
            catch (WebFetchException ex)
            {
                Logger.Error(ex);
                throw;
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw;
            }
        }
Example #2
0
        public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest request)
        {
            try
            {
                Logger.Info($"Requested Url: {request.Url.ToString()}");
                var urlToFetch    = request.Url.ToString().Replace(Constants.BufferText, string.Empty);
                var isHttpRequest = request.Url.Scheme == "https";
                if (isHttpRequest && !urlToFetch.Contains("favicon"))
                {
                    var requestHeaders = request.RequestHeaders;

                    if (requestHeaders.ContainsKey("Range"))
                    {
                        var options = new WebFetchOptions
                        {
                            Range = RequestHelpers.RangeStringToArray(requestHeaders["Range"])
                        };

                        var task         = WebFetchService.FetchResourceAsync(urlToFetch, options);
                        var safeResponse = task.WaitAndUnwrapException();

                        var stream   = new MemoryStream(safeResponse.Data);
                        var response = new WebResourceResponse(safeResponse.MimeType, "UTF-8", stream);
                        response.SetStatusCodeAndReasonPhrase(206, "Partial Content");
                        response.ResponseHeaders = new Dictionary <string, string>
                        {
                            { "Accept-Ranges", "bytes" },
                            { "content-type", safeResponse.MimeType },
                            { "Content-Range", safeResponse.Headers["Content-Range"] },
                            { "Content-Length", safeResponse.Headers["Content-Length"] },
                        };
                        return(response);
                    }
                    else
                    {
                        var safeResponse = WebFetchService.FetchResourceAsync(urlToFetch).Result;
                        var stream       = new MemoryStream(safeResponse.Data);
                        var response     = new WebResourceResponse(safeResponse.MimeType, "UTF-8", stream);
                        return(response);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);

                if (ex.InnerException != null)
                {
                    using (var stream = new MemoryStream())
                    {
                        var urlToFetch = request.Url.ToString().Replace(Constants.BufferText, string.Empty);
                        var mimeType   = MimeTypeMap.Singleton.GetMimeTypeFromExtension(urlToFetch) ?? "text/html";
                        var response   = new WebResourceResponse(mimeType, "UTF-8", stream);
                        response.SetStatusCodeAndReasonPhrase(404, "Not Found");
                        return(response);
                    }
                }
            }
            return(base.ShouldInterceptRequest(view, request));
        }
        /// <summary>
        /// Helper function to read the file's content, and return an
        /// http compliant response based on the mime-type and options provided
        /// </summary>
        /// <param name="fileMdInfo">Opened file's MdInfo</param>
        /// <param name="openedFile">Open file</param>
        /// <param name="options">WebFetch options (ex. range to read)</param>
        /// <returns>Data as List &lt; byte &gt;, startIndex, endIndex, and size</returns>
        public async Task <(List <byte>, ulong, ulong, ulong)> ReadContentFromFile(
            MDataInfo fileMdInfo,
            WebFile openedFile,
            WebFetchOptions options = null)
        {
            try
            {
                var fileHandle = await _session.NFS.FileOpenAsync(fileMdInfo, openedFile.File, SafeApp.Misc.NFS.OpenMode.Read);

                var fileSize = await _session.NFS.FileSizeAsync(fileHandle);

                if (options == null)
                {
                    var fileData = await _session.NFS.FileReadAsync(fileHandle, 0, fileSize - 1);

                    return(fileData, 0, fileSize - 1, fileSize);
                }
                else
                {
                    var   partStartIndex = options.Range[0].Start > 0 ? options.Range[0].Start : 0;
                    ulong partEndIndex;

                    if (options.Range[0].End > 0)
                    {
                        partEndIndex = options.Range[0].End;
                    }
                    else
                    {
                        partEndIndex = fileSize - 1;
                    }

                    var partSize = partEndIndex - partStartIndex + 1;
                    var fileData = await _session.NFS.FileReadAsync(fileHandle, partStartIndex, partSize);

                    return(fileData, partStartIndex, partEndIndex, partSize);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }
            return(null, 0, 0, 0);
        }
        public async Task <WebFetchResponse> FetchAsync(string url, WebFetchOptions options = null)
        {
            try
            {
                var response = new WebFetchResponse();
                var fetchUrl = url.Replace("https://", "safe://");
                var data     = await _session.Fetch.FetchAsync(fetchUrl);

                if (data is FilesContainer filesContainer)
                {
                    ulong nrsContainerVersion = filesContainer.ResolvedFrom.Version;
                    if (filesContainer.FilesMap.Files != null && filesContainer.FilesMap.Files.Count > 0)
                    {
                        var indexFileInfo = filesContainer
                                            .FilesMap
                                            .Files
                                            .FirstOrDefault(
                            file => file.FileName == $"/{_default_page}" ||
                            file.FileName == $"{_default_page}");

                        if (!indexFileInfo.Equals(default(FileInfo)))
                        {
                            var indexFileLink = indexFileInfo
                                                .FileMetaData
                                                .FirstOrDefault(meta => meta.MetaDataKey == "link").MetaDataValue;

                            if (!string.IsNullOrEmpty(indexFileLink))
                            {
                                var fetchResponse = await FetchAsync(indexFileLink);

                                fetchResponse.CurrentNrsVersion = nrsContainerVersion;
                                fetchResponse.LatestNrsVersion  = await GetLatestVersionAsync(fetchUrl);

                                return(fetchResponse);
                            }
                        }
                    }
                }
                else if (data is PublishedImmutableData fetchedData)
                {
                    response.LatestNrsVersion = await GetLatestVersionAsync(fetchUrl);

                    response.CurrentNrsVersion = fetchedData.ResolvedFrom.Version;
                    response.Data     = fetchedData.Data;
                    response.MimeType = fetchedData.MediaType;
                    response.Headers.Add("Content-Type", fetchedData.MediaType);
                    return(response);
                }

                throw new WebFetchException(
                          WebFetchConstants.NoSuchPublicName,
                          WebFetchConstants.NoSuchPublicNameMessage);
            }
            catch (WebFetchException ex)
            {
                Logger.Error(ex);
                throw;
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw;
            }
        }
Example #5
0
        public static async Task <WebFetchResponse> FetchResourceAsync(string url, WebFetchOptions options = null)
        {
            try
            {
                if (!App.IsConnectedToInternet)
                {
                    throw new WebFetchException(
                              ErrorConstants.NoInternetConnectionError,
                              ErrorConstants.NoInternetConnection);
                }

                if (App.AppSession == null)
                {
                    throw new WebFetchException(
                              ErrorConstants.SessionNotAvailableError,
                              ErrorConstants.SessionNotAvailable);
                }

                if (App.AppSession.IsDisconnected)
                {
                    throw new WebFetchException(
                              ErrorConstants.ConnectionFailedError,
                              ErrorConstants.ConnectionFailed);
                }

                return(await WebFetch.FetchAsync(url, options));
            }
            catch (WebFetchException ex)
            {
                Logger.Error(ex);

                string htmlErrorPageString;
                switch (ex.ErrorCode)
                {
                case WebFetchConstants.NoSuchData:
                case WebFetchConstants.NoSuchEntry:
                case WebFetchConstants.NoSuchPublicName:
                case WebFetchConstants.NoSuchServiceName:
                case WebFetchConstants.FileNotFound:
                    htmlErrorPageString = await CreateHtmlErrorPage(ErrorConstants.PageNotFound, ex.Message);

                    break;

                case ErrorConstants.SessionNotAvailableError:
                    htmlErrorPageString = await CreateHtmlErrorPage(
                        ErrorConstants.SessionNotAvailableTitle,
                        ErrorConstants.SessionNotAvailableMsg);

                    break;

                case ErrorConstants.ConnectionFailedError:
                    htmlErrorPageString = await CreateHtmlErrorPage(
                        ErrorConstants.ConnectionFailedTitle,
                        ErrorConstants.ConnectionFailedMsg);

                    break;

                case ErrorConstants.NoInternetConnectionError:
                    htmlErrorPageString = await CreateHtmlErrorPage(
                        ErrorConstants.NoInternetConnectionTitle,
                        ErrorConstants.NoInternetConnectionMsg);

                    break;

                default:
                    htmlErrorPageString = await CreateHtmlErrorPage(
                        ErrorConstants.ErrorOccured,
                        ex.Message);

                    break;
                }

                return(new WebFetchResponse
                {
                    Data = Encoding.ASCII.GetBytes(htmlErrorPageString),
                    MimeType = ErrorConstants.ErrorPageMimeType
                });
            }
            catch (FfiException ex)
            {
                Logger.Error(ex);

                string htmlErrorPageString;
                if (ex.ErrorCode == -11 &&
                    Connectivity.NetworkAccess != NetworkAccess.Internet)
                {
                    htmlErrorPageString = await CreateHtmlErrorPage(
                        ErrorConstants.NoInternetConnectionTitle,
                        ErrorConstants.NoInternetConnectionMsg);
                }
                else
                {
                    htmlErrorPageString = await CreateHtmlErrorPage(
                        ErrorConstants.ErrorOccured,
                        ErrorConstants.UnableToFetchDataMsg);
                }
                return(new WebFetchResponse
                {
                    Data = Encoding.ASCII.GetBytes(htmlErrorPageString),
                    MimeType = ErrorConstants.ErrorPageMimeType
                });
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw;
            }
        }
Example #6
0
        public async Task <WebFetchResponse> FetchAsync(string url, WebFetchOptions options = null)
        {
            try
            {
                var response = new WebFetchResponse();
                var fetchUrl = url.Replace("https://", "safe://");
                var data     = await App
                               .AppSession
                               .Fetch
                               .FetchAsync(fetchUrl);

                if (data is FilesContainer filesContainer)
                {
                    if (filesContainer.FilesMap.Files != null && filesContainer.FilesMap.Files.Count > 0)
                    {
                        var indexFileInfo = filesContainer
                                            .FilesMap
                                            .Files
                                            .FirstOrDefault(
                            file => file.FileName == $"/{_defaultPage}" ||
                            file.FileName == $"{_defaultPage}");

                        if (!indexFileInfo.Equals(default(FileInfo)))
                        {
                            var indexFileLink = indexFileInfo
                                                .FileMetaData
                                                .FirstOrDefault(meta => meta.MetaDataKey == "link")
                                                .MetaDataValue;

                            if (!string.IsNullOrEmpty(indexFileLink))
                            {
                                var fetchResponse = await FetchAsync(indexFileLink);

                                fetchResponse.CurrentNrsVersion = await GetVersion(fetchUrl);

                                fetchResponse.LatestNrsVersion = await GetVersion(fetchUrl, true);

                                fetchResponse.FetchDataType = typeof(FilesContainer);
                                return(fetchResponse);
                            }
                        }
                        else
                        {
                            var content = await CreateFilesContainerPageAsync(filesContainer.FilesMap.Files);

                            response.CurrentNrsVersion = await GetVersion(fetchUrl);

                            response.LatestNrsVersion = await GetVersion(fetchUrl, true);

                            response.FetchDataType = typeof(FilesContainer);
                            response.Data          = content.ToUtfBytes();
                            response.MimeType      = "text/html";
                            response.Headers.Add("Content-Type", "text/html");
                            return(response);
                        }
                    }
                }
                else if (data is PublicImmutableData fetchedData)
                {
                    response.Data          = fetchedData.Data;
                    response.MimeType      = fetchedData.MediaType;
                    response.FetchDataType = typeof(PublicImmutableData);
                    response.Headers.Add("Content-Type", fetchedData.MediaType);

                    if (options != null)
                    {
                        response.Headers.Add("Content-Range", $"bytes 0-{response.Data.Length - 1}/{response.Data.Length}");
                        response.Headers.Add("Content-Length", $"{response.Data.Length}");
                    }

                    return(response);
                }
                else if (data is SafeDataFetchFailed fetchFailed)
                {
                    throw new WebFetchException(
                              WebFetchConstants.NoSuchData,
                              WebFetchConstants.NoSuchDataMessage);
                }

                throw new WebFetchException(
                          WebFetchConstants.NoSuchPublicName,
                          WebFetchConstants.NoSuchPublicNameMessage);
            }
            catch (WebFetchException ex)
            {
                Logger.Error(ex);
                throw;
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw;
            }
        }