HttpWebRequest.cs 46 KB

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