// // System.Net.FileWebRequest // // Author: // Lawrence Pit (loz@cable.a2000.nl) // using System; using System.Collections; using System.IO; using System.Runtime.Serialization; using System.Runtime.Remoting.Messaging; using System.Threading; namespace System.Net { [Serializable] public class FileWebRequest : WebRequest, ISerializable { private Uri uri; private WebHeaderCollection webHeaders; private ICredentials credentials; private string connectionGroup; private string method; private int timeout; private Stream requestStream = null; private FileWebResponse webResponse = null; private AutoResetEvent requestEndEvent = null; private bool requesting = false; private bool asyncResponding = false; // Constructors internal FileWebRequest (Uri uri) { this.uri = uri; this.webHeaders = new WebHeaderCollection (); this.method = "GET"; this.timeout = System.Threading.Timeout.Infinite; } [MonoTODO] protected FileWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) { throw new NotImplementedException (); } // Properties // currently not used according to spec public override string ConnectionGroupName { get { return connectionGroup; } set { connectionGroup = value; } } public override long ContentLength { get { try { return Int64.Parse (webHeaders ["Content-Length"]); } catch (Exception) { return 0; } } set { if (value < 0) throw new ArgumentException ("value"); webHeaders ["Content-Length"] = Convert.ToString (value); } } public override string ContentType { get { return webHeaders ["Content-Type"]; } set { webHeaders ["Content-Type"] = value; } } public override ICredentials Credentials { get { return credentials; } set { credentials = value; } } public override WebHeaderCollection Headers { get { return webHeaders; } } // currently not used according to spec public override string Method { get { return this.method; } set { this.method = value; } } // currently not used according to spec public override bool PreAuthenticate { get { throw new NotSupportedException (); } set { throw new NotSupportedException (); } } // currently not used according to spec public override IWebProxy Proxy { get { throw new NotSupportedException (); } set { throw new NotSupportedException (); } } public override Uri RequestUri { get { return this.uri; } } public override int Timeout { get { return timeout; } set { if (value < 0) throw new ArgumentException ("value"); timeout = value; } } // Methods private delegate Stream GetRequestStreamCallback (); private delegate WebResponse GetResponseCallback (); public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) { if (method == null || (!method.Equals ("PUT") && !method.Equals ("POST"))) throw new ProtocolViolationException ("Cannot send file when method is: " + this.method + ". Method must be PUT."); // workaround for bug 24943 Exception e = null; lock (this) { if (asyncResponding || webResponse != null) e = new InvalidOperationException ("This operation cannot be performed after the request has been submitted."); else if (requesting) e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress."); else requesting = true; } if (e != null) throw e; /* lock (this) { if (asyncResponding || webResponse != null) throw new InvalidOperationException ("This operation cannot be performed after the request has been submitted."); if (requesting) throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress."); requesting = true; } */ GetRequestStreamCallback c = new GetRequestStreamCallback (this.GetRequestStreamInternal); return c.BeginInvoke (callback, state); } public override Stream EndGetRequestStream (IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException ("asyncResult"); if (!asyncResult.IsCompleted) asyncResult.AsyncWaitHandle.WaitOne (); AsyncResult async = (AsyncResult) asyncResult; GetRequestStreamCallback cb = (GetRequestStreamCallback) async.AsyncDelegate; return cb.EndInvoke (asyncResult); } public override Stream GetRequestStream() { IAsyncResult asyncResult = BeginGetRequestStream (null, null); if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) { throw new WebException("The request timed out", WebExceptionStatus.Timeout); } return EndGetRequestStream (asyncResult); } internal Stream GetRequestStreamInternal () { this.requestStream = new FileWebStream ( this, FileMode.CreateNew, FileAccess.Write, FileShare.Read); return this.requestStream; } public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state) { // workaround for bug 24943 Exception e = null; lock (this) { if (asyncResponding) e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress."); else asyncResponding = true; } if (e != null) throw e; /* lock (this) { if (asyncResponding) throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress."); asyncResponding = true; } */ GetResponseCallback c = new GetResponseCallback (this.GetResponseInternal); return c.BeginInvoke (callback, state); } public override WebResponse EndGetResponse (IAsyncResult asyncResult) { if (asyncResult == null) throw new ArgumentNullException ("asyncResult"); if (!asyncResult.IsCompleted) asyncResult.AsyncWaitHandle.WaitOne (); AsyncResult async = (AsyncResult) asyncResult; GetResponseCallback cb = (GetResponseCallback) async.AsyncDelegate; WebResponse webResponse = cb.EndInvoke(asyncResult); asyncResponding = false; return webResponse; } public override WebResponse GetResponse () { IAsyncResult asyncResult = BeginGetResponse (null, null); if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) { throw new WebException("The request timed out", WebExceptionStatus.Timeout); } return EndGetResponse (asyncResult); } public WebResponse GetResponseInternal () { if (webResponse != null) return webResponse; lock (this) { if (requesting) { requestEndEvent = new AutoResetEvent (false); } } if (requestEndEvent != null) { requestEndEvent.WaitOne (); } FileStream fileStream = new FileWebStream ( this, FileMode.Open, FileAccess.Read, FileShare.Read); this.webResponse = new FileWebResponse (this.uri, fileStream); return (WebResponse) this.webResponse; } [MonoTODO] void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext) { throw new NotImplementedException (); } internal void Close () { // already done in class below // if (requestStream != null) { // requestStream.Close (); // } lock (this) { requesting = false; if (requestEndEvent != null) requestEndEvent.Set (); // requestEndEvent = null; } } // to catch the Close called on the FileStream internal class FileWebStream : FileStream { FileWebRequest webRequest; internal FileWebStream (FileWebRequest webRequest, FileMode mode, FileAccess access, FileShare share) : base (webRequest.RequestUri.LocalPath, mode, access, share) { this.webRequest = webRequest; } public override void Close() { base.Close (); FileWebRequest req = webRequest; webRequest = null; if (req != null) req.Close (); } } } }