/// <summary>
        /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
        /// </summary>
        /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
        /// <param name="options">The options to apply to this web request.</param>
        /// <returns>
        /// The writer the caller should write out the entity data to.
        /// </returns>
        /// <exception cref="ProtocolException">Thrown for any network error.</exception>
        /// <remarks>
        ///     <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
        /// and any other appropriate properties <i>before</i> calling this method.</para>
        ///     <para>Implementations should catch <see cref="WebException"/> and wrap it in a
        /// <see cref="ProtocolException"/> to abstract away the transport and provide
        /// a single exception type for hosts to catch.</para>
        /// </remarks>
        public Stream GetRequestStream(HttpWebRequest request, DirectWebRequestOptions options)
        {
            ErrorUtilities.VerifyArgumentNotNull(request, "request");
            ErrorUtilities.VerifySupported(this.CanSupport(options), MessagingStrings.DirectWebRequestOptionsNotSupported, options, this.GetType().Name);

            return(GetRequestStreamCore(request, options));
        }
Esempio n. 2
0
        /// <summary>
        /// Adds message types to the set that this factory can create.
        /// </summary>
        /// <param name="messageTypes">The message types that this factory may instantiate.</param>
        public virtual void AddMessageTypes(IEnumerable <MessageDescription> messageTypes)
        {
            Requires.NotNull(messageTypes, "messageTypes");
            Requires.True(messageTypes.All(msg => msg != null), "messageTypes");

            var unsupportedMessageTypes = new List <MessageDescription>(0);

            foreach (MessageDescription messageDescription in messageTypes)
            {
                bool supportedMessageType = false;

                // First see whether this message fits the recognized pattern for request messages.
                if (typeof(IDirectedProtocolMessage).IsAssignableFrom(messageDescription.MessageType))
                {
                    foreach (ConstructorInfo ctor in messageDescription.Constructors)
                    {
                        ParameterInfo[] parameters = ctor.GetParameters();
                        if (parameters.Length == 2 && parameters[0].ParameterType == typeof(Uri) && parameters[1].ParameterType == typeof(Version))
                        {
                            supportedMessageType = true;
                            this.requestMessageTypes.Add(messageDescription, ctor);
                            break;
                        }
                    }
                }

                // Also see if this message fits the recognized pattern for response messages.
                if (typeof(IDirectResponseProtocolMessage).IsAssignableFrom(messageDescription.MessageType))
                {
                    var responseCtors = new Dictionary <Type, ConstructorInfo>(messageDescription.Constructors.Length);
                    foreach (ConstructorInfo ctor in messageDescription.Constructors)
                    {
                        ParameterInfo[] parameters = ctor.GetParameters();
                        if (parameters.Length == 1 && typeof(IDirectedProtocolMessage).IsAssignableFrom(parameters[0].ParameterType))
                        {
                            responseCtors.Add(parameters[0].ParameterType, ctor);
                        }
                    }

                    if (responseCtors.Count > 0)
                    {
                        supportedMessageType = true;
                        this.responseMessageTypes.Add(messageDescription, responseCtors);
                    }
                }

                if (!supportedMessageType)
                {
                    unsupportedMessageTypes.Add(messageDescription);
                }
            }

            ErrorUtilities.VerifySupported(
                !unsupportedMessageTypes.Any(),
                MessagingStrings.StandardMessageFactoryUnsupportedMessageType,
                unsupportedMessageTypes.ToStringDeferred());
        }
Esempio n. 3
0
        /// <summary>
        /// Gets the public facing URL for the given incoming HTTP request.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="serverVariables">The server variables to consider part of the request.</param>
        /// <returns>
        /// The URI that the outside world used to create this request.
        /// </returns>
        /// <remarks>
        /// Although the <paramref name="serverVariables"/> value can be obtained from
        /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
        /// in so we can simulate injected values from our unit tests since the actual property
        /// is a read-only kind of <see cref="NameValueCollection"/>.
        /// </remarks>
        internal static Uri GetPublicFacingUrl(HttpRequest request, NameValueCollection serverVariables)
        {
            Contract.Requires <ArgumentNullException>(request != null);
            Contract.Requires <ArgumentNullException>(serverVariables != null);

            // Due to URL rewriting, cloud computing (i.e. Azure)
            // and web farms, etc., we have to be VERY careful about what
            // we consider the incoming URL.  We want to see the URL as it would
            // appear on the public-facing side of the hosting web site.
            // HttpRequest.Url gives us the internal URL in a cloud environment,
            // So we use a variable that (at least from what I can tell) gives us
            // the public URL:
            if (serverVariables["HTTP_HOST"] != null)
            {
                ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
                string     scheme           = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
                Uri        hostAndPort      = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
                UriBuilder publicRequestUri = new UriBuilder(request.Url);
                publicRequestUri.Scheme = scheme;
                publicRequestUri.Host   = hostAndPort.Host;
                publicRequestUri.Port   = hostAndPort.Port;               // CC missing Uri.Port contract that's on UriBuilder.Port
                return(publicRequestUri.Uri);
            }
            else
            {
                // Failover to the method that works for non-web farm enviroments.
                // We use Request.Url for the full path to the server, and modify it
                // with Request.RawUrl to capture both the cookieless session "directory" if it exists
                // and the original path in case URL rewriting is going on.  We don't want to be
                // fooled by URL rewriting because we're comparing the actual URL with what's in
                // the return_to parameter in some cases.
                // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
                // session, but not the URL rewriting problem.
                return(new Uri(request.Url, request.RawUrl));
            }
        }
        /// <summary>
        /// Processes an <see cref="HttpWebRequest"/> and converts the
        /// <see cref="HttpWebResponse"/> to a <see cref="DirectWebResponse"/> instance.
        /// </summary>
        /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
        /// <param name="options">The options to apply to this web request.</param>
        /// <returns>
        /// An instance of <see cref="DirectWebResponse"/> describing the response.
        /// </returns>
        /// <exception cref="ProtocolException">Thrown for any network error.</exception>
        /// <remarks>
        ///     <para>Implementations should catch <see cref="WebException"/> and wrap it in a
        /// <see cref="ProtocolException"/> to abstract away the transport and provide
        /// a single exception type for hosts to catch.  The <see cref="WebException.Response"/>
        /// value, if set, shoud be Closed before throwing.</para>
        /// </remarks>
        public DirectWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options)
        {
            ErrorUtilities.VerifyArgumentNotNull(request, "request");
            ErrorUtilities.VerifySupported(this.CanSupport(options), MessagingStrings.DirectWebRequestOptionsNotSupported, options, this.GetType().Name);

            // This request MAY have already been prepared by GetRequestStream, but
            // we have no guarantee, so do it just to be safe.
            PrepareRequest(request, false);

            try {
                Logger.DebugFormat("HTTP {0} {1}", request.Method, request.RequestUri);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                return(new NetworkDirectWebResponse(request.RequestUri, response));
            } catch (WebException ex) {
                HttpWebResponse response = (HttpWebResponse)ex.Response;
                if (response != null && response.StatusCode == HttpStatusCode.ExpectationFailed &&
                    request.ServicePoint.Expect100Continue)
                {
                    // Some OpenID servers doesn't understand the Expect header and send 417 error back.
                    // If this server just failed from that, alter the ServicePoint for this server
                    // so that we don't send that header again next time (whenever that is).
                    // "Expect: 100-Continue" HTTP header. (see Google Code Issue 72)
                    // We don't want to blindly set all ServicePoints to not use the Expect header
                    // as that would be a security hole allowing any visitor to a web site change
                    // the web site's global behavior when calling that host.
                    request.ServicePoint.Expect100Continue = false;                     // TODO: investigate that CAS may throw here

                    // An alternative to ServicePoint if we don't have permission to set that,
                    // but we'd have to set it BEFORE each request.
                    ////request.Expect = "";
                }

                if ((options & DirectWebRequestOptions.AcceptAllHttpResponses) != 0 && response != null &&
                    response.StatusCode != HttpStatusCode.ExpectationFailed)
                {
                    Logger.InfoFormat("The HTTP error code {0} {1} is being accepted because the {2} flag is set.", (int)response.StatusCode, response.StatusCode, DirectWebRequestOptions.AcceptAllHttpResponses);
                    return(new NetworkDirectWebResponse(request.RequestUri, response));
                }

                if (Logger.IsErrorEnabled)
                {
                    if (response != null)
                    {
                        using (var reader = new StreamReader(ex.Response.GetResponseStream())) {
                            Logger.ErrorFormat("WebException from {0}: {1}{2}", ex.Response.ResponseUri, Environment.NewLine, reader.ReadToEnd());
                        }
                    }
                    else
                    {
                        Logger.ErrorFormat("WebException {1} from {0}, no response available.", request.RequestUri, ex.Status);
                    }
                }

                // Be sure to close the response stream to conserve resources and avoid
                // filling up all our incoming pipes and denying future requests.
                // If in the future, some callers actually want to read this response
                // we'll need to figure out how to reliably call Close on exception
                // responses at all callers.
                response.Close();

                throw ErrorUtilities.Wrap(ex, MessagingStrings.ErrorInRequestReplyMessage);
            }
        }