예제 #1
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                var nextState = handler.VclSynth(vclContext);

                SwitchState(handler, nextState);
                return(Task.CompletedTask);
            }
예제 #2
0
            public override Task ExecuteAsync(VclHandler handler, VclContext vclContext)
            {
                // Handle case where we exceed number of backend retries
                if (++handler._backendAttempt >= handler.MaxBackendRetries)
                {
                    SwitchState(handler, VclBackendAction.Abandon);
                    return(Task.CompletedTask);
                }

                // Setup BE request parameters
                vclContext.BackendRequest =
                    new VclBackendRequest
                {
                    Method = vclContext.Request.Method,
                    Uri    = vclContext.Request.Url
                };
                foreach (var entry in vclContext.Request.Headers)
                {
                    vclContext.BackendRequest.Headers.Add(entry.Key, entry.Value);
                }

                // TODO: Handle translation of certain request METHOD values
                // TODO: Handle filtering out certain HTTP headers
                // TODO: Handle adding/modifying certain HTTP headers

                // Enter fetch state
                SwitchState(handler, VclBackendAction.Fetch);
                return(Task.CompletedTask);
            }
예제 #3
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Copy information from object into response
                vclContext.Response =
                    new VclResponse
                {
                    StatusCode        = vclContext.Object.StatusCode,
                    StatusDescription = vclContext.Object.StatusDescription,
                };

                foreach (var header in vclContext.Object.Headers)
                {
                    vclContext.Response.Headers.Add(header.Key, header.Value);
                }

                if (vclContext.Object.Body != null)
                {
                    vclContext.Response.CopyBodyFrom(vclContext.Object.Body);
                }

                // Get result of calling extended code
                var nextState = handler.VclDeliver(vclContext);

                // Translate official supported action into internal code
                if (nextState == VclFrontendAction.Deliver)
                {
                    nextState = VclFrontendAction.DeliverContent;
                }

                SwitchState(handler, nextState);
                return(Task.CompletedTask);
            }
예제 #4
0
            public override Task ExecuteAsync(VclHandler handler, VclContext vclContext)
            {
                // Disconnect backend request/response objects (unless we are in pipe mode)
                vclContext.BackendRequest  = null;
                vclContext.BackendResponse = null;

                return(Task.CompletedTask);
            }
예제 #5
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Allow VCL to tweak receive parameters
                var nextState = handler.VclReceive(vclContext);

                SwitchState(handler, nextState);
                return(Task.CompletedTask);
            }
예제 #6
0
            protected virtual void SwitchState(VclHandler handler, VclFrontendAction frontendAction)
            {
                if (!ValidTransitionStates.Contains(frontendAction))
                {
                    throw new InvalidOperationException($"Invalid attempt to transition front-end from {State} to {frontendAction}.");
                }

                handler.Logger?.LogDebug($"Client state transition from {State} to {frontendAction}");
                handler._currentFrontendState = VclFrontendHandlerStateFactory.Get(frontendAction);
            }
예제 #7
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Get result of calling extended code
                var nextState = handler.VclError(vclContext);

                // Translate official supported action into internal code
                if (nextState == VclFrontendAction.Deliver)
                {
                    nextState = VclFrontendAction.DeliverContent;
                }

                SwitchState(handler, nextState);
                return(Task.CompletedTask);
            }
예제 #8
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Attempt to do a lookup given the hash code
                var result = handler.Cache.Get <VclObject>($"VclObject:{vclContext.Request.Hash}");

                if (result == null)
                {
                    SwitchState(handler, VclFrontendAction.Miss);
                }
                else
                {
                    vclContext.Object = result;
                    SwitchState(handler, VclFrontendAction.Hit);
                }
                return(Task.CompletedTask);
            }
예제 #9
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Setup real response
                requestContext.Response.StatusCode   = vclContext.Response.StatusCode;
                requestContext.Response.ReasonPhrase = vclContext.Response.StatusDescription;
                foreach (var header in vclContext.Response.Headers)
                {
                    requestContext.Response.Headers.Add(header.Key, new StringValues(header.Value));
                }

                // Copy content body if we have one
                vclContext.Response.Body?.CopyTo(requestContext.Response.Body);

                // TODO: Setup cache TTL value (this uses kernel caching in HTTP.SYS driver)
                //requestContext.Response.CacheTtl = TimeSpan.FromSeconds(vclContext.Response.)

                SwitchState(handler, VclFrontendAction.Done);
                return(Task.CompletedTask);
            }
예제 #10
0
            public override Task ExecuteAsync(VclHandler handler, VclContext vclContext)
            {
                var result = handler.VclBackendResponse(vclContext);

                if (result != VclBackendAction.Deliver)
                {
                    SwitchState(handler, result);
                }

                // Create an object from the response
                vclContext.Object =
                    new VclObject
                {
                    StatusCode        = vclContext.BackendResponse.StatusCode,
                    StatusDescription = vclContext.BackendResponse.StatusDescription,
                    DoEsiProcessing   = vclContext.BackendResponse.DoEsiProcessing,
                    Uncacheable       = vclContext.BackendResponse.Uncacheable,
                    Ttl = vclContext.BackendResponse.Ttl,
                };
                foreach (var header in vclContext.BackendResponse.Headers)
                {
                    vclContext.Object.Headers.Add(header.Key, header.Value);
                }

                if (vclContext.BackendResponse.Body != null)
                {
                    vclContext.Object.CopyBodyFrom(vclContext.BackendResponse.Body);
                }

                // Handle caching the object if we are allowed to
                if (!vclContext.Object.Uncacheable)
                {
                    handler.Cache.Set(
                        $"VclObject:{vclContext.Request.Hash}",
                        vclContext.Object,
                        TimeSpan.FromSeconds(vclContext.Object.Ttl));
                }

                SwitchState(handler, result);
                return(Task.CompletedTask);
            }
예제 #11
0
            public override async Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Instruct backend request to execute
                var result = await handler
                             .ProcessBackendFetchAsync(vclContext)
                             .ConfigureAwait(false);

                // Detect error state and force request restart
                if (result == VclBackendAction.Abandon)
                {
                    SwitchState(handler, VclFrontendAction.Restart);
                    return;
                }

                // If the result is cachable then do it now
                if (!vclContext.BackendResponse.Uncacheable)
                {
                }

                SwitchState(handler, VclFrontendAction.Deliver);
            }
예제 #12
0
            public override Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext)
            {
                // Update restart count and abort with hard error if we exceed max-retries
                vclContext.Request.Restarts++;
                if (vclContext.Request.Restarts >= handler.MaxFrontendRetries)
                {
                    vclContext.Response =
                        new VclResponse
                    {
                        StatusCode        = 500,
                        StatusDescription = "IMProxy request failed"
                    };
                    SwitchState(handler, VclFrontendAction.Synth);
                    return(Task.CompletedTask);
                }

                vclContext.Local.Ip        = requestContext.Request.LocalIpAddress;
                vclContext.Remote.Ip       = requestContext.Request.RemoteIpAddress;
                vclContext.Client.Ip       = requestContext.Request.RemoteIpAddress;
                vclContext.Client.Port     = requestContext.Request.RemotePort;
                vclContext.Server.HostName = Environment.MachineName;
                vclContext.Server.Identity = "foobar";
                vclContext.Server.Ip       = requestContext.Request.LocalIpAddress;
                vclContext.Server.Port     = requestContext.Request.LocalPort;
                vclContext.Request.Method  = requestContext.Request.Method;
                vclContext.Request.Url     = requestContext.Request.RawUrl;
                vclContext.Request.CanGzip =
                    requestContext.Request.Headers["Accept-Encoding"].Equals("gzip") ||
                    requestContext.Request.Headers["Accept-Encoding"].Equals("x-gzip");
                vclContext.Request.ProtocolVersion = requestContext.Request.ProtocolVersion.ToString(2);
                foreach (var header in requestContext.Request.Headers)
                {
                    vclContext.Request.Headers.Add(header.Key, header.Value.ToString());
                }

                SwitchState(handler, VclFrontendAction.Receive);
                return(Task.CompletedTask);
            }
예제 #13
0
 public override Task ExecuteAsync(VclHandler handler, VclContext vclContext)
 {
     return(Task.CompletedTask);
 }
예제 #14
0
 public abstract Task ExecuteAsync(VclHandler handler, RequestContext requestContext, VclContext vclContext);
예제 #15
0
            public override async Task ExecuteAsync(VclHandler handler, VclContext vclContext)
            {
                var result = handler.VclBackendFetch(vclContext);

                if (result != VclBackendAction.Fetch)
                {
                    SwitchState(handler, result);
                    return;
                }

                // Issue request to backend
                var httpClient     = new HttpClient();
                var backendRequest =
                    new HttpRequestMessage
                {
                    Method     = new HttpMethod(vclContext.BackendRequest.Method),
                    RequestUri = new Uri(vclContext.BackendRequest.Uri)
                };

                foreach (var entry in vclContext.BackendRequest.Headers)
                {
                    backendRequest.Headers.Add(entry.Key, entry.Value);
                }

                // Get raw response from backend
                var backendResponse = await httpClient
                                      .SendAsync(backendRequest)
                                      .ConfigureAwait(false);

                // Setup VCL backend response
                vclContext.BackendResponse =
                    new VclBackendResponse
                {
                    StatusCode        = (int)backendResponse.StatusCode,
                    StatusDescription = backendResponse.ReasonPhrase
                };
                foreach (var item in backendResponse.Headers)
                {
                    vclContext.BackendResponse.Headers.Add(item.Key, string.Join(",", item.Value));
                }

                // Detect backend error
                if (!backendResponse.IsSuccessStatusCode)
                {
                    SwitchState(handler, VclBackendAction.Error);
                    return;
                }

                // If we have a content body in the response then copy it now
                // TODO: May need to steal VirtualStream code that uses MemoryStream until content
                //  exceeds certain size where it switches to a temporary file
                if (backendResponse.Content != null)
                {
                    using (var contentBodyStream = await backendResponse.Content.ReadAsStreamAsync())
                    {
                        vclContext.BackendResponse.CopyBodyFrom(contentBodyStream);
                    }
                }

                // Setup response TTL value
                if (backendResponse.Headers.CacheControl.SharedMaxAge != null)
                {
                    vclContext.BackendResponse.Ttl = (int)backendResponse.Headers.CacheControl.SharedMaxAge.Value.TotalSeconds;
                }
                else if (backendResponse.Headers.CacheControl.MaxAge != null)
                {
                    vclContext.BackendResponse.Ttl = (int)backendResponse.Headers.CacheControl.MaxAge.Value.TotalSeconds;
                }
                else if (backendResponse.Headers.TryGetValues("Expires", out var expiryValues))
                {
                    var expiryDate = DateTime.Parse(expiryValues.First());
                    vclContext.BackendResponse.Ttl = (int)(expiryDate - DateTime.UtcNow).TotalSeconds;
                }
                else
                {
                    vclContext.BackendResponse.Ttl = handler.DefaultTtl;
                }

                // Switch state
                SwitchState(handler, VclBackendAction.Response);
            }
예제 #16
0
 public abstract Task ExecuteAsync(VclHandler handler, VclContext vclContext);