2007-02-16 Geoff Norton <gnorton@customerdna.com>
[mono.git] / mcs / class / System / System.Net / VMWHttpProvider.jvm.cs
1 using System;\r
2 using System.IO;\r
3 using System.Threading;\r
4 \r
5 using mainsoft.apache.commons.httpclient;\r
6 using mainsoft.apache.commons.httpclient.methods;\r
7 using mainsoft.apache.commons.httpclient.@params;\r
8 using mainsoft.apache.commons.httpclient.auth;\r
9 \r
10 namespace System.Net\r
11 {\r
12         /// <summary>\r
13         /// Summary description for VMWHttpProvider.\r
14         /// </summary>\r
15         internal class VMWHttpProvider : HttpProvider\r
16         {\r
17                 protected static HttpClient _client;     //todo init it in static constructor\r
18                 protected static HttpStateCache _stateCache = new HttpStateCache();\r
19 \r
20                 protected static object LOCK_OBJECT = new object();\r
21                 \r
22                 \r
23 \r
24                 protected HttpMethod _method;\r
25                 protected HttpState _state;\r
26                 protected HostConfiguration _hostConfig;\r
27                 \r
28                 protected HttpWebResponse _response;\r
29                 protected bool _hasResponse;\r
30                 protected bool _hasRequest;\r
31                 protected Stream _writeStream;\r
32                 private GHWebAsyncResult _asyncWrite;\r
33                 private GHWebAsyncResult _asyncRead;\r
34 \r
35                 private bool _isConnectionOpened;\r
36                 \r
37                 static VMWHttpProvider()\r
38                 {\r
39                         if(java.lang.System.getProperty("mainsoft.apache.commons.logging.Log") == null)\r
40                                 java.lang.System.setProperty("mainsoft.apache.commons.logging.Log",\r
41                                         "mainsoft.apache.commons.logging.impl.SimpleLog");\r
42                         if(java.lang.System.getProperty("mainsoft.apache.commons.logging.simplelog.showdatetime") == null)\r
43                                 java.lang.System.setProperty("mainsoft.apache.commons.logging.simplelog.showdatetime",\r
44                                         "true");\r
45                         if(java.lang.System.getProperty("mainsoft.apache.commons.logging.simplelog.log.httpclient.wire") == null)\r
46                                 java.lang.System.setProperty("mainsoft.apache.commons.logging.simplelog.log.httpclient.wire",\r
47                                         "error");\r
48                         if(java.lang.System.getProperty("mainsoft.apache.commons.logging.simplelog.log.mainsoft.apache.commons.httpclient")\r
49                                 == null)\r
50                                 java.lang.System.setProperty("mainsoft.apache.commons.logging.simplelog.log.mainsoft.apache.commons.httpclient",\r
51                                         "error");\r
52                         if(java.lang.System.getProperty("mainsoft.apache.commons.logging.simplelog.log.httpclient.wire.header")\r
53                                 == null)\r
54                                 java.lang.System.setProperty("mainsoft.apache.commons.logging.simplelog.log.httpclient.wire.header", \r
55                                         "error");\r
56 \r
57                 }\r
58                 public VMWHttpProvider(Uri uri) : base (uri)\r
59                 {\r
60                 }\r
61 \r
62                 internal override ServicePoint ServicePoint\r
63                 {\r
64                         get {throw new NotImplementedException();}\r
65                 }\r
66 \r
67 \r
68 \r
69                 public override bool IsRequestStarted()\r
70                 {\r
71                         if(_method == null)\r
72                                 return false;\r
73                         return _method.isRequestSent();\r
74                 }\r
75 \r
76                 public override Uri GetAddress()\r
77                 {\r
78                         if(_method == null)\r
79                                 return GetOriginalAddress();\r
80                         mainsoft.apache.commons.httpclient.URI javaURI =  _method.getURI();\r
81                         return new Uri(javaURI.ToString());\r
82                 }\r
83 \r
84                 public override bool IsHaveResponse()\r
85                 {\r
86                         return _hasResponse;\r
87                 }\r
88 \r
89                 private void SetJavaCredential(NetworkCredential nc, string type)\r
90                 {\r
91                         SetJavaCredential(nc, type, false);\r
92                 }\r
93 \r
94                 private void SetJavaCredential(NetworkCredential nc, string type, bool proxyCredentials)\r
95                 {\r
96                         type = type.ToLower();\r
97                         string host = null;\r
98                         \r
99                         if(!proxyCredentials)\r
100                                 host = GetOriginalAddress().Host;\r
101                         else\r
102                                 host = ((WebProxy)this.Proxy).Address.Host;\r
103 \r
104                         string domain = (nc.Domain == null) ? host : nc.Domain;\r
105 \r
106                         if(type.Equals("any"))\r
107                         {\r
108                                 if(!proxyCredentials)\r
109                                 {\r
110                                         _state.setCredentials(AuthScope.ANY,\r
111                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
112                                         _state.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "Ntlm"),\r
113                                                 new NTCredentials(nc.UserName, nc.Password, host, domain));\r
114                                 }\r
115                                 else\r
116                                 {\r
117                                         _state.setProxyCredentials(AuthScope.ANY,\r
118                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
119                                         _state.setProxyCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "Ntlm"),\r
120                                                 new NTCredentials(nc.UserName, nc.Password, host, domain));\r
121                                 }\r
122                         }\r
123                         else if(type.Equals("basic"))\r
124                         {\r
125                                 if(!proxyCredentials)\r
126                                 {\r
127                                         _state.setCredentials(new AuthScope(AuthScope.ANY_HOST,\r
128                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, "basic"),\r
129                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
130                                 }\r
131                                 else\r
132                                 {\r
133                                         _state.setProxyCredentials(new AuthScope(AuthScope.ANY_HOST,\r
134                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, "basic"),\r
135                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
136                                 }\r
137                         }\r
138                         else if(type.Equals("digest"))\r
139                         {\r
140                                 if(!proxyCredentials)\r
141                                 {\r
142                                         _state.setCredentials(new AuthScope(AuthScope.ANY_HOST,\r
143                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, "digest"),\r
144                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
145                                 }\r
146                                 else\r
147                                 {\r
148                                         _state.setProxyCredentials(new AuthScope(AuthScope.ANY_HOST,\r
149                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, "digest"),\r
150                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
151                                 }\r
152                         }\r
153                         else if(type.Equals("ntlm"))\r
154                         {\r
155                                 if(!proxyCredentials)\r
156                                 {\r
157                                         _state.setCredentials(new AuthScope(AuthScope.ANY_HOST,\r
158                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, "ntlm"),\r
159                                                 new NTCredentials(nc.UserName, nc.Password, host, domain));\r
160                                 }\r
161                                 else\r
162                                 {\r
163                                         _state.setProxyCredentials(new AuthScope(AuthScope.ANY_HOST,\r
164                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, "ntlm"),\r
165                                                 new NTCredentials(nc.UserName, nc.Password, host, domain));\r
166                                 }\r
167                         }\r
168                         else\r
169                         {\r
170                                 if(!proxyCredentials)\r
171                                 {\r
172                                         _state.setCredentials(new AuthScope(AuthScope.ANY_HOST,\r
173                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, type),\r
174                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
175                                 }\r
176                                 else\r
177                                 {\r
178                                         _state.setProxyCredentials(new AuthScope(AuthScope.ANY_HOST,\r
179                                                 AuthScope.ANY_PORT, AuthScope.ANY_REALM, type),\r
180                                                 new UsernamePasswordCredentials(nc.UserName, nc.Password));\r
181                                 }\r
182                         }\r
183 \r
184                 }\r
185                 private void InitProxyCredentials()\r
186                 {\r
187                         if(this.Proxy == null)\r
188                                 return;\r
189 \r
190                         if(!(this.Proxy is WebProxy))\r
191                                 return;\r
192                         \r
193                         WebProxy proxy = (WebProxy)this.Proxy;\r
194                         ICredentials creds = proxy.Credentials;\r
195 \r
196                         if(creds == null)\r
197                                 return;\r
198 \r
199                         if(creds is CredentialCache)\r
200                         {\r
201                                 string type = "basic";\r
202                                 NetworkCredential nc = ((CredentialCache)creds).GetCredential(proxy.Address, "basic");\r
203                                 if(nc == null)\r
204                                 {\r
205                                         type = "digest";\r
206                                         nc = ((CredentialCache)creds).GetCredential(proxy.Address, "digest");\r
207                                         if(nc == null)\r
208                                         {\r
209                                                 type = "ntlm";\r
210                                                 nc = ((CredentialCache)creds).GetCredential(proxy.Address, "ntlm");\r
211                                         }\r
212                                 }\r
213                                 if(nc != null)\r
214                                 {\r
215                                         SetJavaCredential(nc, type, true);\r
216                                 }\r
217                         }\r
218                         else if (creds is NetworkCredential)\r
219                         {\r
220                                 SetJavaCredential((NetworkCredential)creds, "any", true);\r
221                         }\r
222 \r
223                         _method.setDoAuthentication(true);\r
224                 }\r
225 \r
226                 private void InitCredentials()\r
227                 {\r
228                         if(_credentials == null)\r
229                                 return;\r
230                         if(_credentials is CredentialCache)\r
231                         {\r
232                                 NetworkCredential nc = ((CredentialCache)_credentials).GetCredential(GetOriginalAddress(), "basic");\r
233                                 string type = "basic";\r
234                                 if(nc == null)\r
235                                 {\r
236                                         nc = ((CredentialCache)_credentials).GetCredential(GetOriginalAddress(), "digest");\r
237                                         type = "digest";\r
238                                         if(nc == null)\r
239                                         {\r
240                                                 nc = ((CredentialCache)_credentials).GetCredential(GetOriginalAddress(), "ntlm");\r
241                                                 type = "ntlm";\r
242                                         }\r
243                                 }\r
244                                 if(nc != null)\r
245                                 {\r
246                                         SetJavaCredential(nc, type);\r
247                                 }\r
248                         }\r
249                         else if(_credentials is NetworkCredential)\r
250                         {\r
251                                 SetJavaCredential((NetworkCredential)_credentials, "any");\r
252                         }\r
253 \r
254                         _method.setDoAuthentication(true);\r
255                 }\r
256 \r
257                 private void InitHostConfig()\r
258                 {\r
259                         if(this.Proxy == null)\r
260                                 return;\r
261                         if(this.Proxy.IsBypassed(GetOriginalAddress()))\r
262                                 return;\r
263 \r
264                         _hostConfig = new HostConfiguration();                  \r
265                         _hostConfig.setHost(new HttpHost(_method.getURI()));\r
266 \r
267                         \r
268                         if(this.Proxy is WebProxy)\r
269                         {\r
270                                 WebProxy wp = (WebProxy) this.Proxy;\r
271                                 _hostConfig.setProxyHost(new ProxyHost(wp.Address.Host, wp.Address.Port));\r
272                         }\r
273                         else\r
274                                 throw new NotImplementedException("Cannot accept Proxy which is not System.Net.WebProxy instance");\r
275 \r
276                         \r
277                 }\r
278 \r
279                 private void SetConnectionHeader(string val)\r
280                 {\r
281                         string connectionHeader = (this.Proxy != null) ? "Proxy-Connection" : "Connection";\r
282                         Headers.RemoveInternal ((this.Proxy != null) ? "Proxy-Connection" : "Connection");\r
283                         \r
284                         if(val != null)\r
285                                 _method.setRequestHeader(connectionHeader, val);\r
286 \r
287                         if (_keepAlive) \r
288                         {\r
289                                 _method.addRequestHeader (connectionHeader, "keep-alive");\r
290                                 Headers.SetInternal(connectionHeader,"keep-alive");\r
291                         }\r
292                         else if (!_keepAlive && _version == HttpVersion.Version11) \r
293                         {\r
294                                 _method.addRequestHeader (connectionHeader, "close");\r
295                                 Headers.SetInternal(connectionHeader,"close");\r
296                         }\r
297 \r
298                 }\r
299                 private bool OpenConnection()\r
300                 {\r
301                         lock(this)\r
302                         {\r
303                                 if(_isConnectionOpened)\r
304                                         return false;\r
305                                 _isConnectionOpened = true;\r
306                         }\r
307                         InitClient();\r
308                         InitMethod();\r
309 \r
310                         _state = _stateCache.GetHttpState();\r
311 \r
312                         //todo insert needed Authontication, Cookies info to state!\r
313                         _method.setDoAuthentication(this.PreAuthenticate);\r
314                         \r
315                         InitHostConfig();\r
316                         InitCredentials();\r
317                         InitProxyCredentials();\r
318                         \r
319                         if(this.ProtocolVersion == HttpVersion.Version11)\r
320                                 _method.getParams().setVersion(mainsoft.apache.commons.httpclient.HttpVersion.HTTP_1_1);\r
321                         else if(ProtocolVersion == HttpVersion.Version10)\r
322                                 _method.getParams().setVersion(mainsoft.apache.commons.httpclient.HttpVersion.HTTP_1_0);\r
323                         else \r
324                                 throw new ProtocolViolationException("Unsupported protocol version: " + ProtocolVersion);\r
325 \r
326                         if(!(_method is mainsoft.apache.commons.httpclient.methods.EntityEnclosingMethod))\r
327                         {\r
328                                 _method.setFollowRedirects(this.AllowAutoRedirect);\r
329                         }\r
330                         else\r
331                         {\r
332                                 if(!AllowWriteStreamBuffering && _contentLength < 0 && !SendChunked)\r
333                                         throw new ProtocolViolationException();\r
334                                 if(SendChunked)\r
335                                         ((EntityEnclosingMethod)_method).setContentChunked(SendChunked);                                \r
336                         }\r
337                         if(MaxAutoRedirections != _defaultMaxRedirectsNum)\r
338                         {\r
339                                 _method.getParams().setParameter(HttpClientParams.MAX_REDIRECTS,\r
340                                         new java.lang.Integer(MaxAutoRedirections));\r
341                         }\r
342                         \r
343                         \r
344                         \r
345                         foreach(string k in Headers)\r
346                         {       \r
347                                 if(k.ToLower().Equals("connection"))\r
348                                         continue;\r
349                                 string val = Headers[k];\r
350                                 val = (val == null) ? "" : val;\r
351                                 _method.setRequestHeader(k, val);\r
352                         }\r
353 \r
354                         if (this.CookieContainer != null) \r
355                         {\r
356                                 string cookieHeader = this.CookieContainer.GetCookieHeader (this.GetOriginalAddress());\r
357                                 if (cookieHeader != "")\r
358                                         _method.setRequestHeader("Cookie", cookieHeader);\r
359                         }\r
360                         SetConnectionHeader(Headers["Connection"]);\r
361                         \r
362                         _method.getParams().setSoTimeout(ReadWriteTimeout);\r
363 \r
364                         return true;\r
365                         \r
366                 }\r
367 \r
368                 private static void InitClient()\r
369                 {\r
370                         lock(LOCK_OBJECT)\r
371                         {\r
372                                 if(_client == null)\r
373                                 {\r
374                                         mainsoft.apache.commons.httpclient.MultiThreadedHttpConnectionManager manager =\r
375                                                 new mainsoft.apache.commons.httpclient.MultiThreadedHttpConnectionManager();\r
376                                         manager.setConnectionStaleCheckingEnabled(true);\r
377                                         manager.setMaxTotalConnections(200);\r
378                                         //by some reasons RFC something - the default \r
379                                         //value will be 2 , so we need to change it ...\r
380                                         manager.setMaxConnectionsPerHost(20);\r
381                                         _client = new HttpClient(manager);\r
382                                         _client.getParams().setIntParameter(HttpClientParams.MAX_REDIRECTS, _defaultMaxRedirectsNum);\r
383                                         _client.getParams().setParameter(HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, new java.lang.Boolean(true));\r
384                                         _client.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, new java.lang.Long(30000));\r
385                                         _client.getParams().setParameter(HttpClientParams.USER_AGENT, \r
386                                                         "VMW4J HttpClient (based on Jakarta Commons HttpClient)");\r
387                                 }\r
388                         }\r
389                 }\r
390 \r
391                 private void InitMethod()\r
392                 {\r
393                         lock(this)\r
394                         {\r
395                                 if(_method == null)\r
396                                 {\r
397                                         string uriString = this.GetOriginalAddress().AbsoluteUri;\r
398 \r
399                                         if(this.MethodName == null || this.MethodName == "")\r
400                                         {\r
401                                                 this.MethodName = "GET";\r
402                                         }\r
403                         \r
404                                         string name = this.MethodName.ToUpper().Trim();\r
405 \r
406                                         switch(name)\r
407                                         {\r
408                                                 case "GET" : _method = new GetMethod(uriString); break;\r
409                                                 case "PUT" : _method = new PutMethod(uriString); break;\r
410                                                 case "POST": _method = new PostMethod(uriString); break;\r
411                                                 case "HEAD": _method = new HeadMethod(uriString); break;\r
412                                                 case "TRACE": _method = new TraceMethod(uriString);break;\r
413                                                 case "DELETE": _method = new DeleteMethod(uriString);break;\r
414                                                 case "OPTIONS": _method = new OptionsMethod(uriString);break;\r
415                                                 default: _method = new GenericMethod(uriString, MethodName); break;\r
416                                         }\r
417                                 }\r
418                         }\r
419                 }\r
420 \r
421                 private void InitHostConfiguration()\r
422                 {\r
423                         lock(this)\r
424                         {\r
425                                 if(_hostConfig == null)\r
426                                 {\r
427                                         _hostConfig = new HostConfiguration();\r
428                                 }\r
429                         }\r
430                 }\r
431 \r
432                 \r
433 \r
434                 public override Stream GetRequestStream()\r
435                 {\r
436                         bool isPutPost = String.Compare("post", MethodName, true) == 0 \r
437                                 || String.Compare("put", MethodName, true) == 0;\r
438                         if(!isPutPost)\r
439                                 throw new ProtocolViolationException();\r
440                         lock(this)\r
441                         {\r
442                                 if(_writeStream != null)\r
443                                         return _writeStream;\r
444                                 this.OpenConnection();\r
445 \r
446                                 //java.io.PipedInputStream inJavaStream = new java.io.PipedInputStream();\r
447                                 //java.io.PipedOutputStream outJavaStream = new java.io.PipedOutputStream(inJavaStream);\r
448                                                         \r
449                                 long contLen = _contentLength;\r
450                                 \r
451                                 OutputStreamRequestEntity reqEntity = new OutputStreamRequestEntity(contLen);\r
452 \r
453                                 _writeStream = new VMWRequestStream(reqEntity, contLen);\r
454                         \r
455                                 EntityEnclosingMethod method = (EntityEnclosingMethod)_method;\r
456                                 if(AllowWriteStreamBuffering )\r
457                                         method.setRequestEntity(reqEntity);\r
458                                 else if(!AllowWriteStreamBuffering && contLen < 0 && !SendChunked)\r
459                                         throw new ProtocolViolationException();\r
460                                 else\r
461                                         method.setRequestEntity(reqEntity);\r
462                         \r
463                                 _hasRequest = true;\r
464                                 return _writeStream;\r
465                         }\r
466                 }\r
467                 private bool isRedirectNeeded(HttpMethod method)\r
468                 {\r
469                         switch (method.getStatusCode()) \r
470                         {\r
471                                 case 302:\r
472                                 case 301:\r
473                                 case 303:\r
474                                 case 307:\r
475                                         if (method.getFollowRedirects()) \r
476                                                 return true;\r
477                                         else \r
478                                                 return false;\r
479                                 default:\r
480                                         return false;\r
481                         } //end of switch\r
482                 }\r
483 \r
484                 private void synchHeaders()\r
485                 {\r
486                         foreach(string k in Headers)\r
487                         {       \r
488                                 if(k.ToLower().Equals("connection"))\r
489                                         continue;\r
490                                 string val = Headers[k];\r
491                                 val = (val == null) ? "" : val;\r
492                                 _method.setRequestHeader(k, val);\r
493                         }\r
494                 }\r
495 \r
496                 public override WebResponse GetResponse()\r
497                 {\r
498                         lock(this)\r
499                         {\r
500                                 if(!_isConnectionOpened)\r
501                                         OpenConnection();\r
502                                 if(_response == null)\r
503                                 {\r
504                                         try\r
505                                         {       \r
506                                                 synchHeaders();\r
507                                                 _client.executeMethod(_hostConfig, _method, _state);\r
508                                                 //todo right place to re-put all headers again...\r
509                                                 mainsoft.apache.commons.httpclient.Header hostHeader =\r
510                                                         _method.getRequestHeader("Host");\r
511                                                 if(hostHeader != null)\r
512                                                         Headers.SetInternal("Host", hostHeader.getValue());\r
513 \r
514                                                 _response = new HttpWebResponse(_method, _state, _stateCache, GetAddress(), this.MethodName);\r
515                                                 \r
516                                                 if(_response != null && \r
517                                                         _response.Cookies != null && \r
518                                                         _response.Cookies.Count > 0)\r
519                                                 {\r
520                                                         if(CookieContainer != null)\r
521                                                         {\r
522                                                                 foreach(Cookie cooky in _response.Cookies)\r
523                                                                 {\r
524                                                                         CookieContainer.Add(GetAddress(), cooky);\r
525                                                                 }\r
526                                                         }\r
527                                                 }\r
528 \r
529                                                 _hasResponse = true;\r
530                                                 int respCodeAsInt = (int) _response.StatusCode;\r
531                                                 if(respCodeAsInt >= 400)\r
532                                                 {\r
533                                                         // The WebException contains the readable (not closed) response stream.\r
534                                                         // So, in case of WebException, we should read all data from the \r
535                                                         // network response stream into the memory stream, and after that\r
536                                                         // close the underlying network stream. The following requests to read\r
537                                                         // from the stream will actually read from the memory stream.\r
538                                                         // So, the this.Abort() should not be called in this case.\r
539                                                         _response.ReadAllAndClose();\r
540                                                         //this.Abort();\r
541                                                         throw new WebException("The remote server returned an error: (" + respCodeAsInt +") " +_response.StatusCode, null, WebExceptionStatus.ProtocolError, _response);\r
542                                                 }\r
543                                                 if(isRedirectNeeded(_method) && _method.getResponseHeader("location") == null)\r
544                                                 {\r
545                                                         // See comments above for the error >= 400\r
546                                                         _response.ReadAllAndClose();\r
547                                                         //this.Abort();\r
548                                                         throw new WebException("Got response code "+_response.StatusCode+", but no location provided", null, WebExceptionStatus.ProtocolError, _response);\r
549                                                 }\r
550                                         }\r
551                                         catch(ProtocolException e)\r
552                                         {\r
553                                                 throw new WebException("", e);\r
554                                         }\r
555                                         catch(java.net.ConnectException e)\r
556                                         {\r
557                                                 throw new WebException("Unable to connect to the remote server.", e);\r
558                                         }\r
559                                         catch(java.net.SocketTimeoutException e)\r
560                                         {\r
561                                                 throw new WebException("Timeout exceeded", e);\r
562                                         }\r
563                                         catch(java.io.IOException e)\r
564                                         {\r
565                                                 throw new WebException("", e);\r
566                                         }\r
567                                 }\r
568                                 return _response;\r
569                         }\r
570 \r
571                 }\r
572 \r
573                 public override void Abort()\r
574                 {\r
575                         _isAborted = true;\r
576                         try\r
577                         {\r
578                                 if(_hasResponse)\r
579                                 {\r
580                                         _response.Close();\r
581                                 }\r
582                         }\r
583                         finally\r
584                         {\r
585                                 _method.releaseConnection();                            \r
586                         }\r
587                 }\r
588 \r
589                 public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)\r
590                 {\r
591                         lock(this)\r
592                         {\r
593                                 if(_asyncWrite != null)\r
594                                 {\r
595                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous " +\r
596                                                 "method while a previous call is still in progress.");\r
597                                 }\r
598         \r
599                                 _asyncWrite = new GHWebAsyncResult (this, callback, state);\r
600                                 if (_hasRequest) \r
601                                 {\r
602                                         if (_writeStream != null) \r
603                                         {\r
604                                                 _asyncWrite.SetCompleted (true, _writeStream);\r
605                                                 _asyncWrite.DoCallback ();\r
606                                                 return _asyncWrite;\r
607                                         }\r
608                                 }\r
609                                 \r
610                                 \r
611                                 try\r
612                                 {\r
613                                         this.GetRequestStream();                                        \r
614                                 }\r
615                                 catch(Exception e)\r
616                                 {\r
617                                         _asyncWrite.SetCompleted(false, e);\r
618                                 }\r
619 \r
620                                 _asyncWrite.SetCompleted (true, _writeStream);\r
621                                 _asyncWrite.DoCallback ();\r
622                                 return _asyncWrite;\r
623                                 \r
624                         }\r
625                 }   \r
626 \r
627                 public override Stream EndGetRequestStream(IAsyncResult asyncResult)\r
628                 {\r
629                         if (asyncResult == null)\r
630                                 throw new ArgumentNullException ("asyncResult");\r
631 \r
632                         GHWebAsyncResult result = asyncResult as GHWebAsyncResult;\r
633                         if (result == null)\r
634                                 throw new ArgumentException ("Invalid IAsyncResult");\r
635 \r
636                         _asyncWrite = result;\r
637 \r
638                         result.WaitUntilComplete ();\r
639 \r
640                         Exception e = result.Exception;\r
641                         \r
642                         if (e != null)\r
643                                 throw e;\r
644 \r
645                         return result.WriteStream;\r
646                 }\r
647 \r
648                 public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)\r
649                 {\r
650                         lock(this)\r
651                         {\r
652                                 if(_asyncRead != null && !_hasResponse)\r
653                                 {\r
654                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous " +\r
655                                                 "method while a previous call is still in progress.");\r
656                                 }\r
657         \r
658                                 _asyncRead = new GHWebAsyncResult (this, callback, state);\r
659                                 if (_hasResponse) \r
660                                 {\r
661                                         if (_response != null) \r
662                                         {\r
663                                                 _asyncRead.SetCompleted (true, _writeStream);\r
664                                                 _asyncRead.DoCallback ();\r
665                                                 return _asyncRead;\r
666                                         }\r
667                                 }\r
668                                 \r
669 \r
670                                 try\r
671                                 {\r
672                                         GetResponse();\r
673                                 }\r
674                                 catch(Exception e)\r
675                                 {\r
676                                         _asyncRead.SetCompleted(false, e);\r
677                                 }\r
678                                 _asyncRead.SetCompleted (true, _writeStream);\r
679                                 _asyncRead.DoCallback ();       \r
680                                 return _asyncRead;\r
681                                 \r
682                         }\r
683                 }\r
684 \r
685                 public override WebResponse EndGetResponse(IAsyncResult asyncResult)\r
686                 {\r
687                         if (asyncResult == null)\r
688                                 throw new ArgumentNullException ("asyncResult");\r
689 \r
690                         GHWebAsyncResult result = asyncResult as GHWebAsyncResult;\r
691                         if (result == null)\r
692                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");\r
693 \r
694                         \r
695                         _asyncRead = result;\r
696                         if (!result.WaitUntilComplete (_timeout, false)) \r
697                         {\r
698                                 Abort ();\r
699                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
700                         }\r
701                         \r
702                         return result.Response;\r
703                 }\r
704 \r
705 \r
706 \r
707 \r
708 \r
709 \r
710 \r
711                 \r
712 \r
713 \r
714 \r
715 \r
716                 #region VMWRequestStream class\r
717                 internal class VMWRequestStream : Stream, IDisposable\r
718                 {\r
719 \r
720                         private java.io.OutputStream _javaOutput;\r
721                         private long _len;\r
722                         private long _contentLength;\r
723 \r
724                         internal VMWRequestStream (java.io.OutputStream stream) :\r
725                                 this(stream , -1L)\r
726                         {\r
727                         }\r
728 \r
729                         internal VMWRequestStream (java.io.OutputStream stream, long contentLength)\r
730                         {\r
731                                 _javaOutput = stream;\r
732                                 _contentLength = contentLength;\r
733                                 _len = 0;\r
734                         }\r
735                         public override bool CanRead\r
736                         {\r
737                                 get    {return false;}\r
738                         }\r
739 \r
740                         public override bool CanWrite\r
741                         {\r
742                                 get{return true;}\r
743                         }\r
744 \r
745                         public override bool CanSeek\r
746                         {\r
747                                 get { return false;}\r
748                         }\r
749 \r
750                         public override long Length\r
751                         {\r
752                                 get{ return _len;}\r
753                         }\r
754 \r
755                         public override long Position\r
756                         {\r
757                                 get\r
758                                 {\r
759                                         return _len;\r
760                                 }\r
761 \r
762                                 set\r
763                                 {\r
764                                         throw new NotSupportedException();\r
765                                 }\r
766                         }\r
767 \r
768                         private volatile bool _closed = false;\r
769 \r
770                         public override void Close()\r
771                         {\r
772                                 if(!_closed)\r
773                                 {\r
774                                         lock(this)\r
775                                         {\r
776                                                 if(!_closed)\r
777                                                 {\r
778                                                         _closed = true;\r
779                                                         _javaOutput.flush();\r
780                                                         _javaOutput.close();\r
781                                                 }\r
782                                         }\r
783                                 }\r
784                         }\r
785 \r
786                         public override void Flush()\r
787                         {\r
788                                 _javaOutput.flush();\r
789                         }\r
790 \r
791                         public override int ReadByte()\r
792                         {\r
793                                 throw new NotSupportedException();\r
794                         }\r
795 \r
796                         public override int Read(byte[] buffer, int offset, int count)\r
797                         {\r
798                                 throw new NotSupportedException();\r
799                         }\r
800 \r
801                         public override void Write(byte[] buffer, int offset, int count)\r
802                         {\r
803                                 if(_contentLength >= 0)\r
804                                 {\r
805                                         _len += count;\r
806                                         if(_len > _contentLength)\r
807                                         {\r
808                                                 throw new  System.Net.ProtocolViolationException(\r
809                                                         "Bytes to be written to the stream exceed Content-Length bytes size specified.");\r
810                                         }\r
811                                 }\r
812                                 _javaOutput.write(vmw.common.TypeUtils.ToSByteArray(buffer), offset, count);\r
813 \r
814                                 if(_contentLength == _len)\r
815                                 {\r
816                                         _javaOutput.flush();\r
817                                         _javaOutput.close();\r
818                                 }\r
819                         }\r
820 \r
821                         public override long Seek(long offset, SeekOrigin origin)\r
822                         {\r
823                                 throw new NotSupportedException();\r
824                         }\r
825 \r
826                         public override void SetLength(long length)\r
827                         {\r
828                                 throw new NotSupportedException();\r
829                         }\r
830 \r
831                         void IDisposable.Dispose()\r
832                         {\r
833                                 try\r
834                                 {\r
835                                         Close();\r
836                                 }\r
837                                 catch(Exception)\r
838                                 {\r
839                                 }\r
840                         }\r
841                 }\r
842                 \r
843                 #endregion\r
844 \r
845                 #region GHWebAsyncResult\r
846                 internal class GHWebAsyncResult  : IAsyncResult\r
847                 {\r
848                         private object _state;\r
849                         private AsyncCallback _callback;\r
850                         private ManualResetEvent _handle;\r
851                         private bool _isCompleted = false;\r
852                         private bool _callbackDone;\r
853                         private Stream _writeStream;\r
854                         private HttpProvider _provider;\r
855 \r
856                         private Exception _exception;\r
857 \r
858                         #region   Constructors\r
859 \r
860                         public GHWebAsyncResult(HttpProvider provider, \r
861                                 AsyncCallback callback, object state) : \r
862                                 this(state, callback)\r
863                         {\r
864                                 _provider = provider;\r
865                         }\r
866 \r
867                         public GHWebAsyncResult(object state, AsyncCallback callback)\r
868                         {\r
869                                 _state = state;\r
870                                 _callback = callback;\r
871                         }\r
872                         #endregion\r
873 \r
874                         #region IAsyncResult Members\r
875 \r
876                         public object AsyncState\r
877                         {\r
878                                 get\r
879                                 {\r
880                                         return _state;\r
881                                 }\r
882                         }\r
883 \r
884                         public bool CompletedSynchronously\r
885                         {\r
886                                 get\r
887                                 {\r
888                                         // TODO:  Add HWebAsyncResult.CompletedSynchronously getter implementation\r
889                                         return false;\r
890                                 }\r
891                         }\r
892 \r
893                         public WaitHandle AsyncWaitHandle \r
894                         {\r
895                                 get \r
896                                 {\r
897                                         if (_handle == null) \r
898                                         {\r
899                                                 lock (this) \r
900                                                 {\r
901                                                         if (_handle == null)\r
902                                                                 _handle = new ManualResetEvent (_isCompleted);\r
903                                                 }\r
904                                         }\r
905                                 \r
906                                         return _handle;\r
907                                 }\r
908                         }\r
909 \r
910                         public bool IsCompleted\r
911                         {\r
912                                 get\r
913                                 {\r
914                                         return _isCompleted;    \r
915                                 }\r
916                         }\r
917 \r
918                         #endregion\r
919 \r
920                         #region Internal Properties\r
921 \r
922                         internal Stream WriteStream\r
923                         {\r
924                                 get\r
925                                 {\r
926                                         return _writeStream;\r
927                                 }\r
928                         }\r
929 \r
930                         internal Exception Exception\r
931                         {\r
932                                 get\r
933                                 {\r
934                                         return _exception;\r
935                                 }\r
936                         }\r
937 \r
938                         internal HttpWebResponse Response\r
939                         {\r
940                                 get\r
941                                 {\r
942                                         return ((VMWHttpProvider)_provider)._response;\r
943                                 }\r
944                         }\r
945 \r
946                         #endregion\r
947 \r
948                         #region Internal Methods\r
949 \r
950                         internal void SetCompleted(bool res, Stream writeStream)\r
951                         {\r
952                                 _isCompleted = res;\r
953                                 _writeStream = writeStream;\r
954                                 ((ManualResetEvent) AsyncWaitHandle).Set ();\r
955                         }\r
956 \r
957                         internal void SetCompleted(bool res, Exception exc)\r
958                         {\r
959                                 _isCompleted = res;\r
960                                 _exception = exc;\r
961                                 ((ManualResetEvent) AsyncWaitHandle).Set ();\r
962                         }\r
963 \r
964                         internal void DoCallback()\r
965                         {\r
966                                 if (!_callbackDone && _callback != null) \r
967                                 {\r
968                                         _callbackDone = true;\r
969                                         _callback (this);\r
970                                 }\r
971                         }\r
972 \r
973                         internal void WaitUntilComplete()\r
974                         {\r
975                                 if(_isCompleted)\r
976                                         return;\r
977                                 AsyncWaitHandle.WaitOne ();\r
978                         }\r
979 \r
980                         internal bool WaitUntilComplete (int timeout, bool exitContext)\r
981                         {\r
982                                 if (_isCompleted)\r
983                                         return true;\r
984 \r
985                                 return AsyncWaitHandle.WaitOne (timeout, exitContext);\r
986                         }\r
987                         #endregion\r
988 \r
989                 }\r
990 \r
991                 #endregion\r
992 \r
993                 #region OutputStreamRequestEntity\r
994 \r
995                 internal class OutputStreamRequestEntity : java.io.OutputStream, RequestEntity\r
996                 {\r
997                         private long _contentLength;\r
998                         private java.io.ByteArrayOutputStream _out;\r
999                         private sbyte[] _buffer;\r
1000 \r
1001                         internal OutputStreamRequestEntity(): this(-1)\r
1002                         {\r
1003                         }\r
1004 \r
1005                         internal OutputStreamRequestEntity(long length)\r
1006                         {\r
1007                                 _contentLength = length;\r
1008                                 int tmp = (int) _contentLength;\r
1009 \r
1010                                 if(tmp <=0)\r
1011                                         tmp = 4096;\r
1012                                 _out = new java.io.ByteArrayOutputStream(tmp);\r
1013                         }\r
1014 \r
1015                         #region RequestEntity Members\r
1016 \r
1017                         public bool isRepeatable()\r
1018                         {\r
1019                                 return ((_out != null) || (_buffer != null));\r
1020                         }\r
1021 \r
1022                         public long getContentLength()\r
1023                         {\r
1024                                 if(_out != null)\r
1025                                 {\r
1026                                         _buffer = _out.toByteArray();\r
1027                                 }\r
1028                                 if(_buffer != null)\r
1029                                 {\r
1030                                         _contentLength = _buffer.Length;\r
1031                                         _out = null;\r
1032                                 }\r
1033                                 return _contentLength;\r
1034                         }\r
1035 \r
1036                         public void writeRequest(java.io.OutputStream output)\r
1037                         {\r
1038                                 if(_out != null)\r
1039                                         _buffer = _out.toByteArray();\r
1040                                 if(_buffer != null)\r
1041                                 {\r
1042                                         output.write(_buffer, 0, _buffer.Length);\r
1043                                         _out = null;\r
1044                                 }\r
1045                                 else throw new ApplicationException();\r
1046                         }\r
1047 \r
1048                         public string getContentType()\r
1049                         {\r
1050                                 return null;\r
1051                         }\r
1052 \r
1053                         #endregion\r
1054 \r
1055                         public override void write(int i)\r
1056                         {\r
1057                                 _out.write(i);\r
1058                         }\r
1059 \r
1060                 }\r
1061 \r
1062                 #endregion\r
1063 \r
1064 \r
1065 \r
1066 \r
1067 \r
1068 \r
1069 \r
1070         }\r
1071 }\r