//
// System.Net.FileWebRequest
//
// Author:
// Lawrence Pit (loz@cable.a2000.nl)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
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 long contentLength;
private FileAccess fileAccess = FileAccess.Read;
private string method = "GET";
private IWebProxy proxy;
private bool preAuthenticate;
private int timeout = 100000;
private Stream requestStream;
private FileWebResponse webResponse;
private AutoResetEvent requestEndEvent;
private bool requesting;
private bool asyncResponding;
// Constructors
internal FileWebRequest (Uri uri)
{
this.uri = uri;
this.webHeaders = new WebHeaderCollection ();
}
#if NET_2_0
[Obsolete ("Serialization is obsoleted for this type", false)]
#endif
protected FileWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
SerializationInfo info = serializationInfo;
webHeaders = (WebHeaderCollection) info.GetValue ("headers", typeof (WebHeaderCollection));
proxy = (IWebProxy) info.GetValue ("proxy", typeof (IWebProxy));
uri = (Uri) info.GetValue ("uri", typeof (Uri));
connectionGroup = info.GetString ("connectionGroupName");
method = info.GetString ("method");
contentLength = info.GetInt64 ("contentLength");
timeout = info.GetInt32 ("timeout");
fileAccess = (FileAccess) info.GetValue ("fileAccess", typeof (FileAccess));
preAuthenticate = info.GetBoolean ("preauthenticate");
}
// Properties
// currently not used according to spec
public override string ConnectionGroupName {
get { return connectionGroup; }
set { connectionGroup = value; }
}
public override long ContentLength {
get { return contentLength; }
set {
if (value < 0)
#if NET_2_0
throw new ArgumentException ("The Content-Length value must be greater than or equal to zero.", "value");
#else
throw new ArgumentException ("value");
#endif
contentLength = 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 {
if (value == null || value.Length == 0)
#if NET_2_0
throw new ArgumentException ("Cannot set null or blank "
+ "methods on request.", "value");
#else
throw new ArgumentException ("Cannot set null or blank "
+ "methods on request.");
#endif
this.method = value;
}
}
// currently not used according to spec
public override bool PreAuthenticate {
get { return preAuthenticate; }
set { preAuthenticate = value; }
}
// currently not used according to spec
public override IWebProxy Proxy {
get { return proxy; }
set { proxy = value; }
}
public override Uri RequestUri {
get { return this.uri; }
}
public override int Timeout {
get { return timeout; }
set {
if (value < -1)
#if NET_2_0
throw new ArgumentOutOfRangeException ("Timeout can be "
+ "only set to 'System.Threading.Timeout.Infinite' "
+ "or a value >= 0.");
#else
throw new ArgumentOutOfRangeException ("value");
#endif
timeout = value;
}
}
#if NET_2_0
public override bool UseDefaultCredentials
{
get {
throw new NotSupportedException ();
}
set {
throw new NotSupportedException ();
}
}
#endif
// Methods
private delegate Stream GetRequestStreamCallback ();
private delegate WebResponse GetResponseCallback ();
#if NET_2_0
static Exception GetMustImplement ()
{
return new NotImplementedException ();
}
/* LAMESPEC: Docs suggest this was present in 1.1 and
* 1.0 profiles, but the masterinfos say otherwise
*/
[MonoTODO]
public override void Abort ()
{
throw GetMustImplement ();
}
#endif
public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state)
{
if (string.Compare ("GET", method, true) == 0 ||
string.Compare ("HEAD", method, true) == 0 ||
string.Compare ("CONNECT", method, true) == 0)
throw new ProtocolViolationException ("Cannot send a content-body with this verb-type.");
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.Create,
FileAccess.Write,
FileShare.Read);
return this.requestStream;
}
public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
{
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);
}
WebResponse GetResponseInternal ()
{
if (webResponse != null)
return webResponse;
lock (this) {
if (requesting) {
requestEndEvent = new AutoResetEvent (false);
}
}
if (requestEndEvent != null) {
requestEndEvent.WaitOne ();
}
FileStream fileStream = null;
try {
fileStream = new FileWebStream (this, FileMode.Open,
FileAccess.Read, FileShare.Read);
} catch (Exception ex) {
throw new WebException (ex.Message, ex);
}
this.webResponse = new FileWebResponse (this.uri, fileStream);
return (WebResponse) this.webResponse;
}
void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
GetObjectData (serializationInfo, streamingContext);
}
#if NET_2_0
protected override
#endif
void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
SerializationInfo info = serializationInfo;
info.AddValue ("headers", webHeaders, typeof (WebHeaderCollection));
info.AddValue ("proxy", proxy, typeof (IWebProxy));
info.AddValue ("uri", uri, typeof (Uri));
info.AddValue ("connectionGroupName", connectionGroup);
info.AddValue ("method", method);
info.AddValue ("contentLength", contentLength);
info.AddValue ("timeout", timeout);
info.AddValue ("fileAccess", fileAccess);
#if NET_2_0
info.AddValue ("preauthenticate", false);
#else
info.AddValue ("preauthenticate", preAuthenticate);
#endif
}
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 ();
}
}
}
}
|