namespace DotNetOpenAuth.ApplicationBlock {
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using DotNetOpenAuth.Messaging;
public static class Util {
///
/// Pseudo-random data generator.
///
internal static readonly Random NonCryptoRandomDataGenerator = new Random();
///
/// Sets the channel's outgoing HTTP requests to use default network credentials.
///
/// The channel to modify.
public static void UseDefaultNetworkCredentialsOnOutgoingHttpRequests(this Channel channel)
{
Debug.Assert(!(channel.WebRequestHandler is WrappingWebRequestHandler), "Wrapping an already wrapped web request handler. This is legal, but highly suspect of a bug as you don't want to wrap the same channel repeatedly to apply the same effect.");
AddOutgoingHttpRequestTransform(channel, http => http.Credentials = CredentialCache.DefaultNetworkCredentials);
}
///
/// Adds some action to any outgoing HTTP request on this channel.
///
/// The channel's whose outgoing HTTP requests should be modified.
/// The action to perform on outgoing HTTP requests.
internal static void AddOutgoingHttpRequestTransform(this Channel channel, Action action) {
if (channel == null) {
throw new ArgumentNullException("channel");
}
if (action == null) {
throw new ArgumentNullException("action");
}
channel.WebRequestHandler = new WrappingWebRequestHandler(channel.WebRequestHandler, action);
}
///
/// Enumerates through the individual set bits in a flag enum.
///
/// The flags enum value.
/// An enumeration of just the set bits in the flags enum.
internal static IEnumerable GetIndividualFlags(Enum flags) {
long flagsLong = Convert.ToInt64(flags);
for (int i = 0; i < sizeof(long) * 8; i++) { // long is the type behind the largest enum
// Select an individual application from the scopes.
long individualFlagPosition = (long)Math.Pow(2, i);
long individualFlag = flagsLong & individualFlagPosition;
if (individualFlag == individualFlagPosition) {
yield return individualFlag;
}
}
}
internal static Uri GetCallbackUrlFromContext() {
Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_");
return callback;
}
///
/// Copies the contents of one stream to another.
///
/// The stream to copy from, at the position where copying should begin.
/// The stream to copy to, at the position where bytes should be written.
/// The total number of bytes copied.
///
/// Copying begins at the streams' current positions.
/// The positions are NOT reset after copying is complete.
///
internal static int CopyTo(this Stream copyFrom, Stream copyTo) {
return CopyTo(copyFrom, copyTo, int.MaxValue);
}
///
/// Copies the contents of one stream to another.
///
/// The stream to copy from, at the position where copying should begin.
/// The stream to copy to, at the position where bytes should be written.
/// The maximum bytes to copy.
/// The total number of bytes copied.
///
/// Copying begins at the streams' current positions.
/// The positions are NOT reset after copying is complete.
///
internal static int CopyTo(this Stream copyFrom, Stream copyTo, int maximumBytesToCopy) {
if (copyFrom == null) {
throw new ArgumentNullException("copyFrom");
}
if (copyTo == null) {
throw new ArgumentNullException("copyTo");
}
byte[] buffer = new byte[1024];
int readBytes;
int totalCopiedBytes = 0;
while ((readBytes = copyFrom.Read(buffer, 0, Math.Min(1024, maximumBytesToCopy))) > 0) {
int writeBytes = Math.Min(maximumBytesToCopy, readBytes);
copyTo.Write(buffer, 0, writeBytes);
totalCopiedBytes += writeBytes;
maximumBytesToCopy -= writeBytes;
}
return totalCopiedBytes;
}
///
/// Wraps some instance of a web request handler in order to perform some extra operation on all
/// outgoing HTTP requests.
///
private class WrappingWebRequestHandler : IDirectWebRequestHandler
{
///
/// The handler being wrapped.
///
private readonly IDirectWebRequestHandler wrappedHandler;
///
/// The action to perform on outgoing HTTP requests.
///
private readonly Action action;
///
/// Initializes a new instance of the class.
///
/// The HTTP handler to wrap.
/// The action to perform on outgoing HTTP requests.
internal WrappingWebRequestHandler(IDirectWebRequestHandler wrappedHandler, Action action)
{
if (wrappedHandler == null) {
throw new ArgumentNullException("wrappedHandler");
}
if (action == null) {
throw new ArgumentNullException("action");
}
this.wrappedHandler = wrappedHandler;
this.action = action;
}
#region Implementation of IDirectWebRequestHandler
///
/// Determines whether this instance can support the specified options.
///
/// The set of options that might be given in a subsequent web request.
///
/// true if this instance can support the specified options; otherwise, false.
///
public bool CanSupport(DirectWebRequestOptions options)
{
return this.wrappedHandler.CanSupport(options);
}
///
/// Prepares an that contains an POST entity for sending the entity.
///
/// The that should contain the entity.
///
/// The stream the caller should write out the entity data to.
///
/// Thrown for any network error.
///
/// The caller should have set the
/// and any other appropriate properties before calling this method.
/// Callers must close and dispose of the request stream when they are done
/// writing to it to avoid taking up the connection too long and causing long waits on
/// subsequent requests.
/// Implementations should catch and wrap it in a
/// to abstract away the transport and provide
/// a single exception type for hosts to catch.
///
public Stream GetRequestStream(HttpWebRequest request)
{
this.action(request);
return this.wrappedHandler.GetRequestStream(request);
}
///
/// Prepares an that contains an POST entity for sending the entity.
///
/// The that should contain the entity.
/// The options to apply to this web request.
///
/// The stream the caller should write out the entity data to.
///
/// Thrown for any network error.
///
/// The caller should have set the
/// and any other appropriate properties before calling this method.
/// Callers must close and dispose of the request stream when they are done
/// writing to it to avoid taking up the connection too long and causing long waits on
/// subsequent requests.
/// Implementations should catch and wrap it in a
/// to abstract away the transport and provide
/// a single exception type for hosts to catch.
///
public Stream GetRequestStream(HttpWebRequest request, DirectWebRequestOptions options)
{
this.action(request);
return this.wrappedHandler.GetRequestStream(request, options);
}
///
/// Processes an and converts the
/// to a instance.
///
/// The to handle.
/// An instance of describing the response.
/// Thrown for any network error.
///
/// Implementations should catch and wrap it in a
/// to abstract away the transport and provide
/// a single exception type for hosts to catch. The
/// value, if set, should be Closed before throwing.
///
public IncomingWebResponse GetResponse(HttpWebRequest request)
{
// If the request has an entity, the action would have already been processed in GetRequestStream.
if (request.Method == "GET")
{
this.action(request);
}
return this.wrappedHandler.GetResponse(request);
}
///
/// Processes an and converts the
/// to a instance.
///
/// The to handle.
/// The options to apply to this web request.
/// An instance of describing the response.
/// Thrown for any network error.
///
/// Implementations should catch and wrap it in a
/// to abstract away the transport and provide
/// a single exception type for hosts to catch. The
/// value, if set, should be Closed before throwing.
///
public IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options)
{
// If the request has an entity, the action would have already been processed in GetRequestStream.
if (request.Method == "GET") {
this.action(request);
}
return this.wrappedHandler.GetResponse(request, options);
}
#endregion
}
}
}