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 } } }