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");
224 throw ExceptionHelper.RequestAbortedException;
225 if (!CanGetRequestStream()) {
226 Exception e = new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
227 GlobalLog.LeaveException("FileWebRequest::BeginGetRequestStream", e);
230 if (m_response != null) {
231 Exception e = new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
232 GlobalLog.LeaveException("FileWebRequest::BeginGetRequestStream", e);
236 if (m_writePending) {
237 Exception e = new InvalidOperationException(SR.GetString(SR.net_repcall));
238 GlobalLog.LeaveException("FileWebRequest::BeginGetRequestStream", e);
241 m_writePending = true;
244 //we need to force the capture of the identity and context to make sure the
245 //posted callback doesn't inavertently gain access to something it shouldn't.
246 m_ReadAResult = new LazyAsyncResult(this, state, callback);
247 ThreadPool.QueueUserWorkItem(s_GetRequestStreamCallback, m_ReadAResult);
248 } catch (Exception exception) {
252 if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetRequestStream", exception);
256 if (FrameworkEventSource.Log.IsEnabled()) {
257 LogBeginGetRequestStream(success, synchronous: false);
260 GlobalLog.Leave("FileWebRequest::BeginGetRequestSteam");
263 return m_ReadAResult;
266 [HostProtection(ExternalThreading=true)]
267 public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
269 GlobalLog.Enter("FileWebRequest::BeginGetResponse");
276 throw ExceptionHelper.RequestAbortedException;
279 Exception e = new InvalidOperationException(SR.GetString(SR.net_repcall));
280 GlobalLog.LeaveException("FileWebRequest::BeginGetResponse", e);
283 m_readPending = true;
286 m_WriteAResult = new LazyAsyncResult(this,state,callback);
287 ThreadPool.QueueUserWorkItem(s_GetResponseCallback,m_WriteAResult);
288 } catch (Exception exception) {
292 if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetResponse", exception);
296 if (FrameworkEventSource.Log.IsEnabled()) {
297 LogBeginGetResponse(success, synchronous: false);
300 GlobalLog.Leave("FileWebRequest::BeginGetResponse");
303 return m_WriteAResult;
306 private bool CanGetRequestStream() {
307 return !KnownHttpVerb.Parse(m_method).ContentBodyNotAllowed;
310 public override Stream EndGetRequestStream(IAsyncResult asyncResult)
312 GlobalLog.Enter("FileWebRequest::EndGetRequestStream");
316 bool success = false;
319 LazyAsyncResult ar = asyncResult as LazyAsyncResult;
320 if (asyncResult == null || ar == null) {
321 Exception e = asyncResult == null? new ArgumentNullException("asyncResult"): new ArgumentException(SR.GetString(SR.InvalidAsyncResult), "asyncResult");
322 GlobalLog.LeaveException("FileWebRequest::EndGetRequestStream", e);
326 object result = ar.InternalWaitForCompletion();
327 if(result is Exception){
328 throw (Exception)result;
330 stream = (Stream) result;
331 m_writePending = false;
335 } catch (Exception exception) {
336 if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetRequestStream", exception);
339 GlobalLog.Leave("FileWebRequest::EndGetRequestStream");
341 if (FrameworkEventSource.Log.IsEnabled()) {
342 LogEndGetRequestStream(success, synchronous: false);
350 public override WebResponse EndGetResponse(IAsyncResult asyncResult)
352 GlobalLog.Enter("FileWebRequest::EndGetResponse");
354 WebResponse response;
356 bool success = false;
359 LazyAsyncResult ar = asyncResult as LazyAsyncResult;
360 if (asyncResult == null || ar == null) {
361 Exception e = asyncResult == null? new ArgumentNullException("asyncResult"): new ArgumentException(SR.GetString(SR.InvalidAsyncResult), "asyncResult");
362 GlobalLog.LeaveException("FileWebRequest::EndGetRequestStream", e);
367 object result = ar.InternalWaitForCompletion();
368 if(result is Exception){
369 throw (Exception)result;
371 response = (WebResponse) result;
372 m_readPending = false;
376 } catch (Exception exception) {
377 if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetResponse", exception);
380 GlobalLog.Leave("FileWebRequest::EndGetResponse");
383 // there is no statusCode in FileWebRequest object, defaulting it to zero.
384 if (FrameworkEventSource.Log.IsEnabled()) {
385 LogEndGetResponse(success, synchronous: false, statusCode: 0);
393 public override Stream GetRequestStream()
395 GlobalLog.Enter("FileWebRequest::GetRequestStream");
400 result = BeginGetRequestStream(null, null);
402 if ((Timeout != System.Threading.Timeout.Infinite) && !result.IsCompleted) {
403 if (!result.AsyncWaitHandle.WaitOne(Timeout, false) || !result.IsCompleted) {
404 if (m_stream != null) {
407 Exception e = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
408 GlobalLog.LeaveException("FileWebRequest::GetRequestStream", e);
412 } catch (Exception exception) {
413 if(Logging.On)Logging.Exception(Logging.Web, this, "GetRequestStream", exception);
416 GlobalLog.Leave("FileWebRequest::GetRequestStream");
418 return EndGetRequestStream(result);
421 public override WebResponse GetResponse() {
422 GlobalLog.Enter("FileWebRequest::GetResponse");
429 result = BeginGetResponse(null, null);
431 if ((Timeout != System.Threading.Timeout.Infinite) && !result.IsCompleted) {
432 if (!result.AsyncWaitHandle.WaitOne(Timeout, false) || !result.IsCompleted) {
433 if (m_response != null) {
436 Exception e = new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
437 GlobalLog.LeaveException("FileWebRequest::GetResponse", e);
441 } catch (Exception exception) {
442 if(Logging.On)Logging.Exception(Logging.Web, this, "GetResponse", exception);
445 GlobalLog.Leave("FileWebRequest::GetResponse");
447 return EndGetResponse(result);
450 private static void GetRequestStreamCallback(object state)
452 GlobalLog.Enter("FileWebRequest::GetRequestStreamCallback");
453 LazyAsyncResult asyncResult = (LazyAsyncResult) state;
454 FileWebRequest request = (FileWebRequest)asyncResult.AsyncObject;
458 if (request.m_stream == null)
460 request.m_stream = new FileWebStream(request, request.m_uri.LocalPath, FileMode.Create, FileAccess.Write, FileShare.Read);
461 request.m_fileAccess = FileAccess.Write;
462 request.m_writing = true;
467 // any exceptions previously thrown must be passed to the callback
468 Exception ex = new WebException(e.Message, e);
469 GlobalLog.LeaveException("FileWebRequest::GetRequestStreamCallback", ex);
471 // if the callback throws, correct behavior is to crash the process
472 asyncResult.InvokeCallback(ex);
476 // if the callback throws, correct behavior is to crash the process
477 asyncResult.InvokeCallback(request.m_stream);
478 GlobalLog.Leave("FileWebRequest::GetRequestStreamCallback");
481 private static void GetResponseCallback(object state)
483 GlobalLog.Enter("FileWebRequest::GetResponseCallback");
484 LazyAsyncResult asyncResult = (LazyAsyncResult) state;
485 FileWebRequest request = (FileWebRequest)asyncResult.AsyncObject;
487 if (request.m_writePending || request.m_writing) {
489 if (request.m_writePending || request.m_writing) {
490 request.m_readerEvent = new ManualResetEvent(false);
494 if (request.m_readerEvent != null)
495 request.m_readerEvent.WaitOne();
499 if (request.m_response == null)
500 request.m_response = new FileWebResponse(request, request.m_uri, request.m_fileAccess, !request.m_syncHint);
504 // any exceptions previously thrown must be passed to the callback
505 Exception ex = new WebException(e.Message, e);
506 GlobalLog.LeaveException("FileWebRequest::GetResponseCallback", ex);
508 // if the callback throws, correct behavior is to crash the process
509 asyncResult.InvokeCallback(ex);
513 // if the callback throws, the correct behavior is to crash the process
514 asyncResult.InvokeCallback(request.m_response);
515 GlobalLog.Leave("FileWebRequest::GetResponseCallback");
518 internal void UnblockReader() {
519 GlobalLog.Enter("FileWebRequest::UnblockReader");
521 if (m_readerEvent != null) {
526 GlobalLog.Leave("FileWebRequest::UnblockReader");
529 // NOT SUPPORTED method
530 public override bool UseDefaultCredentials {
532 throw ExceptionHelper.PropertyNotSupportedException;
535 throw ExceptionHelper.PropertyNotSupportedException;
539 public override void Abort()
541 GlobalLog.Enter("FileWebRequest::Abort");
542 if(Logging.On)Logging.PrintWarning(Logging.Web, NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled));
544 if (Interlocked.Increment(ref m_Aborted) == 1)
546 LazyAsyncResult readAResult = m_ReadAResult;
547 LazyAsyncResult writeAResult = m_WriteAResult;
549 WebException webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
551 Stream requestStream = m_stream;
553 if (readAResult != null && !readAResult.IsCompleted)
554 readAResult.InvokeCallback(webException);
555 if (writeAResult != null && !writeAResult.IsCompleted)
556 writeAResult.InvokeCallback(webException);
558 if (requestStream != null)
559 if (requestStream is ICloseEx)
560 ((ICloseEx)requestStream).CloseEx(CloseExState.Abort);
562 requestStream.Close();
564 if (m_response != null)
565 ((ICloseEx)m_response).CloseEx(CloseExState.Abort);
567 } catch (Exception exception) {
568 if(Logging.On)Logging.Exception(Logging.Web, this, "Abort", exception);
571 GlobalLog.Leave("FileWebRequest::Abort");
576 internal class FileWebRequestCreator : IWebRequestCreate {
578 internal FileWebRequestCreator() {
581 public WebRequest Create(Uri uri) {
582 return new FileWebRequest(uri);
586 internal sealed class FileWebStream : FileStream, ICloseEx {
588 FileWebRequest m_request;
590 [ResourceExposure(ResourceScope.Machine)]
591 [ResourceConsumption(ResourceScope.Machine)]
592 public FileWebStream(FileWebRequest request, string path, FileMode mode, FileAccess access, FileShare sharing)
593 : base(path, mode, access, sharing)
595 GlobalLog.Enter("FileWebStream::FileWebStream");
597 GlobalLog.Leave("FileWebStream::FileWebStream");
600 [ResourceExposure(ResourceScope.Machine)]
601 [ResourceConsumption(ResourceScope.Machine)]
602 public FileWebStream(FileWebRequest request, string path, FileMode mode, FileAccess access, FileShare sharing, int length, bool async)
603 : base(path, mode, access, sharing, length, async)
605 GlobalLog.Enter("FileWebStream::FileWebStream");
607 GlobalLog.Leave("FileWebStream::FileWebStream");
610 protected override void Dispose(bool disposing) {
611 GlobalLog.Enter("FileWebStream::Close");
613 if (disposing && m_request != null) {
614 m_request.UnblockReader();
618 base.Dispose(disposing);
620 GlobalLog.Leave("FileWebStream::Close");
623 void ICloseEx.CloseEx(CloseExState closeState) {
624 if ((closeState & CloseExState.Abort) != 0)
625 SafeFileHandle.Close();
630 public override int Read(byte[] buffer, int offset, int size) {
633 return base.Read(buffer, offset, size);
641 public override void Write(byte[] buffer, int offset, int size) {
644 base.Write(buffer, offset, size);
652 public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
655 return base.BeginRead(buffer, offset, size, callback, state);
663 public override int EndRead(IAsyncResult ar) {
665 return base.EndRead(ar);
673 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
676 return base.BeginWrite(buffer, offset, size, callback, state);
684 public override void EndWrite(IAsyncResult ar) {
694 private void CheckError() {
695 if (m_request.Aborted) {
696 throw new WebException(
697 NetRes.GetWebStatusString(
698 "net_requestaborted",
699 WebExceptionStatus.RequestCanceled),
700 WebExceptionStatus.RequestCanceled);