aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2019-08-19 00:21:38 +0800
committer杨宇千 <crupest@outlook.com>2019-08-19 00:21:38 +0800
commit4bbaaf45c64da897c4832aceeeec2549cfbd901a (patch)
tree70ef2814622b2b3e3578b4fe1d3afbf26cacb768
parentee113b27d276524f29560f00e944851bf5bdf6a8 (diff)
downloadtimeline-4bbaaf45c64da897c4832aceeeec2549cfbd901a.tar.gz
timeline-4bbaaf45c64da897c4832aceeeec2549cfbd901a.tar.bz2
timeline-4bbaaf45c64da897c4832aceeeec2549cfbd901a.zip
Improve avatar validation.
-rw-r--r--Timeline/Controllers/UserAvatarController.cs36
-rw-r--r--Timeline/Services/UserAvatarService.cs41
2 files changed, 60 insertions, 17 deletions
diff --git a/Timeline/Controllers/UserAvatarController.cs b/Timeline/Controllers/UserAvatarController.cs
index 6dc767df..710ca764 100644
--- a/Timeline/Controllers/UserAvatarController.cs
+++ b/Timeline/Controllers/UserAvatarController.cs
@@ -19,9 +19,28 @@ namespace Timeline.Controllers
public const int Put_UserNotExist = -2001;
public const int Put_Forbid = -2002;
+ public const int Put_BadFormat_CantDecode = -2011;
+ public const int Put_BadFormat_UnmatchedFormat = -2012;
+ public const int Put_BadFormat_BadSize = -2013;
public const int Delete_UserNotExist = -3001;
public const int Delete_Forbid = -3002;
+
+
+ public static int From(AvatarDataException.ErrorReason error)
+ {
+ switch (error)
+ {
+ case AvatarDataException.ErrorReason.CantDecode:
+ return Put_BadFormat_CantDecode;
+ case AvatarDataException.ErrorReason.UnmatchedFormat:
+ return Put_BadFormat_UnmatchedFormat;
+ case AvatarDataException.ErrorReason.BadSize:
+ return Put_BadFormat_BadSize;
+ default:
+ throw new Exception("Unknown AvatarDataException.ErrorReason value.");
+ }
+ }
}
private readonly ILogger<UserAvatarController> _logger;
@@ -43,9 +62,9 @@ namespace Timeline.Controllers
var avatar = await _service.GetAvatar(username);
return File(avatar.Data, avatar.Type);
}
- catch (UserNotExistException)
+ catch (UserNotExistException e)
{
- _logger.LogInformation($"Attempt to get a avatar of a non-existent user failed. Username: {username} .");
+ _logger.LogInformation(e, $"Attempt to get a avatar of a non-existent user failed. Username: {username} .");
return NotFound(new CommonResponse(ErrorCodes.Get_UserNotExist, "User does not exist."));
}
}
@@ -76,11 +95,16 @@ namespace Timeline.Controllers
_logger.LogInformation($"Succeed to put a avatar of a user. Username: {username} ; Mime Type: {Request.ContentType} .");
return Ok();
}
- catch (UserNotExistException)
+ catch (UserNotExistException e)
{
- _logger.LogInformation($"Attempt to put a avatar of a non-existent user failed. Username: {username} .");
+ _logger.LogInformation(e, $"Attempt to put a avatar of a non-existent user failed. Username: {username} .");
return BadRequest(new CommonResponse(ErrorCodes.Put_UserNotExist, "User does not exist."));
}
+ catch (AvatarDataException e)
+ {
+ _logger.LogInformation(e, $"Attempt to put a avatar of a bad format failed. Username: {username} .");
+ return BadRequest(new CommonResponse(ErrorCodes.From(e.Error), "Bad format."));
+ }
}
[HttpDelete("users/{username}/avatar")]
@@ -101,9 +125,9 @@ namespace Timeline.Controllers
_logger.LogInformation($"Succeed to delete a avatar of a user. Username: {username} .");
return Ok();
}
- catch (UserNotExistException)
+ catch (UserNotExistException e)
{
- _logger.LogInformation($"Attempt to delete a avatar of a non-existent user failed. Username: {username} .");
+ _logger.LogInformation(e, $"Attempt to delete a avatar of a non-existent user failed. Username: {username} .");
return BadRequest(new CommonResponse(ErrorCodes.Delete_UserNotExist, "User does not exist."));
}
}
diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs
index 2a73cde5..dd0e5e7c 100644
--- a/Timeline/Services/UserAvatarService.cs
+++ b/Timeline/Services/UserAvatarService.cs
@@ -24,12 +24,29 @@ namespace Timeline.Services
[Serializable]
public class AvatarDataException : Exception
{
- public AvatarDataException(Avatar avatar, string message) : base(message) { Avatar = avatar; }
- public AvatarDataException(Avatar avatar, string message, Exception inner) : base(message, inner) { Avatar = avatar; }
+ public enum ErrorReason
+ {
+ /// <summary>
+ /// Decoding image failed.
+ /// </summary>
+ CantDecode,
+ /// <summary>
+ /// Decoding succeeded but the real type is not the specified type.
+ /// </summary>
+ UnmatchedFormat,
+ /// <summary>
+ /// Image is not a square.
+ /// </summary>
+ BadSize
+ }
+
+ public AvatarDataException(Avatar avatar, ErrorReason error, string message) : base(message) { Avatar = avatar; Error = error; }
+ public AvatarDataException(Avatar avatar, ErrorReason error, string message, Exception inner) : base(message, inner) { Avatar = avatar; Error = error; }
protected AvatarDataException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+ public ErrorReason Error { get; set; }
public Avatar Avatar { get; set; }
}
@@ -49,7 +66,12 @@ namespace Timeline.Services
public interface IUserAvatarValidator
{
- Task<(bool valid, string message)> Validate(Avatar avatar);
+ /// <summary>
+ /// Validate a avatar's format and size info.
+ /// </summary>
+ /// <param name="avatar">The avatar to validate.</param>
+ /// <exception cref="AvatarDataException">Thrown when validation failed.</exception>
+ Task Validate(Avatar avatar);
}
public interface IUserAvatarService
@@ -96,7 +118,7 @@ namespace Timeline.Services
public class UserAvatarValidator : IUserAvatarValidator
{
- public Task<(bool valid, string message)> Validate(Avatar avatar)
+ public Task Validate(Avatar avatar)
{
return Task.Run(() =>
{
@@ -105,15 +127,14 @@ namespace Timeline.Services
using (var image = Image.Load(avatar.Data, out IImageFormat format))
{
if (!format.MimeTypes.Contains(avatar.Type))
- return (false, "Image's actual mime type is not the specified one.");
+ throw new AvatarDataException(avatar, AvatarDataException.ErrorReason.UnmatchedFormat, "Image's actual mime type is not the specified one.");
if (image.Width != image.Height)
- return (false, "Image is not a square, aka width is not equal to height.");
+ throw new AvatarDataException(avatar, AvatarDataException.ErrorReason.BadSize, "Image is not a square, aka, width is not equal to height.");
}
- return (true, "A good avatar.");
}
catch (UnknownImageFormatException e)
{
- return (false, $"Failed to decode image. Exception: {e} .");
+ throw new AvatarDataException(avatar, AvatarDataException.ErrorReason.CantDecode, "Failed to decode image. See inner exception.", e);
}
});
}
@@ -196,9 +217,7 @@ namespace Timeline.Services
}
else
{
- (bool valid, string message) = await _avatarValidator.Validate(avatar);
- if (!valid)
- throw new AvatarDataException(avatar, $"Failed to validate image. {message}");
+ await _avatarValidator.Validate(avatar);
if (avatarEntity == null)
{