예제 #1
0
        public static async Task EndHttpHandlerRequestAsync(this IResponse httpRes, bool skipHeaders = false, bool skipClose = false, Func <IResponse, Task> afterHeaders = null)
        {
            if (!skipHeaders)
            {
                httpRes.ApplyGlobalResponseHeaders();
            }

            if (afterHeaders != null)
            {
                await afterHeaders(httpRes);
            }

            var req = httpRes.Request;

            if (req != null && !req.Items.ContainsKey(Keywords.HasLogged))
            {
                HostContext.TryResolve <IRequestLogger>()?
                .Log(req, req.Dto, null, TimeSpan.Zero);
            }

            if (!skipClose && !httpRes.IsClosed)
            {
                httpRes.Close();
            }

            HostContext.CompleteRequest(req);
        }
예제 #2
0
        public static async Task EndHttpHandlerRequestAsync(this IResponse httpRes, bool skipHeaders = false, bool skipClose = false, Func <IResponse, Task> afterHeaders = null)
        {
            if (!skipHeaders)
            {
                httpRes.ApplyGlobalResponseHeaders();
            }

            if (afterHeaders != null)
            {
                try
                {
                    await afterHeaders(httpRes).ConfigAwait();
                }
                catch (Exception e)
                {
                    var log = LogManager.LogFactory.GetLogger(typeof(HttpExtensions));
                    log.Error("Error executing async afterHeaders: " + e.Message, e);
                }
            }

            var req = httpRes.Request;

            if (req != null && !req.Items.ContainsKey(Keywords.HasLogged))
            {
                HostContext.TryResolve <IRequestLogger>()?.Log(req, req.Dto, httpRes.Dto, TimeSpan.Zero);
            }

            if (!skipClose && !httpRes.IsClosed)
            {
                await httpRes.CloseAsync().ConfigAwait();
            }

            HostContext.CompleteRequest(req);
        }
예제 #3
0
        public override Task ProcessRequestAsync(IRequest req, IResponse res, string operationName)
        {
            if (HostContext.ApplyCustomHandlerRequestFilters(req, res))
            {
                return(EmptyTask);
            }

            res.ApplyGlobalResponseHeaders();

            var feature = HostContext.GetPlugin <ServerEventsFeature>();

            if (feature.OnHeartbeatInit != null)
            {
                feature.OnHeartbeatInit(req);
            }

            var subscriptionId = req.QueryString["id"];

            if (!req.TryResolve <IServerEvents>().Pulse(subscriptionId))
            {
                res.StatusCode        = 404;
                res.StatusDescription = "Subscription {0} does not exist".Fmt(subscriptionId);
            }
            res.EndHttpHandlerRequest(skipHeaders: true);
            return(EmptyTask);
        }
예제 #4
0
        public override Task ProcessRequestAsync(IRequest req, IResponse res, string operationName)
        {
            if (HostContext.ApplyCustomHandlerRequestFilters(req, res))
            {
                return(TypeConstants.EmptyTask);
            }

            res.ApplyGlobalResponseHeaders();

            var serverEvents = req.TryResolve <IServerEvents>();

            serverEvents.RemoveExpiredSubscriptions();

            var feature = HostContext.GetPlugin <ServerEventsFeature>();

            if (feature.OnHeartbeatInit != null)
            {
                feature.OnHeartbeatInit(req);
            }

            if (req.Response.IsClosed)
            {
                return(TypeConstants.EmptyTask);
            }

            var subscriptionId = req.QueryString["id"];
            var subscription   = serverEvents.GetSubscriptionInfo(subscriptionId);

            if (subscription == null)
            {
                res.StatusCode        = 404;
                res.StatusDescription = ErrorMessages.SubscriptionNotExistsFmt.Fmt(subscriptionId);
                res.EndHttpHandlerRequest(skipHeaders: true);
                return(TypeConstants.EmptyTask);
            }

            if (!feature.CanAccessSubscription(req, subscription))
            {
                res.StatusCode        = 403;
                res.StatusDescription = "Invalid User Address";
                res.EndHttpHandlerRequest(skipHeaders: true);
                return(TypeConstants.EmptyTask);
            }

            if (!serverEvents.Pulse(subscriptionId))
            {
                res.StatusCode        = 404;
                res.StatusDescription = "Subscription {0} does not exist".Fmt(subscriptionId);
            }
            res.EndHttpHandlerRequest(skipHeaders: true);
            return(TypeConstants.EmptyTask);
        }
예제 #5
0
 /// <summary>
 /// End a HttpHandler Request
 /// </summary>
 public static void EndHttpHandlerRequest(this IResponse httpRes, bool skipHeaders = false, bool skipClose = false, Action <IResponse> afterHeaders = null)
 {
     if (!skipHeaders)
     {
         httpRes.ApplyGlobalResponseHeaders();
     }
     afterHeaders?.Invoke(httpRes);
     if (!skipClose && !httpRes.IsClosed)
     {
         httpRes.Close();
     }
     HostContext.CompleteRequest(httpRes.Request);
 }
예제 #6
0
        public static async Task WriteErrorToResponse(this IResponse httpRes, IRequest httpReq,
                                                      string contentType, string operationName, string errorMessage, Exception ex, int statusCode)
        {
            if (ex == null)
            {
                ex = new Exception(errorMessage);
            }

            var errorDto = ex.ToErrorResponse();

            httpRes.Dto = errorDto;
            HostContext.AppHost.OnExceptionTypeFilter(ex, errorDto.ResponseStatus);

            if (await HandleCustomErrorHandler(httpRes, httpReq, contentType, statusCode, errorDto, ex))
            {
                return;
            }

            if (!httpRes.HasStarted)
            {
                if ((httpRes.ContentType == null || httpRes.ContentType == MimeTypes.Html) &&
                    contentType != null && contentType != httpRes.ContentType)
                {
                    httpRes.ContentType = contentType;
                }
                if (HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(contentType))
                {
                    httpRes.ContentType += ContentFormat.Utf8Suffix;
                }

                var hold = httpRes.StatusDescription;
                var hasDefaultStatusDescription = hold == null || hold == "OK";

                httpRes.StatusCode = statusCode;

                httpRes.StatusDescription = hasDefaultStatusDescription
                    ? (errorMessage ?? HttpStatus.GetStatusDescription(statusCode))
                    : hold;

                httpRes.ApplyGlobalResponseHeaders();
            }

            var serializer = HostContext.ContentTypes.GetStreamSerializerAsync(contentType ?? httpRes.ContentType);

            if (serializer != null)
            {
                await serializer(httpReq, errorDto, httpRes.OutputStream);
            }

            httpRes.EndHttpHandlerRequest(skipHeaders: true);
        }
예제 #7
0
        /// <summary>
        /// End a HttpHandler Request
        /// </summary>
        public static void EndHttpHandlerRequest(this IResponse httpRes, bool skipHeaders = false, bool skipClose = false, Action <IResponse> afterHeaders = null)
        {
            if (!skipHeaders)
            {
                httpRes.ApplyGlobalResponseHeaders();
            }
            if (afterHeaders != null)
            {
                afterHeaders(httpRes);
            }
            if (!skipClose)
            {
                httpRes.Close();
            }

            //skipHeaders used when Apache+mod_mono doesn't like:
            //response.OutputStream.Flush();
            //response.Close();
        }
        public static void WriteBytesToResponse(this IResponse res, byte[] responseBytes, string contentType)
        {
            res.ContentType = HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(contentType)
                ? contentType + ContentFormat.Utf8Suffix
                : contentType;

            res.ApplyGlobalResponseHeaders();
            res.SetContentLength(responseBytes.Length);

            try
            {
                res.OutputStream.Write(responseBytes, 0, responseBytes.Length);
                res.Flush();
            }
            catch (Exception ex)
            {
                ex.HandleResponseWriteException(res.Request, res, contentType);
            }
            finally
            {
                res.EndRequest(skipHeaders: true);
            }
        }
예제 #9
0
        /// <summary>
        /// End a HttpHandler Request
        /// </summary>
        public static void EndHttpHandlerRequest(this IResponse httpRes, bool skipHeaders = false, bool skipClose = false, Action <IResponse> afterHeaders = null)
        {
            if (!skipHeaders)
            {
                httpRes.ApplyGlobalResponseHeaders();
            }

            afterHeaders?.Invoke(httpRes);

            var req = httpRes.Request;

            if (req != null && !req.Items.ContainsKey(Keywords.HasLogged))
            {
                HostContext.TryResolve <IRequestLogger>()?.Log(req, req.Dto, httpRes.Dto, TimeSpan.Zero);
            }

            if (!skipClose && !httpRes.IsClosed)
            {
                httpRes.Close();
            }

            HostContext.CompleteRequest(req);
        }
예제 #10
0
        public static async Task WriteBytesToResponse(this IResponse res, byte[] responseBytes, string contentType, CancellationToken token = default(CancellationToken))
        {
            res.ContentType = HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(contentType)
                ? contentType + ContentFormat.Utf8Suffix
                : contentType;

            res.ApplyGlobalResponseHeaders();
            res.SetContentLength(responseBytes.Length);

            try
            {
                await res.OutputStream.WriteAsync(responseBytes, token);

                await res.FlushAsync(token);
            }
            catch (Exception ex)
            {
                await ex.HandleResponseWriteException(res.Request, res, contentType);
            }
            finally
            {
                res.EndRequest(skipHeaders: true);
            }
        }
예제 #11
0
        public override Task ProcessRequestAsync(IRequest req, IResponse res, string operationName)
        {
            if (HostContext.ApplyCustomHandlerRequestFilters(req, res))
            {
                return(TypeConstants.EmptyTask);
            }

            var feature = HostContext.GetPlugin <ServerEventsFeature>();

            var session = req.GetSession();

            if (feature.LimitToAuthenticatedUsers && !session.IsAuthenticated)
            {
                session.ReturnFailedAuthentication(req);
                return(TypeConstants.EmptyTask);
            }

            res.ContentType = MimeTypes.ServerSentEvents;
            res.AddHeader(HttpHeaders.CacheControl, "no-cache");
            res.ApplyGlobalResponseHeaders();
            res.UseBufferedStream = false;
            res.KeepAlive         = true;

            if (feature.OnInit != null)
            {
                feature.OnInit(req);
            }

            res.Flush();

            var serverEvents = req.TryResolve <IServerEvents>();
            var userAuthId   = session != null ? session.UserAuthId : null;
            var anonUserId   = serverEvents.GetNextSequence("anonUser");
            var userId       = userAuthId ?? ("-" + anonUserId);
            var displayName  = session.GetSafeDisplayName()
                               ?? "user" + anonUserId;

            var now            = DateTime.UtcNow;
            var subscriptionId = SessionExtensions.CreateRandomSessionId();

            //Handle both ?channel=A,B,C or ?channels=A,B,C
            var channels = new List <string>();
            var channel  = req.QueryString["channel"];

            if (!string.IsNullOrEmpty(channel))
            {
                channels.AddRange(channel.Split(','));
            }
            channel = req.QueryString["channels"];
            if (!string.IsNullOrEmpty(channel))
            {
                channels.AddRange(channel.Split(','));
            }

            if (channels.Count == 0)
            {
                channels = EventSubscription.UnknownChannel.ToList();
            }

            var subscription = new EventSubscription(res)
            {
                CreatedAt       = now,
                LastPulseAt     = now,
                Channels        = channels.ToArray(),
                SubscriptionId  = subscriptionId,
                UserId          = userId,
                UserName        = session != null ? session.UserName : null,
                DisplayName     = displayName,
                SessionId       = req.GetSessionId(),
                IsAuthenticated = session != null && session.IsAuthenticated,
                UserAddress     = req.UserHostAddress,
                OnPublish       = feature.OnPublish,
                //OnError = feature.OnError,
                Meta =
                {
                    { "userId",                           userId                                                                 },
                    { "displayName",                      displayName                                                            },
                    { "channels",                         string.Join(",", channels)                                             },
                    { AuthMetadataProvider.ProfileUrlKey, session.GetProfileUrl() ?? AuthMetadataProvider.DefaultNoProfileImgUrl },
                }
            };

            if (feature.OnCreated != null)
            {
                feature.OnCreated(subscription, req);
            }

            if (req.Response.IsClosed)
            {
                return(TypeConstants.EmptyTask); //Allow short-circuiting in OnCreated callback
            }
            var heartbeatUrl = feature.HeartbeatPath != null
                ? req.ResolveAbsoluteUrl("~/".CombineWith(feature.HeartbeatPath)).AddQueryParam("id", subscriptionId)
                : null;

            var unRegisterUrl = feature.UnRegisterPath != null
                ? req.ResolveAbsoluteUrl("~/".CombineWith(feature.UnRegisterPath)).AddQueryParam("id", subscriptionId)
                : null;

            heartbeatUrl  = AddSessionParamsIfAny(heartbeatUrl, req);
            unRegisterUrl = AddSessionParamsIfAny(unRegisterUrl, req);

            subscription.ConnectArgs = new Dictionary <string, string>(subscription.Meta)
            {
                { "id", subscriptionId },
                { "unRegisterUrl", unRegisterUrl },
                { "heartbeatUrl", heartbeatUrl },
                { "updateSubscriberUrl", req.ResolveAbsoluteUrl("~/event-subscribers/" + subscriptionId) },
                { "heartbeatIntervalMs", ((long)feature.HeartbeatInterval.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) },
                { "idleTimeoutMs", ((long)feature.IdleTimeout.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }
            };

            if (feature.OnConnect != null)
            {
                feature.OnConnect(subscription, subscription.ConnectArgs);
            }

            serverEvents.Register(subscription, subscription.ConnectArgs);

            var tcs = new TaskCompletionSource <bool>();

            subscription.OnDispose = _ =>
            {
                try
                {
                    res.EndHttpHandlerRequest(skipHeaders: true);
                }
                catch { }
                tcs.SetResult(true);
            };

            return(tcs.Task);
        }
예제 #12
0
        public static async Task WriteErrorToResponse(this IResponse httpRes, IRequest httpReq,
                                                      string contentType, string operationName, string errorMessage, Exception ex, int statusCode)
        {
            if (ex == null)
            {
                ex = new Exception(errorMessage);
            }

            httpRes.Dto = HostContext.AppHost.CreateErrorResponse(ex, request: httpReq?.Dto);

            if (await HandleCustomErrorHandler(httpRes, httpReq, contentType, statusCode, httpRes.Dto, ex))
            {
                return;
            }

            var hostConfig = HostContext.Config;

            if (!httpRes.HasStarted)
            {
                if ((httpRes.ContentType == null || httpRes.ContentType == MimeTypes.Html) &&
                    contentType != null && contentType != httpRes.ContentType)
                {
                    httpRes.ContentType = contentType;
                }
                if (hostConfig.AppendUtf8CharsetOnContentTypes.Contains(contentType))
                {
                    httpRes.ContentType += ContentFormat.Utf8Suffix;
                }

                var hold = httpRes.StatusDescription;
                var hasDefaultStatusDescription = hold is null or "OK";

                httpRes.StatusCode = statusCode;

                httpRes.StatusDescription = hasDefaultStatusDescription
                    ? (errorMessage ?? HttpStatus.GetStatusDescription(statusCode))
                    : hold;

                httpRes.ApplyGlobalResponseHeaders();
            }

            var callback = httpReq.GetJsonpCallback();
            var doJsonp  = hostConfig.AllowJsonpRequests && !string.IsNullOrEmpty(callback);

            if (doJsonp)
            {
                httpRes.StatusCode = 200;
                await httpRes.OutputStream.WriteAsync(DataCache.CreateJsonpPrefix(callback));
            }

            var serializer = HostContext.ContentTypes.GetStreamSerializerAsync(contentType ?? httpRes.ContentType);

            if (serializer != null)
            {
                var jsconfig = hostConfig.AllowJsConfig ? httpReq?.QueryString[Keywords.JsConfig] : null;
                using (jsconfig != null ? JsConfig.CreateScope(jsconfig) : null)
                {
                    await serializer(httpReq, httpRes.Dto, httpRes.OutputStream);
                }
            }

            if (doJsonp)
            {
                await httpRes.OutputStream.WriteAsync(DataCache.JsonpSuffix);
            }

            httpRes.EndHttpHandlerRequest(skipHeaders: true);
        }
예제 #13
0
        public override Task ProcessRequestAsync(IRequest req, IResponse res, string operationName)
        {
            var feature = HostContext.GetPlugin <ServerEventsFeature>();

            var session = req.GetSession();

            if (feature.LimitToAuthenticatedUsers && !session.IsAuthenticated)
            {
                session.ReturnFailedAuthentication(req);
                return(EmptyTask);
            }

            res.ContentType = MimeTypes.ServerSentEvents;
            res.AddHeader(HttpHeaders.CacheControl, "no-cache");
            res.ApplyGlobalResponseHeaders();
            res.UseBufferedStream = false;
            res.KeepAlive         = true;

            if (feature.OnInit != null)
            {
                feature.OnInit(req);
            }

            res.Flush();

            var serverEvents = req.TryResolve <IServerEvents>();
            var userAuthId   = session != null ? session.UserAuthId : null;
            var anonUserId   = serverEvents.GetNextSequence("anonUser");
            var userId       = userAuthId ?? ("-" + anonUserId);
            var displayName  = session.GetSafeDisplayName()
                               ?? "user" + anonUserId;

            var now            = DateTime.UtcNow;
            var subscriptionId = SessionExtensions.CreateRandomSessionId();
            var subscription   = new EventSubscription(res)
            {
                CreatedAt       = now,
                LastPulseAt     = now,
                Channel         = req.QueryString["channel"] ?? EventSubscription.UnknownChannel,
                SubscriptionId  = subscriptionId,
                UserId          = userId,
                UserName        = session != null ? session.UserName : null,
                DisplayName     = displayName,
                SessionId       = req.GetPermanentSessionId(),
                IsAuthenticated = session != null && session.IsAuthenticated,
                OnPublish       = feature.OnPublish,
                Meta            =
                {
                    { "userId",                           userId                                                                 },
                    { "displayName",                      displayName                                                            },
                    { AuthMetadataProvider.ProfileUrlKey, session.GetProfileUrl() ?? AuthMetadataProvider.DefaultNoProfileImgUrl },
                }
            };

            if (feature.OnCreated != null)
            {
                feature.OnCreated(subscription, req);
            }

            var heartbeatUrl = req.ResolveAbsoluteUrl("~/".CombineWith(feature.HeartbeatPath))
                               .AddQueryParam("id", subscriptionId);
            var unRegisterUrl = req.ResolveAbsoluteUrl("~/".CombineWith(feature.UnRegisterPath))
                                .AddQueryParam("id", subscriptionId);
            var privateArgs = new Dictionary <string, string>(subscription.Meta)
            {
                { "id", subscriptionId },
                { "unRegisterUrl", unRegisterUrl },
                { "heartbeatUrl", heartbeatUrl },
                { "heartbeatIntervalMs", ((long)feature.HeartbeatInterval.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) },
                { "idleTimeoutMs", ((long)feature.IdleTimeout.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }
            };

            if (feature.OnConnect != null)
            {
                feature.OnConnect(subscription, privateArgs);
            }

            serverEvents.Register(subscription, privateArgs);

            var tcs = new TaskCompletionSource <bool>();

            subscription.OnDispose = _ =>
            {
                try
                {
                    res.EndHttpHandlerRequest(skipHeaders: true);
                }
                catch { }
                tcs.SetResult(true);
            };

            return(tcs.Task);
        }