HttpChannelFactory.cs 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections.ObjectModel;
  7. using System.Diagnostics;
  8. using System.IdentityModel.Policy;
  9. using System.IdentityModel.Selectors;
  10. using System.IdentityModel.Tokens;
  11. using System.IO;
  12. using System.Net;
  13. using System.Net.Cache;
  14. using System.Net.Security;
  15. using System.Runtime;
  16. using System.Runtime.CompilerServices;
  17. using System.Runtime.Diagnostics;
  18. using System.Security;
  19. using System.Security.Authentication.ExtendedProtection;
  20. using System.Security.Cryptography;
  21. using System.Security.Permissions;
  22. using System.Security.Principal;
  23. using System.ServiceModel;
  24. using System.ServiceModel.Description;
  25. using System.ServiceModel.Diagnostics;
  26. using System.ServiceModel.Diagnostics.Application;
  27. using System.ServiceModel.Security;
  28. using System.ServiceModel.Security.Tokens;
  29. using System.Text;
  30. using System.Threading;
  31. class HttpChannelFactory<TChannel>
  32. : TransportChannelFactory<TChannel>,
  33. IHttpTransportFactorySettings
  34. {
  35. static bool httpWebRequestWebPermissionDenied = false;
  36. static RequestCachePolicy requestCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
  37. readonly ClientWebSocketFactory clientWebSocketFactory;
  38. bool allowCookies;
  39. AuthenticationSchemes authenticationScheme;
  40. HttpCookieContainerManager httpCookieContainerManager;
  41. // Double-checked locking pattern requires volatile for read/write synchronization
  42. volatile MruCache<Uri, Uri> credentialCacheUriPrefixCache;
  43. bool decompressionEnabled;
  44. // Double-checked locking pattern requires volatile for read/write synchronization
  45. [Fx.Tag.SecurityNote(Critical = "This cache stores strings that contain domain/user name/password. Must not be settable from PT code.")]
  46. [SecurityCritical]
  47. volatile MruCache<string, string> credentialHashCache;
  48. [Fx.Tag.SecurityNote(Critical = "This hash algorithm takes strings that contain domain/user name/password. Must not be settable from PT code.")]
  49. [SecurityCritical]
  50. HashAlgorithm hashAlgorithm;
  51. bool keepAliveEnabled;
  52. int maxBufferSize;
  53. IWebProxy proxy;
  54. WebProxyFactory proxyFactory;
  55. SecurityCredentialsManager channelCredentials;
  56. SecurityTokenManager securityTokenManager;
  57. TransferMode transferMode;
  58. ISecurityCapabilities securityCapabilities;
  59. WebSocketTransportSettings webSocketSettings;
  60. ConnectionBufferPool bufferPool;
  61. Lazy<string> webSocketSoapContentType;
  62. internal HttpChannelFactory(HttpTransportBindingElement bindingElement, BindingContext context)
  63. : base(bindingElement, context, HttpTransportDefaults.GetDefaultMessageEncoderFactory())
  64. {
  65. // validate setting interactions
  66. if (bindingElement.TransferMode == TransferMode.Buffered)
  67. {
  68. if (bindingElement.MaxReceivedMessageSize > int.MaxValue)
  69. {
  70. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  71. new ArgumentOutOfRangeException("bindingElement.MaxReceivedMessageSize",
  72. SR.GetString(SR.MaxReceivedMessageSizeMustBeInIntegerRange)));
  73. }
  74. if (bindingElement.MaxBufferSize != bindingElement.MaxReceivedMessageSize)
  75. {
  76. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("bindingElement",
  77. SR.GetString(SR.MaxBufferSizeMustMatchMaxReceivedMessageSize));
  78. }
  79. }
  80. else
  81. {
  82. if (bindingElement.MaxBufferSize > bindingElement.MaxReceivedMessageSize)
  83. {
  84. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("bindingElement",
  85. SR.GetString(SR.MaxBufferSizeMustNotExceedMaxReceivedMessageSize));
  86. }
  87. }
  88. if (TransferModeHelper.IsRequestStreamed(bindingElement.TransferMode) &&
  89. bindingElement.AuthenticationScheme != AuthenticationSchemes.Anonymous)
  90. {
  91. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("bindingElement", SR.GetString(
  92. SR.HttpAuthDoesNotSupportRequestStreaming));
  93. }
  94. this.allowCookies = bindingElement.AllowCookies;
  95. #pragma warning disable 618
  96. if (!this.allowCookies)
  97. {
  98. Collection<HttpCookieContainerBindingElement> httpCookieContainerBindingElements = context.BindingParameters.FindAll<HttpCookieContainerBindingElement>();
  99. if (httpCookieContainerBindingElements.Count > 1)
  100. {
  101. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MultipleCCbesInParameters, typeof(HttpCookieContainerBindingElement))));
  102. }
  103. if (httpCookieContainerBindingElements.Count == 1)
  104. {
  105. this.allowCookies = true;
  106. context.BindingParameters.Remove<HttpCookieContainerBindingElement>();
  107. }
  108. }
  109. #pragma warning restore 618
  110. if (this.allowCookies)
  111. {
  112. this.httpCookieContainerManager = new HttpCookieContainerManager();
  113. }
  114. if (!bindingElement.AuthenticationScheme.IsSingleton())
  115. {
  116. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.HttpRequiresSingleAuthScheme,
  117. bindingElement.AuthenticationScheme));
  118. }
  119. this.authenticationScheme = bindingElement.AuthenticationScheme;
  120. this.decompressionEnabled = bindingElement.DecompressionEnabled;
  121. this.keepAliveEnabled = bindingElement.KeepAliveEnabled;
  122. this.maxBufferSize = bindingElement.MaxBufferSize;
  123. this.transferMode = bindingElement.TransferMode;
  124. if (bindingElement.Proxy != null)
  125. {
  126. this.proxy = bindingElement.Proxy;
  127. }
  128. else if (bindingElement.ProxyAddress != null)
  129. {
  130. if (bindingElement.UseDefaultWebProxy)
  131. {
  132. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UseDefaultWebProxyCantBeUsedWithExplicitProxyAddress)));
  133. }
  134. if (bindingElement.ProxyAuthenticationScheme == AuthenticationSchemes.Anonymous)
  135. {
  136. this.proxy = new WebProxy(bindingElement.ProxyAddress, bindingElement.BypassProxyOnLocal);
  137. }
  138. else
  139. {
  140. this.proxy = null;
  141. this.proxyFactory =
  142. new WebProxyFactory(bindingElement.ProxyAddress, bindingElement.BypassProxyOnLocal,
  143. bindingElement.ProxyAuthenticationScheme);
  144. }
  145. }
  146. else if (!bindingElement.UseDefaultWebProxy)
  147. {
  148. this.proxy = new WebProxy();
  149. }
  150. this.channelCredentials = context.BindingParameters.Find<SecurityCredentialsManager>();
  151. this.securityCapabilities = bindingElement.GetProperty<ISecurityCapabilities>(context);
  152. this.webSocketSettings = WebSocketHelper.GetRuntimeWebSocketSettings(bindingElement.WebSocketSettings);
  153. int webSocketBufferSize = WebSocketHelper.ComputeClientBufferSize(this.MaxReceivedMessageSize);
  154. this.bufferPool = new ConnectionBufferPool(webSocketBufferSize);
  155. Collection<ClientWebSocketFactory> clientWebSocketFactories = context.BindingParameters.FindAll<ClientWebSocketFactory>();
  156. if (clientWebSocketFactories.Count > 1)
  157. {
  158. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(
  159. "context",
  160. SR.GetString(SR.MultipleClientWebSocketFactoriesSpecified, typeof(BindingContext).Name, typeof(ClientWebSocketFactory).Name));
  161. }
  162. else
  163. {
  164. this.clientWebSocketFactory = clientWebSocketFactories.Count == 0 ? null : clientWebSocketFactories[0];
  165. }
  166. this.webSocketSoapContentType = new Lazy<string>(() => { return this.MessageEncoderFactory.CreateSessionEncoder().ContentType; }, LazyThreadSafetyMode.ExecutionAndPublication);
  167. }
  168. public bool AllowCookies
  169. {
  170. get
  171. {
  172. return this.allowCookies;
  173. }
  174. }
  175. public AuthenticationSchemes AuthenticationScheme
  176. {
  177. get
  178. {
  179. return this.authenticationScheme;
  180. }
  181. }
  182. public bool DecompressionEnabled
  183. {
  184. get
  185. {
  186. return this.decompressionEnabled;
  187. }
  188. }
  189. public virtual bool IsChannelBindingSupportEnabled
  190. {
  191. get
  192. {
  193. return false;
  194. }
  195. }
  196. public bool KeepAliveEnabled
  197. {
  198. get
  199. {
  200. return this.keepAliveEnabled;
  201. }
  202. }
  203. public SecurityTokenManager SecurityTokenManager
  204. {
  205. get
  206. {
  207. return this.securityTokenManager;
  208. }
  209. }
  210. public int MaxBufferSize
  211. {
  212. get
  213. {
  214. return maxBufferSize;
  215. }
  216. }
  217. public IWebProxy Proxy
  218. {
  219. get
  220. {
  221. return this.proxy;
  222. }
  223. }
  224. public TransferMode TransferMode
  225. {
  226. get
  227. {
  228. return transferMode;
  229. }
  230. }
  231. public override string Scheme
  232. {
  233. get
  234. {
  235. return Uri.UriSchemeHttp;
  236. }
  237. }
  238. public WebSocketTransportSettings WebSocketSettings
  239. {
  240. get { return this.webSocketSettings; }
  241. }
  242. internal string WebSocketSoapContentType
  243. {
  244. get
  245. {
  246. return this.webSocketSoapContentType.Value;
  247. }
  248. }
  249. protected ConnectionBufferPool WebSocketBufferPool
  250. {
  251. get { return this.bufferPool; }
  252. }
  253. // must be called under lock (this.credentialHashCache)
  254. HashAlgorithm HashAlgorithm
  255. {
  256. [SecurityCritical]
  257. get
  258. {
  259. if (this.hashAlgorithm == null)
  260. {
  261. this.hashAlgorithm = CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest);
  262. }
  263. else
  264. {
  265. this.hashAlgorithm.Initialize();
  266. }
  267. return this.hashAlgorithm;
  268. }
  269. }
  270. int IHttpTransportFactorySettings.MaxBufferSize
  271. {
  272. get { return MaxBufferSize; }
  273. }
  274. TransferMode IHttpTransportFactorySettings.TransferMode
  275. {
  276. get { return TransferMode; }
  277. }
  278. protected ClientWebSocketFactory ClientWebSocketFactory
  279. {
  280. get
  281. {
  282. return this.clientWebSocketFactory;
  283. }
  284. }
  285. public override T GetProperty<T>()
  286. {
  287. if (typeof(T) == typeof(ISecurityCapabilities))
  288. {
  289. return (T)(object)this.securityCapabilities;
  290. }
  291. if (typeof(T) == typeof(IHttpCookieContainerManager))
  292. {
  293. return (T)(object)this.GetHttpCookieContainerManager();
  294. }
  295. return base.GetProperty<T>();
  296. }
  297. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  298. [MethodImpl(MethodImplOptions.NoInlining)]
  299. private HttpCookieContainerManager GetHttpCookieContainerManager()
  300. {
  301. return this.httpCookieContainerManager;
  302. }
  303. internal virtual SecurityMessageProperty CreateReplySecurityProperty(HttpWebRequest request,
  304. HttpWebResponse response)
  305. {
  306. // Don't pull in System.Authorization if we don't need to!
  307. if (!response.IsMutuallyAuthenticated)
  308. {
  309. return null;
  310. }
  311. return CreateMutuallyAuthenticatedReplySecurityProperty(response);
  312. }
  313. internal Exception CreateToMustEqualViaException(Uri to, Uri via)
  314. {
  315. return new ArgumentException(SR.GetString(SR.HttpToMustEqualVia, to, via));
  316. }
  317. [MethodImpl(MethodImplOptions.NoInlining)]
  318. SecurityMessageProperty CreateMutuallyAuthenticatedReplySecurityProperty(HttpWebResponse response)
  319. {
  320. string spn = AuthenticationManager.CustomTargetNameDictionary[response.ResponseUri.AbsoluteUri];
  321. if (spn == null)
  322. {
  323. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.HttpSpnNotFound,
  324. response.ResponseUri)));
  325. }
  326. ReadOnlyCollection<IAuthorizationPolicy> spnPolicies = SecurityUtils.CreatePrincipalNameAuthorizationPolicies(spn);
  327. SecurityMessageProperty remoteSecurity = new SecurityMessageProperty();
  328. remoteSecurity.TransportToken = new SecurityTokenSpecification(null, spnPolicies);
  329. remoteSecurity.ServiceSecurityContext = new ServiceSecurityContext(spnPolicies);
  330. return remoteSecurity;
  331. }
  332. internal override int GetMaxBufferSize()
  333. {
  334. return MaxBufferSize;
  335. }
  336. SecurityTokenProviderContainer CreateAndOpenTokenProvider(TimeSpan timeout, AuthenticationSchemes authenticationScheme,
  337. EndpointAddress target, Uri via, ChannelParameterCollection channelParameters)
  338. {
  339. SecurityTokenProvider tokenProvider = null;
  340. switch (authenticationScheme)
  341. {
  342. case AuthenticationSchemes.Anonymous:
  343. break;
  344. case AuthenticationSchemes.Basic:
  345. tokenProvider = TransportSecurityHelpers.GetUserNameTokenProvider(this.SecurityTokenManager, target, via, this.Scheme, authenticationScheme, channelParameters);
  346. break;
  347. case AuthenticationSchemes.Negotiate:
  348. case AuthenticationSchemes.Ntlm:
  349. tokenProvider = TransportSecurityHelpers.GetSspiTokenProvider(this.SecurityTokenManager, target, via, this.Scheme, authenticationScheme, channelParameters);
  350. break;
  351. case AuthenticationSchemes.Digest:
  352. tokenProvider = TransportSecurityHelpers.GetDigestTokenProvider(this.SecurityTokenManager, target, via, this.Scheme, authenticationScheme, channelParameters);
  353. break;
  354. default:
  355. // The setter for this property should prevent this.
  356. throw Fx.AssertAndThrow("CreateAndOpenTokenProvider: Invalid authentication scheme");
  357. }
  358. SecurityTokenProviderContainer result;
  359. if (tokenProvider != null)
  360. {
  361. result = new SecurityTokenProviderContainer(tokenProvider);
  362. result.Open(timeout);
  363. }
  364. else
  365. {
  366. result = null;
  367. }
  368. return result;
  369. }
  370. protected virtual void ValidateCreateChannelParameters(EndpointAddress remoteAddress, Uri via)
  371. {
  372. base.ValidateScheme(via);
  373. if (this.MessageVersion.Addressing == AddressingVersion.None && remoteAddress.Uri != via)
  374. {
  375. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateToMustEqualViaException(remoteAddress.Uri, via));
  376. }
  377. }
  378. protected override TChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
  379. {
  380. EndpointAddress httpRemoteAddress = remoteAddress != null && WebSocketHelper.IsWebSocketUri(remoteAddress.Uri) ?
  381. new EndpointAddress(WebSocketHelper.NormalizeWsSchemeWithHttpScheme(remoteAddress.Uri), remoteAddress) :
  382. remoteAddress;
  383. Uri httpVia = WebSocketHelper.IsWebSocketUri(via) ? WebSocketHelper.NormalizeWsSchemeWithHttpScheme(via) : via;
  384. return this.OnCreateChannelCore(httpRemoteAddress, httpVia);
  385. }
  386. protected virtual TChannel OnCreateChannelCore(EndpointAddress remoteAddress, Uri via)
  387. {
  388. ValidateCreateChannelParameters(remoteAddress, via);
  389. this.ValidateWebSocketTransportUsage();
  390. if (typeof(TChannel) == typeof(IRequestChannel))
  391. {
  392. return (TChannel)(object)new HttpRequestChannel((HttpChannelFactory<IRequestChannel>)(object)this, remoteAddress, via, ManualAddressing);
  393. }
  394. else
  395. {
  396. return (TChannel)(object)new ClientWebSocketTransportDuplexSessionChannel((HttpChannelFactory<IDuplexSessionChannel>)(object)this, this.clientWebSocketFactory, remoteAddress, via, this.WebSocketBufferPool);
  397. }
  398. }
  399. protected void ValidateWebSocketTransportUsage()
  400. {
  401. Type channelType = typeof(TChannel);
  402. if (channelType == typeof(IRequestChannel) && this.WebSocketSettings.TransportUsage == WebSocketTransportUsage.Always)
  403. {
  404. throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(
  405. SR.WebSocketCannotCreateRequestClientChannelWithCertainWebSocketTransportUsage,
  406. typeof(TChannel),
  407. WebSocketTransportSettings.TransportUsageMethodName,
  408. typeof(WebSocketTransportSettings).Name,
  409. this.WebSocketSettings.TransportUsage)));
  410. }
  411. else if (channelType == typeof(IDuplexSessionChannel))
  412. {
  413. if (this.WebSocketSettings.TransportUsage == WebSocketTransportUsage.Never)
  414. {
  415. throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(
  416. SR.WebSocketCannotCreateRequestClientChannelWithCertainWebSocketTransportUsage,
  417. typeof(TChannel),
  418. WebSocketTransportSettings.TransportUsageMethodName,
  419. typeof(WebSocketTransportSettings).Name,
  420. this.WebSocketSettings.TransportUsage)));
  421. }
  422. else if (!WebSocketHelper.OSSupportsWebSockets() && this.ClientWebSocketFactory == null)
  423. {
  424. throw FxTrace.Exception.AsError(new PlatformNotSupportedException(SR.GetString(SR.WebSocketsClientSideNotSupported, typeof(ClientWebSocketFactory).FullName)));
  425. }
  426. }
  427. }
  428. [MethodImpl(MethodImplOptions.NoInlining)]
  429. void InitializeSecurityTokenManager()
  430. {
  431. if (this.channelCredentials == null)
  432. {
  433. this.channelCredentials = ClientCredentials.CreateDefaultCredentials();
  434. }
  435. this.securityTokenManager = this.channelCredentials.CreateSecurityTokenManager();
  436. }
  437. protected virtual bool IsSecurityTokenManagerRequired()
  438. {
  439. if (this.AuthenticationScheme != AuthenticationSchemes.Anonymous)
  440. {
  441. return true;
  442. }
  443. if (this.proxyFactory != null && this.proxyFactory.AuthenticationScheme != AuthenticationSchemes.Anonymous)
  444. {
  445. return true;
  446. }
  447. else
  448. {
  449. return false;
  450. }
  451. }
  452. protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
  453. {
  454. this.OnOpen(timeout);
  455. return new CompletedAsyncResult(callback, state);
  456. }
  457. protected override void OnEndOpen(IAsyncResult result)
  458. {
  459. CompletedAsyncResult.End(result);
  460. }
  461. protected override void OnOpen(TimeSpan timeout)
  462. {
  463. if (IsSecurityTokenManagerRequired())
  464. {
  465. this.InitializeSecurityTokenManager();
  466. }
  467. if (this.AllowCookies &&
  468. !this.httpCookieContainerManager.IsInitialized) // We don't want to overwrite the CookieContainer if someone has set it already.
  469. {
  470. this.httpCookieContainerManager.CookieContainer = new CookieContainer();
  471. }
  472. // we need to make sure System.Net will buffer faults (sent as 500 requests) up to our allowed size
  473. // Their value is in Kbytes and ours is in bytes. We round up so that the KB value is large enough to
  474. // encompass our MaxReceivedMessageSize. See MB#20860 and related for details
  475. if (!httpWebRequestWebPermissionDenied && HttpWebRequest.DefaultMaximumErrorResponseLength != -1)
  476. {
  477. int MaxReceivedMessageSizeKbytes;
  478. if (MaxBufferSize >= (int.MaxValue - 1024)) // make sure NCL doesn't overflow
  479. {
  480. MaxReceivedMessageSizeKbytes = -1;
  481. }
  482. else
  483. {
  484. MaxReceivedMessageSizeKbytes = (int)(MaxBufferSize / 1024);
  485. if (MaxReceivedMessageSizeKbytes * 1024 < MaxBufferSize)
  486. {
  487. MaxReceivedMessageSizeKbytes++;
  488. }
  489. }
  490. if (MaxReceivedMessageSizeKbytes == -1
  491. || MaxReceivedMessageSizeKbytes > HttpWebRequest.DefaultMaximumErrorResponseLength)
  492. {
  493. try
  494. {
  495. HttpWebRequest.DefaultMaximumErrorResponseLength = MaxReceivedMessageSizeKbytes;
  496. }
  497. catch (SecurityException exception)
  498. {
  499. // CSDMain\33725 - setting DefaultMaximumErrorResponseLength should not fail HttpChannelFactory.OnOpen
  500. // if the user does not have the permission to do so.
  501. httpWebRequestWebPermissionDenied = true;
  502. DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
  503. }
  504. }
  505. }
  506. }
  507. protected override void OnClosed()
  508. {
  509. base.OnClosed();
  510. if (this.bufferPool != null)
  511. {
  512. this.bufferPool.Close();
  513. }
  514. }
  515. static internal void TraceResponseReceived(HttpWebResponse response, Message message, object receiver)
  516. {
  517. if (DiagnosticUtility.ShouldTraceVerbose)
  518. {
  519. if (response != null && response.ResponseUri != null)
  520. {
  521. TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.HttpResponseReceived, SR.GetString(SR.TraceCodeHttpResponseReceived), new StringTraceRecord("ResponseUri", response.ResponseUri.ToString()), receiver, null, message);
  522. }
  523. else
  524. {
  525. TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.HttpResponseReceived, SR.GetString(SR.TraceCodeHttpResponseReceived), receiver, message);
  526. }
  527. }
  528. }
  529. [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method AppendWindowsAuthenticationInfo to access the credential domain/user name/password.")]
  530. [SecurityCritical]
  531. [MethodImpl(MethodImplOptions.NoInlining)]
  532. string AppendWindowsAuthenticationInfo(string inputString, NetworkCredential credential,
  533. AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel)
  534. {
  535. return SecurityUtils.AppendWindowsAuthenticationInfo(inputString, credential, authenticationLevel, impersonationLevel);
  536. }
  537. protected virtual string OnGetConnectionGroupPrefix(HttpWebRequest httpWebRequest, SecurityTokenContainer clientCertificateToken)
  538. {
  539. return string.Empty;
  540. }
  541. internal static bool IsWindowsAuth(AuthenticationSchemes authScheme)
  542. {
  543. Fx.Assert(authScheme.IsSingleton(), "authenticationScheme used in an Http(s)ChannelFactory must be a singleton value.");
  544. return authScheme == AuthenticationSchemes.Negotiate ||
  545. authScheme == AuthenticationSchemes.Ntlm;
  546. }
  547. [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method AppendWindowsAuthenticationInfo to access the credential domain/user name/password.",
  548. Safe = "Uses the domain/user name/password to store and compute a hash. The store is SecurityCritical. The hash leaks but" +
  549. "the hash cannot be reversed to the domain/user name/password.")]
  550. [SecuritySafeCritical]
  551. string GetConnectionGroupName(HttpWebRequest httpWebRequest, NetworkCredential credential, AuthenticationLevel authenticationLevel,
  552. TokenImpersonationLevel impersonationLevel, SecurityTokenContainer clientCertificateToken)
  553. {
  554. if (this.credentialHashCache == null)
  555. {
  556. lock (ThisLock)
  557. {
  558. if (this.credentialHashCache == null)
  559. {
  560. this.credentialHashCache = new MruCache<string, string>(5);
  561. }
  562. }
  563. }
  564. // The following line is a work-around for VSWhidbey 558605. In particular, we need to isolate our
  565. // connection groups based on whether we are streaming the request.
  566. string inputString = TransferModeHelper.IsRequestStreamed(this.TransferMode) ? "streamed" : string.Empty;
  567. if (IsWindowsAuth(this.AuthenticationScheme))
  568. {
  569. // for NTLM & Negotiate, System.Net doesn't pool connections by default. This is because
  570. // IIS doesn't re-authenticate NTLM connections (made for a perf reason), and HttpWebRequest
  571. // shared connections among multiple callers.
  572. // This causes Indigo a performance problem in turn. We mitigate this by (1) enabling
  573. // connection sharing for NTLM connections on our pool, and (2) scoping the pool we use
  574. // to be based on the NetworkCredential that is being used to authenticate the connection.
  575. // Therefore we're only sharing connections among the same Credential.
  576. // Setting this will fail in partial trust, and that's ok since this is an optimization.
  577. if (!httpWebRequestWebPermissionDenied)
  578. {
  579. try
  580. {
  581. httpWebRequest.UnsafeAuthenticatedConnectionSharing = true;
  582. }
  583. catch (SecurityException e)
  584. {
  585. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  586. httpWebRequestWebPermissionDenied = true;
  587. }
  588. }
  589. inputString = AppendWindowsAuthenticationInfo(inputString, credential, authenticationLevel, impersonationLevel);
  590. }
  591. string prefix = this.OnGetConnectionGroupPrefix(httpWebRequest, clientCertificateToken);
  592. inputString = string.Concat(prefix, inputString);
  593. string credentialHash = null;
  594. // we have to lock around each call to TryGetValue since the MruCache modifies the
  595. // contents of it's mruList in a single-threaded manner underneath TryGetValue
  596. if (!string.IsNullOrEmpty(inputString))
  597. {
  598. lock (this.credentialHashCache)
  599. {
  600. if (!this.credentialHashCache.TryGetValue(inputString, out credentialHash))
  601. {
  602. byte[] inputBytes = new UTF8Encoding().GetBytes(inputString);
  603. byte[] digestBytes = this.HashAlgorithm.ComputeHash(inputBytes);
  604. credentialHash = Convert.ToBase64String(digestBytes);
  605. this.credentialHashCache.Add(inputString, credentialHash);
  606. }
  607. }
  608. }
  609. return credentialHash;
  610. }
  611. Uri GetCredentialCacheUriPrefix(Uri via)
  612. {
  613. Uri result;
  614. if (this.credentialCacheUriPrefixCache == null)
  615. {
  616. lock (ThisLock)
  617. {
  618. if (this.credentialCacheUriPrefixCache == null)
  619. {
  620. this.credentialCacheUriPrefixCache = new MruCache<Uri, Uri>(10);
  621. }
  622. }
  623. }
  624. lock (this.credentialCacheUriPrefixCache)
  625. {
  626. if (!this.credentialCacheUriPrefixCache.TryGetValue(via, out result))
  627. {
  628. result = new UriBuilder(via.Scheme, via.Host, via.Port).Uri;
  629. this.credentialCacheUriPrefixCache.Add(via, result);
  630. }
  631. }
  632. return result;
  633. }
  634. // core code for creating an HttpWebRequest
  635. HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, NetworkCredential credential,
  636. TokenImpersonationLevel impersonationLevel, AuthenticationLevel authenticationLevel,
  637. SecurityTokenProviderContainer proxyTokenProvider, SecurityTokenContainer clientCertificateToken, TimeSpan timeout, bool isWebSocketRequest)
  638. {
  639. Uri httpWebRequestUri = isWebSocketRequest ? WebSocketHelper.GetWebSocketUri(via) : via;
  640. HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(httpWebRequestUri);
  641. Fx.Assert(httpWebRequest.Method.Equals("GET", StringComparison.OrdinalIgnoreCase), "the default HTTP method of HttpWebRequest should be 'Get'.");
  642. if (!isWebSocketRequest)
  643. {
  644. httpWebRequest.Method = "POST";
  645. if (TransferModeHelper.IsRequestStreamed(TransferMode))
  646. {
  647. httpWebRequest.SendChunked = true;
  648. httpWebRequest.AllowWriteStreamBuffering = false;
  649. }
  650. else
  651. {
  652. httpWebRequest.AllowWriteStreamBuffering = true;
  653. }
  654. }
  655. httpWebRequest.CachePolicy = requestCachePolicy;
  656. httpWebRequest.KeepAlive = this.keepAliveEnabled;
  657. if (this.decompressionEnabled)
  658. {
  659. httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
  660. }
  661. else
  662. {
  663. httpWebRequest.AutomaticDecompression = DecompressionMethods.None;
  664. }
  665. if (credential != null)
  666. {
  667. CredentialCache credentials = new CredentialCache();
  668. credentials.Add(this.GetCredentialCacheUriPrefix(via),
  669. AuthenticationSchemesHelper.ToString(this.authenticationScheme), credential);
  670. httpWebRequest.Credentials = credentials;
  671. }
  672. httpWebRequest.AuthenticationLevel = authenticationLevel;
  673. httpWebRequest.ImpersonationLevel = impersonationLevel;
  674. string connectionGroupName = GetConnectionGroupName(httpWebRequest, credential, authenticationLevel, impersonationLevel, clientCertificateToken);
  675. X509CertificateEndpointIdentity remoteCertificateIdentity = to.Identity as X509CertificateEndpointIdentity;
  676. if (remoteCertificateIdentity != null)
  677. {
  678. connectionGroupName = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}[{1}]", connectionGroupName, remoteCertificateIdentity.Certificates[0].Thumbprint);
  679. }
  680. if (!string.IsNullOrEmpty(connectionGroupName))
  681. {
  682. httpWebRequest.ConnectionGroupName = connectionGroupName;
  683. }
  684. if (AuthenticationScheme == AuthenticationSchemes.Basic)
  685. {
  686. httpWebRequest.PreAuthenticate = true;
  687. }
  688. if (this.proxy != null)
  689. {
  690. httpWebRequest.Proxy = this.proxy;
  691. }
  692. else if (this.proxyFactory != null)
  693. {
  694. httpWebRequest.Proxy = this.proxyFactory.CreateWebProxy(httpWebRequest, proxyTokenProvider, timeout);
  695. }
  696. if (this.AllowCookies)
  697. {
  698. httpWebRequest.CookieContainer = this.httpCookieContainerManager.CookieContainer;
  699. }
  700. // we do this at the end so that we access the correct ServicePoint
  701. httpWebRequest.ServicePoint.UseNagleAlgorithm = false;
  702. return httpWebRequest;
  703. }
  704. void ApplyManualAddressing(ref EndpointAddress to, ref Uri via, Message message)
  705. {
  706. if (ManualAddressing)
  707. {
  708. Uri toHeader = message.Headers.To;
  709. if (toHeader == null)
  710. {
  711. throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ManualAddressingRequiresAddressedMessages)), message);
  712. }
  713. to = new EndpointAddress(toHeader);
  714. if (this.MessageVersion.Addressing == AddressingVersion.None)
  715. {
  716. via = toHeader;
  717. }
  718. }
  719. // now apply query string property
  720. object property;
  721. if (message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out property))
  722. {
  723. HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)property;
  724. if (!string.IsNullOrEmpty(requestProperty.QueryString))
  725. {
  726. UriBuilder uriBuilder = new UriBuilder(via);
  727. if (requestProperty.QueryString.StartsWith("?", StringComparison.Ordinal))
  728. {
  729. uriBuilder.Query = requestProperty.QueryString.Substring(1);
  730. }
  731. else
  732. {
  733. uriBuilder.Query = requestProperty.QueryString;
  734. }
  735. via = uriBuilder.Uri;
  736. }
  737. }
  738. }
  739. [MethodImpl(MethodImplOptions.NoInlining)]
  740. void CreateAndOpenTokenProvidersCore(EndpointAddress to, Uri via, ChannelParameterCollection channelParameters, TimeSpan timeout, out SecurityTokenProviderContainer tokenProvider, out SecurityTokenProviderContainer proxyTokenProvider)
  741. {
  742. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  743. tokenProvider = CreateAndOpenTokenProvider(timeoutHelper.RemainingTime(), this.AuthenticationScheme, to, via, channelParameters);
  744. if (this.proxyFactory != null)
  745. {
  746. proxyTokenProvider = CreateAndOpenTokenProvider(timeoutHelper.RemainingTime(), this.proxyFactory.AuthenticationScheme, to, via, channelParameters);
  747. }
  748. else
  749. {
  750. proxyTokenProvider = null;
  751. }
  752. }
  753. internal void CreateAndOpenTokenProviders(EndpointAddress to, Uri via, ChannelParameterCollection channelParameters, TimeSpan timeout, out SecurityTokenProviderContainer tokenProvider, out SecurityTokenProviderContainer proxyTokenProvider)
  754. {
  755. if (!IsSecurityTokenManagerRequired())
  756. {
  757. tokenProvider = null;
  758. proxyTokenProvider = null;
  759. }
  760. else
  761. {
  762. CreateAndOpenTokenProvidersCore(to, via, channelParameters, timeout, out tokenProvider, out proxyTokenProvider);
  763. }
  764. }
  765. internal HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, SecurityTokenProviderContainer tokenProvider,
  766. SecurityTokenProviderContainer proxyTokenProvider, SecurityTokenContainer clientCertificateToken, TimeSpan timeout, bool isWebSocketRequest)
  767. {
  768. TokenImpersonationLevel impersonationLevel;
  769. AuthenticationLevel authenticationLevel;
  770. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  771. NetworkCredential credential = HttpChannelUtilities.GetCredential(this.authenticationScheme,
  772. tokenProvider, timeoutHelper.RemainingTime(), out impersonationLevel, out authenticationLevel);
  773. return GetWebRequest(to, via, credential, impersonationLevel, authenticationLevel, proxyTokenProvider, clientCertificateToken, timeoutHelper.RemainingTime(), isWebSocketRequest);
  774. }
  775. internal static bool MapIdentity(EndpointAddress target, AuthenticationSchemes authenticationScheme)
  776. {
  777. if ((target.Identity == null) || (target.Identity is X509CertificateEndpointIdentity))
  778. {
  779. return false;
  780. }
  781. return IsWindowsAuth(authenticationScheme);
  782. }
  783. bool MapIdentity(EndpointAddress target)
  784. {
  785. return MapIdentity(target, this.AuthenticationScheme);
  786. }
  787. protected class HttpRequestChannel : RequestChannel
  788. {
  789. // Double-checked locking pattern requires volatile for read/write synchronization
  790. volatile bool cleanupIdentity;
  791. HttpChannelFactory<IRequestChannel> factory;
  792. SecurityTokenProviderContainer tokenProvider;
  793. SecurityTokenProviderContainer proxyTokenProvider;
  794. ServiceModelActivity activity = null;
  795. ChannelParameterCollection channelParameters;
  796. public HttpRequestChannel(HttpChannelFactory<IRequestChannel> factory, EndpointAddress to, Uri via, bool manualAddressing)
  797. : base(factory, to, via, manualAddressing)
  798. {
  799. this.factory = factory;
  800. }
  801. public HttpChannelFactory<IRequestChannel> Factory
  802. {
  803. get { return this.factory; }
  804. }
  805. internal ServiceModelActivity Activity
  806. {
  807. get { return this.activity; }
  808. }
  809. protected ChannelParameterCollection ChannelParameters
  810. {
  811. get
  812. {
  813. return this.channelParameters;
  814. }
  815. }
  816. public override T GetProperty<T>()
  817. {
  818. if (typeof(T) == typeof(ChannelParameterCollection))
  819. {
  820. if (this.State == CommunicationState.Created)
  821. {
  822. lock (ThisLock)
  823. {
  824. if (this.channelParameters == null)
  825. {
  826. this.channelParameters = new ChannelParameterCollection();
  827. }
  828. }
  829. }
  830. return (T)(object)this.channelParameters;
  831. }
  832. else
  833. {
  834. return base.GetProperty<T>();
  835. }
  836. }
  837. void PrepareOpen()
  838. {
  839. if (Factory.MapIdentity(RemoteAddress))
  840. {
  841. lock (ThisLock)
  842. {
  843. cleanupIdentity = HttpTransportSecurityHelpers.AddIdentityMapping(Via, RemoteAddress);
  844. }
  845. }
  846. }
  847. void CreateAndOpenTokenProviders(TimeSpan timeout)
  848. {
  849. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  850. if (!ManualAddressing)
  851. {
  852. Factory.CreateAndOpenTokenProviders(this.RemoteAddress, this.Via, this.channelParameters, timeoutHelper.RemainingTime(), out this.tokenProvider, out this.proxyTokenProvider);
  853. }
  854. }
  855. void CloseTokenProviders(TimeSpan timeout)
  856. {
  857. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  858. if (this.tokenProvider != null)
  859. {
  860. tokenProvider.Close(timeoutHelper.RemainingTime());
  861. }
  862. if (this.proxyTokenProvider != null)
  863. {
  864. proxyTokenProvider.Close(timeoutHelper.RemainingTime());
  865. }
  866. }
  867. void AbortTokenProviders()
  868. {
  869. if (this.tokenProvider != null)
  870. {
  871. tokenProvider.Abort();
  872. }
  873. if (this.proxyTokenProvider != null)
  874. {
  875. proxyTokenProvider.Abort();
  876. }
  877. }
  878. protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
  879. {
  880. PrepareOpen();
  881. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  882. CreateAndOpenTokenProviders(timeoutHelper.RemainingTime());
  883. return new CompletedAsyncResult(callback, state);
  884. }
  885. protected override void OnOpen(TimeSpan timeout)
  886. {
  887. PrepareOpen();
  888. CreateAndOpenTokenProviders(timeout);
  889. }
  890. protected override void OnEndOpen(IAsyncResult result)
  891. {
  892. CompletedAsyncResult.End(result);
  893. }
  894. void PrepareClose(bool aborting)
  895. {
  896. if (cleanupIdentity)
  897. {
  898. lock (ThisLock)
  899. {
  900. if (cleanupIdentity)
  901. {
  902. cleanupIdentity = false;
  903. HttpTransportSecurityHelpers.RemoveIdentityMapping(Via, RemoteAddress, !aborting);
  904. }
  905. }
  906. }
  907. }
  908. protected override void OnAbort()
  909. {
  910. PrepareClose(true);
  911. AbortTokenProviders();
  912. base.OnAbort();
  913. }
  914. protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
  915. {
  916. IAsyncResult retval = null;
  917. using (ServiceModelActivity.BoundOperation(this.activity))
  918. {
  919. PrepareClose(false);
  920. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  921. CloseTokenProviders(timeoutHelper.RemainingTime());
  922. retval = base.BeginWaitForPendingRequests(timeoutHelper.RemainingTime(), callback, state);
  923. }
  924. ServiceModelActivity.Stop(this.activity);
  925. return retval;
  926. }
  927. protected override void OnEndClose(IAsyncResult result)
  928. {
  929. using (ServiceModelActivity.BoundOperation(this.activity))
  930. {
  931. base.EndWaitForPendingRequests(result);
  932. }
  933. ServiceModelActivity.Stop(this.activity);
  934. }
  935. protected override void OnClose(TimeSpan timeout)
  936. {
  937. using (ServiceModelActivity.BoundOperation(this.activity))
  938. {
  939. PrepareClose(false);
  940. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  941. CloseTokenProviders(timeoutHelper.RemainingTime());
  942. base.WaitForPendingRequests(timeoutHelper.RemainingTime());
  943. }
  944. ServiceModelActivity.Stop(this.activity);
  945. }
  946. protected override IAsyncRequest CreateAsyncRequest(Message message, AsyncCallback callback, object state)
  947. {
  948. if (DiagnosticUtility.ShouldUseActivity && this.activity == null)
  949. {
  950. this.activity = ServiceModelActivity.CreateActivity();
  951. if (null != FxTrace.Trace)
  952. {
  953. FxTrace.Trace.TraceTransfer(this.activity.Id);
  954. }
  955. ServiceModelActivity.Start(this.activity, SR.GetString(SR.ActivityReceiveBytes, this.RemoteAddress.Uri.ToString()), ActivityType.ReceiveBytes);
  956. }
  957. return new HttpChannelAsyncRequest(this, callback, state);
  958. }
  959. protected override IRequest CreateRequest(Message message)
  960. {
  961. return new HttpChannelRequest(this, Factory);
  962. }
  963. public virtual HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, ref TimeoutHelper timeoutHelper)
  964. {
  965. return GetWebRequest(to, via, null, ref timeoutHelper);
  966. }
  967. protected HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, SecurityTokenContainer clientCertificateToken, ref TimeoutHelper timeoutHelper)
  968. {
  969. SecurityTokenProviderContainer webRequestTokenProvider;
  970. SecurityTokenProviderContainer webRequestProxyTokenProvider;
  971. if (this.ManualAddressing)
  972. {
  973. this.Factory.CreateAndOpenTokenProviders(to, via, this.channelParameters, timeoutHelper.RemainingTime(),
  974. out webRequestTokenProvider, out webRequestProxyTokenProvider);
  975. }
  976. else
  977. {
  978. webRequestTokenProvider = this.tokenProvider;
  979. webRequestProxyTokenProvider = this.proxyTokenProvider;
  980. }
  981. try
  982. {
  983. return this.Factory.GetWebRequest(to, via, webRequestTokenProvider, webRequestProxyTokenProvider, clientCertificateToken, timeoutHelper.RemainingTime(), false);
  984. }
  985. finally
  986. {
  987. if (this.ManualAddressing)
  988. {
  989. if (webRequestTokenProvider != null)
  990. {
  991. webRequestTokenProvider.Abort();
  992. }
  993. if (webRequestProxyTokenProvider != null)
  994. {
  995. webRequestProxyTokenProvider.Abort();
  996. }
  997. }
  998. }
  999. }
  1000. protected IAsyncResult BeginGetWebRequest(
  1001. EndpointAddress to, Uri via, SecurityTokenContainer clientCertificateToken, ref TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
  1002. {
  1003. return new GetWebRequestAsyncResult(this, to, via, clientCertificateToken, ref timeoutHelper, callback, state);
  1004. }
  1005. public virtual IAsyncResult BeginGetWebRequest(
  1006. EndpointAddress to, Uri via, ref TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
  1007. {
  1008. return BeginGetWebRequest(to, via, null, ref timeoutHelper, callback, state);
  1009. }
  1010. public virtual HttpWebRequest EndGetWebRequest(IAsyncResult result)
  1011. {
  1012. return GetWebRequestAsyncResult.End(result);
  1013. }
  1014. public virtual bool WillGetWebRequestCompleteSynchronously()
  1015. {
  1016. return ((this.tokenProvider == null) && !Factory.ManualAddressing);
  1017. }
  1018. internal virtual void OnWebRequestCompleted(HttpWebRequest request)
  1019. {
  1020. // empty
  1021. }
  1022. class HttpChannelRequest : IRequest
  1023. {
  1024. HttpRequestChannel channel;
  1025. HttpChannelFactory<IRequestChannel> factory;
  1026. EndpointAddress to;
  1027. Uri via;
  1028. HttpWebRequest webRequest;
  1029. HttpAbortReason abortReason;
  1030. ChannelBinding channelBinding;
  1031. int webRequestCompleted;
  1032. EventTraceActivity eventTraceActivity;
  1033. public HttpChannelRequest(HttpRequestChannel channel, HttpChannelFactory<IRequestChannel> factory)
  1034. {
  1035. this.channel = channel;
  1036. this.to = channel.RemoteAddress;
  1037. this.via = channel.Via;
  1038. this.factory = factory;
  1039. }
  1040. public void SendRequest(Message message, TimeSpan timeout)
  1041. {
  1042. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  1043. factory.ApplyManualAddressing(ref this.to, ref this.via, message);
  1044. this.webRequest = channel.GetWebRequest(this.to, this.via, ref timeoutHelper);
  1045. Message request = message;
  1046. try
  1047. {
  1048. if (channel.State != CommunicationState.Opened)
  1049. {
  1050. // if we were aborted while getting our request or doing correlation,
  1051. // we need to abort the web request and bail
  1052. Cleanup();
  1053. channel.ThrowIfDisposedOrNotOpen();
  1054. }
  1055. HttpChannelUtilities.SetRequestTimeout(this.webRequest, timeoutHelper.RemainingTime());
  1056. HttpOutput httpOutput = HttpOutput.CreateHttpOutput(this.webRequest, this.factory, request, this.factory.IsChannelBindingSupportEnabled);
  1057. bool success = false;
  1058. try
  1059. {
  1060. httpOutput.Send(timeoutHelper.RemainingTime());
  1061. this.channelBinding = httpOutput.TakeChannelBinding();
  1062. httpOutput.Close();
  1063. success = true;
  1064. if (FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
  1065. {
  1066. this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
  1067. if (TD.MessageSentByTransportIsEnabled())
  1068. {
  1069. TD.MessageSentByTransport(eventTraceActivity, this.to.Uri.AbsoluteUri);
  1070. }
  1071. }
  1072. }
  1073. finally
  1074. {
  1075. if (!success)
  1076. {
  1077. httpOutput.Abort(HttpAbortReason.Aborted);
  1078. }
  1079. }
  1080. }
  1081. finally
  1082. {
  1083. if (!object.ReferenceEquals(request, message))
  1084. {
  1085. request.Close();
  1086. }
  1087. }
  1088. }
  1089. void Cleanup()
  1090. {
  1091. if (this.webRequest != null)
  1092. {
  1093. HttpChannelUtilities.AbortRequest(this.webRequest);
  1094. this.TryCompleteWebRequest(this.webRequest);
  1095. }
  1096. ChannelBindingUtility.Dispose(ref this.channelBinding);
  1097. }
  1098. public void Abort(RequestChannel channel)
  1099. {
  1100. Cleanup();
  1101. abortReason = HttpAbortReason.Aborted;
  1102. }
  1103. public void Fault(RequestChannel channel)
  1104. {
  1105. Cleanup();
  1106. }
  1107. [System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104",
  1108. Justification = "This is an old method from previous release.")]
  1109. public Message WaitForReply(TimeSpan timeout)
  1110. {
  1111. if (TD.HttpResponseReceiveStartIsEnabled())
  1112. {
  1113. TD.HttpResponseReceiveStart(this.eventTraceActivity);
  1114. }
  1115. HttpWebResponse response = null;
  1116. WebException responseException = null;
  1117. try
  1118. {
  1119. try
  1120. {
  1121. response = (HttpWebResponse)webRequest.GetResponse();
  1122. }
  1123. catch (NullReferenceException nullReferenceException)
  1124. {
  1125. // workaround for Whidbey bug #558605 - only happens in streamed case.
  1126. if (TransferModeHelper.IsRequestStreamed(this.factory.transferMode))
  1127. {
  1128. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1129. HttpChannelUtilities.CreateNullReferenceResponseException(nullReferenceException));
  1130. }
  1131. throw;
  1132. }
  1133. if (TD.MessageReceivedByTransportIsEnabled())
  1134. {
  1135. TD.MessageReceivedByTransport(this.eventTraceActivity ?? EventTraceActivity.Empty,
  1136. response.ResponseUri != null ? response.ResponseUri.AbsoluteUri : string.Empty,
  1137. EventTraceActivity.GetActivityIdFromThread());
  1138. }
  1139. if (DiagnosticUtility.ShouldTraceVerbose)
  1140. {
  1141. HttpChannelFactory<TChannel>.TraceResponseReceived(response, null, this);
  1142. }
  1143. }
  1144. catch (WebException webException)
  1145. {
  1146. responseException = webException;
  1147. response = HttpChannelUtilities.ProcessGetResponseWebException(webException, this.webRequest,
  1148. abortReason);
  1149. }
  1150. HttpInput httpInput = HttpChannelUtilities.ValidateRequestReplyResponse(this.webRequest, response,
  1151. this.factory, responseException, this.channelBinding);
  1152. this.channelBinding = null;
  1153. Message replyMessage = null;
  1154. if (httpInput != null)
  1155. {
  1156. Exception exception = null;
  1157. replyMessage = httpInput.ParseIncomingMessage(out exception);
  1158. Fx.Assert(exception == null, "ParseIncomingMessage should not set an exception after parsing a response message.");
  1159. if (replyMessage != null)
  1160. {
  1161. HttpChannelUtilities.AddReplySecurityProperty(this.factory, this.webRequest, response,
  1162. replyMessage);
  1163. if (FxTrace.Trace.IsEnd2EndActivityTracingEnabled && (eventTraceActivity != null))
  1164. {
  1165. EventTraceActivityHelper.TryAttachActivity(replyMessage, eventTraceActivity);
  1166. }
  1167. }
  1168. }
  1169. this.TryCompleteWebRequest(this.webRequest);
  1170. return replyMessage;
  1171. }
  1172. public void OnReleaseRequest()
  1173. {
  1174. this.TryCompleteWebRequest(this.webRequest);
  1175. }
  1176. void TryCompleteWebRequest(HttpWebRequest request)
  1177. {
  1178. if (request == null)
  1179. {
  1180. return;
  1181. }
  1182. if (Interlocked.CompareExchange(ref this.webRequestCompleted, 1, 0) == 0)
  1183. {
  1184. this.channel.OnWebRequestCompleted(request);
  1185. }
  1186. }
  1187. }
  1188. class HttpChannelAsyncRequest : TraceAsyncResult, IAsyncRequest
  1189. {
  1190. static AsyncCallback onProcessIncomingMessage = Fx.ThunkCallback(new AsyncCallback(OnParseIncomingMessage));
  1191. static AsyncCallback onGetResponse = Fx.ThunkCallback(new AsyncCallback(OnGetResponse));
  1192. static AsyncCallback onGetWebRequestCompleted;
  1193. static AsyncCallback onSend = Fx.ThunkCallback(new AsyncCallback(OnSend));
  1194. static Action<object> onSendTimeout;
  1195. ChannelBinding channelBinding;
  1196. HttpChannelFactory<IRequestChannel> factory;
  1197. HttpRequestChannel channel;
  1198. HttpOutput httpOutput;
  1199. HttpInput httpInput;
  1200. Message message;
  1201. Message requestMessage;
  1202. Message replyMessage;
  1203. HttpWebResponse response;
  1204. HttpWebRequest request;
  1205. object sendLock = new object();
  1206. IOThreadTimer sendTimer;
  1207. TimeoutHelper timeoutHelper;
  1208. EndpointAddress to;
  1209. Uri via;
  1210. HttpAbortReason abortReason;
  1211. int webRequestCompleted;
  1212. EventTraceActivity eventTraceActivity;
  1213. public HttpChannelAsyncRequest(HttpRequestChannel channel, AsyncCallback callback, object state)
  1214. : base(callback, state)
  1215. {
  1216. this.channel = channel;
  1217. this.to = channel.RemoteAddress;
  1218. this.via = channel.Via;
  1219. this.factory = channel.Factory;
  1220. }
  1221. IOThreadTimer SendTimer
  1222. {
  1223. get
  1224. {
  1225. if (this.sendTimer == null)
  1226. {
  1227. if (onSendTimeout == null)
  1228. {
  1229. onSendTimeout = new Action<object>(OnSendTimeout);
  1230. }
  1231. this.sendTimer = new IOThreadTimer(onSendTimeout, this, false);
  1232. }
  1233. return this.sendTimer;
  1234. }
  1235. }
  1236. public static void End(IAsyncResult result)
  1237. {
  1238. AsyncResult.End<HttpChannelAsyncRequest>(result);
  1239. }
  1240. public void BeginSendRequest(Message message, TimeSpan timeout)
  1241. {
  1242. this.message = this.requestMessage = message;
  1243. this.timeoutHelper = new TimeoutHelper(timeout);
  1244. if (FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
  1245. {
  1246. this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
  1247. }
  1248. factory.ApplyManualAddressing(ref this.to, ref this.via, this.requestMessage);
  1249. if (this.channel.WillGetWebRequestCompleteSynchronously())
  1250. {
  1251. SetWebRequest(channel.GetWebRequest(this.to, this.via, ref this.timeoutHelper));
  1252. if (this.SendWebRequest())
  1253. {
  1254. base.Complete(true);
  1255. }
  1256. }
  1257. else
  1258. {
  1259. if (onGetWebRequestCompleted == null)
  1260. {
  1261. onGetWebRequestCompleted = Fx.ThunkCallback(
  1262. new AsyncCallback(OnGetWebRequestCompletedCallback));
  1263. }
  1264. IAsyncResult result = channel.BeginGetWebRequest(
  1265. to, via, ref this.timeoutHelper, onGetWebRequestCompleted, this);
  1266. if (result.CompletedSynchronously)
  1267. {
  1268. if (TD.MessageSentByTransportIsEnabled())
  1269. {
  1270. TD.MessageSentByTransport(this.eventTraceActivity, this.to.Uri.AbsoluteUri);
  1271. }
  1272. if (this.OnGetWebRequestCompleted(result))
  1273. {
  1274. base.Complete(true);
  1275. }
  1276. }
  1277. }
  1278. }
  1279. static void OnGetWebRequestCompletedCallback(IAsyncResult result)
  1280. {
  1281. if (result.CompletedSynchronously)
  1282. {
  1283. return;
  1284. }
  1285. HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
  1286. Exception completionException = null;
  1287. bool completeSelf;
  1288. try
  1289. {
  1290. completeSelf = thisPtr.OnGetWebRequestCompleted(result);
  1291. }
  1292. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1293. catch (Exception e)
  1294. {
  1295. if (Fx.IsFatal(e))
  1296. {
  1297. throw;
  1298. }
  1299. completeSelf = true;
  1300. completionException = e;
  1301. }
  1302. if (completeSelf)
  1303. {
  1304. thisPtr.Complete(false, completionException);
  1305. }
  1306. }
  1307. void AbortSend()
  1308. {
  1309. CancelSendTimer();
  1310. if (this.request != null)
  1311. {
  1312. this.TryCompleteWebRequest(this.request);
  1313. this.abortReason = HttpAbortReason.TimedOut;
  1314. httpOutput.Abort(this.abortReason);
  1315. }
  1316. }
  1317. void CancelSendTimer()
  1318. {
  1319. lock (sendLock)
  1320. {
  1321. if (this.sendTimer != null)
  1322. {
  1323. this.sendTimer.Cancel();
  1324. this.sendTimer = null;
  1325. }
  1326. }
  1327. }
  1328. bool OnGetWebRequestCompleted(IAsyncResult result)
  1329. {
  1330. SetWebRequest(this.channel.EndGetWebRequest(result));
  1331. return this.SendWebRequest();
  1332. }
  1333. bool SendWebRequest()
  1334. {
  1335. this.httpOutput = HttpOutput.CreateHttpOutput(this.request, this.factory, this.requestMessage, this.factory.IsChannelBindingSupportEnabled);
  1336. bool success = false;
  1337. try
  1338. {
  1339. bool result = false;
  1340. SetSendTimeout(timeoutHelper.RemainingTime());
  1341. IAsyncResult asyncResult = httpOutput.BeginSend(timeoutHelper.RemainingTime(), onSend, this);
  1342. success = true;
  1343. if (asyncResult.CompletedSynchronously)
  1344. {
  1345. result = CompleteSend(asyncResult);
  1346. }
  1347. return result;
  1348. }
  1349. finally
  1350. {
  1351. if (!success)
  1352. {
  1353. this.httpOutput.Abort(HttpAbortReason.Aborted);
  1354. if (!object.ReferenceEquals(this.message, this.requestMessage))
  1355. {
  1356. this.requestMessage.Close();
  1357. }
  1358. }
  1359. }
  1360. }
  1361. bool CompleteSend(IAsyncResult result)
  1362. {
  1363. bool success = false;
  1364. try
  1365. {
  1366. httpOutput.EndSend(result);
  1367. this.channelBinding = httpOutput.TakeChannelBinding();
  1368. httpOutput.Close();
  1369. success = true;
  1370. if (TD.MessageSentByTransportIsEnabled())
  1371. {
  1372. TD.MessageSentByTransport(this.eventTraceActivity, this.to.Uri.AbsoluteUri);
  1373. }
  1374. }
  1375. finally
  1376. {
  1377. if (!success)
  1378. {
  1379. httpOutput.Abort(HttpAbortReason.Aborted);
  1380. }
  1381. if (!object.ReferenceEquals(this.message, this.requestMessage))
  1382. {
  1383. this.requestMessage.Close();
  1384. }
  1385. }
  1386. try
  1387. {
  1388. IAsyncResult getResponseResult;
  1389. try
  1390. {
  1391. getResponseResult = request.BeginGetResponse(onGetResponse, this);
  1392. }
  1393. catch (NullReferenceException nullReferenceException)
  1394. {
  1395. // workaround for Whidbey bug #558605 - only happens in streamed case.
  1396. if (TransferModeHelper.IsRequestStreamed(this.factory.transferMode))
  1397. {
  1398. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1399. HttpChannelUtilities.CreateNullReferenceResponseException(nullReferenceException));
  1400. }
  1401. throw;
  1402. }
  1403. if (getResponseResult.CompletedSynchronously)
  1404. {
  1405. return CompleteGetResponse(getResponseResult);
  1406. }
  1407. return false;
  1408. }
  1409. catch (IOException ioException)
  1410. {
  1411. throw TraceUtility.ThrowHelperError(new CommunicationException(ioException.Message,
  1412. ioException), this.requestMessage);
  1413. }
  1414. catch (WebException webException)
  1415. {
  1416. throw TraceUtility.ThrowHelperError(new CommunicationException(webException.Message,
  1417. webException), this.requestMessage);
  1418. }
  1419. catch (ObjectDisposedException objectDisposedException)
  1420. {
  1421. if (abortReason == HttpAbortReason.Aborted)
  1422. {
  1423. throw TraceUtility.ThrowHelperError(new CommunicationObjectAbortedException(SR.GetString(SR.HttpRequestAborted, to.Uri),
  1424. objectDisposedException), this.requestMessage);
  1425. }
  1426. throw TraceUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.HttpRequestTimedOut,
  1427. to.Uri, this.timeoutHelper.OriginalTimeout), objectDisposedException), this.requestMessage);
  1428. }
  1429. }
  1430. [System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104",
  1431. Justification = "This is an old method from previous release.")]
  1432. bool CompleteGetResponse(IAsyncResult result)
  1433. {
  1434. using (ServiceModelActivity.BoundOperation(this.channel.Activity))
  1435. {
  1436. HttpWebResponse response = null;
  1437. WebException responseException = null;
  1438. try
  1439. {
  1440. try
  1441. {
  1442. CancelSendTimer();
  1443. response = (HttpWebResponse)request.EndGetResponse(result);
  1444. }
  1445. catch (NullReferenceException nullReferenceException)
  1446. {
  1447. // workaround for Whidbey bug #558605 - only happens in streamed case.
  1448. if (TransferModeHelper.IsRequestStreamed(this.factory.transferMode))
  1449. {
  1450. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1451. HttpChannelUtilities.CreateNullReferenceResponseException(nullReferenceException));
  1452. }
  1453. throw;
  1454. }
  1455. if (TD.MessageReceivedByTransportIsEnabled())
  1456. {
  1457. TD.MessageReceivedByTransport(
  1458. this.eventTraceActivity ?? EventTraceActivity.Empty,
  1459. this.to.Uri.AbsoluteUri,
  1460. EventTraceActivity.GetActivityIdFromThread());
  1461. }
  1462. if (DiagnosticUtility.ShouldTraceVerbose)
  1463. {
  1464. HttpChannelFactory<TChannel>.TraceResponseReceived(response, this.message, this);
  1465. }
  1466. }
  1467. catch (WebException webException)
  1468. {
  1469. responseException = webException;
  1470. response = HttpChannelUtilities.ProcessGetResponseWebException(webException, request,
  1471. abortReason);
  1472. }
  1473. return ProcessResponse(response, responseException);
  1474. }
  1475. }
  1476. void Cleanup()
  1477. {
  1478. if (this.request != null)
  1479. {
  1480. HttpChannelUtilities.AbortRequest(this.request);
  1481. this.TryCompleteWebRequest(this.request);
  1482. }
  1483. ChannelBindingUtility.Dispose(ref this.channelBinding);
  1484. }
  1485. void SetSendTimeout(TimeSpan timeout)
  1486. {
  1487. // We also set the timeout on the HttpWebRequest so that we can subsequently use it in the
  1488. // exception message in the event of a timeout.
  1489. HttpChannelUtilities.SetRequestTimeout(this.request, timeout);
  1490. if (timeout == TimeSpan.MaxValue)
  1491. {
  1492. CancelSendTimer();
  1493. }
  1494. else
  1495. {
  1496. SendTimer.Set(timeout);
  1497. }
  1498. }
  1499. public void Abort(RequestChannel channel)
  1500. {
  1501. Cleanup();
  1502. abortReason = HttpAbortReason.Aborted;
  1503. }
  1504. public void Fault(RequestChannel channel)
  1505. {
  1506. Cleanup();
  1507. }
  1508. void SetWebRequest(HttpWebRequest webRequest)
  1509. {
  1510. this.request = webRequest;
  1511. if (channel.State != CommunicationState.Opened)
  1512. {
  1513. // if we were aborted while getting our request, we need to abort the web request and bail
  1514. Cleanup();
  1515. channel.ThrowIfDisposedOrNotOpen();
  1516. }
  1517. }
  1518. public Message End()
  1519. {
  1520. HttpChannelAsyncRequest.End(this);
  1521. return replyMessage;
  1522. }
  1523. bool ProcessResponse(HttpWebResponse response, WebException responseException)
  1524. {
  1525. this.httpInput = HttpChannelUtilities.ValidateRequestReplyResponse(this.request, response,
  1526. this.factory, responseException, this.channelBinding);
  1527. this.channelBinding = null;
  1528. if (httpInput != null)
  1529. {
  1530. this.response = response;
  1531. IAsyncResult result =
  1532. httpInput.BeginParseIncomingMessage(onProcessIncomingMessage, this);
  1533. if (!result.CompletedSynchronously)
  1534. {
  1535. return false;
  1536. }
  1537. CompleteParseIncomingMessage(result);
  1538. }
  1539. else
  1540. {
  1541. this.replyMessage = null;
  1542. }
  1543. this.TryCompleteWebRequest(this.request);
  1544. return true;
  1545. }
  1546. void CompleteParseIncomingMessage(IAsyncResult result)
  1547. {
  1548. Exception exception = null;
  1549. this.replyMessage = this.httpInput.EndParseIncomingMessage(result, out exception);
  1550. Fx.Assert(exception == null, "ParseIncomingMessage should not set an exception after parsing a response message.");
  1551. if (this.replyMessage != null)
  1552. {
  1553. HttpChannelUtilities.AddReplySecurityProperty(this.factory, this.request, this.response,
  1554. this.replyMessage);
  1555. }
  1556. }
  1557. static void OnParseIncomingMessage(IAsyncResult result)
  1558. {
  1559. if (result.CompletedSynchronously)
  1560. {
  1561. return;
  1562. }
  1563. HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
  1564. Exception completionException = null;
  1565. try
  1566. {
  1567. thisPtr.CompleteParseIncomingMessage(result);
  1568. }
  1569. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1570. catch (Exception e)
  1571. {
  1572. if (Fx.IsFatal(e))
  1573. {
  1574. throw;
  1575. }
  1576. completionException = e;
  1577. }
  1578. thisPtr.Complete(false, completionException);
  1579. }
  1580. static void OnSend(IAsyncResult result)
  1581. {
  1582. if (result.CompletedSynchronously)
  1583. {
  1584. return;
  1585. }
  1586. HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
  1587. Exception completionException = null;
  1588. bool completeSelf;
  1589. try
  1590. {
  1591. completeSelf = thisPtr.CompleteSend(result);
  1592. }
  1593. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1594. catch (Exception e)
  1595. {
  1596. if (Fx.IsFatal(e))
  1597. {
  1598. throw;
  1599. }
  1600. completeSelf = true;
  1601. completionException = e;
  1602. }
  1603. if (completeSelf)
  1604. {
  1605. thisPtr.Complete(false, completionException);
  1606. }
  1607. }
  1608. static void OnSendTimeout(object state)
  1609. {
  1610. HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)state;
  1611. thisPtr.AbortSend();
  1612. }
  1613. [System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104",
  1614. Justification = "This is an old method from previous release.")]
  1615. static void OnGetResponse(IAsyncResult result)
  1616. {
  1617. if (result.CompletedSynchronously)
  1618. {
  1619. return;
  1620. }
  1621. HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
  1622. Exception completionException = null;
  1623. bool completeSelf;
  1624. try
  1625. {
  1626. completeSelf = thisPtr.CompleteGetResponse(result);
  1627. }
  1628. catch (WebException webException)
  1629. {
  1630. completeSelf = true;
  1631. completionException = new CommunicationException(webException.Message, webException);
  1632. }
  1633. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1634. catch (Exception e)
  1635. {
  1636. if (Fx.IsFatal(e))
  1637. {
  1638. throw;
  1639. }
  1640. completeSelf = true;
  1641. completionException = e;
  1642. }
  1643. if (completeSelf)
  1644. {
  1645. thisPtr.Complete(false, completionException);
  1646. }
  1647. }
  1648. public void OnReleaseRequest()
  1649. {
  1650. this.TryCompleteWebRequest(this.request);
  1651. }
  1652. void TryCompleteWebRequest(HttpWebRequest request)
  1653. {
  1654. if (request == null)
  1655. {
  1656. return;
  1657. }
  1658. if (Interlocked.CompareExchange(ref this.webRequestCompleted, 1, 0) == 0)
  1659. {
  1660. this.channel.OnWebRequestCompleted(request);
  1661. }
  1662. }
  1663. }
  1664. class GetWebRequestAsyncResult : AsyncResult
  1665. {
  1666. static AsyncCallback onGetSspiCredential;
  1667. static AsyncCallback onGetUserNameCredential;
  1668. SecurityTokenContainer clientCertificateToken;
  1669. HttpChannelFactory<IRequestChannel> factory;
  1670. SecurityTokenProviderContainer proxyTokenProvider;
  1671. HttpWebRequest request;
  1672. EndpointAddress to;
  1673. TimeoutHelper timeoutHelper;
  1674. SecurityTokenProviderContainer tokenProvider;
  1675. Uri via;
  1676. public GetWebRequestAsyncResult(HttpRequestChannel channel,
  1677. EndpointAddress to, Uri via, SecurityTokenContainer clientCertificateToken, ref TimeoutHelper timeoutHelper,
  1678. AsyncCallback callback, object state)
  1679. : base(callback, state)
  1680. {
  1681. this.to = to;
  1682. this.via = via;
  1683. this.clientCertificateToken = clientCertificateToken;
  1684. this.timeoutHelper = timeoutHelper;
  1685. this.factory = channel.Factory;
  1686. this.tokenProvider = channel.tokenProvider;
  1687. this.proxyTokenProvider = channel.proxyTokenProvider;
  1688. if (factory.ManualAddressing)
  1689. {
  1690. this.factory.CreateAndOpenTokenProviders(to, via, channel.channelParameters, timeoutHelper.RemainingTime(),
  1691. out this.tokenProvider, out this.proxyTokenProvider);
  1692. }
  1693. bool completeSelf = false;
  1694. IAsyncResult result = null;
  1695. if (factory.AuthenticationScheme == AuthenticationSchemes.Anonymous)
  1696. {
  1697. SetupWebRequest(AuthenticationLevel.None, TokenImpersonationLevel.None, null);
  1698. completeSelf = true;
  1699. }
  1700. else if (factory.AuthenticationScheme == AuthenticationSchemes.Basic)
  1701. {
  1702. if (onGetUserNameCredential == null)
  1703. {
  1704. onGetUserNameCredential = Fx.ThunkCallback(new AsyncCallback(OnGetUserNameCredential));
  1705. }
  1706. result = TransportSecurityHelpers.BeginGetUserNameCredential(
  1707. tokenProvider, timeoutHelper.RemainingTime(), onGetUserNameCredential, this);
  1708. if (result.CompletedSynchronously)
  1709. {
  1710. CompleteGetUserNameCredential(result);
  1711. completeSelf = true;
  1712. }
  1713. }
  1714. else
  1715. {
  1716. if (onGetSspiCredential == null)
  1717. {
  1718. onGetSspiCredential = Fx.ThunkCallback(new AsyncCallback(OnGetSspiCredential));
  1719. }
  1720. result = TransportSecurityHelpers.BeginGetSspiCredential(
  1721. tokenProvider, timeoutHelper.RemainingTime(), onGetSspiCredential, this);
  1722. if (result.CompletedSynchronously)
  1723. {
  1724. CompleteGetSspiCredential(result);
  1725. completeSelf = true;
  1726. }
  1727. }
  1728. if (completeSelf)
  1729. {
  1730. CloseTokenProvidersIfRequired();
  1731. base.Complete(true);
  1732. }
  1733. }
  1734. public static HttpWebRequest End(IAsyncResult result)
  1735. {
  1736. GetWebRequestAsyncResult thisPtr = AsyncResult.End<GetWebRequestAsyncResult>(result);
  1737. return thisPtr.request;
  1738. }
  1739. void CompleteGetUserNameCredential(IAsyncResult result)
  1740. {
  1741. NetworkCredential credential =
  1742. TransportSecurityHelpers.EndGetUserNameCredential(result);
  1743. SetupWebRequest(AuthenticationLevel.None, TokenImpersonationLevel.None, credential);
  1744. }
  1745. void CompleteGetSspiCredential(IAsyncResult result)
  1746. {
  1747. AuthenticationLevel authenticationLevel;
  1748. TokenImpersonationLevel impersonationLevel;
  1749. NetworkCredential credential =
  1750. TransportSecurityHelpers.EndGetSspiCredential(result, out impersonationLevel, out authenticationLevel);
  1751. if (factory.AuthenticationScheme == AuthenticationSchemes.Digest)
  1752. {
  1753. HttpChannelUtilities.ValidateDigestCredential(ref credential, impersonationLevel);
  1754. }
  1755. else if (factory.AuthenticationScheme == AuthenticationSchemes.Ntlm)
  1756. {
  1757. if (authenticationLevel == AuthenticationLevel.MutualAuthRequired)
  1758. {
  1759. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
  1760. SR.GetString(SR.CredentialDisallowsNtlm)));
  1761. }
  1762. }
  1763. SetupWebRequest(authenticationLevel, impersonationLevel, credential);
  1764. }
  1765. void SetupWebRequest(AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel, NetworkCredential credential)
  1766. {
  1767. this.request = factory.GetWebRequest(to, via, credential, impersonationLevel,
  1768. authenticationLevel, this.proxyTokenProvider, this.clientCertificateToken, timeoutHelper.RemainingTime(), false);
  1769. }
  1770. void CloseTokenProvidersIfRequired()
  1771. {
  1772. if (this.factory.ManualAddressing)
  1773. {
  1774. if (this.tokenProvider != null)
  1775. {
  1776. tokenProvider.Abort();
  1777. }
  1778. if (this.proxyTokenProvider != null)
  1779. {
  1780. proxyTokenProvider.Abort();
  1781. }
  1782. }
  1783. }
  1784. static void OnGetSspiCredential(IAsyncResult result)
  1785. {
  1786. if (result.CompletedSynchronously)
  1787. {
  1788. return;
  1789. }
  1790. GetWebRequestAsyncResult thisPtr = (GetWebRequestAsyncResult)result.AsyncState;
  1791. Exception completionException = null;
  1792. try
  1793. {
  1794. thisPtr.CompleteGetSspiCredential(result);
  1795. thisPtr.CloseTokenProvidersIfRequired();
  1796. }
  1797. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1798. catch (Exception e)
  1799. {
  1800. if (Fx.IsFatal(e))
  1801. {
  1802. throw;
  1803. }
  1804. completionException = e;
  1805. }
  1806. thisPtr.Complete(false, completionException);
  1807. }
  1808. static void OnGetUserNameCredential(IAsyncResult result)
  1809. {
  1810. if (result.CompletedSynchronously)
  1811. {
  1812. return;
  1813. }
  1814. GetWebRequestAsyncResult thisPtr = (GetWebRequestAsyncResult)result.AsyncState;
  1815. Exception completionException = null;
  1816. try
  1817. {
  1818. thisPtr.CompleteGetUserNameCredential(result);
  1819. thisPtr.CloseTokenProvidersIfRequired();
  1820. }
  1821. #pragma warning suppress 56500 // [....], transferring exception to another thread
  1822. catch (Exception e)
  1823. {
  1824. if (Fx.IsFatal(e))
  1825. {
  1826. throw;
  1827. }
  1828. completionException = e;
  1829. }
  1830. thisPtr.Complete(false, completionException);
  1831. }
  1832. }
  1833. }
  1834. class WebProxyFactory
  1835. {
  1836. Uri address;
  1837. bool bypassOnLocal;
  1838. AuthenticationSchemes authenticationScheme;
  1839. public WebProxyFactory(Uri address, bool bypassOnLocal, AuthenticationSchemes authenticationScheme)
  1840. {
  1841. this.address = address;
  1842. this.bypassOnLocal = bypassOnLocal;
  1843. if (!authenticationScheme.IsSingleton())
  1844. {
  1845. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.HttpRequiresSingleAuthScheme,
  1846. authenticationScheme));
  1847. }
  1848. this.authenticationScheme = authenticationScheme;
  1849. }
  1850. internal AuthenticationSchemes AuthenticationScheme
  1851. {
  1852. get
  1853. {
  1854. return authenticationScheme;
  1855. }
  1856. }
  1857. public IWebProxy CreateWebProxy(HttpWebRequest request, SecurityTokenProviderContainer tokenProvider, TimeSpan timeout)
  1858. {
  1859. WebProxy result = new WebProxy(this.address, this.bypassOnLocal);
  1860. if (this.authenticationScheme != AuthenticationSchemes.Anonymous)
  1861. {
  1862. TokenImpersonationLevel impersonationLevel;
  1863. AuthenticationLevel authenticationLevel;
  1864. NetworkCredential credential = HttpChannelUtilities.GetCredential(this.authenticationScheme,
  1865. tokenProvider, timeout, out impersonationLevel, out authenticationLevel);
  1866. // The impersonation level for target auth is also used for proxy auth (by System.Net). Therefore,
  1867. // fail if the level stipulated for proxy auth is more restrictive than that for target auth.
  1868. if (!TokenImpersonationLevelHelper.IsGreaterOrEqual(impersonationLevel, request.ImpersonationLevel))
  1869. {
  1870. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
  1871. SR.ProxyImpersonationLevelMismatch, impersonationLevel, request.ImpersonationLevel)));
  1872. }
  1873. // The authentication level for target auth is also used for proxy auth (by System.Net).
  1874. // Therefore, fail if proxy auth requires mutual authentication but target auth does not.
  1875. if ((authenticationLevel == AuthenticationLevel.MutualAuthRequired) &&
  1876. (request.AuthenticationLevel != AuthenticationLevel.MutualAuthRequired))
  1877. {
  1878. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
  1879. SR.ProxyAuthenticationLevelMismatch, authenticationLevel, request.AuthenticationLevel)));
  1880. }
  1881. CredentialCache credentials = new CredentialCache();
  1882. credentials.Add(this.address, AuthenticationSchemesHelper.ToString(this.authenticationScheme),
  1883. credential);
  1884. result.Credentials = credentials;
  1885. }
  1886. return result;
  1887. }
  1888. }
  1889. }
  1890. }