|
//------------------------------------------------------------------------------
// <copyright file="RequestResponse.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Services.Protocols
{
using System.IO;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using System.Threading;
using System.Text;
using System.Runtime.InteropServices;
using System.Net;
using System.Globalization;
using System.Diagnostics;
using System.Web.Services.Diagnostics;
internal class RequestResponseUtils
{
private RequestResponseUtils() { }
/*
internal static string UTF8StreamToString(Stream stream) {
long position = 0;
if (stream.CanSeek)
position = stream.Position;
StreamReader reader = new StreamReader(stream, new System.Text.UTF8Encoding());
string result = reader.ReadToEnd();
if (stream.CanSeek)
stream.Position = position;
return result;
}
*/
//
internal static Encoding GetEncoding(string contentType)
{
string charset = ContentType.GetCharset(contentType);
Encoding e = null;
try
{
if (charset != null && charset.Length > 0)
e = Encoding.GetEncoding(charset);
}
catch (Exception ex)
{
if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
{
throw;
}
if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, typeof(RequestResponseUtils), "GetEncoding", ex);
}
// default to ASCII encoding per RFC 2376/3023
return e == null ? new ASCIIEncoding() : e;
}
internal static Encoding GetEncoding2(string contentType)
{
// default to old text/* behavior for non-application base
if (!ContentType.IsApplication(contentType))
return GetEncoding(contentType);
string charset = ContentType.GetCharset(contentType);
Encoding e = null;
try
{
if (charset != null && charset.Length > 0)
e = Encoding.GetEncoding(charset);
}
catch (Exception ex)
{
if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
{
throw;
}
if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, typeof(RequestResponseUtils), "GetEncoding2", ex);
}
// no default per application/* mime type
return e;
}
internal static string ReadResponse(WebResponse response)
{
return ReadResponse(response, response.GetResponseStream());
}
internal static string ReadResponse(WebResponse response, Stream stream)
{
Encoding e = GetEncoding(response.ContentType);
if (e == null) e = Encoding.Default;
StreamReader reader = new StreamReader(stream, e, true);
try
{
return reader.ReadToEnd();
}
finally
{
stream.Close();
}
}
// used to copy an unbuffered stream to a buffered stream.
internal static Stream StreamToMemoryStream(Stream stream)
{
MemoryStream memoryStream = new MemoryStream(1024);
byte[] buffer = new byte[1024];
int count;
while ((count = stream.Read(buffer, 0, buffer.Length)) != 0)
{
memoryStream.Write(buffer, 0, count);
}
memoryStream.Position = 0;
return memoryStream;
}
internal static string CreateResponseExceptionString(WebResponse response)
{
return CreateResponseExceptionString(response, response.GetResponseStream());
}
internal static string CreateResponseExceptionString(WebResponse response, Stream stream)
{
if (response is HttpWebResponse)
{
HttpWebResponse httpResponse = (HttpWebResponse)response;
int statusCode = (int)httpResponse.StatusCode;
if (statusCode >= 400 && statusCode != 500)
return Res.GetString(Res.WebResponseKnownError, statusCode, httpResponse.StatusDescription);
}
//
string content = (stream != null) ? ReadResponse(response, stream) : string.Empty;
if (content.Length > 0)
{
content = HttpUtility.HtmlDecode(content);
StringBuilder sb = new StringBuilder();
sb.Append(Res.GetString(Res.WebResponseUnknownError));
sb.Append(Environment.NewLine);
sb.Append("--");
sb.Append(Environment.NewLine);
sb.Append(content);
sb.Append(Environment.NewLine);
sb.Append("--");
sb.Append(".");
return sb.ToString();
}
else
return Res.GetString(Res.WebResponseUnknownErrorEmptyBody);
}
internal static int GetBufferSize(int contentLength)
{
int bufferSize;
if (contentLength == -1)
bufferSize = 8000;
else if (contentLength <= 16000)
bufferSize = contentLength;
else
bufferSize = 16000;
return bufferSize;
}
static class HttpUtility
{
internal static string HtmlDecode(string s)
{
if (s == null)
return null;
// See if this string needs to be decoded at all. If no
// ampersands are found, then no special HTML-encoded chars
// are in the string.
if (s.IndexOf('&') < 0)
return s;
StringBuilder builder = new StringBuilder();
StringWriter writer = new StringWriter(builder, CultureInfo.InvariantCulture);
HtmlDecode(s, writer);
return builder.ToString();
}
private static char[] s_entityEndingChars = new char[] { ';', '&' };
public static void HtmlDecode(string s, TextWriter output)
{
if (s == null)
return;
if (s.IndexOf('&') < 0)
{
output.Write(s); // good as is
return;
}
int l = s.Length;
for (int i = 0; i < l; i++)
{
char ch = s[i];
if (ch == '&')
{
// We found a '&'. Now look for the next ';' or '&'. The idea is that
// if we find another '&' before finding a ';', then this is not an entity,
// and the next '&' might start a real entity (VSWhidbey 275184)
int index = s.IndexOfAny(s_entityEndingChars, i + 1);
if (index > 0 && s[index] == ';')
{
string entity = s.Substring(i + 1, index - i - 1);
if (entity.Length > 1 && entity[0] == '#')
{
try
{
// The # syntax can be in decimal or hex, e.g.
// å --> decimal
// å --> same char in hex
// See http://www.w3.org/TR/REC-html40/charset.html#entities
if (entity[1] == 'x' || entity[1] == 'X')
ch = (char)Int32.Parse(entity.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
else
ch = (char)Int32.Parse(entity.Substring(1), CultureInfo.InvariantCulture);
i = index; // already looked at everything until semicolon
}
catch (System.FormatException e)
{
i++; //if the number isn't valid, ignore it
if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, typeof(HttpUtility), "HtmlDecode", e);
}
catch (System.ArgumentException e)
{
i++; // if there is no number, ignore it.
if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, typeof(HttpUtility), "HtmlDecode", e);
}
}
else
{
i = index; // already looked at everything until semicolon
char entityChar = HtmlEntities.Lookup(entity);
if (entityChar != (char)0)
{
ch = entityChar;
}
else
{
output.Write('&');
output.Write(entity);
output.Write(';');
continue;
}
}
}
}
output.Write(ch);
}
}
// helper class for lookup of HTML encoding entities
static class HtmlEntities
{
private static object _lookupLockObject = new object();
// The list is from http://www.w3.org/TR/REC-html40/sgml/entities.html
private static String[] _entitiesList = new String[] {
"\x0022-quot",
"\x0026-amp",
"\x003c-lt",
"\x003e-gt",
"\x00a0-nbsp",
"\x00a1-iexcl",
"\x00a2-cent",
"\x00a3-pound",
"\x00a4-curren",
"\x00a5-yen",
"\x00a6-brvbar",
"\x00a7-sect",
"\x00a8-uml",
"\x00a9-copy",
"\x00aa-ordf",
"\x00ab-laquo",
"\x00ac-not",
"\x00ad-shy",
"\x00ae-reg",
"\x00af-macr",
"\x00b0-deg",
"\x00b1-plusmn",
"\x00b2-sup2",
"\x00b3-sup3",
"\x00b4-acute",
"\x00b5-micro",
"\x00b6-para",
"\x00b7-middot",
"\x00b8-cedil",
"\x00b9-sup1",
"\x00ba-ordm",
"\x00bb-raquo",
"\x00bc-frac14",
"\x00bd-frac12",
"\x00be-frac34",
"\x00bf-iquest",
"\x00c0-Agrave",
"\x00c1-Aacute",
"\x00c2-Acirc",
"\x00c3-Atilde",
"\x00c4-Auml",
"\x00c5-Aring",
"\x00c6-AElig",
"\x00c7-Ccedil",
"\x00c8-Egrave",
"\x00c9-Eacute",
"\x00ca-Ecirc",
"\x00cb-Euml",
"\x00cc-Igrave",
"\x00cd-Iacute",
"\x00ce-Icirc",
"\x00cf-Iuml",
"\x00d0-ETH",
"\x00d1-Ntilde",
"\x00d2-Ograve",
"\x00d3-Oacute",
"\x00d4-Ocirc",
"\x00d5-Otilde",
"\x00d6-Ouml",
"\x00d7-times",
"\x00d8-Oslash",
"\x00d9-Ugrave",
"\x00da-Uacute",
"\x00db-Ucirc",
"\x00dc-Uuml",
"\x00dd-Yacute",
"\x00de-THORN",
"\x00df-szlig",
"\x00e0-agrave",
"\x00e1-aacute",
"\x00e2-acirc",
"\x00e3-atilde",
"\x00e4-auml",
"\x00e5-aring",
"\x00e6-aelig",
"\x00e7-ccedil",
"\x00e8-egrave",
"\x00e9-eacute",
"\x00ea-ecirc",
"\x00eb-euml",
"\x00ec-igrave",
"\x00ed-iacute",
"\x00ee-icirc",
"\x00ef-iuml",
"\x00f0-eth",
"\x00f1-ntilde",
"\x00f2-ograve",
"\x00f3-oacute",
"\x00f4-ocirc",
"\x00f5-otilde",
"\x00f6-ouml",
"\x00f7-divide",
"\x00f8-oslash",
"\x00f9-ugrave",
"\x00fa-uacute",
"\x00fb-ucirc",
"\x00fc-uuml",
"\x00fd-yacute",
"\x00fe-thorn",
"\x00ff-yuml",
"\x0152-OElig",
"\x0153-oelig",
"\x0160-Scaron",
"\x0161-scaron",
"\x0178-Yuml",
"\x0192-fnof",
"\x02c6-circ",
"\x02dc-tilde",
"\x0391-Alpha",
"\x0392-Beta",
"\x0393-Gamma",
"\x0394-Delta",
"\x0395-Epsilon",
"\x0396-Zeta",
"\x0397-Eta",
"\x0398-Theta",
"\x0399-Iota",
"\x039a-Kappa",
"\x039b-Lambda",
"\x039c-Mu",
"\x039d-Nu",
"\x039e-Xi",
"\x039f-Omicron",
"\x03a0-Pi",
"\x03a1-Rho",
"\x03a3-Sigma",
"\x03a4-Tau",
"\x03a5-Upsilon",
"\x03a6-Phi",
"\x03a7-Chi",
"\x03a8-Psi",
"\x03a9-Omega",
"\x03b1-alpha",
"\x03b2-beta",
"\x03b3-gamma",
"\x03b4-delta",
"\x03b5-epsilon",
"\x03b6-zeta",
"\x03b7-eta",
"\x03b8-theta",
"\x03b9-iota",
"\x03ba-kappa",
"\x03bb-lambda",
"\x03bc-mu",
"\x03bd-nu",
"\x03be-xi",
"\x03bf-omicron",
"\x03c0-pi",
"\x03c1-rho",
"\x03c2-sigmaf",
"\x03c3-sigma",
"\x03c4-tau",
"\x03c5-upsilon",
"\x03c6-phi",
"\x03c7-chi",
"\x03c8-psi",
"\x03c9-omega",
"\x03d1-thetasym",
"\x03d2-upsih",
"\x03d6-piv",
"\x2002-ensp",
"\x2003-emsp",
"\x2009-thinsp",
"\x200c-zwnj",
"\x200d-zwj",
"\x200e-lrm",
"\x200f-rlm",
"\x2013-ndash",
"\x2014-mdash",
"\x2018-lsquo",
"\x2019-rsquo",
"\x201a-sbquo",
"\x201c-ldquo",
"\x201d-rdquo",
"\x201e-bdquo",
"\x2020-dagger",
"\x2021-Dagger",
"\x2022-bull",
"\x2026-hellip",
"\x2030-permil",
"\x2032-prime",
"\x2033-Prime",
"\x2039-lsaquo",
"\x203a-rsaquo",
"\x203e-oline",
"\x2044-frasl",
"\x20ac-euro",
"\x2111-image",
"\x2118-weierp",
"\x211c-real",
"\x2122-trade",
"\x2135-alefsym",
"\x2190-larr",
"\x2191-uarr",
"\x2192-rarr",
"\x2193-darr",
"\x2194-harr",
"\x21b5-crarr",
"\x21d0-lArr",
"\x21d1-uArr",
"\x21d2-rArr",
"\x21d3-dArr",
"\x21d4-hArr",
"\x2200-forall",
"\x2202-part",
"\x2203-exist",
"\x2205-empty",
"\x2207-nabla",
"\x2208-isin",
"\x2209-notin",
"\x220b-ni",
"\x220f-prod",
"\x2211-sum",
"\x2212-minus",
"\x2217-lowast",
"\x221a-radic",
"\x221d-prop",
"\x221e-infin",
"\x2220-ang",
"\x2227-and",
"\x2228-or",
"\x2229-cap",
"\x222a-cup",
"\x222b-int",
"\x2234-there4",
"\x223c-sim",
"\x2245-cong",
"\x2248-asymp",
"\x2260-ne",
"\x2261-equiv",
"\x2264-le",
"\x2265-ge",
"\x2282-sub",
"\x2283-sup",
"\x2284-nsub",
"\x2286-sube",
"\x2287-supe",
"\x2295-oplus",
"\x2297-otimes",
"\x22a5-perp",
"\x22c5-sdot",
"\x2308-lceil",
"\x2309-rceil",
"\x230a-lfloor",
"\x230b-rfloor",
"\x2329-lang",
"\x232a-rang",
"\x25ca-loz",
"\x2660-spades",
"\x2663-clubs",
"\x2665-hearts",
"\x2666-diams",
};
// Double-checked locking pattern requires volatile for read/write synchronization
private static volatile Hashtable _entitiesLookupTable;
internal /*public*/ static char Lookup(String entity)
{
if (_entitiesLookupTable == null)
{
// populate hashtable on demand
lock (_lookupLockObject)
{
if (_entitiesLookupTable == null)
{
Hashtable t = new Hashtable();
foreach (String s in _entitiesList)
t[s.Substring(2)] = s[0]; // 1st char is the code, 2nd '-'
_entitiesLookupTable = t;
}
}
}
Object obj = _entitiesLookupTable[entity];
if (obj != null)
return (char)obj;
else
return (char)0;
}
}
}
}
}
|