예제 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="HttpConnection"/> class.
        /// </summary>
        /// <param name="server">The server.</param>
        /// <param name="id">The identifier.</param>
        /// <param name="client">The client.</param>
        public HttpConnection(HttpServer server, Guid id, TcpClient client)
        {
            this.client = client;
            this.address = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
            this.server = server;
            this.id = id;
            this.protocol = HttpProtocol.HTTP;

            // process
            Utilities.InvokeAsync(Process);
        }
 public TargetResult()
 {
     Url = string.Empty;
     Html = string.Empty;
     ResponseHeaders = new NameValueCollection();
     Protocol = HttpProtocol.HTTP;
     Banner = string.Empty;
     WebServer = string.Empty;
     Success = false;
     Hostname = string.Empty;
 }
 /// <summary>
 /// Basic emitter to send synchronous HTTP requests
 /// </summary>
 /// <param name="endpoint">Collector domain</param>
 /// <param name="protocol">HttpProtocol.HTTP or HttpProtocol.HTTPS</param>
 /// <param name="port">Port to connect to</param>
 /// <param name="method">HttpMethod.GET or HttpMethod.POST</param>
 /// <param name="bufferSize">Maximum number of events queued before the buffer is flushed automatically.
 /// Defaults to 10 for POST requests and 1 for GET requests.</param>
 /// <param name="onSuccess">Callback executed when every request in a flush has status code 200.
 /// Gets passed the number of events flushed.</param>
 /// <param name="onFailure">Callback executed when not every request in a flush has status code 200.
 /// Gets passed the number of events sent successfully and a list of unsuccessful events.</param>
 /// <param name="offlineModeEnabled">Whether to store unsent requests using MSMQ</param>
 public Emitter(string endpoint, HttpProtocol protocol = HttpProtocol.HTTP, int? port = null, HttpMethod method = HttpMethod.GET, int? bufferSize = null, Action<int> onSuccess = null, Action<int, List<Dictionary<string, string>>> onFailure = null, bool offlineModeEnabled = true)
 {
     collectorUri = GetCollectorUri(endpoint, protocol, port, method);
     this.method = method;
     this.buffer = new List<Dictionary<string, string>>();
     this.bufferSize = Math.Max(1, bufferSize ?? (method == HttpMethod.GET ? 1 : 10));
     this.onSuccess = onSuccess;
     this.onFailure = onFailure;
     this.OfflineModeEnabled = offlineModeEnabled;
     Log.Logger.Info(String.Format("{0} initialized with endpoint {1}", this.GetType(), collectorUri));
 }
예제 #4
0
        public ProxyHttpProtocol(Control dispatcher, IUrlFilter urlFilter)
        {
            ArgumentUtility.CheckNotNull ("dispatcher", dispatcher);
              ArgumentUtility.CheckNotNull ("urlFilter", urlFilter);

              _dispatcher = dispatcher;
              _urlFilter = urlFilter;

              _dispatcher.Dispatcher.Invoke (
              () =>
              {
            var originalHttpHandler = new HttpProtocol();
            _wrapped = (IInternetProtocol) originalHttpHandler;
              });
        }
예제 #5
0
 /// <summary>
 /// Converts the <see cref="sourceValue" /> parameter to the <see cref="destinationType" /> parameter using <see cref="formatProvider"
 /// /> and <see cref="ignoreCase" />
 /// </summary>
 /// <param name="sourceValue">the <see cref="System.Object"/> to convert from</param>
 /// <param name="destinationType">the <see cref="System.Type" /> to convert to</param>
 /// <param name="formatProvider">not used by this TypeConverter.</param>
 /// <param name="ignoreCase">when set to <c>true</c>, will ignore the case when converting.</param>
 /// <returns>
 /// an instance of <see cref="HttpProtocol" />, or <c>null</c> if there is no suitable conversion.
 /// </returns>
 public override object ConvertFrom(object sourceValue, global::System.Type destinationType, global::System.IFormatProvider formatProvider, bool ignoreCase) => HttpProtocol.CreateFrom(sourceValue);
예제 #6
0
 public HttpClient(string hostName, int port = -1, HttpProtocol protocol = HttpProtocol.Auto)
 {
     Connection = HttpConnectionStream.ConnectToServer(hostName, port, protocol);
     RawStream  = Connection;
 }
예제 #7
0
 /// <summary> Construct a parser using the provided HttpProtocol.
 /// A feedback object printing to System.Console is used.
 /// </summary>
 /// <param name="connection">HttpProtocol object.
 /// </param>
 /// <throws>  ParserException If the creation of the underlying Lexer </throws>
 /// <summary> cannot be performed.
 /// </summary>
 public Parser(HttpProtocol connection) : this(connection, STDOUT)
 {
 }
예제 #8
0
 public void GetHttpProtocol_ThrowErrorForUnknownVersion(Version version)
 {
     Assert.Throws <ArgumentOutOfRangeException>(() => HttpProtocol.GetHttpProtocol(version));
 }
 public static string ToSerialString(this HttpProtocol value) => value switch
 {
        /// <summary>
        /// Inits the Snowplow Tracker; after this point it can be accessed globally.
        /// </summary>
        /// <param name="emitterUri">The emitter URI</param>
        /// <param name="protocol">The protocol to use</param>
        /// <param name="port">The port the collector is on</param>
        /// <param name="method">The method to use</param>
        /// <param name="useClientSession">Whether to enable client session</param>
        /// <param name="useMobileContext">Whether to enable mobile contexts</param>
        /// <param name="useGeoLocationContext">Whether to enable geo-location contexts</param>
        public static void Init(
            string emitterUri,
            HttpProtocol protocol = HttpProtocol.HTTP,
            int?port                   = null,
            HttpMethod method          = HttpMethod.GET,
            bool useClientSession      = false,
            bool useMobileContext      = false,
            bool useGeoLocationContext = false)
        {
            var logger = new ConsoleLogger();

            var dest = new SnowplowHttpCollectorEndpoint(emitterUri, method: method, port: port, protocol: protocol, l: logger);

            // Note: Maintain reference to Storage as this will need to be disposed of manually
            _storage = new LiteDBStorage(SnowplowTrackerPlatformExtension.Current.GetLocalFilePath("events.db"));
            var queue = new PersistentBlockingQueue(_storage, new PayloadToJsonString());

            // Note: When using GET requests the sendLimit equals the number of concurrent requests - to many of these will break your application!
            var sendLimit = method == HttpMethod.GET ? 10 : 100;

            // Note: To make the tracker more battery friendly and less likely to drain batteries there are two settings to take note of here:
            //       1. The stopPollIntervalMs: Controls how often we look to the database for more events
            //       2. The deviceOnlineMethod: Is run before going to the database or attempting to send events, this will prevent any I/O from
            //          occurring unless you have an active network connection
            var emitter = new AsyncEmitter(dest, queue, sendLimit: sendLimit, stopPollIntervalMs: 1000, sendSuccessMethod: EventSuccessCallback,
                                           deviceOnlineMethod: SnowplowTrackerPlatformExtension.Current.IsDeviceOnline, l: logger);

            var userId = PropertyManager.GetStringValue(KEY_USER_ID, SnowplowCore.Utils.GetGUID());

            PropertyManager.SaveKeyValue(KEY_USER_ID, userId);

            var subject = new Subject()
                          .SetPlatform(Platform.Mob)
                          .SetUserId(userId)
                          .SetLang("en");

            if (useClientSession)
            {
                _clientSession = new ClientSession(SnowplowTrackerPlatformExtension.Current.GetLocalFilePath("client_session.dict"), l: logger);
            }

            // Note: You can either attach contexts to each event individually or for the more common contexts such as Desktop, Mobile and GeoLocation
            //       you can pass a delegate method which will then be called for each event automatically.

            MobileContextDelegate mobileContextDelegate = null;

            if (useMobileContext)
            {
                mobileContextDelegate = SnowplowTrackerPlatformExtension.Current.GetMobileContext;
            }

            GeoLocationContextDelegate geoLocationContextDelegate = null;

            if (useMobileContext)
            {
                geoLocationContextDelegate = SnowplowTrackerPlatformExtension.Current.GetGeoLocationContext;
            }

            // Attach the created objects and begin all required background threads!
            Instance.Start(emitter: emitter, subject: subject, clientSession: _clientSession, trackerNamespace: _trackerNamespace,
                           appId: _appId, encodeBase64: false, synchronous: false, mobileContextDelegate: mobileContextDelegate,
                           geoLocationContextDelegate: geoLocationContextDelegate, l: logger);

            // Reset session counters
            SessionMadeCount    = 0;
            SessionSuccessCount = 0;
            SessionFailureCount = 0;
        }
예제 #11
0
 public void RequestQueuedStop(HttpProtocol httpProtocol, string httpVersion)
 {
     Interlocked.Decrement(ref _httpRequestQueueLength);
 }
예제 #12
0
 protected MessageBody(HttpProtocol context)
 {
     _context = context;
 }
        private TargetResult Connect(HttpProtocol Protocol, string IPAddress, int Port)
        {
            TargetResult Result = new TargetResult();
            string Address = string.Empty;
            if (Protocol == HttpProtocol.HTTP)
                Address = "http://" + IPAddress + ":" + Port.ToString();
            else if (Protocol == HttpProtocol.HTTPs)
                Address = "https://" + IPAddress + ":" + Port.ToString();

            CreateWebrequest webRequest = new CreateWebrequest();
            Result.Html = webRequest.StringGetWebPage(Address, string.Empty);
            Result.Url = Address;
            Result.Protocol = Protocol;

            if (webRequest.Response != null)
            {
                Result.ResponseHeaders = webRequest.Response.Headers;
                Result.Banner = webRequest.Response.Server;
                Result.WebServer = GetWebServer(webRequest.Response.Server);
                IPHostEntry Hostname = Dns.GetHostEntry(IPAddress);
                Result.Hostname = Hostname.HostName;
                Result.Success = true;
                Result.StatusCode = webRequest.Response.StatusCode;
            }
            else
            {
                Result.Success = false;
            }

            return Result;
        }
예제 #14
0
 public Target()
 {
     Address  = string.Empty;
     Port     = -1;
     Protocol = HttpProtocol.HTTP;
 }
예제 #15
0
        private void _OnLoginRes(Http.HttpRequestHandler.NetworkMsgType type, string message, AbstractHttpProtocol proto)
        {
            if (type == Http.HttpRequestHandler.NetworkMsgType.network)
            {
                //网络出现问题
                _RaiseNetworkErrorEvent();
                return;
            }
            int errorCode = ErrorCode.SERVICE_ERROR;

            if (proto != null)
            {
                HttpProtocol <User_LoginOrRegister_Request, User_LoginOrRegister_Response> p = proto as HttpProtocol <User_LoginOrRegister_Request, User_LoginOrRegister_Response>;
                if (p != null)
                {
                    errorCode = p.error_code;
                    User_LoginOrRegister_Response res = p.GetResMsg();
                    if (p.error_code == ErrorCode.SUCCESS && res != null && res.uid > 0)
                    {
                        PVPGlobal.isLogined = true;
                        PVPGlobal.userInfo  = new User(res);
                        //登陆成功
                        _StartSocketTcpConnect(res);
                    }
                    else
                    {
                        PVPGlobal.isLogined = false;
                    }
                }
            }

            if (ICM.handlerRegister != null && ICM.handlerRegister.loginOrRegisterEventHandler != null)
            {
                ICM.handlerRegister.loginOrRegisterEventHandler(errorCode);
            }
        }
예제 #16
0
        /// <summary>
        /// 用户登陆
        /// </summary>
        /// <param name="loginType">Login type.</param>
        /// <param name="account">Account.</param>
        /// <param name="password">Password.</param>
        /// <param name="facebookAccessToken">Facebook access token.</param>
        /// <param name="timeout">Timeout.</param>
        public void Login(LoginType loginType, string account = "", string password = "", string facebookAccessToken = "", float timeout = 5)
        {
            this.Close();

            string uniqueIdentifier = SystemInfo.deviceUniqueIdentifier;

            PVPProtobuf_Token.User_LoginOrRegister_Request loginRequest = new PVPProtobuf_Token.User_LoginOrRegister_Request();
            loginRequest.login_type = (Int32)loginType;
            loginRequest.account    = account;
            loginRequest.password   = password;
            if (loginType == LoginType.Guest)
            {
                loginRequest.unique_identifier = SystemInfo.deviceUniqueIdentifier;
            }
            else
            {
                loginRequest.unique_identifier = "";
            }
            loginRequest.facebook_access_token = facebookAccessToken;
            if (String.IsNullOrEmpty(Config.appKey))
            {
                throw new Exception("You have not init pvp sdk , please call PVPGlobal.Init(string appKey) and set appKey. ");
            }
            loginRequest.app_key = Config.appKey;
            #if UNITY_ANDROID
            loginRequest.device_type = (int)DeviceType.Android;
            #elif UNITY_IOS
            loginRequest.device_type = (int)DeviceType.IOS;
            #else
            loginRequest.device_type = (int)DeviceType.OTHER;
            #endif
            HttpProtocol <User_LoginOrRegister_Request, User_LoginOrRegister_Response> loginProtocol = new HttpProtocol <User_LoginOrRegister_Request, User_LoginOrRegister_Response> ();
            loginProtocol.SetReqMsg(loginRequest);
            Http.HttpRequestHandler h = new Http.HttpRequestHandler();
            h.PostRequest(loginProtocol, _OnLoginRes);
        }
예제 #17
0
 protected StartLine(HttpProtocol protocol)
 {
     Protocol = protocol;
 }
예제 #18
0
        internal void ParseCorrectHttpVersion(string httpVersionText, HttpProtocol expectedProtocol)
        {
            var header = new HttpRequestHeader($"GET /myFile {httpVersionText}");

            Assert.Equal(header.Protocol, expectedProtocol);
        }
예제 #19
0
        public static HttpResponse SendRequest(HttpRequest request, string hostName, int port = -1, HttpProtocol protocol = HttpProtocol.Auto)
        {
            var client = new HttpClient(hostName, port, protocol);

            return(client.SendRequest(request));
        }
예제 #20
0
 public void RequestUpgradedStop(HttpProtocol httpProtocol)
 {
     Interlocked.Decrement(ref _currentUpgradedHttpRequests);
 }
 /// <summary>
 /// Asynchronous emitter to send non-blocking HTTP requests
 /// </summary>
 /// <param name="endpoint">Collector domain</param>
 /// <param name="protocol">HttpProtocol.HTTP or HttpProtocol.HTTPS</param>
 /// <param name="port">Port to connect to</param>
 /// <param name="method">HttpMethod.GET or HttpMethod.POST</param>
 /// <param name="bufferSize">Maximum number of events queued before the buffer is flushed automatically.
 /// Defaults to 10 for POST requests and 1 for GET requests.</param>
 /// <param name="onSuccess">Callback executed when every request in a flush has status code 200.
 /// Gets passed the number of events flushed.</param>
 /// <param name="onFailure">Callback executed when not every request in a flush has status code 200.
 /// Gets passed the number of events sent successfully and a list of unsuccessful events.</param>
 /// <param name="offlineModeEnabled">Whether to store unsent requests using MSMQ</param>
 public AsyncEmitter(string endpoint, HttpProtocol protocol = HttpProtocol.HTTP, int?port = null, HttpMethod method = HttpMethod.GET, int?bufferSize = null, Action <int> onSuccess = null, Action <int, List <Dictionary <string, string> > > onFailure = null, bool offlineModeEnabled = true) :
     base(endpoint, protocol, port, method, bufferSize, onSuccess, onFailure, offlineModeEnabled)
 {
     tasks = new List <Task>();
 }
예제 #22
0
 public StatusLine(HttpProtocol protocol, HttpStatusCode status) : base(protocol)
 {
     StatusCode = status;
 }
예제 #23
0
 private void HttpInitialize(String url)
 {
     HttpProtocol httpProtocol = new HttpProtocol(url);
 }
예제 #24
0
        /// <summary>
        /// Start processing the request.
        /// </summary>
        /// <returns></returns>
        internal Task <HttpContext> SendAsync(CancellationToken cancellationToken)
        {
            var registration = cancellationToken.Register(ClientInitiatedAbort);

            // Everything inside this function happens in the SERVER's execution context (unless PreserveExecutionContext is true)
            async Task RunRequestAsync()
            {
                // HTTP/2 specific features must be added after the request has been configured.
                if (HttpProtocol.IsHttp2(_httpContext.Request.Protocol))
                {
                    _httpContext.Features.Set <IHttpResetFeature>(this);
                }

                // This will configure IHttpContextAccessor so it needs to happen INSIDE this function,
                // since we are now inside the Server's execution context. If it happens outside this cont
                // it will be lost when we abandon the execution context.
                _testContext = _application.CreateContext(_httpContext.Features);
                try
                {
                    await _application.ProcessRequestAsync(_testContext);

                    // Determine whether request body was complete when the delegate exited.
                    // This could throw an error if there was a pending server read. Needs to
                    // happen before completing the response so the response returns the error.
                    var requestBodyInProgress = RequestBodyReadInProgress();
                    if (requestBodyInProgress)
                    {
                        // If request is still in progress then abort it.
                        CancelRequestBody();
                    }

                    // Matches Kestrel server: response is completed before request is drained
                    await CompleteResponseAsync();

                    if (!requestBodyInProgress)
                    {
                        // Writer was already completed in send request callback.
                        await _requestPipe.Reader.CompleteAsync();

                        // Don't wait for request to drain. It could block indefinitely. In a real server
                        // we would wait for a timeout and then kill the socket.
                        // Potential future improvement: add logging that the request timed out
                    }

                    _application.DisposeContext(_testContext, exception: null);
                }
                catch (Exception ex)
                {
                    Abort(ex);
                    _application.DisposeContext(_testContext, ex);
                }
                finally
                {
                    registration.Dispose();
                }
            }

            // Async offload, don't let the test code block the caller.
            if (_preserveExecutionContext)
            {
                _ = Task.Factory.StartNew(RunRequestAsync);
            }
            else
            {
                ThreadPool.UnsafeQueueUserWorkItem(_ =>
                {
                    _ = RunRequestAsync();
                }, null);
            }

            return(_responseTcs.Task);
        }
예제 #25
0
 public void RequestStart(HttpProtocol httpProtocol)
 {
     if (IsEnabled())
     {
         Core(httpProtocol);
     }
예제 #26
0
 /// <summary> Constructor for custom HTTP access.
 /// This would be used to create a parser for a URLConnection that needs
 /// a special setup or negotiation conditioning beyond what is available
 /// from the {@link #getConnectionManager ConnectionManager}.
 /// </summary>
 /// <param name="connection">A fully conditioned connection. The connect()
 /// method will be called so it need not be connected yet.
 /// </param>
 /// <param name="fb">The object to use for message communication.
 /// </param>
 /// <throws>  ParserException If the creation of the underlying Lexer </throws>
 /// <summary> cannot be performed.
 /// </summary>
 public Parser(HttpProtocol connection, IParserFeedBack fb) : this(new Lexer(connection), fb)
 {
     this.m_obHttpProtocol = connection;
 }
예제 #27
0
        /// <summary>
        /// Proxies a normal (i.e. non-upgradable) request to the upstream server, and the response back to our client.
        /// </summary>
        /// <remarks>
        /// Normal proxying comprises the following steps:
        ///    (0) Disable ASP .NET Core limits for streaming requests
        ///    (1) Create outgoing HttpRequestMessage
        ///    (2) Setup copy of request body (background)             Downstream --► Proxy --► Upstream
        ///    (3) Copy request headers                                Downstream --► Proxy --► Upstream
        ///    (4) Send the outgoing request using HttpMessageInvoker  Downstream --► Proxy --► Upstream
        ///    (5) Copy response status line                           Downstream ◄-- Proxy ◄-- Upstream
        ///    (6) Copy response headers                               Downstream ◄-- Proxy ◄-- Upstream
        ///    (7) Copy response body                                  Downstream ◄-- Proxy ◄-- Upstream
        ///    (8) Copy response trailer headers and finish response   Downstream ◄-- Proxy ◄-- Upstream
        ///    (9) Wait for completion of step 2: copying request body Downstream --► Proxy --► Upstream
        ///
        /// ASP .NET Core (Kestrel) will finally send response trailers (if any)
        /// after we complete the steps above and relinquish control.
        /// </remarks>
        private async Task NormalProxyAsync(
            HttpContext context,
            Uri targetUri,
            HttpMessageInvoker httpClient,
            ProxyTelemetryContext proxyTelemetryContext,
            CancellationToken shortCancellation,
            CancellationToken longCancellation)
        {
            Contracts.CheckValue(context, nameof(context));
            Contracts.CheckValue(targetUri, nameof(targetUri));
            Contracts.CheckValue(httpClient, nameof(httpClient));

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 0: Disable ASP .NET Core limits for streaming requests
            var isIncomingHttp2 = HttpProtocol.IsHttp2(context.Request.Protocol);

            // NOTE: We heuristically assume gRPC-looking requests may require streaming semantics.
            // See https://github.com/microsoft/reverse-proxy/issues/118 for design discussion.
            var isStreamingRequest = isIncomingHttp2 && GrpcProtocolHelper.IsGrpcContentType(context.Request.ContentType);

            if (isStreamingRequest)
            {
                DisableMinRequestBodyDataRateAndMaxRequestBodySize(context);
            }

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 1: Create outgoing HttpRequestMessage
            var upstreamRequest = new HttpRequestMessage(HttpUtilities.GetHttpMethod(context.Request.Method), targetUri)
            {
                // We request HTTP/2, but HttpClient will fallback to HTTP/1.1 if it cannot establish HTTP/2 with the target.
                // This is done without extra round-trips thanks to ALPN. We can detect a downgrade after calling HttpClient.SendAsync
                // (see Step 3 below). TBD how this will change when HTTP/3 is supported.
                Version = Http2Version,
            };

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 2: Setup copy of request body (background) Downstream --► Proxy --► Upstream
            // Note that we must do this before step (3) because step (3) may also add headers to the HttpContent that we set up here.
            var bodyToUpstreamContent = SetupCopyBodyUpstream(context.Request.Body, upstreamRequest, in proxyTelemetryContext, isStreamingRequest, longCancellation);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 3: Copy request headers Downstream --► Proxy --► Upstream
            CopyHeadersToUpstream(context, upstreamRequest);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 4: Send the outgoing request using HttpClient
            ////this.logger.LogInformation($"   Starting Proxy --> upstream request");
            var upstreamResponse = await httpClient.SendAsync(upstreamRequest, shortCancellation);

            // Detect connection downgrade, which may be problematic for e.g. gRPC.
            if (isIncomingHttp2 && upstreamResponse.Version.Major != 2)
            {
                // TODO: Do something on connection downgrade...
                Log.HttpDowngradeDeteced(_logger);
            }

            // Assert that, if we are proxying content upstream, it must have started by now
            // (since HttpClient.SendAsync has already completed asynchronously).
            // If this check fails, there is a coding defect which would otherwise
            // cause us to wait forever in step 9, so fail fast here.
            if (bodyToUpstreamContent != null && !bodyToUpstreamContent.Started)
            {
                // TODO: bodyToUpstreamContent is never null. HttpClient might would not need to read the body in some scenarios, such as an early auth failure with Expect: 100-continue.
                throw new InvalidOperationException("Proxying the downstream request body to the upstream server hasn't started. This is a coding defect.");
            }

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 5: Copy response status line Downstream ◄-- Proxy ◄-- Upstream
            ////this.logger.LogInformation($"   Setting downstream <-- Proxy status: {(int)upstreamResponse.StatusCode} {upstreamResponse.ReasonPhrase}");
            context.Response.StatusCode = (int)upstreamResponse.StatusCode;
            context.Features.Get <IHttpResponseFeature>().ReasonPhrase = upstreamResponse.ReasonPhrase;

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 6: Copy response headers Downstream ◄-- Proxy ◄-- Upstream
            CopyHeadersToDownstream(upstreamResponse, context.Response.Headers);

            // NOTE: it may *seem* wise to call `context.Response.StartAsync()` at this point
            // since it looks like we are ready to send back response headers
            // (and this might help reduce extra delays while we wait to receive the body from upstream).
            // HOWEVER, this would produce the wrong result if it turns out that there is no content
            // from the upstream -- instead of sending headers and terminating the stream at once,
            // we would send headers thinking a body may be coming, and there is none.
            // This is problematic on gRPC connections when the upstream server encounters an error,
            // in which case it immediately returns the response headers and trailing headers, but no content,
            // and clients misbehave if the initial headers response does not indicate stream end.

            // TODO: Some of the tasks in steps (7) - (9) may go unobserved depending on what fails first. Needs more consideration.

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 7: Copy response body Downstream ◄-- Proxy ◄-- Upstream
            await CopyBodyDownstreamAsync(upstreamResponse.Content, context.Response.Body, proxyTelemetryContext, longCancellation);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 8: Copy response trailer headers and finish response Downstream ◄-- Proxy ◄-- Upstream
            CopyTrailingHeadersToDownstream(upstreamResponse, context);

            if (isStreamingRequest)
            {
                // NOTE: We must call `CompleteAsync` so that Kestrel will flush all bytes to the client.
                // In the case where there was no response body,
                // this is also when headers and trailing headers are sent to the client.
                // Without this, the client might wait forever waiting for response bytes,
                // while we might wait forever waiting for request bytes,
                // leading to a stuck connection and no way to make progress.
                await context.Response.CompleteAsync();
            }

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 9: Wait for completion of step 2: copying request body Downstream --► Proxy --► Upstream
            if (bodyToUpstreamContent != null)
            {
                ////this.logger.LogInformation($"   Waiting for downstream --> Proxy --> upstream body proxying to complete");
                await bodyToUpstreamContent.ConsumptionTask;
            }
        }
예제 #28
0
        public void GetHttpProtocol_CorrectIETFVersion(Version version, string expected)
        {
            var actual = HttpProtocol.GetHttpProtocol(version);

            Assert.Equal(expected, actual);
        }
예제 #29
0
파일: Request.cs 프로젝트: fan92rus/GenHTTP
        internal Request(IServer server, IEndPoint endPoint, IClientConnection client, IClientConnection localClient, HttpProtocol protocol, FlexibleRequestMethod method,
                         RoutingTarget target, IHeaderCollection headers, ICookieCollection?cookies, IForwardingCollection?forwardings,
                         IRequestQuery?query, Stream?content)
        {
            Client      = client;
            LocalClient = localClient;

            Server   = server;
            EndPoint = endPoint;

            ProtocolType = protocol;
            Method       = method;
            Target       = target;

            _Cookies     = cookies;
            _Forwardings = forwardings;
            _Query       = query;

            Headers = headers;

            Content = content;
        }
예제 #30
0
 public void IsHttp10_Success(string protocol, bool match)
 {
     Assert.Equal(match, HttpProtocol.IsHttp10(protocol));
 }
 private static string GetCollectorUri(string endpoint, HttpProtocol protocol, int? port, HttpMethod method)
 {
     string path;
     string requestProtocol = (protocol == HttpProtocol.HTTP) ? "http" : "https";
     if (method == HttpMethod.GET)
     {
         path = "/i";
     }
     else
     {
         path = "/com.snowplowanalytics.snowplow/tp2";
     }
     if (port == null)
     {
         return String.Format("{0}://{1}{2}", requestProtocol, endpoint, path);
     }
     else
     {
         return String.Format("{0}://{1}:{2}{3}", requestProtocol, endpoint, port.ToString(), path);
     }
 }
 /// <summary>
 /// Asynchronous emitter to send non-blocking HTTP requests
 /// </summary>
 /// <param name="endpoint">Collector domain</param>
 /// <param name="protocol">HttpProtocol.HTTP or HttpProtocol.HTTPS</param>
 /// <param name="port">Port to connect to</param>
 /// <param name="method">HttpMethod.GET or HttpMethod.POST</param>
 /// <param name="bufferSize">Maximum number of events queued before the buffer is flushed automatically.
 /// Defaults to 10 for POST requests and 1 for GET requests.</param>
 /// <param name="onSuccess">Callback executed when every request in a flush has status code 200.
 /// Gets passed the number of events flushed.</param>
 /// <param name="onFailure">Callback executed when not every request in a flush has status code 200.
 /// Gets passed the number of events sent successfully and a list of unsuccessful events.</param>
 /// <param name="offlineModeEnabled">Whether to store unsent requests using MSMQ</param>
 public AsyncEmitter(string endpoint, HttpProtocol protocol = HttpProtocol.HTTP, int? port = null, HttpMethod method = HttpMethod.GET, int? bufferSize = null, Action<int> onSuccess = null, Action<int, List<Dictionary<string, string>>> onFailure = null, bool offlineModeEnabled = true)
     : base(endpoint, protocol, port, method, bufferSize, onSuccess, onFailure, offlineModeEnabled)
 {
     tasks = new List<Task>();
 }
 /// <summary>
 /// Sets the http protocol.
 /// </summary>
 /// <param name="httpProtocol">Http protocol.</param>
 public void SetHttpProtocol(HttpProtocol httpProtocol)
 {
     this.httpProtocol = httpProtocol;
     this.collectorUri = MakeCollectorUri(this.endpoint, this.httpProtocol, this.httpMethod);
 }
예제 #34
0
 protected HttpMessage(HttpProtocol protocol)
 {
     Protocol = protocol;
 }
예제 #35
0
        /// <summary>
        /// Proxies a normal (i.e. non-upgradable) request to the upstream server, and the response back to our client.
        /// </summary>
        /// <remarks>
        /// Normal proxying comprises the following steps:
        ///    (1)  Create outgoing HttpRequestMessage
        ///    (2)  Setup copy of request body (background)             Downstream --► Proxy --► Upstream
        ///    (3)  Copy request headers                                Downstream --► Proxy --► Upstream
        ///    (4)  Send the outgoing request using HttpMessageInvoker  Downstream --► Proxy --► Upstream
        ///    (5)  Copy response status line                           Downstream ◄-- Proxy ◄-- Upstream
        ///    (6)  Copy response headers                               Downstream ◄-- Proxy ◄-- Upstream
        ///    (7)  Send response headers                               Downstream ◄-- Proxy ◄-- Upstream
        ///    (8)  Copy response body                                  Downstream ◄-- Proxy ◄-- Upstream
        ///    (9)  Wait for completion of step 2: copying request body Downstream --► Proxy --► Upstream
        ///    (10) Copy response trailer headers                       Downstream ◄-- Proxy ◄-- Upstream
        ///
        /// ASP .NET Core (Kestrel) will finally send response trailers (if any)
        /// after we complete the steps above and relinquish control.
        /// </remarks>
        private async Task NormalProxyAsync(
            HttpContext context,
            Uri targetUri,
            HttpMessageInvoker httpClient,
            ProxyTelemetryContext proxyTelemetryContext,
            CancellationToken shortCancellation,
            CancellationToken longCancellation)
        {
            Contracts.CheckValue(context, nameof(context));
            Contracts.CheckValue(targetUri, nameof(targetUri));
            Contracts.CheckValue(httpClient, nameof(httpClient));

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 1: Create outgoing HttpRequestMessage
            var upstreamRequest = new HttpRequestMessage(HttpUtilities.GetHttpMethod(context.Request.Method), targetUri)
            {
                // We request HTTP/2, but HttpClient will fallback to HTTP/1.1 if it cannot establish HTTP/2 with the target.
                // This is done without extra round-trips thanks to ALPN. We can detect a downgrade after calling HttpClient.SendAsync
                // (see Step 3 below). TBD how this will change when HTTP/3 is supported.
                Version = Http2Version,
            };

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 2: Setup copy of request body (background) Downstream --► Proxy --► Upstream
            // Note that we must do this before step (3) because step (3) may also add headers to the HttpContent that we set up here.
            var bodyToUpstreamContent = SetupCopyBodyUpstream(context.Request.Body, upstreamRequest, in proxyTelemetryContext, longCancellation);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 3: Copy request headers Downstream --► Proxy --► Upstream
            CopyHeadersToUpstream(context.Request.Headers, upstreamRequest);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 4: Send the outgoing request using HttpClient
            ////this.logger.LogInformation($"   Starting Proxy --> upstream request");
            var upstreamResponse = await httpClient.SendAsync(upstreamRequest, shortCancellation);

            // Detect connection downgrade, which may be problematic for e.g. gRPC.
            if (upstreamResponse.Version.Major != 2 && HttpProtocol.IsHttp2(context.Request.Protocol))
            {
                // TODO: Do something on connection downgrade...
                _logger.LogInformation($"HTTP version downgrade detected! This may break gRPC communications.");
            }

            // Assert that, if we are proxying content upstream, it must have started by now
            // (since HttpClient.SendAsync has already completed asynchronously).
            // If this check fails, there is a coding defect which would otherwise
            // cause us to wait forever in step 9, so fail fast here.
            if (bodyToUpstreamContent != null && !bodyToUpstreamContent.Started)
            {
                throw new InvalidOperationException("Proxying the downstream request body to the upstream server hasn't started. This is a coding defect.");
            }

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 5: Copy response status line Downstream ◄-- Proxy ◄-- Upstream
            ////this.logger.LogInformation($"   Setting downstream <-- Proxy status: {(int)upstreamResponse.StatusCode} {upstreamResponse.ReasonPhrase}");
            context.Response.StatusCode = (int)upstreamResponse.StatusCode;
            context.Features.Get <IHttpResponseFeature>().ReasonPhrase = upstreamResponse.ReasonPhrase;

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 6: Copy response headers Downstream ◄-- Proxy ◄-- Upstream
            CopyHeadersToDownstream(upstreamResponse, context.Response.Headers);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 7: Send response headers Downstream ◄-- Proxy ◄-- Upstream
            // This is important to avoid any extra delays in sending response headers
            // e.g. if the upstream server is slow to provide its response body.
            ////this.logger.LogInformation($"   Starting downstream <-- Proxy response");
            // TODO: Some of the tasks in steps (7) - (9) may go unobserved depending on what fails first. Needs more consideration.
            await context.Response.StartAsync(shortCancellation);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 8: Copy response body Downstream ◄-- Proxy ◄-- Upstream
            await CopyBodyDownstreamAsync(upstreamResponse.Content, context.Response.Body, proxyTelemetryContext, longCancellation);

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 9: Wait for completion of step 2: copying request body Downstream --► Proxy --► Upstream
            if (bodyToUpstreamContent != null)
            {
                ////this.logger.LogInformation($"   Waiting for downstream --> Proxy --> upstream body proxying to complete");
                await bodyToUpstreamContent.ConsumptionTask;
            }

            // :::::::::::::::::::::::::::::::::::::::::::::
            // :: Step 10: Copy response trailer headers Downstream ◄-- Proxy ◄-- Upstream
            CopyTrailingHeadersToDownstream(upstreamResponse, context);
        }
 public Target()
 {
     Address = string.Empty;
     Port = -1;
     Protocol = HttpProtocol.HTTP;
 }
예제 #37
0
 public HttpRequest(HttpProtocol protocol, string method, string path, NameValueCollection headers)
     : base(protocol, headers)
 {
     Method = method;
     Path   = path;
 }