internal static Task <bool> HandleResponseWriteException(this Exception originalEx, IRequest request, IResponse response, string defaultContentType)
        {
            HostContext.RaiseAndHandleUncaughtException(request, response, request.OperationName, originalEx);

            if (!HostContext.Config.WriteErrorsToResponse)
            {
                return(originalEx.AsTaskException <bool>());
            }

            var errorMessage = $"Error occured while Processing Request: [{originalEx.GetType().GetOperationName()}] {originalEx.Message}";

            try
            {
                if (!response.IsClosed)
                {
                    response.WriteErrorToResponse(
                        request,
                        defaultContentType ?? request.ResponseContentType,
                        request.OperationName,
                        errorMessage,
                        originalEx,
                        (int)HttpStatusCode.InternalServerError);
                }
            }
            catch (Exception writeErrorEx)
            {
                //Exception in writing to response should not hide the original exception
                Log.Info("Failed to write error to response: {0}", writeErrorEx);
                return(originalEx.AsTaskException <bool>());
            }
            return(TypeConstants.TrueTask);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Writes to response.
        /// Response headers are customizable by implementing IHasOptions an returning Dictionary of Http headers.
        /// </summary>
        /// <param name="response">The response.</param>
        /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param>
        /// <param name="defaultAction">The default action.</param>
        /// <param name="request">The serialization context.</param>
        /// <param name="bodyPrefix">Add prefix to response body if any</param>
        /// <param name="bodySuffix">Add suffix to response body if any</param>
        /// <returns></returns>
        public static Task <bool> WriteToResponse(this IResponse response, object result, ResponseSerializerDelegate defaultAction, IRequest request, byte[] bodyPrefix, byte[] bodySuffix)
        {
            using (Profiler.Current.Step("Writing to Response"))
            {
                var defaultContentType = request.ResponseContentType;
                try
                {
                    if (result == null)
                    {
                        response.EndRequestWithNoContent();
                        return(TrueTask);
                    }

                    ApplyGlobalResponseHeaders(response);

                    IDisposable resultScope = null;

                    var httpResult = result as IHttpResult;
                    if (httpResult != null)
                    {
                        if (httpResult.ResultScope != null)
                        {
                            resultScope = httpResult.ResultScope();
                        }

                        if (httpResult.RequestContext == null)
                        {
                            httpResult.RequestContext = request;
                        }

                        var paddingLength = bodyPrefix != null ? bodyPrefix.Length : 0;
                        if (bodySuffix != null)
                        {
                            paddingLength += bodySuffix.Length;
                        }

                        httpResult.PaddingLength = paddingLength;

                        var httpError = httpResult as IHttpError;
                        if (httpError != null)
                        {
                            response.Dto = httpError.CreateErrorResponse();
                            if (response.HandleCustomErrorHandler(request,
                                                                  defaultContentType, httpError.Status, response.Dto))
                            {
                                return(TrueTask);
                            }
                        }

                        response.Dto = response.Dto ?? httpResult.GetDto();

                        response.StatusCode        = httpResult.Status;
                        response.StatusDescription = (httpResult.StatusDescription ?? httpResult.StatusCode.ToString()).Localize(request);
                        if (string.IsNullOrEmpty(httpResult.ContentType))
                        {
                            httpResult.ContentType = defaultContentType;
                        }
                        response.ContentType = httpResult.ContentType;

                        if (httpResult.Cookies != null)
                        {
                            foreach (var cookie in httpResult.Cookies)
                            {
                                response.SetCookie(cookie);
                            }
                        }
                    }
                    else
                    {
                        response.Dto = result;
                    }

                    /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */
                    var responseOptions = result as IHasOptions;
                    if (responseOptions != null)
                    {
                        //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction)
                        const string reservedOptions = ".";

                        foreach (var responseHeaders in responseOptions.Options)
                        {
                            if (responseHeaders.Key.Contains(reservedOptions))
                            {
                                continue;
                            }
                            if (responseHeaders.Key == HttpHeaders.ContentLength)
                            {
                                response.SetContentLength(long.Parse(responseHeaders.Value));
                                continue;
                            }

                            if (Log.IsDebugEnabled)
                            {
                                Log.DebugFormat("Setting Custom HTTP Header: {0}: {1}", responseHeaders.Key, responseHeaders.Value);
                            }

                            if (Env.IsMono && responseHeaders.Key.EqualsIgnoreCase(HttpHeaders.ContentType))
                            {
                                response.ContentType = responseHeaders.Value;
                            }
                            else
                            {
                                response.AddHeader(responseHeaders.Key, responseHeaders.Value);
                            }
                        }
                    }

                    //ContentType='text/html' is the default for a HttpResponse
                    //Do not override if another has been set
                    if (response.ContentType == null || response.ContentType == MimeTypes.Html)
                    {
                        response.ContentType = defaultContentType;
                    }
                    if (bodyPrefix != null && response.ContentType.IndexOf(MimeTypes.Json, StringComparison.InvariantCultureIgnoreCase) >= 0)
                    {
                        response.ContentType = MimeTypes.JavaScript;
                    }

                    if (HostContext.Config.AppendUtf8CharsetOnContentTypes.Contains(response.ContentType))
                    {
                        response.ContentType += ContentFormat.Utf8Suffix;
                    }

                    using (resultScope)
                    {
                        var disposableResult = result as IDisposable;
                        if (WriteToOutputStream(response, result, bodyPrefix, bodySuffix))
                        {
                            response.Flush(); //required for Compression
                            if (disposableResult != null)
                            {
                                disposableResult.Dispose();
                            }
                            return(TrueTask);
                        }

                        if (httpResult != null)
                        {
                            result = httpResult.Response;
                        }

                        var responseText = result as string;
                        if (responseText != null)
                        {
                            if (bodyPrefix != null)
                            {
                                response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length);
                            }
                            WriteTextToResponse(response, responseText, defaultContentType);
                            if (bodySuffix != null)
                            {
                                response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length);
                            }
                            return(TrueTask);
                        }

                        if (defaultAction == null)
                        {
                            throw new ArgumentNullException("defaultAction", String.Format(
                                                                "As result '{0}' is not a supported responseType, a defaultAction must be supplied",
                                                                (result != null ? result.GetType().GetOperationName() : "")));
                        }

                        if (bodyPrefix != null)
                        {
                            response.OutputStream.Write(bodyPrefix, 0, bodyPrefix.Length);
                        }

                        if (result != null)
                        {
                            defaultAction(request, result, response);
                        }

                        if (bodySuffix != null)
                        {
                            response.OutputStream.Write(bodySuffix, 0, bodySuffix.Length);
                        }

                        if (disposableResult != null)
                        {
                            disposableResult.Dispose();
                        }
                    }

                    return(FalseTask);
                }
                catch (Exception originalEx)
                {
                    HostContext.RaiseAndHandleUncaughtException(request, response, request.OperationName, originalEx);

                    if (!HostContext.Config.WriteErrorsToResponse)
                    {
                        return(originalEx.AsTaskException <bool>());
                    }

                    var errorMessage = String.Format(
                        "Error occured while Processing Request: [{0}] {1}", originalEx.GetType().GetOperationName(), originalEx.Message);

                    try
                    {
                        if (!response.IsClosed)
                        {
                            response.WriteErrorToResponse(
                                request,
                                defaultContentType,
                                request.OperationName,
                                errorMessage,
                                originalEx,
                                (int)HttpStatusCode.InternalServerError);
                        }
                    }
                    catch (Exception writeErrorEx)
                    {
                        //Exception in writing to response should not hide the original exception
                        Log.Info("Failed to write error to response: {0}", writeErrorEx);
                        return(originalEx.AsTaskException <bool>());
                    }
                    return(TrueTask);
                }
                finally
                {
                    response.EndRequest(skipHeaders: true);
                }
            }
        }