1 //------------------------------------------------------------------------------
2 // <copyright file="filewebrequest.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 using System.Runtime.Serialization;
10 using System.Security.Permissions;
11 using System.Threading;
12 using System.Runtime.Versioning;
13 using System.Diagnostics.CodeAnalysis;
14 using System.Diagnostics.Tracing;
17 public class FileWebRequest : WebRequest, ISerializable {
19 private static WaitCallback s_GetRequestStreamCallback = new WaitCallback(GetRequestStreamCallback);
20 private static WaitCallback s_GetResponseCallback = new WaitCallback(GetResponseCallback);
22 private static ContextCallback s_WrappedGetRequestStreamCallback = new ContextCallback(GetRequestStreamCallback);
23 private static ContextCallback s_WrappedResponseCallback = new ContextCallback(GetResponseCallback);
28 string m_connectionGroupName;
30 ICredentials m_credentials;
31 FileAccess m_fileAccess;
32 WebHeaderCollection m_headers;
33 string m_method = "GET";
34 bool m_preauthenticate;
36 ManualResetEvent m_readerEvent;
38 WebResponse m_response;
41 int m_timeout = WebRequest.DefaultTimeout;
45 private LazyAsyncResult m_WriteAResult;
46 private LazyAsyncResult m_ReadAResult;
47 private int m_Aborted;
51 internal FileWebRequest(Uri uri)
53 if ((object)uri.Scheme != (object)Uri.UriSchemeFile)
54 throw new ArgumentOutOfRangeException("uri");
57 m_fileAccess = FileAccess.Read;
58 m_headers = new WebHeaderCollection(WebHeaderCollectionType.FileWebRequest);
63 // ISerializable constructor
66 [Obsolete("Serialization is obsoleted for this type. http://go.microsoft.com/fwlink/?linkid=14202")]
67 protected FileWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext):base(serializationInfo, streamingContext) {
68 m_headers = (WebHeaderCollection)serializationInfo.GetValue("headers", typeof(WebHeaderCollection));
69 m_proxy = (IWebProxy)serializationInfo.GetValue("proxy", typeof(IWebProxy));
70 m_uri = (Uri)serializationInfo.GetValue("uri", typeof(Uri));
71 m_connectionGroupName = serializationInfo.GetString("connectionGroupName");
72 m_method = serializationInfo.GetString("method");
73 m_contentLength = serializationInfo.GetInt64("contentLength");
74 m_timeout = serializationInfo.GetInt32("timeout");
75 m_fileAccess = (FileAccess )serializationInfo.GetInt32("fileAccess");
79 // ISerializable method
82 [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
83 [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)]
84 void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
86 GetObjectData(serializationInfo, streamingContext);
90 // FxCop: provide some way for derived classes to access GetObjectData even if the derived class
91 // explicitly re-inherits ISerializable.
93 [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
94 protected override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
96 serializationInfo.AddValue("headers", m_headers, typeof(WebHeaderCollection));
97 serializationInfo.AddValue("proxy", m_proxy, typeof(IWebProxy));
98 serializationInfo.AddValue("uri", m_uri, typeof(Uri));
99 serializationInfo.AddValue("connectionGroupName", m_connectionGroupName);
100 serializationInfo.AddValue("method", m_method);
101 serializationInfo.AddValue("contentLength", m_contentLength);
102 serializationInfo.AddValue("timeout", m_timeout);
103 serializationInfo.AddValue("fileAccess", m_fileAccess);
105 //we're leaving this for legacy. V1.1 and V1.0 had this field in the serialization constructor
106 serializationInfo.AddValue("preauthenticate", false);
107 base.GetObjectData(serializationInfo, streamingContext);
113 internal bool Aborted {
115 return m_Aborted != 0;
119 public override string ConnectionGroupName {
121 return m_connectionGroupName;
124 m_connectionGroupName = value;
128 public override long ContentLength {
130 return m_contentLength;
134 throw new ArgumentException(SR.GetString(SR.net_clsmall), "value");
136 m_contentLength = value;
140 public override string ContentType {
142 return m_headers["Content-Type"];
145 m_headers["Content-Type"] = value;
149 public override ICredentials Credentials {
151 return m_credentials;
154 m_credentials = value;
158 public override WebHeaderCollection Headers {
164 public override string Method {
169 if (ValidationHelper.IsBlankString(value)) {
170 throw new ArgumentException(SR.GetString(SR.net_badmethod), "value");
176 public override bool PreAuthenticate {
178 return m_preauthenticate;
181 m_preauthenticate = true;
185 public override IWebProxy Proxy {
194 //UEUE changed default from infinite to 100 seconds
195 public override int Timeout {
200 if ((value < 0) && (value != System.Threading.Timeout.Infinite)) {
201 throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_ge_zero));
207 public override Uri RequestUri {
215 [HostProtection(ExternalThreading=true)]
216 public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)
218 GlobalLog.Enter("FileWebRequest::BeginGetRequestStream");
222 throw ExceptionHelper.RequestAbortedException;
223 if (!CanGetRequestStream()) {
224 Exception e = new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
225 GlobalLog.LeaveException("FileWebRequest::BeginGetRequestStream", e);
228 if (m_response != null) {
229 Exception e = new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
230 GlobalLog.LeaveException("FileWebRequest::BeginGetRequestStream", e);
234 if (m_writePending) {
235 Exception e = new InvalidOperationException(SR.GetString(SR.net_repcall));
236 GlobalLog.LeaveException("FileWebRequest::BeginGetRequestStream", e);
239 m_writePending = true;
242 //we need to force the capture of the identity and context to make sure the
243 //posted callback doesn't inavertently gain access to something it shouldn't.
244 m_ReadAResult = new LazyAsyncResult(this, state, callback);
245 ThreadPool.QueueUserWorkItem(s_GetRequestStreamCallback, m_ReadAResult);
246 } catch (Exception exception) {
248 if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetRequestStream", exception);
252 if (FrameworkEventSource.Log.IsEnabled()) {
253 LogBeginGetRequestStream(success, synchronous: false);
256 GlobalLog.Leave("FileWebRequest::BeginGetRequestSteam");
259 return m_ReadAResult;
262 [HostProtection(ExternalThreading=true)]
263 public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
265 GlobalLog.Enter("FileWebRequest::BeginGetResponse");
270 throw ExceptionHelper.RequestAbortedException;
273 Exception e = new InvalidOperationException(SR.GetString(SR.net_repcall));
274 GlobalLog.LeaveException("FileWebRequest::BeginGetResponse", e);
277 m_readPending = true;
280 m_WriteAResult = new LazyAsyncResult(this,state,callback);
281 ThreadPool.QueueUserWorkItem(s_GetResponseCallback,m_WriteAResult);
282 } catch (Exception exception) {
284 if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetResponse", exception);
288 if (FrameworkEventSource.Log.IsEnabled()) {
289 LogBeginGetResponse(success, synchronous: false);
292 GlobalLog.Leave("FileWebRequest::BeginGetResponse");
295 return m_WriteAResult;
298 private bool CanGetRequestStream() {
299 return !KnownHttpVerb.Parse(m_method).ContentBodyNotAllowed;
302 public override Stream EndGetRequestStream(IAsyncResult asyncResult)
304 GlobalLog.Enter("FileWebRequest::EndGetRequestStream");
307 bool success = false;
309 LazyAsyncResult ar = asyncResult as LazyAsyncResult;
310 if (asyncResult == null || ar == null) {
311 Exception e = asyncResult == null? new ArgumentNullException("asyncResult"): new ArgumentException(SR.GetString(SR.InvalidAsyncResult), "asyncResult");
312 GlobalLog.LeaveException("FileWebRequest::EndGetRequestStream", e);
316 object result = ar.InternalWaitForCompletion();
317 if(result is Exception){
318 throw (Exception)result;
320 stream = (Stream) result;
321 m_writePending = false;
323 } catch (Exception exception) {
324 if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetRequestStream", exception);
327 GlobalLog.Leave("FileWebRequest::EndGetRequestStream");
329 if (FrameworkEventSource.Log.IsEnabled()) {
330 LogEndGetRequestStream(success, synchronous: false);
338 public override WebResponse EndGetResponse(IAsyncResult asyncResult)
340 GlobalLog.Enter("FileWebRequest::EndGetResponse");
342 WebResponse response;
343 bool success = false;
345 LazyAsyncResult ar = asyncResult as LazyAsyncResult;
346 if (asyncResult == null || ar == null) {
347 Exception e = asyncResult == null? new ArgumentNullException("asyncResult"): new ArgumentException(SR.GetString(SR.InvalidAsyncResult), "asyncResult");
348 GlobalLog.LeaveException("FileWebRequest::EndGetRequestStream", e);
353 object result = ar.InternalWaitForCompletion();
354 if(result is Exception){
355 throw (Exception)result;
357 response = (WebResponse) result;
358 m_readPending = false;
360 } catch (Exception exception) {
361 if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetResponse", exception);
364 GlobalLog.Leave("FileWebRequest::EndGetResponse");
367 // there is no statusCode in FileWebRequest object, defaulting it to zero.
368 if (FrameworkEventSource.Log.IsEnabled()) {
369 LogEndGetResponse(success, synchronous: false, statusCode: 0);
377 public override Stream GetRequestStream()
379 GlobalLog.Enter("FileWebRequest::GetRequestStream");
384 result = BeginGetRequestStream(null, null);
386 if ((Timeout != System.Threading.Timeout.Infinite) && !result.IsCompleted) {
387 if (!result.AsyncWaitHandle.WaitOne(Timeout, false) || !result.IsCompleted) {
388 if (m_stream != null) {
391 Exception e = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
392 GlobalLog.LeaveException("FileWebRequest::GetRequestStream", e);
396 } catch (Exception exception) {
397 if(Logging.On)Logging.Exception(Logging.Web, this, "GetRequestStream", exception);
400 GlobalLog.Leave("FileWebRequest::GetRequestStream");
402 return EndGetRequestStream(result);
405 public override WebResponse GetResponse() {
406 GlobalLog.Enter("FileWebRequest::GetResponse");
413 result = BeginGetResponse(null, null);
415 if ((Timeout != System.Threading.Timeout.Infinite) && !result.IsCompleted) {
416 if (!result.AsyncWaitHandle.WaitOne(Timeout, false) || !result.IsCompleted) {
417 if (m_response != null) {
420 Exception e = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
421 GlobalLog.LeaveException("FileWebRequest::GetResponse", e);
425 } catch (Exception exception) {
426 if(Logging.On)Logging.Exception(Logging.Web, this, "GetResponse", exception);
429 GlobalLog.Leave("FileWebRequest::GetResponse");
431 return EndGetResponse(result);
434 private static void GetRequestStreamCallback(object state)
436 GlobalLog.Enter("FileWebRequest::GetRequestStreamCallback");
437 LazyAsyncResult asyncResult = (LazyAsyncResult) state;
438 FileWebRequest request = (FileWebRequest)asyncResult.AsyncObject;
442 if (request.m_stream == null)
444 request.m_stream = new FileWebStream(request, request.m_uri.LocalPath, FileMode.Create, FileAccess.Write, FileShare.Read);
445 request.m_fileAccess = FileAccess.Write;
446 request.m_writing = true;
451 // any exceptions previously thrown must be passed to the callback
452 Exception ex = new WebException(e.Message, e);
453 GlobalLog.LeaveException("FileWebRequest::GetRequestStreamCallback", ex);
455 // if the callback throws, correct behavior is to crash the process
456 asyncResult.InvokeCallback(ex);
460 // if the callback throws, correct behavior is to crash the process
461 asyncResult.InvokeCallback(request.m_stream);
462 GlobalLog.Leave("FileWebRequest::GetRequestStreamCallback");
465 private static void GetResponseCallback(object state)
467 GlobalLog.Enter("FileWebRequest::GetResponseCallback");
468 LazyAsyncResult asyncResult = (LazyAsyncResult) state;
469 FileWebRequest request = (FileWebRequest)asyncResult.AsyncObject;
471 if (request.m_writePending || request.m_writing) {
473 if (request.m_writePending || request.m_writing) {
474 request.m_readerEvent = new ManualResetEvent(false);
478 if (request.m_readerEvent != null)
479 request.m_readerEvent.WaitOne();
483 if (request.m_response == null)
484 request.m_response = new FileWebResponse(request, request.m_uri, request.m_fileAccess, !request.m_syncHint);
488 // any exceptions previously thrown must be passed to the callback
489 Exception ex = new WebException(e.Message, e);
490 GlobalLog.LeaveException("FileWebRequest::GetResponseCallback", ex);
492 // if the callback throws, correct behavior is to crash the process
493 asyncResult.InvokeCallback(ex);
497 // if the callback throws, the correct behavior is to crash the process
498 asyncResult.InvokeCallback(request.m_response);
499 GlobalLog.Leave("FileWebRequest::GetResponseCallback");
502 internal void UnblockReader() {
503 GlobalLog.Enter("FileWebRequest::UnblockReader");
505 if (m_readerEvent != null) {
510 GlobalLog.Leave("FileWebRequest::UnblockReader");
513 // NOT SUPPORTED method
514 public override bool UseDefaultCredentials {
516 throw ExceptionHelper.PropertyNotSupportedException;
519 throw ExceptionHelper.PropertyNotSupportedException;
523 public override void Abort()
525 GlobalLog.Enter("FileWebRequest::Abort");
526 if(Logging.On)Logging.PrintWarning(Logging.Web, NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled));
528 if (Interlocked.Increment(ref m_Aborted) == 1)
530 LazyAsyncResult readAResult = m_ReadAResult;
531 LazyAsyncResult writeAResult = m_WriteAResult;
533 WebException webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
535 Stream requestStream = m_stream;
537 if (readAResult != null && !readAResult.IsCompleted)
538 readAResult.InvokeCallback(webException);
539 if (writeAResult != null && !writeAResult.IsCompleted)
540 writeAResult.InvokeCallback(webException);
542 if (requestStream != null)
543 if (requestStream is ICloseEx)
544 ((ICloseEx)requestStream).CloseEx(CloseExState.Abort);
546 requestStream.Close();
548 if (m_response != null)
549 ((ICloseEx)m_response).CloseEx(CloseExState.Abort);
551 } catch (Exception exception) {
552 if(Logging.On)Logging.Exception(Logging.Web, this, "Abort", exception);
555 GlobalLog.Leave("FileWebRequest::Abort");
560 internal class FileWebRequestCreator : IWebRequestCreate {
562 internal FileWebRequestCreator() {
565 public WebRequest Create(Uri uri) {
566 return new FileWebRequest(uri);
570 internal sealed class FileWebStream : FileStream, ICloseEx {
572 FileWebRequest m_request;
574 [ResourceExposure(ResourceScope.Machine)]
575 [ResourceConsumption(ResourceScope.Machine)]
576 public FileWebStream(FileWebRequest request, string path, FileMode mode, FileAccess access, FileShare sharing)
577 : base(path, mode, access, sharing)
579 GlobalLog.Enter("FileWebStream::FileWebStream");
581 GlobalLog.Leave("FileWebStream::FileWebStream");
584 [ResourceExposure(ResourceScope.Machine)]
585 [ResourceConsumption(ResourceScope.Machine)]
586 public FileWebStream(FileWebRequest request, string path, FileMode mode, FileAccess access, FileShare sharing, int length, bool async)
587 : base(path, mode, access, sharing, length, async)
589 GlobalLog.Enter("FileWebStream::FileWebStream");
591 GlobalLog.Leave("FileWebStream::FileWebStream");
594 protected override void Dispose(bool disposing) {
595 GlobalLog.Enter("FileWebStream::Close");
597 if (disposing && m_request != null) {
598 m_request.UnblockReader();
602 base.Dispose(disposing);
604 GlobalLog.Leave("FileWebStream::Close");
607 void ICloseEx.CloseEx(CloseExState closeState) {
608 if ((closeState & CloseExState.Abort) != 0)
609 SafeFileHandle.Close();
614 public override int Read(byte[] buffer, int offset, int size) {
617 return base.Read(buffer, offset, size);
625 public override void Write(byte[] buffer, int offset, int size) {
628 base.Write(buffer, offset, size);
636 public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
639 return base.BeginRead(buffer, offset, size, callback, state);
647 public override int EndRead(IAsyncResult ar) {
649 return base.EndRead(ar);
657 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
660 return base.BeginWrite(buffer, offset, size, callback, state);
668 public override void EndWrite(IAsyncResult ar) {
678 private void CheckError() {
679 if (m_request.Aborted) {
680 throw new WebException(
681 NetRes.GetWebStatusString(
682 "net_requestaborted",
683 WebExceptionStatus.RequestCanceled),
684 WebExceptionStatus.RequestCanceled);