HttpWebRequest.cs 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693
  1. //
  2. // System.Net.HttpWebRequest
  3. //
  4. // Authors:
  5. // Lawrence Pit ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (c) 2002 Lawrence Pit
  9. // (c) 2003 Ximian, Inc. (http://www.ximian.com)
  10. // (c) 2004 Novell, Inc. (http://www.novell.com)
  11. //
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System;
  33. using System.Collections;
  34. using System.Configuration;
  35. using System.Globalization;
  36. using System.IO;
  37. using System.Net;
  38. using System.Net.Cache;
  39. using System.Net.Sockets;
  40. using System.Runtime.Remoting.Messaging;
  41. using System.Runtime.Serialization;
  42. using System.Security.Cryptography.X509Certificates;
  43. using System.Text;
  44. using System.Threading;
  45. namespace System.Net
  46. {
  47. [Serializable]
  48. public class HttpWebRequest : WebRequest, ISerializable {
  49. Uri requestUri;
  50. Uri actualUri;
  51. bool hostChanged;
  52. bool allowAutoRedirect = true;
  53. bool allowBuffering = true;
  54. X509CertificateCollection certificates;
  55. string connectionGroup;
  56. bool haveContentLength;
  57. long contentLength = -1;
  58. HttpContinueDelegate continueDelegate;
  59. CookieContainer cookieContainer;
  60. ICredentials credentials;
  61. bool haveResponse;
  62. bool haveRequest;
  63. bool requestSent;
  64. WebHeaderCollection webHeaders;
  65. bool keepAlive = true;
  66. int maxAutoRedirect = 50;
  67. string mediaType = String.Empty;
  68. string method = "GET";
  69. string initialMethod = "GET";
  70. bool pipelined = true;
  71. bool preAuthenticate;
  72. bool usedPreAuth;
  73. Version version = HttpVersion.Version11;
  74. bool force_version;
  75. Version actualVersion;
  76. IWebProxy proxy;
  77. bool sendChunked;
  78. ServicePoint servicePoint;
  79. int timeout = 100000;
  80. WebConnectionStream writeStream;
  81. HttpWebResponse webResponse;
  82. WebAsyncResult asyncWrite;
  83. WebAsyncResult asyncRead;
  84. EventHandler abortHandler;
  85. int aborted;
  86. bool gotRequestStream;
  87. int redirects;
  88. bool expectContinue;
  89. byte[] bodyBuffer;
  90. int bodyBufferLength;
  91. bool getResponseCalled;
  92. Exception saved_exc;
  93. object locker = new object ();
  94. bool finished_reading;
  95. internal WebConnection WebConnection;
  96. DecompressionMethods auto_decomp;
  97. int maxResponseHeadersLength;
  98. static int defaultMaxResponseHeadersLength;
  99. int readWriteTimeout = 300000; // ms
  100. enum NtlmAuthState {
  101. None,
  102. Challenge,
  103. Response
  104. }
  105. AuthorizationState auth_state, proxy_auth_state;
  106. string host;
  107. // Constructors
  108. static HttpWebRequest ()
  109. {
  110. defaultMaxResponseHeadersLength = 64 * 1024;
  111. #if !NET_2_1
  112. NetConfig config = ConfigurationSettings.GetConfig ("system.net/settings") as NetConfig;
  113. if (config != null) {
  114. int x = config.MaxResponseHeadersLength;
  115. if (x != -1)
  116. x *= 64;
  117. defaultMaxResponseHeadersLength = x;
  118. }
  119. #endif
  120. }
  121. #if NET_2_1
  122. public
  123. #else
  124. internal
  125. #endif
  126. HttpWebRequest (Uri uri)
  127. {
  128. this.requestUri = uri;
  129. this.actualUri = uri;
  130. this.proxy = GlobalProxySelection.Select;
  131. this.webHeaders = new WebHeaderCollection (WebHeaderCollection.HeaderInfo.Request);
  132. ThrowOnError = true;
  133. ResetAuthorization ();
  134. }
  135. [Obsolete ("Serialization is obsoleted for this type", false)]
  136. protected HttpWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext)
  137. {
  138. SerializationInfo info = serializationInfo;
  139. requestUri = (Uri) info.GetValue ("requestUri", typeof (Uri));
  140. actualUri = (Uri) info.GetValue ("actualUri", typeof (Uri));
  141. allowAutoRedirect = info.GetBoolean ("allowAutoRedirect");
  142. allowBuffering = info.GetBoolean ("allowBuffering");
  143. certificates = (X509CertificateCollection) info.GetValue ("certificates", typeof (X509CertificateCollection));
  144. connectionGroup = info.GetString ("connectionGroup");
  145. contentLength = info.GetInt64 ("contentLength");
  146. webHeaders = (WebHeaderCollection) info.GetValue ("webHeaders", typeof (WebHeaderCollection));
  147. keepAlive = info.GetBoolean ("keepAlive");
  148. maxAutoRedirect = info.GetInt32 ("maxAutoRedirect");
  149. mediaType = info.GetString ("mediaType");
  150. method = info.GetString ("method");
  151. initialMethod = info.GetString ("initialMethod");
  152. pipelined = info.GetBoolean ("pipelined");
  153. version = (Version) info.GetValue ("version", typeof (Version));
  154. proxy = (IWebProxy) info.GetValue ("proxy", typeof (IWebProxy));
  155. sendChunked = info.GetBoolean ("sendChunked");
  156. timeout = info.GetInt32 ("timeout");
  157. redirects = info.GetInt32 ("redirects");
  158. host = info.GetString ("host");
  159. ResetAuthorization ();
  160. }
  161. void ResetAuthorization ()
  162. {
  163. auth_state = new AuthorizationState (this, false);
  164. proxy_auth_state = new AuthorizationState (this, true);
  165. }
  166. // Properties
  167. public string Accept {
  168. get { return webHeaders ["Accept"]; }
  169. set {
  170. CheckRequestStarted ();
  171. webHeaders.RemoveAndAdd ("Accept", value);
  172. }
  173. }
  174. public Uri Address {
  175. get { return actualUri; }
  176. internal set { actualUri = value; } // Used by Ftp+proxy
  177. }
  178. public bool AllowAutoRedirect {
  179. get { return allowAutoRedirect; }
  180. set { this.allowAutoRedirect = value; }
  181. }
  182. public bool AllowWriteStreamBuffering {
  183. get { return allowBuffering; }
  184. set { allowBuffering = value; }
  185. }
  186. public virtual bool AllowReadStreamBuffering {
  187. get { return false; }
  188. set {
  189. if (value)
  190. throw new InvalidOperationException ();
  191. }
  192. }
  193. static Exception GetMustImplement ()
  194. {
  195. return new NotImplementedException ();
  196. }
  197. public DecompressionMethods AutomaticDecompression
  198. {
  199. get {
  200. return auto_decomp;
  201. }
  202. set {
  203. CheckRequestStarted ();
  204. auto_decomp = value;
  205. }
  206. }
  207. internal bool InternalAllowBuffering {
  208. get {
  209. return (allowBuffering && (method != "HEAD" && method != "GET" &&
  210. method != "MKCOL" && method != "CONNECT" &&
  211. method != "TRACE"));
  212. }
  213. }
  214. public X509CertificateCollection ClientCertificates {
  215. get {
  216. if (certificates == null)
  217. certificates = new X509CertificateCollection ();
  218. return certificates;
  219. }
  220. [MonoTODO]
  221. set {
  222. throw GetMustImplement ();
  223. }
  224. }
  225. public string Connection {
  226. get { return webHeaders ["Connection"]; }
  227. set {
  228. CheckRequestStarted ();
  229. if (string.IsNullOrEmpty (value)) {
  230. webHeaders.RemoveInternal ("Connection");
  231. return;
  232. }
  233. string val = value.ToLowerInvariant ();
  234. if (val.Contains ("keep-alive") || val.Contains ("close"))
  235. throw new ArgumentException ("Keep-Alive and Close may not be set with this property");
  236. if (keepAlive)
  237. value = value + ", Keep-Alive";
  238. webHeaders.RemoveAndAdd ("Connection", value);
  239. }
  240. }
  241. public override string ConnectionGroupName {
  242. get { return connectionGroup; }
  243. set { connectionGroup = value; }
  244. }
  245. public override long ContentLength {
  246. get { return contentLength; }
  247. set {
  248. CheckRequestStarted ();
  249. if (value < 0)
  250. throw new ArgumentOutOfRangeException ("value", "Content-Length must be >= 0");
  251. contentLength = value;
  252. haveContentLength = true;
  253. }
  254. }
  255. internal long InternalContentLength {
  256. set { contentLength = value; }
  257. }
  258. internal bool ThrowOnError { get; set; }
  259. public override string ContentType {
  260. get { return webHeaders ["Content-Type"]; }
  261. set {
  262. if (value == null || value.Trim().Length == 0) {
  263. webHeaders.RemoveInternal ("Content-Type");
  264. return;
  265. }
  266. webHeaders.RemoveAndAdd ("Content-Type", value);
  267. }
  268. }
  269. public HttpContinueDelegate ContinueDelegate {
  270. get { return continueDelegate; }
  271. set { continueDelegate = value; }
  272. }
  273. virtual
  274. public CookieContainer CookieContainer {
  275. get { return cookieContainer; }
  276. set { cookieContainer = value; }
  277. }
  278. public override ICredentials Credentials {
  279. get { return credentials; }
  280. set { credentials = value; }
  281. }
  282. public DateTime Date {
  283. get {
  284. string date = webHeaders ["Date"];
  285. if (date == null)
  286. return DateTime.MinValue;
  287. return DateTime.ParseExact (date, "r", CultureInfo.InvariantCulture).ToLocalTime ();
  288. }
  289. set {
  290. if (value.Equals (DateTime.MinValue))
  291. webHeaders.RemoveInternal ("Date");
  292. else
  293. webHeaders.RemoveAndAdd ("Date", value.ToUniversalTime ().ToString ("r", CultureInfo.InvariantCulture));
  294. }
  295. }
  296. #if !NET_2_1
  297. [MonoTODO]
  298. public static new RequestCachePolicy DefaultCachePolicy
  299. {
  300. get {
  301. throw GetMustImplement ();
  302. }
  303. set {
  304. throw GetMustImplement ();
  305. }
  306. }
  307. #endif
  308. [MonoTODO]
  309. public static int DefaultMaximumErrorResponseLength
  310. {
  311. get {
  312. throw GetMustImplement ();
  313. }
  314. set {
  315. throw GetMustImplement ();
  316. }
  317. }
  318. public string Expect {
  319. get { return webHeaders ["Expect"]; }
  320. set {
  321. CheckRequestStarted ();
  322. string val = value;
  323. if (val != null)
  324. val = val.Trim ().ToLower ();
  325. if (val == null || val.Length == 0) {
  326. webHeaders.RemoveInternal ("Expect");
  327. return;
  328. }
  329. if (val == "100-continue")
  330. throw new ArgumentException ("100-Continue cannot be set with this property.",
  331. "value");
  332. webHeaders.RemoveAndAdd ("Expect", value);
  333. }
  334. }
  335. virtual
  336. public bool HaveResponse {
  337. get { return haveResponse; }
  338. }
  339. public override WebHeaderCollection Headers {
  340. get { return webHeaders; }
  341. set {
  342. CheckRequestStarted ();
  343. WebHeaderCollection newHeaders = new WebHeaderCollection (WebHeaderCollection.HeaderInfo.Request);
  344. int count = value.Count;
  345. for (int i = 0; i < count; i++)
  346. newHeaders.Add (value.GetKey (i), value.Get (i));
  347. webHeaders = newHeaders;
  348. }
  349. }
  350. public
  351. string Host {
  352. get {
  353. if (host == null)
  354. return actualUri.Authority;
  355. return host;
  356. }
  357. set {
  358. if (value == null)
  359. throw new ArgumentNullException ("value");
  360. if (!CheckValidHost (actualUri.Scheme, value))
  361. throw new ArgumentException ("Invalid host: " + value);
  362. host = value;
  363. }
  364. }
  365. static bool CheckValidHost (string scheme, string val)
  366. {
  367. if (val.Length == 0)
  368. return false;
  369. if (val [0] == '.')
  370. return false;
  371. int idx = val.IndexOf ('/');
  372. if (idx >= 0)
  373. return false;
  374. IPAddress ipaddr;
  375. if (IPAddress.TryParse (val, out ipaddr))
  376. return true;
  377. string u = scheme + "://" + val + "/";
  378. return Uri.IsWellFormedUriString (u, UriKind.Absolute);
  379. }
  380. public DateTime IfModifiedSince {
  381. get {
  382. string str = webHeaders ["If-Modified-Since"];
  383. if (str == null)
  384. return DateTime.Now;
  385. try {
  386. return MonoHttpDate.Parse (str);
  387. } catch (Exception) {
  388. return DateTime.Now;
  389. }
  390. }
  391. set {
  392. CheckRequestStarted ();
  393. // rfc-1123 pattern
  394. webHeaders.SetInternal ("If-Modified-Since",
  395. value.ToUniversalTime ().ToString ("r", null));
  396. // TODO: check last param when using different locale
  397. }
  398. }
  399. public bool KeepAlive {
  400. get {
  401. return keepAlive;
  402. }
  403. set {
  404. keepAlive = value;
  405. }
  406. }
  407. public int MaximumAutomaticRedirections {
  408. get { return maxAutoRedirect; }
  409. set {
  410. if (value <= 0)
  411. throw new ArgumentException ("Must be > 0", "value");
  412. maxAutoRedirect = value;
  413. }
  414. }
  415. [MonoTODO ("Use this")]
  416. public int MaximumResponseHeadersLength {
  417. get { return maxResponseHeadersLength; }
  418. set { maxResponseHeadersLength = value; }
  419. }
  420. [MonoTODO ("Use this")]
  421. public static int DefaultMaximumResponseHeadersLength {
  422. get { return defaultMaxResponseHeadersLength; }
  423. set { defaultMaxResponseHeadersLength = value; }
  424. }
  425. public int ReadWriteTimeout {
  426. get { return readWriteTimeout; }
  427. set {
  428. if (requestSent)
  429. throw new InvalidOperationException ("The request has already been sent.");
  430. if (value < -1)
  431. throw new ArgumentOutOfRangeException ("value", "Must be >= -1");
  432. readWriteTimeout = value;
  433. }
  434. }
  435. [MonoTODO]
  436. public int ContinueTimeout {
  437. get { throw new NotImplementedException (); }
  438. set { throw new NotImplementedException (); }
  439. }
  440. public string MediaType {
  441. get { return mediaType; }
  442. set {
  443. mediaType = value;
  444. }
  445. }
  446. public override string Method {
  447. get { return this.method; }
  448. set {
  449. if (value == null || value.Trim () == "")
  450. throw new ArgumentException ("not a valid method");
  451. method = value.ToUpperInvariant ();
  452. if (method != "HEAD" && method != "GET" && method != "POST" && method != "PUT" &&
  453. method != "DELETE" && method != "CONNECT" && method != "TRACE" &&
  454. method != "MKCOL") {
  455. method = value;
  456. }
  457. }
  458. }
  459. public bool Pipelined {
  460. get { return pipelined; }
  461. set { pipelined = value; }
  462. }
  463. public override bool PreAuthenticate {
  464. get { return preAuthenticate; }
  465. set { preAuthenticate = value; }
  466. }
  467. public Version ProtocolVersion {
  468. get { return version; }
  469. set {
  470. if (value != HttpVersion.Version10 && value != HttpVersion.Version11)
  471. throw new ArgumentException ("value");
  472. force_version = true;
  473. version = value;
  474. }
  475. }
  476. public override IWebProxy Proxy {
  477. get { return proxy; }
  478. set {
  479. CheckRequestStarted ();
  480. proxy = value;
  481. servicePoint = null; // we may need a new one
  482. }
  483. }
  484. public string Referer {
  485. get { return webHeaders ["Referer"]; }
  486. set {
  487. CheckRequestStarted ();
  488. if (value == null || value.Trim().Length == 0) {
  489. webHeaders.RemoveInternal ("Referer");
  490. return;
  491. }
  492. webHeaders.SetInternal ("Referer", value);
  493. }
  494. }
  495. public override Uri RequestUri {
  496. get { return requestUri; }
  497. }
  498. public bool SendChunked {
  499. get { return sendChunked; }
  500. set {
  501. CheckRequestStarted ();
  502. sendChunked = value;
  503. }
  504. }
  505. public ServicePoint ServicePoint {
  506. get { return GetServicePoint (); }
  507. }
  508. internal ServicePoint ServicePointNoLock {
  509. get { return servicePoint; }
  510. }
  511. public virtual bool SupportsCookieContainer {
  512. get {
  513. // The managed implementation supports the cookie container
  514. // it is only Silverlight that returns false here
  515. return true;
  516. }
  517. }
  518. public override int Timeout {
  519. get { return timeout; }
  520. set {
  521. if (value < -1)
  522. throw new ArgumentOutOfRangeException ("value");
  523. timeout = value;
  524. }
  525. }
  526. public string TransferEncoding {
  527. get { return webHeaders ["Transfer-Encoding"]; }
  528. set {
  529. CheckRequestStarted ();
  530. string val = value;
  531. if (val != null)
  532. val = val.Trim ().ToLower ();
  533. if (val == null || val.Length == 0) {
  534. webHeaders.RemoveInternal ("Transfer-Encoding");
  535. return;
  536. }
  537. if (val == "chunked")
  538. throw new ArgumentException ("Chunked encoding must be set with the SendChunked property");
  539. if (!sendChunked)
  540. throw new ArgumentException ("SendChunked must be True", "value");
  541. webHeaders.RemoveAndAdd ("Transfer-Encoding", value);
  542. }
  543. }
  544. public override bool UseDefaultCredentials
  545. {
  546. get { return CredentialCache.DefaultCredentials == Credentials; }
  547. set { Credentials = value ? CredentialCache.DefaultCredentials : null; }
  548. }
  549. public string UserAgent {
  550. get { return webHeaders ["User-Agent"]; }
  551. set { webHeaders.SetInternal ("User-Agent", value); }
  552. }
  553. bool unsafe_auth_blah;
  554. public bool UnsafeAuthenticatedConnectionSharing
  555. {
  556. get { return unsafe_auth_blah; }
  557. set { unsafe_auth_blah = value; }
  558. }
  559. internal bool GotRequestStream {
  560. get { return gotRequestStream; }
  561. }
  562. internal bool ExpectContinue {
  563. get { return expectContinue; }
  564. set { expectContinue = value; }
  565. }
  566. internal Uri AuthUri {
  567. get { return actualUri; }
  568. }
  569. internal bool ProxyQuery {
  570. get { return servicePoint.UsesProxy && !servicePoint.UseConnect; }
  571. }
  572. // Methods
  573. internal ServicePoint GetServicePoint ()
  574. {
  575. lock (locker) {
  576. if (hostChanged || servicePoint == null) {
  577. servicePoint = ServicePointManager.FindServicePoint (actualUri, proxy);
  578. hostChanged = false;
  579. }
  580. }
  581. return servicePoint;
  582. }
  583. public void AddRange (int range)
  584. {
  585. AddRange ("bytes", (long) range);
  586. }
  587. public void AddRange (int from, int to)
  588. {
  589. AddRange ("bytes", (long) from, (long) to);
  590. }
  591. public void AddRange (string rangeSpecifier, int range)
  592. {
  593. AddRange (rangeSpecifier, (long) range);
  594. }
  595. public void AddRange (string rangeSpecifier, int from, int to)
  596. {
  597. AddRange (rangeSpecifier, (long) from, (long) to);
  598. }
  599. public
  600. void AddRange (long range)
  601. {
  602. AddRange ("bytes", (long) range);
  603. }
  604. public
  605. void AddRange (long from, long to)
  606. {
  607. AddRange ("bytes", from, to);
  608. }
  609. public
  610. void AddRange (string rangeSpecifier, long range)
  611. {
  612. if (rangeSpecifier == null)
  613. throw new ArgumentNullException ("rangeSpecifier");
  614. if (!WebHeaderCollection.IsHeaderValue (rangeSpecifier))
  615. throw new ArgumentException ("Invalid range specifier", "rangeSpecifier");
  616. string r = webHeaders ["Range"];
  617. if (r == null)
  618. r = rangeSpecifier + "=";
  619. else {
  620. string old_specifier = r.Substring (0, r.IndexOf ('='));
  621. if (String.Compare (old_specifier, rangeSpecifier, StringComparison.OrdinalIgnoreCase) != 0)
  622. throw new InvalidOperationException ("A different range specifier is already in use");
  623. r += ",";
  624. }
  625. string n = range.ToString (CultureInfo.InvariantCulture);
  626. if (range < 0)
  627. r = r + "0" + n;
  628. else
  629. r = r + n + "-";
  630. webHeaders.RemoveAndAdd ("Range", r);
  631. }
  632. public
  633. void AddRange (string rangeSpecifier, long from, long to)
  634. {
  635. if (rangeSpecifier == null)
  636. throw new ArgumentNullException ("rangeSpecifier");
  637. if (!WebHeaderCollection.IsHeaderValue (rangeSpecifier))
  638. throw new ArgumentException ("Invalid range specifier", "rangeSpecifier");
  639. if (from > to || from < 0)
  640. throw new ArgumentOutOfRangeException ("from");
  641. if (to < 0)
  642. throw new ArgumentOutOfRangeException ("to");
  643. string r = webHeaders ["Range"];
  644. if (r == null)
  645. r = rangeSpecifier + "=";
  646. else
  647. r += ",";
  648. r = String.Format ("{0}{1}-{2}", r, from, to);
  649. webHeaders.RemoveAndAdd ("Range", r);
  650. }
  651. public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state)
  652. {
  653. if (Aborted)
  654. throw new WebException ("The request was canceled.", WebExceptionStatus.RequestCanceled);
  655. bool send = !(method == "GET" || method == "CONNECT" || method == "HEAD" ||
  656. method == "TRACE");
  657. if (method == null || !send)
  658. throw new ProtocolViolationException ("Cannot send data when method is: " + method);
  659. if (contentLength == -1 && !sendChunked && !allowBuffering && KeepAlive)
  660. throw new ProtocolViolationException ("Content-Length not set");
  661. string transferEncoding = TransferEncoding;
  662. if (!sendChunked && transferEncoding != null && transferEncoding.Trim () != "")
  663. throw new ProtocolViolationException ("SendChunked should be true.");
  664. lock (locker)
  665. {
  666. if (getResponseCalled)
  667. throw new InvalidOperationException ("The operation cannot be performed once the request has been submitted.");
  668. if (asyncWrite != null) {
  669. throw new InvalidOperationException ("Cannot re-call start of asynchronous " +
  670. "method while a previous call is still in progress.");
  671. }
  672. asyncWrite = new WebAsyncResult (this, callback, state);
  673. initialMethod = method;
  674. if (haveRequest) {
  675. if (writeStream != null) {
  676. asyncWrite.SetCompleted (true, writeStream);
  677. asyncWrite.DoCallback ();
  678. return asyncWrite;
  679. }
  680. }
  681. gotRequestStream = true;
  682. WebAsyncResult result = asyncWrite;
  683. if (!requestSent) {
  684. requestSent = true;
  685. redirects = 0;
  686. servicePoint = GetServicePoint ();
  687. abortHandler = servicePoint.SendRequest (this, connectionGroup);
  688. }
  689. return result;
  690. }
  691. }
  692. public override Stream EndGetRequestStream (IAsyncResult asyncResult)
  693. {
  694. if (asyncResult == null)
  695. throw new ArgumentNullException ("asyncResult");
  696. WebAsyncResult result = asyncResult as WebAsyncResult;
  697. if (result == null)
  698. throw new ArgumentException ("Invalid IAsyncResult");
  699. asyncWrite = result;
  700. result.WaitUntilComplete ();
  701. Exception e = result.Exception;
  702. if (e != null)
  703. throw e;
  704. return result.WriteStream;
  705. }
  706. public override Stream GetRequestStream()
  707. {
  708. IAsyncResult asyncResult = asyncWrite;
  709. if (asyncResult == null) {
  710. asyncResult = BeginGetRequestStream (null, null);
  711. asyncWrite = (WebAsyncResult) asyncResult;
  712. }
  713. if (!asyncResult.IsCompleted && !asyncResult.AsyncWaitHandle.WaitOne (timeout, false)) {
  714. Abort ();
  715. throw new WebException ("The request timed out", WebExceptionStatus.Timeout);
  716. }
  717. return EndGetRequestStream (asyncResult);
  718. }
  719. bool CheckIfForceWrite (SimpleAsyncResult result)
  720. {
  721. if (writeStream == null || writeStream.RequestWritten || !InternalAllowBuffering)
  722. return false;
  723. if (contentLength < 0 && writeStream.CanWrite == true && writeStream.WriteBufferLength < 0)
  724. return false;
  725. if (contentLength < 0 && writeStream.WriteBufferLength >= 0)
  726. InternalContentLength = writeStream.WriteBufferLength;
  727. // This will write the POST/PUT if the write stream already has the expected
  728. // amount of bytes in it (ContentLength) (bug #77753) or if the write stream
  729. // contains data and it has been closed already (xamarin bug #1512).
  730. if (writeStream.WriteBufferLength == contentLength || (contentLength == -1 && writeStream.CanWrite == false))
  731. return writeStream.WriteRequestAsync (result);
  732. return false;
  733. }
  734. public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
  735. {
  736. if (Aborted)
  737. throw new WebException ("The request was canceled.", WebExceptionStatus.RequestCanceled);
  738. if (method == null)
  739. throw new ProtocolViolationException ("Method is null.");
  740. string transferEncoding = TransferEncoding;
  741. if (!sendChunked && transferEncoding != null && transferEncoding.Trim () != "")
  742. throw new ProtocolViolationException ("SendChunked should be true.");
  743. Monitor.Enter (locker);
  744. getResponseCalled = true;
  745. if (asyncRead != null && !haveResponse) {
  746. Monitor.Exit (locker);
  747. throw new InvalidOperationException ("Cannot re-call start of asynchronous " +
  748. "method while a previous call is still in progress.");
  749. }
  750. asyncRead = new WebAsyncResult (this, callback, state);
  751. WebAsyncResult aread = asyncRead;
  752. initialMethod = method;
  753. SimpleAsyncResult.RunWithLock (locker, CheckIfForceWrite, inner => {
  754. var synch = inner.CompletedSynchronously;
  755. if (inner.GotException) {
  756. aread.SetCompleted (synch, inner.Exception);
  757. aread.DoCallback ();
  758. return;
  759. }
  760. if (haveResponse) {
  761. Exception saved = saved_exc;
  762. if (webResponse != null) {
  763. if (saved == null) {
  764. aread.SetCompleted (synch, webResponse);
  765. } else {
  766. aread.SetCompleted (synch, saved);
  767. }
  768. aread.DoCallback ();
  769. return;
  770. } else if (saved != null) {
  771. aread.SetCompleted (synch, saved);
  772. aread.DoCallback ();
  773. return;
  774. }
  775. }
  776. if (!requestSent) {
  777. requestSent = true;
  778. redirects = 0;
  779. servicePoint = GetServicePoint ();
  780. abortHandler = servicePoint.SendRequest (this, connectionGroup);
  781. }
  782. });
  783. return aread;
  784. }
  785. public override WebResponse EndGetResponse (IAsyncResult asyncResult)
  786. {
  787. if (asyncResult == null)
  788. throw new ArgumentNullException ("asyncResult");
  789. WebAsyncResult result = asyncResult as WebAsyncResult;
  790. if (result == null)
  791. throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
  792. if (!result.WaitUntilComplete (timeout, false)) {
  793. Abort ();
  794. throw new WebException("The request timed out", WebExceptionStatus.Timeout);
  795. }
  796. if (result.GotException)
  797. throw result.Exception;
  798. return result.Response;
  799. }
  800. public Stream EndGetRequestStream (IAsyncResult asyncResult, out TransportContext transportContext)
  801. {
  802. transportContext = null;
  803. return EndGetRequestStream (asyncResult);
  804. }
  805. public override WebResponse GetResponse()
  806. {
  807. WebAsyncResult result = (WebAsyncResult) BeginGetResponse (null, null);
  808. return EndGetResponse (result);
  809. }
  810. internal bool FinishedReading {
  811. get { return finished_reading; }
  812. set { finished_reading = value; }
  813. }
  814. internal bool Aborted {
  815. get { return Interlocked.CompareExchange (ref aborted, 0, 0) == 1; }
  816. }
  817. public override void Abort ()
  818. {
  819. if (Interlocked.CompareExchange (ref aborted, 1, 0) == 1)
  820. return;
  821. if (haveResponse && finished_reading)
  822. return;
  823. haveResponse = true;
  824. if (abortHandler != null) {
  825. try {
  826. abortHandler (this, EventArgs.Empty);
  827. } catch (Exception) {}
  828. abortHandler = null;
  829. }
  830. if (asyncWrite != null) {
  831. WebAsyncResult r = asyncWrite;
  832. if (!r.IsCompleted) {
  833. try {
  834. WebException wexc = new WebException ("Aborted.", WebExceptionStatus.RequestCanceled);
  835. r.SetCompleted (false, wexc);
  836. r.DoCallback ();
  837. } catch {}
  838. }
  839. asyncWrite = null;
  840. }
  841. if (asyncRead != null) {
  842. WebAsyncResult r = asyncRead;
  843. if (!r.IsCompleted) {
  844. try {
  845. WebException wexc = new WebException ("Aborted.", WebExceptionStatus.RequestCanceled);
  846. r.SetCompleted (false, wexc);
  847. r.DoCallback ();
  848. } catch {}
  849. }
  850. asyncRead = null;
  851. }
  852. if (writeStream != null) {
  853. try {
  854. writeStream.Close ();
  855. writeStream = null;
  856. } catch {}
  857. }
  858. if (webResponse != null) {
  859. try {
  860. webResponse.Close ();
  861. webResponse = null;
  862. } catch {}
  863. }
  864. }
  865. void ISerializable.GetObjectData (SerializationInfo serializationInfo,
  866. StreamingContext streamingContext)
  867. {
  868. GetObjectData (serializationInfo, streamingContext);
  869. }
  870. protected override void GetObjectData (SerializationInfo serializationInfo,
  871. StreamingContext streamingContext)
  872. {
  873. SerializationInfo info = serializationInfo;
  874. info.AddValue ("requestUri", requestUri, typeof (Uri));
  875. info.AddValue ("actualUri", actualUri, typeof (Uri));
  876. info.AddValue ("allowAutoRedirect", allowAutoRedirect);
  877. info.AddValue ("allowBuffering", allowBuffering);
  878. info.AddValue ("certificates", certificates, typeof (X509CertificateCollection));
  879. info.AddValue ("connectionGroup", connectionGroup);
  880. info.AddValue ("contentLength", contentLength);
  881. info.AddValue ("webHeaders", webHeaders, typeof (WebHeaderCollection));
  882. info.AddValue ("keepAlive", keepAlive);
  883. info.AddValue ("maxAutoRedirect", maxAutoRedirect);
  884. info.AddValue ("mediaType", mediaType);
  885. info.AddValue ("method", method);
  886. info.AddValue ("initialMethod", initialMethod);
  887. info.AddValue ("pipelined", pipelined);
  888. info.AddValue ("version", version, typeof (Version));
  889. info.AddValue ("proxy", proxy, typeof (IWebProxy));
  890. info.AddValue ("sendChunked", sendChunked);
  891. info.AddValue ("timeout", timeout);
  892. info.AddValue ("redirects", redirects);
  893. info.AddValue ("host", host);
  894. }
  895. void CheckRequestStarted ()
  896. {
  897. if (requestSent)
  898. throw new InvalidOperationException ("request started");
  899. }
  900. internal void DoContinueDelegate (int statusCode, WebHeaderCollection headers)
  901. {
  902. if (continueDelegate != null)
  903. continueDelegate (statusCode, headers);
  904. }
  905. void RewriteRedirectToGet ()
  906. {
  907. method = "GET";
  908. webHeaders.RemoveInternal ("Transfer-Encoding");
  909. sendChunked = false;
  910. }
  911. bool Redirect (WebAsyncResult result, HttpStatusCode code, WebResponse response)
  912. {
  913. redirects++;
  914. Exception e = null;
  915. string uriString = null;
  916. switch (code) {
  917. case HttpStatusCode.Ambiguous: // 300
  918. e = new WebException ("Ambiguous redirect.");
  919. break;
  920. case HttpStatusCode.MovedPermanently: // 301
  921. case HttpStatusCode.Redirect: // 302
  922. if (method == "POST")
  923. RewriteRedirectToGet ();
  924. break;
  925. case HttpStatusCode.TemporaryRedirect: // 307
  926. break;
  927. case HttpStatusCode.SeeOther: //303
  928. RewriteRedirectToGet ();
  929. break;
  930. case HttpStatusCode.NotModified: // 304
  931. return false;
  932. case HttpStatusCode.UseProxy: // 305
  933. e = new NotImplementedException ("Proxy support not available.");
  934. break;
  935. case HttpStatusCode.Unused: // 306
  936. default:
  937. e = new ProtocolViolationException ("Invalid status code: " + (int) code);
  938. break;
  939. }
  940. if (method != "GET" && !InternalAllowBuffering)
  941. e = new WebException ("The request requires buffering data to succeed.", null, WebExceptionStatus.ProtocolError, webResponse);
  942. if (e != null)
  943. throw e;
  944. contentLength = -1;
  945. uriString = webResponse.Headers ["Location"];
  946. if (uriString == null)
  947. throw new WebException ("No Location header found for " + (int) code,
  948. WebExceptionStatus.ProtocolError);
  949. Uri prev = actualUri;
  950. try {
  951. actualUri = new Uri (actualUri, uriString);
  952. } catch (Exception) {
  953. throw new WebException (String.Format ("Invalid URL ({0}) for {1}",
  954. uriString, (int) code),
  955. WebExceptionStatus.ProtocolError);
  956. }
  957. hostChanged = (actualUri.Scheme != prev.Scheme || Host != prev.Authority);
  958. return true;
  959. }
  960. string GetHeaders ()
  961. {
  962. bool continue100 = false;
  963. if (sendChunked) {
  964. continue100 = true;
  965. webHeaders.RemoveAndAdd ("Transfer-Encoding", "chunked");
  966. webHeaders.RemoveInternal ("Content-Length");
  967. } else if (contentLength != -1) {
  968. if (auth_state.NtlmAuthState == NtlmAuthState.Challenge || proxy_auth_state.NtlmAuthState == NtlmAuthState.Challenge) {
  969. // We don't send any body with the NTLM Challenge request.
  970. if (haveContentLength || gotRequestStream || contentLength > 0)
  971. webHeaders.SetInternal ("Content-Length", "0");
  972. else
  973. webHeaders.RemoveInternal ("Content-Length");
  974. } else {
  975. if (contentLength > 0)
  976. continue100 = true;
  977. if (haveContentLength || gotRequestStream || contentLength > 0)
  978. webHeaders.SetInternal ("Content-Length", contentLength.ToString ());
  979. }
  980. webHeaders.RemoveInternal ("Transfer-Encoding");
  981. } else {
  982. webHeaders.RemoveInternal ("Content-Length");
  983. }
  984. if (actualVersion == HttpVersion.Version11 && continue100 &&
  985. servicePoint.SendContinue) { // RFC2616 8.2.3
  986. webHeaders.RemoveAndAdd ("Expect" , "100-continue");
  987. expectContinue = true;
  988. } else {
  989. webHeaders.RemoveInternal ("Expect");
  990. expectContinue = false;
  991. }
  992. bool proxy_query = ProxyQuery;
  993. string connectionHeader = (proxy_query) ? "Proxy-Connection" : "Connection";
  994. webHeaders.RemoveInternal ((!proxy_query) ? "Proxy-Connection" : "Connection");
  995. Version proto_version = servicePoint.ProtocolVersion;
  996. bool spoint10 = (proto_version == null || proto_version == HttpVersion.Version10);
  997. if (keepAlive && (version == HttpVersion.Version10 || spoint10)) {
  998. if (webHeaders[connectionHeader] == null
  999. || webHeaders[connectionHeader].IndexOf ("keep-alive", StringComparison.OrdinalIgnoreCase) == -1)
  1000. webHeaders.RemoveAndAdd (connectionHeader, "keep-alive");
  1001. } else if (!keepAlive && version == HttpVersion.Version11) {
  1002. webHeaders.RemoveAndAdd (connectionHeader, "close");
  1003. }
  1004. webHeaders.SetInternal ("Host", Host);
  1005. if (cookieContainer != null) {
  1006. string cookieHeader = cookieContainer.GetCookieHeader (actualUri);
  1007. if (cookieHeader != "")
  1008. webHeaders.RemoveAndAdd ("Cookie", cookieHeader);
  1009. else
  1010. webHeaders.RemoveInternal ("Cookie");
  1011. }
  1012. string accept_encoding = null;
  1013. if ((auto_decomp & DecompressionMethods.GZip) != 0)
  1014. accept_encoding = "gzip";
  1015. if ((auto_decomp & DecompressionMethods.Deflate) != 0)
  1016. accept_encoding = accept_encoding != null ? "gzip, deflate" : "deflate";
  1017. if (accept_encoding != null)
  1018. webHeaders.RemoveAndAdd ("Accept-Encoding", accept_encoding);
  1019. if (!usedPreAuth && preAuthenticate)
  1020. DoPreAuthenticate ();
  1021. return webHeaders.ToString ();
  1022. }
  1023. void DoPreAuthenticate ()
  1024. {
  1025. bool isProxy = (proxy != null && !proxy.IsBypassed (actualUri));
  1026. ICredentials creds = (!isProxy || credentials != null) ? credentials : proxy.Credentials;
  1027. Authorization auth = AuthenticationManager.PreAuthenticate (this, creds);
  1028. if (auth == null)
  1029. return;
  1030. webHeaders.RemoveInternal ("Proxy-Authorization");
  1031. webHeaders.RemoveInternal ("Authorization");
  1032. string authHeader = (isProxy && credentials == null) ? "Proxy-Authorization" : "Authorization";
  1033. webHeaders [authHeader] = auth.Message;
  1034. usedPreAuth = true;
  1035. }
  1036. internal void SetWriteStreamError (WebExceptionStatus status, Exception exc)
  1037. {
  1038. if (Aborted)
  1039. return;
  1040. WebAsyncResult r = asyncWrite;
  1041. if (r == null)
  1042. r = asyncRead;
  1043. if (r != null) {
  1044. string msg;
  1045. WebException wex;
  1046. if (exc == null) {
  1047. msg = "Error: " + status;
  1048. wex = new WebException (msg, status);
  1049. } else {
  1050. msg = String.Format ("Error: {0} ({1})", status, exc.Message);
  1051. wex = new WebException (msg, exc, status);
  1052. }
  1053. r.SetCompleted (false, wex);
  1054. r.DoCallback ();
  1055. }
  1056. }
  1057. internal byte[] GetRequestHeaders ()
  1058. {
  1059. StringBuilder req = new StringBuilder ();
  1060. string query;
  1061. if (!ProxyQuery) {
  1062. query = actualUri.PathAndQuery;
  1063. } else {
  1064. query = String.Format ("{0}://{1}{2}", actualUri.Scheme,
  1065. Host,
  1066. actualUri.PathAndQuery);
  1067. }
  1068. if (!force_version && servicePoint.ProtocolVersion != null && servicePoint.ProtocolVersion < version) {
  1069. actualVersion = servicePoint.ProtocolVersion;
  1070. } else {
  1071. actualVersion = version;
  1072. }
  1073. req.AppendFormat ("{0} {1} HTTP/{2}.{3}\r\n", method, query,
  1074. actualVersion.Major, actualVersion.Minor);
  1075. req.Append (GetHeaders ());
  1076. string reqstr = req.ToString ();
  1077. return Encoding.UTF8.GetBytes (reqstr);
  1078. }
  1079. internal void SetWriteStream (WebConnectionStream stream)
  1080. {
  1081. if (Aborted)
  1082. return;
  1083. writeStream = stream;
  1084. if (bodyBuffer != null) {
  1085. webHeaders.RemoveInternal ("Transfer-Encoding");
  1086. contentLength = bodyBufferLength;
  1087. writeStream.SendChunked = false;
  1088. }
  1089. writeStream.SetHeadersAsync (false, result => {
  1090. if (result.GotException) {
  1091. SetWriteStreamError (result.Exception);
  1092. return;
  1093. }
  1094. haveRequest = true;
  1095. SetWriteStreamInner (inner => {
  1096. if (inner.GotException) {
  1097. SetWriteStreamError (inner.Exception);
  1098. return;
  1099. }
  1100. if (asyncWrite != null) {
  1101. asyncWrite.SetCompleted (inner.CompletedSynchronously, writeStream);
  1102. asyncWrite.DoCallback ();
  1103. asyncWrite = null;
  1104. }
  1105. });
  1106. });
  1107. }
  1108. void SetWriteStreamInner (SimpleAsyncCallback callback)
  1109. {
  1110. SimpleAsyncResult.Run (result => {
  1111. if (bodyBuffer != null) {
  1112. // The body has been written and buffered. The request "user"
  1113. // won't write it again, so we must do it.
  1114. if (auth_state.NtlmAuthState != NtlmAuthState.Challenge && proxy_auth_state.NtlmAuthState != NtlmAuthState.Challenge) {
  1115. // FIXME: this is a blocking call on the thread pool that could lead to thread pool exhaustion
  1116. writeStream.Write (bodyBuffer, 0, bodyBufferLength);
  1117. bodyBuffer = null;
  1118. writeStream.Close ();
  1119. }
  1120. } else if (method != "HEAD" && method != "GET" && method != "MKCOL" && method != "CONNECT" &&
  1121. method != "TRACE") {
  1122. if (getResponseCalled && !writeStream.RequestWritten)
  1123. return writeStream.WriteRequestAsync (result);
  1124. }
  1125. return false;
  1126. }, callback);
  1127. }
  1128. void SetWriteStreamError (Exception exc)
  1129. {
  1130. WebException wexc = exc as WebException;
  1131. if (wexc != null)
  1132. SetWriteStreamError (wexc.Status, wexc);
  1133. else
  1134. SetWriteStreamError (WebExceptionStatus.SendFailure, exc);
  1135. }
  1136. internal void SetResponseError (WebExceptionStatus status, Exception e, string where)
  1137. {
  1138. if (Aborted)
  1139. return;
  1140. lock (locker) {
  1141. string msg = String.Format ("Error getting response stream ({0}): {1}", where, status);
  1142. WebAsyncResult r = asyncRead;
  1143. if (r == null)
  1144. r = asyncWrite;
  1145. WebException wexc;
  1146. if (e is WebException) {
  1147. wexc = (WebException) e;
  1148. } else {
  1149. wexc = new WebException (msg, e, status, null);
  1150. }
  1151. if (r != null) {
  1152. if (!r.IsCompleted) {
  1153. r.SetCompleted (false, wexc);
  1154. r.DoCallback ();
  1155. } else if (r == asyncWrite) {
  1156. saved_exc = wexc;
  1157. }
  1158. haveResponse = true;
  1159. asyncRead = null;
  1160. asyncWrite = null;
  1161. } else {
  1162. haveResponse = true;
  1163. saved_exc = wexc;
  1164. }
  1165. }
  1166. }
  1167. void CheckSendError (WebConnectionData data)
  1168. {
  1169. // Got here, but no one called GetResponse
  1170. int status = data.StatusCode;
  1171. if (status < 400 || status == 401 || status == 407)
  1172. return;
  1173. if (writeStream != null && asyncRead == null && !writeStream.CompleteRequestWritten) {
  1174. // The request has not been completely sent and we got here!
  1175. // We should probably just close and cause an error in any case,
  1176. saved_exc = new WebException (data.StatusDescription, null, WebExceptionStatus.ProtocolError, webResponse);
  1177. if (allowBuffering || sendChunked || writeStream.totalWritten >= contentLength) {
  1178. webResponse.ReadAll ();
  1179. } else {
  1180. writeStream.IgnoreIOErrors = true;
  1181. }
  1182. }
  1183. }
  1184. bool HandleNtlmAuth (WebAsyncResult r)
  1185. {
  1186. bool isProxy = webResponse.StatusCode == HttpStatusCode.ProxyAuthenticationRequired;
  1187. if ((isProxy ? proxy_auth_state.NtlmAuthState : auth_state.NtlmAuthState) == NtlmAuthState.None)
  1188. return false;
  1189. WebConnectionStream wce = webResponse.GetResponseStream () as WebConnectionStream;
  1190. if (wce != null) {
  1191. WebConnection cnc = wce.Connection;
  1192. cnc.PriorityRequest = this;
  1193. ICredentials creds = !isProxy ? credentials : proxy.Credentials;
  1194. if (creds != null) {
  1195. cnc.NtlmCredential = creds.GetCredential (requestUri, "NTLM");
  1196. cnc.UnsafeAuthenticatedConnectionSharing = unsafe_auth_blah;
  1197. }
  1198. }
  1199. r.Reset ();
  1200. finished_reading = false;
  1201. haveResponse = false;
  1202. webResponse.ReadAll ();
  1203. webResponse = null;
  1204. return true;
  1205. }
  1206. internal void SetResponseData (WebConnectionData data)
  1207. {
  1208. lock (locker) {
  1209. if (Aborted) {
  1210. if (data.stream != null)
  1211. data.stream.Close ();
  1212. return;
  1213. }
  1214. WebException wexc = null;
  1215. try {
  1216. webResponse = new HttpWebResponse (actualUri, method, data, cookieContainer);
  1217. } catch (Exception e) {
  1218. wexc = new WebException (e.Message, e, WebExceptionStatus.ProtocolError, null);
  1219. if (data.stream != null)
  1220. data.stream.Close ();
  1221. }
  1222. if (wexc == null && (method == "POST" || method == "PUT")) {
  1223. CheckSendError (data);
  1224. if (saved_exc != null)
  1225. wexc = (WebException) saved_exc;
  1226. }
  1227. WebAsyncResult r = asyncRead;
  1228. bool forced = false;
  1229. if (r == null && webResponse != null) {
  1230. // This is a forced completion (302, 204)...
  1231. forced = true;
  1232. r = new WebAsyncResult (null, null);
  1233. r.SetCompleted (false, webResponse);
  1234. }
  1235. if (r != null) {
  1236. if (wexc != null) {
  1237. haveResponse = true;
  1238. if (!r.IsCompleted)
  1239. r.SetCompleted (false, wexc);
  1240. r.DoCallback ();
  1241. return;
  1242. }
  1243. bool isProxy = ProxyQuery && !proxy.IsBypassed (actualUri);
  1244. bool redirected;
  1245. try {
  1246. redirected = CheckFinalStatus (r);
  1247. if (!redirected) {
  1248. if ((isProxy ? proxy_auth_state.IsNtlmAuthenticated : auth_state.IsNtlmAuthenticated) &&
  1249. webResponse != null && (int)webResponse.StatusCode < 400) {
  1250. WebConnectionStream wce = webResponse.GetResponseStream () as WebConnectionStream;
  1251. if (wce != null) {
  1252. WebConnection cnc = wce.Connection;
  1253. cnc.NtlmAuthenticated = true;
  1254. }
  1255. }
  1256. // clear internal buffer so that it does not
  1257. // hold possible big buffer (bug #397627)
  1258. if (writeStream != null)
  1259. writeStream.KillBuffer ();
  1260. haveResponse = true;
  1261. r.SetCompleted (false, webResponse);
  1262. r.DoCallback ();
  1263. } else {
  1264. if (sendChunked) {
  1265. sendChunked = false;
  1266. webHeaders.RemoveInternal ("Transfer-Encoding");
  1267. }
  1268. if (webResponse != null) {
  1269. if (HandleNtlmAuth (r))
  1270. return;
  1271. webResponse.Close ();
  1272. }
  1273. finished_reading = false;
  1274. haveResponse = false;
  1275. webResponse = null;
  1276. r.Reset ();
  1277. servicePoint = GetServicePoint ();
  1278. abortHandler = servicePoint.SendRequest (this, connectionGroup);
  1279. }
  1280. } catch (WebException wexc2) {
  1281. if (forced) {
  1282. saved_exc = wexc2;
  1283. haveResponse = true;
  1284. }
  1285. r.SetCompleted (false, wexc2);
  1286. r.DoCallback ();
  1287. return;
  1288. } catch (Exception ex) {
  1289. wexc = new WebException (ex.Message, ex, WebExceptionStatus.ProtocolError, null);
  1290. if (forced) {
  1291. saved_exc = wexc;
  1292. haveResponse = true;
  1293. }
  1294. r.SetCompleted (false, wexc);
  1295. r.DoCallback ();
  1296. return;
  1297. }
  1298. }
  1299. }
  1300. }
  1301. struct AuthorizationState
  1302. {
  1303. readonly HttpWebRequest request;
  1304. readonly bool isProxy;
  1305. bool isCompleted;
  1306. NtlmAuthState ntlm_auth_state;
  1307. public bool IsCompleted {
  1308. get { return isCompleted; }
  1309. }
  1310. public NtlmAuthState NtlmAuthState {
  1311. get { return ntlm_auth_state; }
  1312. }
  1313. public bool IsNtlmAuthenticated {
  1314. get { return isCompleted && ntlm_auth_state != NtlmAuthState.None; }
  1315. }
  1316. public AuthorizationState (HttpWebRequest request, bool isProxy)
  1317. {
  1318. this.request = request;
  1319. this.isProxy = isProxy;
  1320. isCompleted = false;
  1321. ntlm_auth_state = NtlmAuthState.None;
  1322. }
  1323. public bool CheckAuthorization (WebResponse response, HttpStatusCode code)
  1324. {
  1325. isCompleted = false;
  1326. if (code == HttpStatusCode.Unauthorized && request.credentials == null)
  1327. return false;
  1328. // FIXME: This should never happen!
  1329. if (isProxy != (code == HttpStatusCode.ProxyAuthenticationRequired))
  1330. return false;
  1331. if (isProxy && (request.proxy == null || request.proxy.Credentials == null))
  1332. return false;
  1333. string [] authHeaders = response.Headers.GetValues_internal (isProxy ? "Proxy-Authenticate" : "WWW-Authenticate", false);
  1334. if (authHeaders == null || authHeaders.Length == 0)
  1335. return false;
  1336. ICredentials creds = (!isProxy) ? request.credentials : request.proxy.Credentials;
  1337. Authorization auth = null;
  1338. foreach (string authHeader in authHeaders) {
  1339. auth = AuthenticationManager.Authenticate (authHeader, request, creds);
  1340. if (auth != null)
  1341. break;
  1342. }
  1343. if (auth == null)
  1344. return false;
  1345. request.webHeaders [isProxy ? "Proxy-Authorization" : "Authorization"] = auth.Message;
  1346. isCompleted = auth.Complete;
  1347. bool is_ntlm = (auth.Module.AuthenticationType == "NTLM");
  1348. if (is_ntlm)
  1349. ntlm_auth_state = (NtlmAuthState)((int) ntlm_auth_state + 1);
  1350. return true;
  1351. }
  1352. public void Reset ()
  1353. {
  1354. isCompleted = false;
  1355. ntlm_auth_state = NtlmAuthState.None;
  1356. request.webHeaders.RemoveInternal (isProxy ? "Proxy-Authorization" : "Authorization");
  1357. }
  1358. public override string ToString ()
  1359. {
  1360. return string.Format ("{0}AuthState [{1}:{2}]", isProxy ? "Proxy" : "", isCompleted, ntlm_auth_state);
  1361. }
  1362. }
  1363. bool CheckAuthorization (WebResponse response, HttpStatusCode code)
  1364. {
  1365. bool isProxy = code == HttpStatusCode.ProxyAuthenticationRequired;
  1366. return isProxy ? proxy_auth_state.CheckAuthorization (response, code) : auth_state.CheckAuthorization (response, code);
  1367. }
  1368. // Returns true if redirected
  1369. bool CheckFinalStatus (WebAsyncResult result)
  1370. {
  1371. if (result.GotException) {
  1372. bodyBuffer = null;
  1373. throw result.Exception;
  1374. }
  1375. Exception throwMe = result.Exception;
  1376. HttpWebResponse resp = result.Response;
  1377. WebExceptionStatus protoError = WebExceptionStatus.ProtocolError;
  1378. HttpStatusCode code = 0;
  1379. if (throwMe == null && webResponse != null) {
  1380. code = webResponse.StatusCode;
  1381. if ((!auth_state.IsCompleted && code == HttpStatusCode.Unauthorized && credentials != null) ||
  1382. (ProxyQuery && !proxy_auth_state.IsCompleted && code == HttpStatusCode.ProxyAuthenticationRequired)) {
  1383. if (!usedPreAuth && CheckAuthorization (webResponse, code)) {
  1384. // Keep the written body, so it can be rewritten in the retry
  1385. if (InternalAllowBuffering) {
  1386. if (writeStream.WriteBufferLength > 0) {
  1387. bodyBuffer = writeStream.WriteBuffer;
  1388. bodyBufferLength = writeStream.WriteBufferLength;
  1389. }
  1390. return true;
  1391. } else if (method != "PUT" && method != "POST") {
  1392. bodyBuffer = null;
  1393. return true;
  1394. }
  1395. if (!ThrowOnError)
  1396. return false;
  1397. writeStream.InternalClose ();
  1398. writeStream = null;
  1399. webResponse.Close ();
  1400. webResponse = null;
  1401. bodyBuffer = null;
  1402. throw new WebException ("This request requires buffering " +
  1403. "of data for authentication or " +
  1404. "redirection to be sucessful.");
  1405. }
  1406. }
  1407. bodyBuffer = null;
  1408. if ((int) code >= 400) {
  1409. string err = String.Format ("The remote server returned an error: ({0}) {1}.",
  1410. (int) code, webResponse.StatusDescription);
  1411. throwMe = new WebException (err, null, protoError, webResponse);
  1412. webResponse.ReadAll ();
  1413. } else if ((int) code == 304 && allowAutoRedirect) {
  1414. string err = String.Format ("The remote server returned an error: ({0}) {1}.",
  1415. (int) code, webResponse.StatusDescription);
  1416. throwMe = new WebException (err, null, protoError, webResponse);
  1417. } else if ((int) code >= 300 && allowAutoRedirect && redirects >= maxAutoRedirect) {
  1418. throwMe = new WebException ("Max. redirections exceeded.", null,
  1419. protoError, webResponse);
  1420. webResponse.ReadAll ();
  1421. }
  1422. }
  1423. bodyBuffer = null;
  1424. if (throwMe == null) {
  1425. bool b = false;
  1426. int c = (int) code;
  1427. if (allowAutoRedirect && c >= 300) {
  1428. b = Redirect (result, code, webResponse);
  1429. if (InternalAllowBuffering && writeStream.WriteBufferLength > 0) {
  1430. bodyBuffer = writeStream.WriteBuffer;
  1431. bodyBufferLength = writeStream.WriteBufferLength;
  1432. }
  1433. if (b && !unsafe_auth_blah) {
  1434. auth_state.Reset ();
  1435. proxy_auth_state.Reset ();
  1436. }
  1437. }
  1438. if (resp != null && c >= 300 && c != 304)
  1439. resp.ReadAll ();
  1440. return b;
  1441. }
  1442. if (!ThrowOnError)
  1443. return false;
  1444. if (writeStream != null) {
  1445. writeStream.InternalClose ();
  1446. writeStream = null;
  1447. }
  1448. webResponse = null;
  1449. throw throwMe;
  1450. }
  1451. internal bool ReuseConnection {
  1452. get;
  1453. set;
  1454. }
  1455. internal WebConnection StoredConnection;
  1456. }
  1457. }