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