sdk/Domain/PolicyConditions.cs (174 lines of code) (raw):
/*
* Copyright (C) Alibaba Cloud Computing
* All rights reserved.
*
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Aliyun.OSS
{
/// <summary>
/// The match mode enum
/// </summary>
public enum MatchMode
{
/// <summary>
/// Unknown
/// </summary>
Unknown,
/// <summary>
/// Exactly match
/// </summary>
Exact,
/// <summary>
/// Match the prefix only
/// </summary>
StartWith,
/// <summary>
/// Match the size range. For example, the policy could be applied the files of size between 1KB to 4KB.
/// </summary>
Range
};
/// <summary>
/// Tuplre type enum.!-- Currently only two tuple {key:value} and three tuple type (tuple1,tuple2,tuple3) are supported.
/// </summary>
internal enum TupleType
{
Unknown,
Two,
Three
};
/// <summary>
/// The abstract Condition Item.
/// </summary>
internal abstract class AbstractConditionItem
{
public string Name { get; set; }
public MatchMode MatchMode { get; set; }
public TupleType TupleType { get; set; }
protected AbstractConditionItem(string name, MatchMode matchMode, TupleType tupleType)
{
Name = name;
MatchMode = matchMode;
TupleType = tupleType;
}
public abstract string Jsonize();
}
/// <summary>
/// EqualConditionItem definition
/// </summary>
internal class EqualConditionItem : AbstractConditionItem
{
public string Value { get; set; }
public EqualConditionItem(string name, string value)
: this(name, value, TupleType.Two)
{ }
public EqualConditionItem(string name, string value, TupleType tupleType)
: base(name, MatchMode.Exact, tupleType)
{
Value = value;
}
public override string Jsonize()
{
string jsonizedCond = null;
switch (TupleType)
{
case TupleType.Two:
jsonizedCond = String.Format("{{\"{0}\":\"{1}\"}},", Util.HttpUtils.JsonEscapeString(Name), Util.HttpUtils.JsonEscapeString(Value));
break;
case TupleType.Three:
jsonizedCond = String.Format("[\"eq\",\"${0}\",\"{1}\"],", Util.HttpUtils.JsonEscapeString(Name), Util.HttpUtils.JsonEscapeString(Value));
break;
default:
throw new InvalidEnumArgumentException("Invalid tuple type " + TupleType.ToString());
}
return jsonizedCond;
}
}
/// <summary>
/// StartwithConditionItem definition.
/// </summary>
internal class StartWithConditionItem : AbstractConditionItem
{
public string Value { get; set; }
public StartWithConditionItem(string name, string value)
: base(name, MatchMode.StartWith, TupleType.Three)
{
Value = value;
}
public override string Jsonize()
{
return String.Format("[\"starts-with\",\"${0}\",\"{1}\"],", Util.HttpUtils.JsonEscapeString(Name), Util.HttpUtils.JsonEscapeString(Value));
}
}
/// <summary>
/// Content size's RangeConditionItem definition.
/// </summary>
internal class RangeConditionItem : AbstractConditionItem
{
public long Minimum { get; set; }
public long Maximum { get; set; }
public RangeConditionItem(string name, long min, long max)
: base(name, MatchMode.Range, TupleType.Three)
{
Minimum = min;
Maximum = max;
}
public override string Jsonize()
{
return String.Format("[\"content-length-range\",{0},{1}],", Minimum, Maximum);
}
}
/// <summary>
/// Conditions list. It specifies all valid fields in the post form.
/// </summary>
public class PolicyConditions
{
/// <summary>
/// Content length range
/// </summary>
public const string CondContentLengthRange = "content-length-range";
/// <summary>
/// The cache control behavior for downloading files
/// </summary>
public const string CondCacheControl = "Cache-Control";
/// <summary>
/// Content types defined in RFC2616
/// </summary>
public const string CondContentType = "Content-Type";
/// <summary>
/// Content disposition behavior
/// </summary>
public const string CondContentDisposition = "Content-Disposition";
/// <summary>
/// The content encoding
/// </summary>
public const string CondContentEncoding = "Content-Encoding";
/// <summary>
/// Expiration time
/// </summary>
public const string CondExpires = "Expires";
/// <summary>
/// object key
/// </summary>
public const string CondKey = "key";
/// <summary>
/// redirect upon success
/// </summary>
public const string CondSuccessActionRedirect = "success_action_redirect";
/// <summary>
/// The action status upon success
/// </summary>
public const string CondSuccessActionStatus = "success_action_status";
/// <summary>
/// The custom metadata prefix
/// </summary>
public const string CondXOssMetaPrefix = "x-oss-meta-";
private IList<AbstractConditionItem> _conds = new List<AbstractConditionItem>();
/// <summary>
/// Adds a condition item with exact MatchMode
/// </summary>
/// <param name="name">Condition name</param>
/// <param name="value">Condition value</param>
public void AddConditionItem(string name, string value)
{
MatchRuleChecker.Check(MatchMode.Exact, name);
_conds.Add(new EqualConditionItem(name, value));
}
/// <summary>
/// Adds a condition item with specified MatchMode
/// </summary>
/// <param name="matchMode">Conditions match mode</param>
/// <param name="name">Condition name</param>
/// <param name="value">Condition value</param>
public void AddConditionItem(MatchMode matchMode, string name, string value)
{
MatchRuleChecker.Check(matchMode, name);
switch (matchMode)
{
case MatchMode.Exact:
_conds.Add(new EqualConditionItem(name, value, TupleType.Three));
break;
case MatchMode.StartWith:
_conds.Add(new StartWithConditionItem(name, value));
break;
default:
throw new InvalidEnumArgumentException("Unsupported match mode " +
matchMode);
}
}
/// <summary>
/// Adds a condition with range match mode.
/// </summary>
/// <param name="name">Condition name</param>
/// <param name="min">Range's low end</param>
/// <param name="max">Range's high end</param>
public void AddConditionItem(string name, long min, long max)
{
if (min > max)
throw new ArgumentException(String.Format("Invalid range [{0}, {1}].", min, max));
_conds.Add(new RangeConditionItem(name, min, max));
}
internal string Jsonize()
{
var jsonizedConds = new StringBuilder();
jsonizedConds.Append("\"conditions\":[");
foreach (var cond in _conds)
jsonizedConds.Append(cond.Jsonize());
if (_conds.Count > 0)
jsonizedConds.Remove(jsonizedConds.Length - 1, 1);
jsonizedConds.Append("]");
return jsonizedConds.ToString();
}
}
internal static class MatchRuleChecker
{
private static IDictionary<string, IList<MatchMode>> _supportedMatchRules
= new Dictionary<string, IList<MatchMode>>();
static MatchRuleChecker()
{
var ordinaryMatchModes = new List<MatchMode> {MatchMode.Exact, MatchMode.StartWith};
var specialMatchModes = new List<MatchMode> {MatchMode.Range};
_supportedMatchRules.Add(PolicyConditions.CondContentLengthRange, specialMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondCacheControl, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondContentType, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondContentDisposition, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondContentEncoding, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondExpires, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondKey, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondSuccessActionRedirect, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondSuccessActionStatus, ordinaryMatchModes);
_supportedMatchRules.Add(PolicyConditions.CondXOssMetaPrefix, ordinaryMatchModes);
}
public static void Check(MatchMode matchMode, string condName)
{
if (_supportedMatchRules.ContainsKey(condName))
{
var mms = _supportedMatchRules[condName];
if (!mms.Contains(matchMode))
{
throw new ArgumentException(
String.Format("Unsupported match mode for condition item {0}", condName));
}
}
}
}
}