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; } }
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 < byte >, 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; } }
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; } }
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; } }