public async Task <EmoteFetchResult> FetchEmoteAsync(string url) { // Get headers var request = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)); // Workaround if server doesn't support HEAD requests if (request.StatusCode == HttpStatusCode.MethodNotAllowed) { request = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); } // Check media type string mediaType; if (request.Content.Headers.ContentType != null) { mediaType = request.Content.Headers.ContentType.MediaType; if (!Global.ValidMediaTypes.Contains(mediaType)) { return(new EmoteFetchResult.Failed("The provided file format is not supported.")); } } else { return(new EmoteFetchResult.Failed("The server responded with invalid headers.")); } // Check file size int maxSize = Global.MaxFileSize; if (request.Content.Headers.ContentLength.HasValue) { var val = request.Content.Headers.ContentLength.Value; if (val <= Global.MaxFileSize) { // val will always be an int here maxSize = (int)val; } else { return(new EmoteFetchResult.Failed("Content length exceeds the 16MiB limit.")); } } // Fetch file const int bufferSize = 4096; var ms = new MemoryStream(); await using (var stream = await _httpClient.GetStreamAsync(url)) { byte[] buffer = new byte[bufferSize]; int count; int size = 0; while ((count = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0) { size += count; if (size > maxSize) { return(new EmoteFetchResult.Failed("File size exceeds the 16MiB limit.")); } await ms.WriteAsync(buffer, 0, count); } } var fileType = _fileTypeGuesser.GuessFileType(ms); if (fileType.MediaType != mediaType) { return(new EmoteFetchResult.Failed("The server provided incorrect headers.")); } if (mediaType == "application/zip") { var extractedFiles = new List <EmoteFile>(); using (var archive = new ZipArchive(ms)) { var fileCount = 0; foreach (var entry in archive.Entries) { // 50 is max that can be added at a time due to discord ratelimits. if (fileCount == 50) { break; } var ext = Global.ValidExtensions.FirstOrDefault(x => entry.Name.EndsWith($".{x}")); if (ext == null) { continue; } var extractedFile = new MemoryStream(); await using (var extracted = entry.Open()) { byte[] buffer = new byte[bufferSize]; int count; int size = 0; while ((count = await extracted.ReadAsync(buffer, 0, buffer.Length)) != 0) { size += count; if (size > Global.MaxFileSize) { _logger.LogDebug($"Skipping {entry.Name}: File too large."); continue; } await extractedFile.WriteAsync(buffer, 0, count); } } var extractedFileType = _fileTypeGuesser.GuessFileType(extractedFile); if (extractedFileType.Extension != "zip" && extractedFileType.Extension != "unknown") { var isGif = extractedFileType.Extension == "gif"; extractedFiles.Add( new EmoteFile(await ResizeToEmoteAsync(extractedFile, isGif), extractedFileType.MediaType, Utils.FormatEmoteName(entry.Name))); fileCount++; } else { _logger.LogDebug($"Skipping {entry.Name}: Not a valid or supported image."); } } } return(new EmoteFetchResult.Multiple(extractedFiles.ToArray())); } var file = new EmoteFile(await ResizeToEmoteAsync(ms, fileType.Extension == "gif"), mediaType); return(new EmoteFetchResult.Single(file)); }
public Single(EmoteFile file) { File = file; }