|
//------------------------------------------------------------------------------
// <copyright file="WmlPageAdapter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Web.Mobile;
using System.Web.UI.MobileControls;
using System.Web.UI.MobileControls.Adapters;
using System.Security.Permissions;
#if COMPILING_FOR_SHIPPED_SOURCE
namespace System.Web.UI.MobileControls.ShippedAdapterSource
#else
namespace System.Web.UI.MobileControls.Adapters
#endif
{
/*
* WmlPageAdapter base class contains wml specific methods.
*
* Copyright (c) 2000 Microsoft Corporation
*/
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter"]/*' />
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
[Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
public class WmlPageAdapter : WmlControlAdapter, IPageAdapter
{
private IList _renderableForms;
private static readonly String _headerBegin = "<?xml version='1.0'";
private static readonly String _headerEncoding = " encoding ='{0}'";
private static readonly String _headerEnd
= "?>\r\n"
+ "<!DOCTYPE wml PUBLIC '-//WAPFORUM//DTD WML 1.1//EN' 'http://www.wapforum.org/DTD/wml_1.1.xml'>";
private static readonly String _cacheExpiry
= "<head>\r\n"
+ "<meta http-equiv=\"Cache-Control\" content=\"max-age=0\" />\r\n"
+ "</head>\r\n";
private static readonly String _contentType = "text/vnd.wap.wml";
private IDictionary _cookielessDataDictionary = null;
///////////////////////////////////////////////////////////////////////////
// Static method used for determining if device should use
// this adapter
///////////////////////////////////////////////////////////////////////////
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.DeviceQualifies"]/*' />
public static bool DeviceQualifies(HttpContext context)
{
MobileCapabilities capabilities = ((MobileCapabilities)context.Request.Browser);
String type = capabilities.PreferredRenderingType;
bool qualifies = (type == MobileCapabilities.PreferredRenderingTypeWml11) ||
(type == MobileCapabilities.PreferredRenderingTypeWml12);
return qualifies;
}
///////////////////////////////////////////////////////////////////////////
// IPageAdapter implementation
///////////////////////////////////////////////////////////////////////////
private MobilePage _page;
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.Page"]/*' />
public override MobilePage Page
{
get
{
return _page;
}
set
{
_page = value;
}
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.CookielessDataDictionary"]/*' />
public IDictionary CookielessDataDictionary
{
get
{
return _cookielessDataDictionary;
}
set
{
_cookielessDataDictionary = value;
}
}
private bool _persistCookielessData = false;
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.PersistCookielessData"]/*' />
public bool PersistCookielessData
{
get
{
return _persistCookielessData;
}
set
{
_persistCookielessData = value;
}
}
private int _optimumPageWeight = 0;
private const int DefaultPageWeight = 800;
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.OptimumPageWeight"]/*' />
public virtual int OptimumPageWeight
{
get
{
if (_optimumPageWeight == 0)
{
_optimumPageWeight = CalculateOptimumPageWeight(DefaultPageWeight);
}
return _optimumPageWeight;
}
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.CreateTextWriter"]/*' />
public virtual HtmlTextWriter CreateTextWriter(TextWriter writer)
{
return new WmlMobileTextWriter(writer, Device, Page);
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.DeterminePostBackMode"]/*' />
public virtual NameValueCollection DeterminePostBackMode(
HttpRequest request,
String postEventSourceID,
String postEventArgumentID,
NameValueCollection baseCollection)
{
NameValueCollection collection = baseCollection;
if (collection != null)
{
if (Device.RequiresSpecialViewStateEncoding)
{
// Reverse the special character replacement done when
// writing out the viewstate value.
String speciallyEncodedState =
baseCollection[MobilePage.ViewStateID];
if (speciallyEncodedState != null)
{
speciallyEncodedState = EncodeSpecialViewState(speciallyEncodedState);
// We need to regenerate the collection since the
// original baseCollection is readonly.
collection = new NameValueCollection();
bool viewStateAdded = false;
for (int i = 0; i < baseCollection.Count; i++)
{
String name = baseCollection.GetKey(i);
if (!viewStateAdded && name == MobilePage.ViewStateID)
{
// This is the viewstate value we want to change.
collection.Add(MobilePage.ViewStateID, speciallyEncodedState);
viewStateAdded = true;
}
else
{
collection.Add(name, baseCollection.Get(i));
}
}
}
}
}
return collection;
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.CacheVaryByHeaders"]/*' />
public virtual IList CacheVaryByHeaders
{
get
{
return null;
}
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.HandleError"]/*' />
public virtual bool HandleError(Exception e, HtmlTextWriter writer)
{
WmlMobileTextWriter wmlWriter = (WmlMobileTextWriter)writer;
bool renderBackButton = Device.NumberOfSoftkeys > 2 && !Device.HasBackButton;
// set mime type, in case init() has not been called yet
Page.Response.ContentType = _contentType;
Exception ex;
if ((e is HttpException && e.InnerException != null) ||
(e is System.Reflection.TargetInvocationException && e.InnerException != null))
{
ex = e.InnerException;
}
else
{
ex = e;
}
if (RequiresUTF8ContentEncoding())
{
Page.Response.ContentEncoding = UTF8Encoding;
}
wmlWriter.BeginResponse();
wmlWriter.BeginFile(Page.Request.Url.ToString(), _contentType, Page.Response.Charset);
RenderXmlHeader(writer);
// First card.
writer.WriteFullBeginTag("wml");
if (Device.SupportsCacheControlMetaTag)
{
writer.Write(_cacheExpiry);
}
else
{
Page.Response.AppendHeader("Cache-Control", "max-age=0");
}
writer.WriteFullBeginTag("card");
writer.WriteFullBeginTag("p");
writer.WriteFullBeginTag("big");
writer.WriteFullBeginTag("b");
wmlWriter.WriteEncodedText(SR.GetString(SR.WmlPageAdapterServerError,
HttpRuntime.AppDomainAppVirtualPath));
writer.WriteEndTag("b");
writer.WriteEndTag("big");
writer.WriteEndTag("p");
writer.WriteFullBeginTag("p");
writer.Write("<do type=\"accept\" label=\"");
writer.Write(GetDefaultLabel(MoreLabel));
writer.Write("\"><go href=\"#more\" /></do>");
if (renderBackButton)
{
writer.Write("<do type=\"prev\" label=\"");
writer.Write(GetDefaultLabel(BackLabel));
writer.WriteLine("\"><prev /></do>");
}
wmlWriter.WriteEncodedText(ex.GetType().ToString());
writer.Write("<br />");
wmlWriter.WriteEncodedText(ex.Message);
writer.Write("<br />");
wmlWriter.WriteEncodedText(SR.GetString(SR.WmlPageAdapterMethod));
if (ex.TargetSite != null) {
wmlWriter.WriteEncodedText(ex.TargetSite.Name);
}
writer.Write("<br />");
writer.WriteEndTag("p");
writer.WriteEndTag("card");
// Stack trace card.
writer.Write("<card id=\"more\">");
writer.Write("<p mode=\"nowrap\">");
if (renderBackButton)
{
writer.Write("<do type=\"prev\" label=\"");
wmlWriter.WriteEncodedText(GetDefaultLabel(BackLabel));
writer.WriteLine("\"><prev /></do>");
}
String stackTrace = ex.StackTrace;
if (stackTrace != null) {
int maximumStackTrace = OptimumPageWeight / 2;
if (stackTrace.Length > maximumStackTrace)
{
wmlWriter.WriteEncodedText(SR.GetString(SR.WmlPageAdapterStackTrace));
writer.Write("<br />");
stackTrace = stackTrace.Substring(0, maximumStackTrace);
}
else
{
wmlWriter.WriteEncodedText(SR.GetString(SR.WmlPageAdapterPartialStackTrace));
writer.Write("<br />");
}
int lineBegin = 0;
int lineEnd;
while (lineBegin < stackTrace.Length)
{
lineEnd = stackTrace.IndexOf("\r\n", lineBegin, StringComparison.Ordinal);
if (lineEnd == -1)
{
lineEnd = stackTrace.Length;
}
wmlWriter.WriteEncodedText(stackTrace.Substring(lineBegin, lineEnd - lineBegin));
writer.Write("<br />");
lineBegin = lineEnd + 2;
}
}
writer.WriteEndTag("p");
writer.WriteEndTag("card");
writer.WriteEndTag("wml");
wmlWriter.EndFile();
wmlWriter.EndResponse();
return true;
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.HandlePagePostBackEvent"]/*' />
public virtual bool HandlePagePostBackEvent(String eventSource, String eventArgument)
{
return false;
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.Render"]/*' />
public override void Render(WmlMobileTextWriter writer)
{
if (RequiresUTF8ContentEncoding())
{
Page.Response.ContentEncoding = UTF8Encoding;
}
writer.BeginResponse();
writer.BeginFile(Page.Request.Url.ToString(), _contentType, Page.Response.Charset);
RenderXmlHeader(writer);
writer.WriteFullBeginTag("wml");
if (Device.SupportsCacheControlMetaTag)
{
writer.Write(_cacheExpiry);
}
else
{
Page.Response.AppendHeader("Cache-Control", "max-age=0");
}
if (Device.CanCombineFormsInDeck)
{
_renderableForms = Page.ActiveForm.GetLinkedForms(OptimumPageWeight);
Debug.Assert(_renderableForms != null, "_renderableForms is null");
}
else
{
_renderableForms = new ArrayList();
_renderableForms.Add(Page.ActiveForm);
}
foreach (Form form in _renderableForms)
{
RenderForm(writer, form);
}
writer.RenderExtraCards();
writer.WriteEndTag("wml");
writer.EndFile();
writer.EndResponse();
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.RenderForm"]/*' />
protected virtual void RenderForm(WmlMobileTextWriter writer, Form form)
{
writer.AnalyzeMode = true;
form.RenderControl(writer);
writer.AnalyzeMode = false;
form.RenderControl(writer);
}
// Should be called by controls/adapters after _renderableForms is
// set in this.Render()
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.IsFormRendered"]/*' />
public virtual bool IsFormRendered(Form form)
{
Debug.Assert(_renderableForms != null, "_renderableForms is null");
return _renderableForms.Contains(form);
}
private void RenderXmlHeader(HtmlTextWriter writer)
{
writer.Write(_headerBegin);
String charset = Page.Response.Charset;
if (charset != null && charset.Length > 0 &&
String.Compare(charset, "utf-8", StringComparison.OrdinalIgnoreCase) != 0)
{
writer.Write(String.Format(CultureInfo.InvariantCulture, _headerEncoding, charset));
}
writer.Write(_headerEnd);
}
/// <include file='doc\WmlPageAdapter.uex' path='docs/doc[@for="WmlPageAdapter.RendersMultipleForms"]/*' />
public virtual bool RendersMultipleForms()
{
return _renderableForms.Count > 1;
}
// '+' <-> '-'
// '=' <-> '.'
// '/' <-> '*'
private static readonly char[] _specialEncodingChars = new char[64]
{
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '/', '-', '\0', '+', '=', '*',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '.', '\0', '\0',
};
internal String EncodeSpecialViewState(String pageState)
{
char[] viewstate = pageState.ToCharArray();
for (int i = 0; i < viewstate.Length; i++)
{
char currentChar = viewstate[i];
// Only check character replacement if within the range
if (currentChar < _specialEncodingChars.Length)
{
char encodingChar = _specialEncodingChars[currentChar];
if (encodingChar != '\0')
{
viewstate[i] = encodingChar;
}
}
}
return new String(viewstate);
}
private static readonly Encoding UTF8Encoding = Encoding.GetEncoding("UTF-8");
private bool _requiresUTF8ContentEncoding = false;
private bool _haveRequiresUTF8ContentEncoding = false;
private bool RequiresUTF8ContentEncoding()
{
if (!_haveRequiresUTF8ContentEncoding)
{
String RequiresUTF8ContentEncodingString = Device["requiresUTF8ContentEncoding"];
if (RequiresUTF8ContentEncodingString == null)
{
if (IsKDDIPhone())
{
_requiresUTF8ContentEncoding = true;
}
}
else
{
_requiresUTF8ContentEncoding = Convert.ToBoolean(RequiresUTF8ContentEncodingString, CultureInfo.InvariantCulture);
}
_haveRequiresUTF8ContentEncoding = true;
}
return _requiresUTF8ContentEncoding;
}
private bool _requiresValueAttributeInInputTag = false;
private bool _haveRequiresValueAttributeInInputTag = false;
internal bool RequiresValueAttributeInInputTag()
{
if (!_haveRequiresValueAttributeInInputTag)
{
String RequiresValueAttributeInInputTagString = Device["requiresValueAttributeInInputTag"];
if (RequiresValueAttributeInInputTagString == null)
{
if (IsKDDIPhone())
{
_requiresValueAttributeInInputTag = true;
}
}
else
{
_requiresValueAttributeInInputTag = Convert.ToBoolean(RequiresValueAttributeInInputTagString, CultureInfo.InvariantCulture);
}
_haveRequiresValueAttributeInInputTag = true;
}
return _requiresValueAttributeInInputTag;
}
private bool _isKDDIPhone = false;
private bool _haveIsKDDIPhone = false;
internal bool IsKDDIPhone()
{
if (!_haveIsKDDIPhone)
{
if (Device.Browser == "Phone.com" &&
Device.MajorVersion == 3 &&
Device.MinorVersion < 0.3)
{
String charset = Page.Request.Headers["x-up-devcap-charset"];
if (charset != null &&
String.Compare(charset, "Shift_JIS", StringComparison.OrdinalIgnoreCase) == 0)
{
_isKDDIPhone = true;
}
}
_haveIsKDDIPhone = true;
}
return _isKDDIPhone;
}
}
}
|