|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//==========================================================================
// File: SdlChannelSink.cs
//
// Summary: Sdl channel sink for generating sdl dynamically on the server.
//
//==========================================================================
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Messaging;
using System.Text;
#if !FEATURE_PAL
using System.Web;
using System.Security.Permissions;
#endif
namespace System.Runtime.Remoting.MetadataServices
{
public class SdlChannelSinkProvider : IServerChannelSinkProvider
{
private IServerChannelSinkProvider _next = null;
private bool _bRemoteApplicationMetadataEnabled = false;
private bool _bMetadataEnabled = true;
public SdlChannelSinkProvider()
{
}
public SdlChannelSinkProvider(IDictionary properties, ICollection providerData)
{
if (properties != null)
{
foreach (DictionaryEntry entry in properties)
{
switch ((String)entry.Key)
{
case "remoteApplicationMetadataEnabled": _bRemoteApplicationMetadataEnabled = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture); break;
case "metadataEnabled": _bMetadataEnabled = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture); break;
default:
CoreChannel.ReportUnknownProviderConfigProperty(
this.GetType().Name, (String)entry.Key);
break;
}
}
}
}
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
public void GetChannelData(IChannelDataStore localChannelData)
{
}
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
public IServerChannelSink CreateSink(IChannelReceiver channel)
{
IServerChannelSink nextSink = null;
if (_next != null)
nextSink = _next.CreateSink(channel);
SdlChannelSink channelSink = new SdlChannelSink(channel, nextSink);
channelSink.RemoteApplicationMetadataEnabled = _bRemoteApplicationMetadataEnabled;
channelSink.MetadataEnabled = _bMetadataEnabled;
return channelSink;
}
public IServerChannelSinkProvider Next
{
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
get { return _next; }
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
set { _next = value; }
}
} // class SdlChannelSinkProvider
public class SdlChannelSink : IServerChannelSink
{
private IChannelReceiver _receiver;
private IServerChannelSink _nextSink;
private bool _bRemoteApplicationMetadataEnabled = false;
private bool _bMetadataEnabled = false;
public SdlChannelSink(IChannelReceiver receiver, IServerChannelSink nextSink)
{
_receiver = receiver;
_nextSink = nextSink;
} // SdlChannelSink
internal bool RemoteApplicationMetadataEnabled
{
get { return _bRemoteApplicationMetadataEnabled; }
set { _bRemoteApplicationMetadataEnabled = value; }
}
internal bool MetadataEnabled
{
get { return _bMetadataEnabled; }
set { _bMetadataEnabled = value; }
}
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
IMessage requestMsg,
ITransportHeaders requestHeaders, Stream requestStream,
out IMessage responseMsg, out ITransportHeaders responseHeaders,
out Stream responseStream)
{
if (requestMsg != null)
{
// The message has already been deserialized so delegate to the next sink.
return _nextSink.ProcessMessage(
sinkStack,
requestMsg, requestHeaders, requestStream,
out responseMsg, out responseHeaders, out responseStream);
}
SdlType sdlType;
if (!ShouldIntercept(requestHeaders, out sdlType))
return _nextSink.ProcessMessage(sinkStack, null, requestHeaders, requestStream,
out responseMsg, out responseHeaders, out responseStream);
// generate sdl and return it
responseHeaders = new TransportHeaders();
GenerateSdl(sdlType, sinkStack, requestHeaders, responseHeaders, out responseStream);
responseMsg = null;
return ServerProcessing.Complete;
} // ProcessMessage
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state,
IMessage msg, ITransportHeaders headers, Stream stream)
{
// We don't need to implement this because we never push ourselves to the sink
// stack.
} // AsyncProcessResponse
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
IMessage msg, ITransportHeaders headers)
{
// We don't need to implement this because we never push ourselves
// to the sink stack.
throw new NotSupportedException();
} // GetResponseStream
public IServerChannelSink NextChannelSink
{
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
get { return _nextSink; }
}
public IDictionary Properties
{
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
get { return null; }
} // Properties
// Should we intercept the call and return some SDL
private bool ShouldIntercept(ITransportHeaders requestHeaders, out SdlType sdlType)
{
sdlType = SdlType.Sdl;
String requestVerb = requestHeaders["__RequestVerb"] as String;
String requestURI = requestHeaders["__RequestUri"] as String;
// http verb must be "GET" to return sdl (and request uri must be set)
if ((requestURI == null) ||
(requestVerb == null) || !requestVerb.Equals("GET"))
return false;
// find last index of ? and look for "sdl" or "sdlx"
int index = requestURI.LastIndexOf('?');
if (index == -1)
return false; // no query string
String queryString = requestURI.Substring(index).ToLower(CultureInfo.InvariantCulture);
// sdl?
if ((String.CompareOrdinal(queryString, "?sdl") == 0) ||
(String.CompareOrdinal(queryString, "?sdlx") == 0))
{
sdlType = SdlType.Sdl;
return true;
}
// wsdl?
if (String.CompareOrdinal(queryString, "?wsdl") == 0)
{
sdlType = SdlType.Wsdl;
return true;
}
return false;
} // ShouldIntercept
private void GenerateSdl(SdlType sdlType,
IServerResponseChannelSinkStack sinkStack,
ITransportHeaders requestHeaders,
ITransportHeaders responseHeaders,
out Stream outputStream)
{
if (!MetadataEnabled)
throw new RemotingException(CoreChannel.GetResourceString("Remoting_MetadataNotEnabled"));
String requestUri = requestHeaders[CommonTransportKeys.RequestUri] as String;
String objectUri = HttpChannelHelper.GetObjectUriFromRequestUri(requestUri);
if (!RemoteApplicationMetadataEnabled &&
(String.Compare(objectUri, "RemoteApplicationMetadata.rem", StringComparison.OrdinalIgnoreCase) == 0))
throw new RemotingException(CoreChannel.GetResourceString("Remoting_RemoteApplicationMetadataNotEnabled"));
// If the host header is present, we will use this in the generated uri's
String hostName = (String)requestHeaders["Host"];
if (hostName != null)
{
// filter out port number if present
int index = hostName.IndexOf(':');
if (index != -1)
hostName = hostName.Substring(0, index);
}
#if !FEATURE_PAL
// For IIS, we will Microsoft the scheme://hostname:port with the incoming value
String iisHostOverride = SetupUrlBashingForIisIfNecessary(hostName);
#endif
ServiceType[] types = null;
if (String.Compare(objectUri, "RemoteApplicationMetadata.rem", StringComparison.OrdinalIgnoreCase) == 0)
{
// get the service description for all registered service types
ActivatedServiceTypeEntry[] activatedTypes =
RemotingConfiguration.GetRegisteredActivatedServiceTypes();
WellKnownServiceTypeEntry[] wellKnownTypes =
RemotingConfiguration.GetRegisteredWellKnownServiceTypes();
// determine total number of types
int typeCount = 0;
if (activatedTypes != null)
typeCount += activatedTypes.Length;
if (wellKnownTypes != null)
typeCount += wellKnownTypes.Length;
types = new ServiceType[typeCount];
// collect data
int co = 0;
if (activatedTypes != null)
{
foreach (ActivatedServiceTypeEntry entry in activatedTypes)
{
types[co++] = new ServiceType(entry.ObjectType, null);
}
}
if (wellKnownTypes != null)
{
foreach (WellKnownServiceTypeEntry entry in wellKnownTypes)
{
String[] urls = _receiver.GetUrlsForUri(entry.ObjectUri);
String url = urls[0];
#if !FEATURE_PAL
if (iisHostOverride != null)
url = HttpChannelHelper.ReplaceChannelUriWithThisString(url, iisHostOverride);
else
#endif
if (hostName != null)
url = HttpChannelHelper.ReplaceMachineNameWithThisString(url, hostName);
types[co++] = new ServiceType(entry.ObjectType, url);
}
}
InternalRemotingServices.RemotingAssert(co == typeCount, "Not all types were processed.");
}
else
{
// get the service description for a particular object
Type objectType = RemotingServices.GetServerTypeForUri(objectUri);
if (objectType == null)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, "Object with uri '{0}' does not exist at server.",
objectUri));
}
String[] urls = _receiver.GetUrlsForUri(objectUri);
String url = urls[0];
#if !FEATURE_PAL
if (iisHostOverride != null)
url = HttpChannelHelper.ReplaceChannelUriWithThisString(url, iisHostOverride);
else
#endif
if (hostName != null)
url = HttpChannelHelper.ReplaceMachineNameWithThisString(url, hostName);
types = new ServiceType[1];
types[0] = new ServiceType(objectType, url);
}
responseHeaders["Content-Type"] = "text/xml";
bool bMemStream = false;
outputStream = sinkStack.GetResponseStream(null, responseHeaders);
if (outputStream == null)
{
outputStream = new MemoryStream(1024);
bMemStream = true;
}
MetaData.ConvertTypesToSchemaToStream(types, sdlType, outputStream);
if (bMemStream)
outputStream.Position = 0;
} // GenerateXmlForUri
// SetupUrlBashingForIisIfNecessaryWorker wrapper.
// Prevents System.Web type load for client sku installations.
internal static string SetupUrlBashingForIisIfNecessary(string hostName)
{
String iisHostOverride = null;
if (!CoreChannel.IsClientSKUInstallation)
{
iisHostOverride = SetupUrlBashingForIisIfNecessaryWorker(hostName);
}
return iisHostOverride;
} // SetupUrlBashingForIisIfNecessary
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static string SetupUrlBashingForIisIfNecessaryWorker(string hostName)
{
// For IIS, we will Microsoft the scheme://hostname:port with the incoming value
String iisHostOverride = null;
HttpContext context = HttpContext.Current;
if (context != null)
{
HttpRequest request = context.Request;
String scheme = null;
if (request.IsSecureConnection)
scheme = "https";
else
scheme = "http";
int port = context.Request.Url.Port;
StringBuilder sb = new StringBuilder(100);
sb.Append(scheme);
sb.Append("://");
if (hostName != null)
sb.Append(hostName);
else
sb.Append(CoreChannel.GetMachineName());
sb.Append(":");
sb.Append(port.ToString(CultureInfo.InvariantCulture));
iisHostOverride = sb.ToString();
}
return iisHostOverride;
} // SetupUrlBashingForIisIfNecessaryWorker
} // class SdlChannelSink
} // namespace System.Runtime.Remoting.Channnels
|