X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FSystem.Net%2FWebClient.cs;h=f1f64d794c09456b604dc8811aa370d7f656a27d;hb=3797b802e3b41c475e5fc9b5aeb09c484388c441;hp=1e9a8cb87f6345b47764e449efc1e2149312859e;hpb=6419036c57b89c2e3f7bc0899fde499cdd9b1d9d;p=mono.git diff --git a/mcs/class/System/System.Net/WebClient.cs b/mcs/class/System/System.Net/WebClient.cs index 1e9a8cb87f6..f1f64d794c0 100644 --- a/mcs/class/System/System.Net/WebClient.cs +++ b/mcs/class/System/System.Net/WebClient.cs @@ -1,27 +1,46 @@ // // System.Net.WebClient // -// Author: -// Lawrence Pit (loz@cable.a2000.nl) +// Authors: +// Lawrence Pit (loz@cable.a2000.nl) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// (c) 2003 Ximian, Inc. (http://www.ximian.com) // using System; -using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; +using System.Text; namespace System.Net { [ComVisible(true)] public sealed class WebClient : Component { - + static readonly string urlEncodedCType = "application/x-www-form-urlencoded"; + static byte [] hexBytes; ICredentials credentials; + WebHeaderCollection headers; + WebHeaderCollection responseHeaders; + Uri baseAddress; + string baseString; + NameValueCollection queryString; // Constructors + static WebClient () + { + hexBytes = new byte [16]; + int index = 0; + for (int i = '0'; i <= '9'; i++, index++) + hexBytes [index] = (byte) i; + + for (int i = 'A'; i <= 'F'; i++, index++) + hexBytes [index] = (byte) i; + } public WebClient () { @@ -29,10 +48,24 @@ namespace System.Net // Properties - [MonoTODO] public string BaseAddress { - get { throw new NotImplementedException (); } - set { throw new NotImplementedException (); } + get { + if (baseString == null) { + if (baseAddress == null) + return ""; + } + + baseString = baseAddress.ToString (); + return baseString; + } + + set { + if (value == null || value == "") { + baseAddress = null; + } else { + baseAddress = new Uri (value); + } + } } public ICredentials Credentials { @@ -40,74 +73,63 @@ namespace System.Net set { credentials = value; } } - [MonoTODO] public WebHeaderCollection Headers { - get { throw new NotImplementedException (); } - set { throw new NotImplementedException (); } + get { + if (headers == null) + headers = new WebHeaderCollection (); + + return headers; + } + set { headers = value; } } - [MonoTODO] public NameValueCollection QueryString { - get { throw new NotImplementedException (); } - set { throw new NotImplementedException (); } + get { + if (queryString == null) + queryString = new NameValueCollection (); + + return queryString; + } + set { queryString = value; } } - [MonoTODO] public WebHeaderCollection ResponseHeaders { - get { throw new NotImplementedException (); } + get { return responseHeaders; } } // Methods - [MonoTODO("depends on OpenRead")] public byte [] DownloadData (string address) { - const int readSize = 8192; - Stream networkStream = OpenRead (address); - ArrayList chunks = new ArrayList (); - byte[] buf = new byte [readSize]; - int size = 0; - int total_size = 0; - do { - size = networkStream.Read (buf, 0, readSize); - byte [] copy = new byte [size]; - Array.Copy (buf, 0, copy,0, size); - chunks.Add (copy); - total_size += size; - } while (size != 0); - - byte [] result = new byte [total_size]; - int target = 0; - foreach (byte [] block in chunks){ - int len = block.Length; - Array.Copy (block, 0, result, target, len); - target += len; - } - networkStream.Close (); - return result; + WebRequest request = SetupRequest (address); + WebResponse response = request.GetResponse (); + Stream st = ProcessResponse (response); + return ReadAll (st, (int) response.ContentLength); } - [MonoTODO("depends on DownloadData")] public void DownloadFile (string address, string fileName) { - byte[] buf = DownloadData (address); - new FileStream (fileName, FileMode.CreateNew).Write (buf, 0, buf.Length); + WebRequest request = SetupRequest (address); + WebResponse response = request.GetResponse (); + Stream st = ProcessResponse (response); + + int cLength = (int) response.ContentLength; + int length = (cLength <= -1 || cLength > 8192) ? 8192 : cLength; + byte [] buffer = new byte [length]; + FileStream f = new FileStream (fileName, FileMode.CreateNew); + + int nread = 0; + while ((nread = st.Read (buffer, 0, length)) != 0) + f.Write (buffer, 0, nread); + + f.Close (); } - [MonoTODO("some tests are required")] public Stream OpenRead (string address) { - Uri uri = new Uri (address); - WebRequest request = null; - - if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) - request = new HttpWebRequest (uri); - else if(uri.Scheme == Uri.UriSchemeFile) - request = new FileWebRequest (uri); - else - throw new NotImplementedException (); - - return request.GetResponse ().GetResponseStream (); + WebRequest request = SetupRequest (address); + WebResponse response = request.GetResponse (); + return ProcessResponse (response); } public Stream OpenWrite (string address) @@ -115,10 +137,10 @@ namespace System.Net return OpenWrite (address, "POST"); } - [MonoTODO] public Stream OpenWrite (string address, string method) { - throw new NotImplementedException (); + WebRequest request = SetupRequest (address, method); + return request.GetRequestStream (); } public byte [] UploadData (string address, byte [] data) @@ -126,10 +148,20 @@ namespace System.Net return UploadData (address, "POST", data); } - [MonoTODO] public byte [] UploadData (string address, string method, byte [] data) { - throw new NotImplementedException (); + if (data == null) + throw new ArgumentNullException ("data"); + + int contentLength = data.Length; + WebRequest request = SetupRequest (address, method, contentLength); + using (Stream stream = request.GetRequestStream ()) { + stream.Write (data, 0, contentLength); + } + + WebResponse response = request.GetResponse (); + Stream st = ProcessResponse (response); + return ReadAll (st, (int) response.ContentLength); } public byte [] UploadFile (string address, string fileName) @@ -137,10 +169,63 @@ namespace System.Net return UploadFile (address, "POST", fileName); } - [MonoTODO] - public byte[] UploadFile (string address, string method, string fileName) + public byte [] UploadFile (string address, string method, string fileName) { - throw new NotImplementedException (); + string fileCType = Headers ["Content-Type"]; + if (fileCType != null) { + string lower = fileCType.ToLower (); + if (lower.StartsWith ("multipart/")) + throw new WebException ("Content-Type cannot be set to a multipart" + + " type for this request."); + } else { + fileCType = "application/octet-stream"; + } + + string boundary = "------------" + DateTime.Now.Ticks.ToString ("x"); + Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary); + WebRequest request = SetupRequest (address, method); + Stream reqStream = null; + Stream fStream = null; + byte [] resultBytes = null; + + try { + fStream = File.OpenRead (fileName); + reqStream = request.GetRequestStream (); + byte [] realBoundary = Encoding.ASCII.GetBytes ("--" + boundary + "\r\n"); + reqStream.Write (realBoundary, 0, realBoundary.Length); + string partHeaders = String.Format ("Content-Disposition: form-data; " + + "name=\"file\"; filename=\"{0}\"\r\n" + + "Content-Type: {1}\r\n\r\n", + Path.GetFileName (fileName), fileCType); + + byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders); + reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length); + int nread; + byte [] buffer = new byte [4096]; + while ((nread = fStream.Read (buffer, 0, 4096)) != 0) + reqStream.Write (buffer, 0, nread); + + reqStream.WriteByte ((byte) '\r'); + reqStream.WriteByte ((byte) '\n'); + reqStream.Write (realBoundary, 0, realBoundary.Length); + reqStream.Close (); + reqStream = null; + WebResponse response = request.GetResponse (); + Stream st = ProcessResponse (response); + resultBytes = ReadAll (st, (int) response.ContentLength); + } catch (WebException) { + throw; + } catch (Exception e) { + throw new WebException ("Error uploading file.", e); + } finally { + if (fStream != null) + fStream.Close (); + + if (reqStream != null) + reqStream.Close (); + } + + return resultBytes; } public byte[] UploadValues (string address, NameValueCollection data) @@ -148,10 +233,229 @@ namespace System.Net return UploadValues (address, "POST", data); } - [MonoTODO] public byte[] UploadValues (string address, string method, NameValueCollection data) { - throw new NotImplementedException (); + if (data == null) + throw new ArgumentNullException ("data"); // MS throws a nullref + + string cType = Headers ["Content-Type"]; + if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0) + throw new WebException ("Content-Type header cannot be changed from its default " + + "value for this request."); + + Headers ["Content-Type"] = urlEncodedCType; + WebRequest request = SetupRequest (address, method); + Stream rqStream = request.GetRequestStream (); + MemoryStream tmpStream = new MemoryStream (); + foreach (string key in data) { + byte [] bytes = Encoding.ASCII.GetBytes (key); + UrlEncodeAndWrite (tmpStream, bytes); + tmpStream.WriteByte ((byte) '='); + bytes = Encoding.ASCII.GetBytes (data [key]); + UrlEncodeAndWrite (tmpStream, bytes); + tmpStream.WriteByte ((byte) '&'); + } + + int length = (int) tmpStream.Length; + if (length > 0) + tmpStream.SetLength (--length); // remove trailing '&' + + tmpStream.WriteByte ((byte) '\r'); + tmpStream.WriteByte ((byte) '\n'); + + byte [] buf = tmpStream.GetBuffer (); + rqStream.Write (buf, 0, length + 2); + rqStream.Close (); + tmpStream.Close (); + + WebResponse response = request.GetResponse (); + Stream st = ProcessResponse (response); + return ReadAll (st, (int) response.ContentLength); + } + + Uri MakeUri (string path) + { + string query = null; + if (queryString != null && queryString.Count != 0) { + // This is not the same as UploadValues, because these 'keys' are not + // urlencoded here. + StringBuilder sb = new StringBuilder (); + sb.Append ('?'); + foreach (string key in queryString) + sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key])); + + if (sb.Length != 0) { + sb.Length--; // remove trailing '&' + query = sb.ToString (); + } + } + + + if (baseAddress == null && query == null) { + try { + return new Uri (path); + } + catch (System.UriFormatException ufe) { + return new Uri ("file://" + path); + } + } + + if (baseAddress == null) + return new Uri (path + query, (query != null)); + + if (query == null) + return new Uri (baseAddress, path); + + return new Uri (baseAddress, path + query, (query != null)); + } + + WebRequest SetupRequest (string address) + { + Uri uri = MakeUri (address); + WebRequest request = WebRequest.Create (uri); + request.Credentials = credentials; + + // Special headers. These are properties of HttpWebRequest. + // What do we do with other requests differnt from HttpWebRequest? + if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) { + HttpWebRequest req = (HttpWebRequest) request; + string expect = headers ["Expect"]; + string contentType = headers ["Content-Type"]; + string accept = headers ["Accept"]; + string connection = headers ["Connection"]; + string userAgent = headers ["User-Agent"]; + string referer = headers ["Referer"]; + headers.RemoveInternal ("Expect"); + headers.RemoveInternal ("Content-Type"); + headers.RemoveInternal ("Accept"); + headers.RemoveInternal ("Connection"); + headers.RemoveInternal ("Referer"); + headers.RemoveInternal ("User-Agent"); + request.Headers = headers; + + if (expect != null && expect != "") + req.Expect = expect; + + if (accept != null && accept != "") + req.Accept = accept; + + if (contentType != null && contentType != "") + req.ContentType = contentType; + + if (connection != null && connection != "") + req.Connection = connection; + + if (userAgent != null && userAgent != "") + req.UserAgent = userAgent; + + if (referer != null && referer != "") + req.Referer = referer; + } + + responseHeaders = null; + return request; + } + + WebRequest SetupRequest (string address, string method) + { + WebRequest request = SetupRequest (address); + request.Method = method; + return request; + } + + WebRequest SetupRequest (string address, string method, int contentLength) + { + WebRequest request = SetupRequest (address, method); + request.ContentLength = contentLength; + return request; + } + + Stream ProcessResponse (WebResponse response) + { + responseHeaders = response.Headers; + return response.GetResponseStream (); + } + + static byte [] ReadAll (Stream stream, int length) + { + MemoryStream ms = null; + + bool nolength = (length == -1); + int size = ((nolength) ? 8192 : length); + if (nolength) + ms = new MemoryStream (); + + int nread = 0; + int offset = 0; + byte [] buffer = new byte [size]; + while ((nread = stream.Read (buffer, offset, size)) != 0) { + if (nolength) { + ms.Write (buffer, 0, nread); + } else { + offset += nread; + size -= nread; + } + } + + if (nolength) + return ms.ToArray (); + + return buffer; + } + + string UrlEncode (string str) + { + StringBuilder result = new StringBuilder (); + + int len = str.Length; + for (int i = 0; i < len; i++) { + char c = str [i]; + if (c == ' ') + result.Append ('+'); + else if ((c < '0' && c != '-' && c != '.') || + (c < 'A' && c > '9') || + (c > 'Z' && c < 'a' && c != '_') || + (c > 'z')) { + result.Append ('%'); + int idx = ((int) c) >> 4; + result.Append ((char) hexBytes [idx]); + idx = ((int) c) & 0x0F; + result.Append ((char) hexBytes [idx]); + } else { + result.Append (c); + } + } + + return result.ToString (); + } + + static void UrlEncodeAndWrite (Stream stream, byte [] bytes) + { + if (bytes == null) + return; + + int len = bytes.Length; + if (len == 0) + return; + + for (int i = 0; i < len; i++) { + char c = (char) bytes [i]; + if (c == ' ') + stream.WriteByte ((byte) '+'); + else if ((c < '0' && c != '-' && c != '.') || + (c < 'A' && c > '9') || + (c > 'Z' && c < 'a' && c != '_') || + (c > 'z')) { + stream.WriteByte ((byte) '%'); + int idx = ((int) c) >> 4; + stream.WriteByte (hexBytes [idx]); + idx = ((int) c) & 0x0F; + stream.WriteByte (hexBytes [idx]); + } else { + stream.WriteByte ((byte) c); + } + } } } } +