示例#1
0
 Return(HttpOptions options,
        Func <HttpConfig, HttpConfig> configurer,
        Func <IHttpObservable, IObservable <HttpFetch <HttpContent> > > query,
        Func <HttpFetchInfo, bool> predicate) =>
 new Impl(query, options, configurer, predicate);
示例#2
0
 public IHttpObservable WithOptions(HttpOptions options) =>
 new Impl(_query, options, Configurer, FilterPredicate);
示例#3
0
        static async Task <T> HttpFetchAsync <T>(IHttpClient http, HttpConfig config,
                                                 HttpMethod method, Uri url, HttpContent content, HttpOptions options,
                                                 Func <HttpConfig, HttpResponseMessage, T> responseSelector,
                                                 Func <HttpConfig, HttpMethod, Uri, HttpContent, T> redirectionSelector)
        {
            var request = new HttpRequestMessage
            {
                Method     = method,
                RequestUri = url,
                Content    = content
            };

            HttpResponseMessage response = null;

            try
            {
                response = await http.SendAsync(request, config)
                           .DontContinueOnCapturedContext();

                IEnumerable <string> setCookies;
                if (response.Headers.TryGetValues("Set-Cookie", out setCookies))
                {
                    var cc = new CookieContainer();
                    foreach (var cookie in setCookies)
                    {
                        try { cc.SetCookies(url, cookie); }
                        catch (CookieException) { /* ignore bad cookies */ }
                    }

                    var mergedCookies =
                        from cookies in new[]
                    {
                        http.Config.Cookies ?? Enumerable.Empty <Cookie>(),
                        cc.GetCookies(url).Cast <Cookie>(),
                    }
                    from c in cookies
                    //
                    // According to RFC 6265[1], "cookies for a given host
                    // are shared across all the ports on that host" so
                    // don't take Cookie.Port into account when grouping.
                    // It is also assumed that Cookie.Domain
                    //
                    // [1] https://tools.ietf.org/html/rfc6265#section-1
                    //
                    group c by new
                    {
                        c.Name,
                        Domain = c.Domain.ToLowerInvariant(),
                        c.Path
                    } into g
                    select g.OrderByDescending(e => e.TimeStamp).First();

                    config = config.WithCookies(mergedCookies.ToArray());
                }

                // Source:
                // https://referencesource.microsoft.com/#System/net/System/Net/HttpWebRequest.cs,5669
                //
                // Check for Redirection
                //
                // Table View:
                // Method            301             302             303             307
                //    *                *               *             GET               *
                // POST              GET             GET             GET            POST
                //
                // Put another way:
                //  301 & 302  - All methods are redirected to the same method but POST. POST is redirected to a GET.
                //  303 - All methods are redirected to GET
                //  307 - All methods are redirected to the same method.
                //

                var sc = response.StatusCode;
                if (sc == HttpStatusCode.Ambiguous ||      // 300
                    sc == HttpStatusCode.Moved ||          // 301
                    sc == HttpStatusCode.Redirect ||       // 302
                    sc == HttpStatusCode.RedirectMethod || // 303
                    sc == HttpStatusCode.RedirectKeepVerb) // 307
                {
                    var redirectionUrl = response.Headers.Location?.AsRelativeTo(response.RequestMessage.RequestUri);
                    if (redirectionUrl == null)
                    {
                        // 300
                        // If the server has a preferred choice of representation,
                        // it SHOULD include the specific URI for that
                        // representation in the Location field; user agents MAY
                        // use the Location field value for automatic redirection.

                        if (sc != HttpStatusCode.Ambiguous)
                        {
                            throw new ProtocolViolationException("Server did not supply a URL for a redirection response.");
                        }
                    }
                    else
                    {
                        if (redirectionUrl.Scheme == "ws" || redirectionUrl.Scheme == "wss")
                        {
                            throw new NotSupportedException($"Redirection to a WebSocket URL ({redirectionUrl}) is not supported.");
                        }

                        if (redirectionUrl.Scheme != Uri.UriSchemeHttp && redirectionUrl.Scheme != Uri.UriSchemeHttps)
                        {
                            throw new ProtocolViolationException(
                                      $"Server sent a redirection response where the redirection URL ({redirectionUrl}) scheme was neither HTTP nor HTTPS.");
                        }

                        return(sc == HttpStatusCode.RedirectMethod ||
                               method == HttpMethod.Post && (sc == HttpStatusCode.Moved || sc == HttpStatusCode.Redirect)
                             ? redirectionSelector(config, HttpMethod.Get, redirectionUrl, null)
                             : redirectionSelector(config, method, redirectionUrl, content));
                    }
                }

                if (!options.ReturnErroneousFetch)
                {
                    response.EnsureSuccessStatusCode();
                }

                var result = responseSelector(config, response);
                response = null; // disown
                return(result);
            }
            finally
            {
                response?.Dispose();
            }
        }
示例#4
0
        static async Task <HttpFetch <HttpContent> > SendAsync(IHttpClient http, HttpConfig config, int id, HttpMethod method, Uri url, HttpContent content = null, HttpOptions options = null)
        {
            http = http.WithConfig(config);

            for (var redirections = 0; ; redirections++)
            {
                if (redirections > MaximumAutomaticRedirections)
                {
                    throw new Exception("The maximum number of redirection responses permitted has been exceeded.");
                }

                var result =
                    await HttpFetchAsync(http, http.Config, method, url, content, options,
                                         (cfg, rsp) => new
                {
                    Config   = cfg,
                    Method   = default(HttpMethod),
                    Url      = default(Uri),
                    Content  = default(HttpContent),
                    Response = rsp,
                },
                                         (cfg, rm, rl, rc) => new
                {
                    Config   = cfg,
                    Method   = rm,
                    Url      = rl,
                    Content  = rc,
                    Response = default(HttpResponseMessage),
                })
                    .DontContinueOnCapturedContext();

                if (result.Response != null)
                {
                    return(result.Response.ToHttpFetch(id, http.WithConfig(result.Config)));
                }

                // TODO tail call recursion?

                http    = http.WithConfig(result.Config);
                method  = result.Method;
                url     = result.Url;
                content = result.Content;
            }
        }
示例#5
0
        static async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpConfig config, HttpOptions options)
        {
            var hwreq = WebRequest.CreateHttp(request.RequestUri);

            hwreq.Method                = request.Method.Method;
            hwreq.Timeout               = (int)config.Timeout.TotalMilliseconds;
            hwreq.CookieContainer       = config.Cookies;
            hwreq.Credentials           = config.Credentials;
            hwreq.UseDefaultCredentials = config.UseDefaultCredentials;

            var userAgent = request.Headers.UserAgent.ToString();

            hwreq.UserAgent = userAgent.Length > 0 ? userAgent : config.UserAgent;

            var referrer = request.Headers.Referrer;

            if (referrer != null)
            {
                hwreq.Referer = referrer.ToString();
            }

            var accept = request.Headers.Accept.ToString();

            if (accept.Length > 0)
            {
                hwreq.Accept = accept;
            }

            var content = request.Content;

            foreach (var e in from e in request.Headers.Concat(content?.Headers ?? Enumerable.Empty <KeyValuePair <string, IEnumerable <string> > >())
                     where !e.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase) &&
                     !e.Key.Equals("User-Agent", StringComparison.OrdinalIgnoreCase) &&
                     !e.Key.Equals("Referer", StringComparison.OrdinalIgnoreCase) &&
                     !e.Key.Equals("Accept", StringComparison.OrdinalIgnoreCase)
                     from v in e.Value
                     select e.Key.AsKeyTo(v))
            {
                hwreq.Headers.Add(e.Key, e.Value);
            }

            HttpWebResponse hwrsp = null;

            try
            {
                if (content != null)
                {
                    // ReSharper disable once PossibleNullReferenceException
                    hwreq.ContentType = content.Headers.ContentType.ToString();
                    using (var s = hwreq.GetRequestStream())
                        await content.CopyToAsync(s);
                }
                return(await CreateResponse(hwreq, hwrsp = (HttpWebResponse)hwreq.GetResponse()));
            }
            catch (WebException e) when(e.Status == WebExceptionStatus.ProtocolError)
            {
                if (!options.ReturnErrorneousFetch)
                {
                    throw;
                }
                return(await CreateResponse(hwreq, hwrsp = (HttpWebResponse)e.Response));
            }
            finally
            {
                hwrsp?.Dispose();
            }
        }
示例#6
0
 public virtual HttpResponseMessage Send(HttpRequestMessage request, HttpConfig config, HttpOptions options) =>
 SendAsync(request, config, options).Result;