File: HostedHttpTransportManager.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (282 lines) | stat: -rw-r--r-- 11,512 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------------------
namespace System.ServiceModel.Activation
{
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.Security;
    using System.Security.Permissions;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Dispatcher;
    using System.Threading;
    using System.Web;

    class HostedHttpTransportManager : HttpTransportManager
    {
        string scheme;
        int port;
        string host;
        static AsyncCallback onHttpContextReceived = Fx.ThunkCallback(OnHttpContextReceived);

        internal HostedHttpTransportManager(BaseUriWithWildcard baseAddress) :
            base(baseAddress.BaseAddress, baseAddress.HostNameComparisonMode)
        {
            base.IsHosted = true;
        }

        internal override bool IsCompatible(HttpChannelListener factory)
        {
            return true;
        }

        internal override void OnClose(TimeSpan timeout)
        {
            // empty
        }

        internal override void OnOpen()
        {
            // empty
        }

        internal override void OnAbort()
        {
            // empty
        }

        internal override string Scheme
        {
            get
            {
                return this.scheme ?? (this.scheme = this.ListenUri.Scheme);
            }
        }

        internal string Host
        {
            get
            {
                return this.host ?? (this.host = this.ListenUri.Host);
            }
        }

        internal int Port
        {
            get
            {
                return this.port == 0 ? (this.port = this.ListenUri.Port) : this.port;
            }
        }

        static bool canTraceConnectionInformation = true;
        public void TraceConnectionInformation(HostedHttpRequestAsyncResult result)
        {
            if (result != null && DiagnosticUtility.ShouldTraceInformation && canTraceConnectionInformation)
            {
                try
                {
                    AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
                    IServiceProvider provider = (IServiceProvider)result.Application.Context;
                    HttpWorkerRequest workerRequest = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
                    string localAddress = string.Format(CultureInfo.InvariantCulture,
                        "{0}:{1}", workerRequest.GetLocalAddress(), workerRequest.GetLocalPort());
                    string remoteAddress = string.Format(CultureInfo.InvariantCulture,
                        "{0}:{1}", workerRequest.GetRemoteAddress(), workerRequest.GetRemotePort());
                    TraceUtility.TraceHttpConnectionInformation(localAddress, remoteAddress, this);
                }
                catch (SecurityException e)
                {
                    canTraceConnectionInformation = false;

                    // not re-throwing on purpose
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
                }
            }
        }

        [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Only returns the activity, doesn't leak the ASP .NET objects.")]
        [SecuritySafeCritical]
        public ServiceModelActivity CreateReceiveBytesActivity(HostedHttpRequestAsyncResult result)
        {
            ServiceModelActivity retval = null;
            if (result != null)
            {
                TraceMessageReceived(result.EventTraceActivity, result.RequestUri);
                if (DiagnosticUtility.ShouldUseActivity)
                {
                    IServiceProvider provider = (IServiceProvider)result.Application.Context;
                    retval = ServiceModelActivity.CreateBoundedActivity(GetRequestTraceIdentifier(provider));
                    StartReceiveBytesActivity(retval, result.RequestUri);
                }
            }
            return retval;
        }

        [Fx.Tag.SecurityNote(Critical = "Uses the HttpWorkerRequest to get the trace identifier, which Demands UnamangedCode.", Safe = "Only returns the trace id, doesn't leak the HttpWorkerRequest.")]
        [SecuritySafeCritical]
        [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
        static Guid GetRequestTraceIdentifier(IServiceProvider provider)
        {
            AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
            return ((HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest))).RequestTraceIdentifier;
        }

        internal void HttpContextReceived(HostedHttpRequestAsyncResult result)
        {
            using (DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.BoundOperation(this.Activity) : null)
            {
                using (ServiceModelActivity activity = this.CreateReceiveBytesActivity(result))
                {
                    this.TraceConnectionInformation(result);
                    HttpChannelListener listener;

                    if (base.TryLookupUri(result.RequestUri, result.GetHttpMethod(),
                        this.HostNameComparisonMode, result.IsWebSocketRequest, out listener))
                    {
                        HostedHttpContext hostedContext = new HostedHttpContext(listener, result);
                        object state = DiagnosticUtility.ShouldUseActivity ? (object)new ActivityHolder(activity, hostedContext) : (object)hostedContext;
                        IAsyncResult httpContextReceivedResult = listener.BeginHttpContextReceived(hostedContext,
                                                                                                        null,
                                                                                                        onHttpContextReceived,
                                                                                                        state);
                        if (httpContextReceivedResult.CompletedSynchronously)
                        {
                            EndHttpContextReceived(httpContextReceivedResult);
                        }

                        return;
                    }

                    if (DiagnosticUtility.ShouldTraceError)
                    {
                        TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.HttpChannelMessageReceiveFailed, SR.TraceCodeHttpChannelMessageReceiveFailed,
                            new StringTraceRecord("IsRecycling", ServiceHostingEnvironment.IsRecycling.ToString(CultureInfo.CurrentCulture)),
                            this, null);
                    }

                    if (ServiceHostingEnvironment.IsRecycling)
                    {
                        throw FxTrace.Exception.AsError(
                            new EndpointNotFoundException(SR.Hosting_ListenerNotFoundForActivationInRecycling(result.RequestUri.ToString())));
                    }
                    else
                    {
                        throw FxTrace.Exception.AsError(
                            new EndpointNotFoundException(SR.Hosting_ListenerNotFoundForActivation(result.RequestUri.ToString())));
                    }
                }
            }
        }

        static void EndHttpContextReceived(IAsyncResult httpContextReceivedResult)
        {
            using (DiagnosticUtility.ShouldUseActivity ? (ActivityHolder)httpContextReceivedResult.AsyncState : null)
            {
                HttpChannelListener channelListener =
                    (DiagnosticUtility.ShouldUseActivity ?
                        ((ActivityHolder)httpContextReceivedResult.AsyncState).context :
                        (HttpRequestContext)httpContextReceivedResult.AsyncState).Listener;

                channelListener.EndHttpContextReceived(httpContextReceivedResult);
            }
        }

        static void OnHttpContextReceived(IAsyncResult httpContextReceivedResult)
        {
            if (httpContextReceivedResult.CompletedSynchronously)
            {
                return;
            }

            Exception completionException = null;
            try
            {
                EndHttpContextReceived(httpContextReceivedResult);
            }
            catch (Exception exception)
            {
                if (Fx.IsFatal(exception))
                {
                    throw;
                }

                completionException = exception;
            }

            if (completionException != null)
            {
                HostedHttpContext context =
                    (HostedHttpContext)(DiagnosticUtility.ShouldUseActivity ?
                        ((ActivityHolder)httpContextReceivedResult.AsyncState).context :
                        httpContextReceivedResult.AsyncState);

                context.CompleteWithException(completionException);
            }
        }
    }

    [Fx.Tag.SecurityNote(Critical = "Captures HttpContext.Current on construction, then can apply that state at a later time and reset on Dispose."
        + "Whole object is critical because where it was initially constructed can be used to control HttpContext.set_Current later and HttpContext.set_Current requires an elevation")]
#pragma warning disable 618 // have not moved to the v4 security model yet
    [SecurityCritical(SecurityCriticalScope.Everything)]
#pragma warning restore 618
    class HostedThreadData
    {
        CultureInfo cultureInfo;
        CultureInfo uiCultureInfo;
        HttpContext httpContext;

        public HostedThreadData()
        {
            this.cultureInfo = CultureInfo.CurrentCulture;
            this.uiCultureInfo = CultureInfo.CurrentUICulture;
            this.httpContext = HttpContext.Current;
        }

        public IDisposable CreateContext()
        {
            return new HostedAspNetContext(this);
        }

        [SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
        static void UnsafeApplyData(HostedThreadData data)
        {
            // We set the CallContext.HostContext directly instead of setting HttpContext.Current because
            // the latter uses a demand instead of a link demand, which is very expensive in partial trust.
            System.Runtime.Remoting.Messaging.CallContext.HostContext = data.httpContext;
            
            Thread currentThread = Thread.CurrentThread;
            if (currentThread.CurrentCulture != data.cultureInfo)
            {
                currentThread.CurrentCulture = data.cultureInfo;
            }

            if (currentThread.CurrentUICulture != data.uiCultureInfo)
            {
                currentThread.CurrentUICulture = data.uiCultureInfo;
            }
        }

        class HostedAspNetContext : IDisposable
        {
            HostedThreadData oldData;

            public HostedAspNetContext(HostedThreadData newData)
            {
                oldData = new HostedThreadData();
                HostedThreadData.UnsafeApplyData(newData);
            }

            public void Dispose()
            {
                HostedThreadData.UnsafeApplyData(oldData);
            }
        }

    }
}