blob: 6999cca3f22b96639bfe4fffb59fb92c4eae87d4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* Kind, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
using PortCMIS.Enums;
using System;
using System.Globalization;
using System.Numerics;
using System.Text;
namespace PortCMIS.Binding
{
/// <summary>
/// This class assembles URLs.
/// </summary>
public class UrlBuilder
{
private UriBuilder uri;
/// <value>
/// The current URL.
/// </value>
public Uri Url
{
get { return uri.Uri; }
}
/// <summary>
/// Creates a new instance with a given URL.
/// </summary>
/// <param name="url">the URL</param>
public UrlBuilder(string url)
{
if (url == null)
{
throw new ArgumentNullException("url");
}
uri = new UriBuilder(url);
}
/// <summary>
/// Adds a parameter.
/// </summary>
/// <param name="name">the parameter name</param>
/// <param name="value">the parameter value</param>
/// <returns>this UrlBuilder object</returns>
public UrlBuilder AddParameter(string name, object value)
{
if (name == null || value == null)
{
return this;
}
string valueStr = Uri.EscapeDataString(UrlBuilder.NormalizeParameter(value));
if (uri.Query != null && uri.Query.Length > 1)
{
uri.Query = uri.Query.Substring(1) + "&" + name + "=" + valueStr;
}
else
{
uri.Query = name + "=" + valueStr;
}
return this;
}
/// <summary>
/// Adds to the URL path.
/// </summary>
/// <param name="path">the path</param>
/// <returns>this UrlBuilder object</returns>
public UrlBuilder AddPath(string path)
{
return AddPathPart(path, false);
}
/// <summary>
/// Adds to the URL path.
/// </summary>
/// <param name="part">the path part</param>
/// <param name="quoteSlash">indicator whether slashes should be quoted or not</param>
/// <returns>this UrlBuilder object</returns>
protected UrlBuilder AddPathPart(string part, bool quoteSlash)
{
if (String.IsNullOrEmpty(part))
{
return this;
}
if (uri.Path.Length == 0 || uri.Path[uri.Path.Length - 1] != '/')
{
uri.Path += "/";
}
if (part[0] == '/')
{
part = part.Substring(1);
}
uri.Path += QuoteURIPathComponent(part, quoteSlash);
return this;
}
private static readonly char[] RFC7232Reserved = ";?:@&=+$,[]".ToCharArray();
private string QuoteURIPathComponent(string s, bool quoteSlash)
{
if (String.IsNullOrEmpty(s))
{
return s;
}
StringBuilder result = new StringBuilder(s);
foreach (char c in RFC7232Reserved)
{
result.Replace(c.ToString(), "%" + Convert.ToByte(c).ToString("X"));
}
if (quoteSlash)
{
result.Replace("/", "%2F");
}
return result.ToString();
}
/// <summary>
/// Normalizes a parameter value.
/// </summary>
/// <param name="value">the value</param>
/// <returns>the normalized value as string</returns>
public static string NormalizeParameter(object value)
{
if (value == null)
{
return null;
}
else if (value is Enum)
{
return ((Enum)value).GetCmisValue();
}
else if (value is bool)
{
return (bool)value ? "true" : "false";
}
else if (value is BigInteger)
{
return ((BigInteger)value).ToString("#", CultureInfo.InvariantCulture);
}
return value.ToString();
}
/// <summary>
/// Returns the current URL.
/// </summary>
/// <returns>the current URL</returns>
public override string ToString()
{
return Url.ToString();
}
}
internal class MimeHelper
{
public const string ContentDisposition = "Content-Disposition";
public const string DispositionAttachment = "attachment";
public const string DispositionFilename = "filename";
private const string MIMESpecials = "()<>@,;:\\\"/[]?=" + "\t ";
private const string RFC2231Specials = "*'%" + MIMESpecials;
private static char[] HexDigits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static string EncodeContentDisposition(string disposition, string filename)
{
if (disposition == null)
{
disposition = DispositionAttachment;
}
return disposition + EncodeRFC2231(DispositionFilename, filename);
}
protected static string EncodeRFC2231(string key, string value)
{
StringBuilder buf = new StringBuilder();
bool encoded = EncodeRFC2231value(value, buf);
if (encoded)
{
return "; " + key + "*=" + buf.ToString();
}
else
{
return "; " + key + "=" + value;
}
}
protected static bool EncodeRFC2231value(string value, StringBuilder buf)
{
buf.Append("UTF-8");
buf.Append("''"); // no language
byte[] bytes;
try
{
bytes = UTF8Encoding.UTF8.GetBytes(value);
}
catch (Exception)
{
return true;
}
bool encoded = false;
for (int i = 0; i < bytes.Length; i++)
{
int ch = bytes[i] & 0xff;
if (ch <= 32 || ch >= 127 || RFC2231Specials.IndexOf((char)ch) != -1)
{
buf.Append('%');
buf.Append(HexDigits[ch >> 4]);
buf.Append(HexDigits[ch & 0xf]);
encoded = true;
}
else
{
buf.Append((char)ch);
}
}
return encoded;
}
}
}