2003-11-18 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpResponse.cs
1 // 
2 // System.Web.HttpResponse
3 //
4 // Authors:
5 //      Patrik Torstensson (Patrik.Torstensson@labs2.com)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
9 //
10 using System;
11 using System.Collections;
12 using System.Globalization;
13 using System.IO;
14 using System.Text;
15 using System.Threading;
16 using System.Web.Util;
17
18 namespace System.Web
19 {
20         public sealed class HttpResponse
21         {
22                 // Chunked encoding static helpers
23                 static byte [] s_arrChunkSuffix = { 10, 13 };
24                 static byte [] s_arrChunkEnd = { 10 , 13 };
25                 static string s_sChunkedPrefix = "\r\n";
26
27                 ArrayList _Headers;
28                         
29                 bool _bClientDisconnected;
30                 bool _bSuppressHeaders;
31                 bool _bSuppressContent;
32                 bool _bChunked;
33                 bool _bEnded;
34                 bool _bBuffering;
35                 bool _bHeadersSent;
36                 bool _bFlushing;
37                 bool filtered;
38                 long _lContentLength;
39                 int _iStatusCode;
40
41                 bool _ClientDisconnected;
42                 bool closed;
43
44                 string  _sContentType;
45                 string  _sCacheControl;
46                 string  _sTransferEncoding;
47                 string  _sCharset;
48                 string  _sStatusDescription;
49
50                 HttpCookieCollection _Cookies;
51                 HttpCachePolicy _CachePolicy;
52
53                 Encoding _ContentEncoding;
54                         
55                 HttpContext _Context;
56                 HttpWriter _Writer;
57                 TextWriter _TextWriter;
58
59                 HttpWorkerRequest _WorkerRequest;
60
61                 ArrayList fileDependencies;
62
63                 public HttpResponse (TextWriter output)
64                 {
65                          _bBuffering = true;
66                          _bFlushing = false;
67                          _bHeadersSent = false;
68
69                          _Headers = new ArrayList ();
70
71                          _sContentType = "text/html";
72
73                          _iStatusCode = 200;
74                          _sCharset = null;
75                          _sCacheControl = null;
76
77                          _lContentLength = 0;
78                          _bSuppressContent = false;
79                          _bSuppressHeaders = false;
80                          _bClientDisconnected = false;
81
82                          _bChunked = false;
83
84                          _TextWriter = output;
85                 }
86
87                 internal HttpResponse (HttpWorkerRequest WorkerRequest, HttpContext Context)
88                 {
89                          _Context = Context;
90                          _WorkerRequest = WorkerRequest;
91
92                          _bBuffering = true;
93                          _bFlushing = false;
94                          _bHeadersSent = false;
95
96                          _Headers = new ArrayList ();
97
98                          _sContentType = "text/html";
99
100                          _iStatusCode = 200;
101                          _sCharset = null;
102                          _sCacheControl = null;
103
104                          _lContentLength = 0;
105                          _bSuppressContent = false;
106                          _bSuppressHeaders = false;
107                          _bClientDisconnected = false;
108
109                          _bChunked = false;
110
111                          _Writer = new HttpWriter (this);
112                          _TextWriter = _Writer;
113                 }
114
115                 internal void FinalFlush ()
116                 {
117                         Flush (true);
118                 }
119
120                 internal void DoFilter (bool really)
121                 {
122                         if (really && null != _Writer) 
123                                 _Writer.FilterData (true);
124
125                         filtered = true;
126                 }
127
128                 [MonoTODO("We need to add cache headers also")]
129                 private ArrayList GenerateHeaders ()
130                 {
131                         ArrayList oHeaders = new ArrayList (_Headers.ToArray ());
132
133                         oHeaders.Add (new HttpResponseHeader ("X-Powered-By", "Mono"));
134                         // save culture info, we need us info here
135                         CultureInfo oSavedInfo = Thread.CurrentThread.CurrentCulture;
136                         Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
137
138                         string date = DateTime.Now.ToUniversalTime ().ToString ("ddd, d MMM yyyy HH:mm:ss ");
139                         oHeaders.Add (new HttpResponseHeader ("Date", date + "GMT"));
140
141                         Thread.CurrentThread.CurrentCulture = oSavedInfo;
142
143                         if (_lContentLength > 0) {
144                                 oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderContentLength,
145                                                                       _lContentLength.ToString ()));
146                         }
147
148                         if (_sContentType != null) {
149                                 if (_sContentType.IndexOf ("charset=") == -1) {
150                                         if (Charset.Length == 0) {
151                                                 Charset = ContentEncoding.HeaderName;
152                                         }
153
154                                         // Time to build our string
155                                         if (Charset.Length > 0) {
156                                                 _sContentType += "; charset=" + Charset;
157                                         }
158                                 }
159
160                                 oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderContentType,
161                                                                       _sContentType));
162                         }
163                         
164                         if (_CachePolicy != null)
165                                 _CachePolicy.SetHeaders (this, oHeaders);
166                         
167                         if (_sCacheControl != null) {
168                                 oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderPragma,
169                                                                       _sCacheControl));
170                         }
171
172                         if (_sTransferEncoding != null) {
173                                 oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderTransferEncoding,
174                                                                       _sTransferEncoding));
175                         }
176
177                         if (_Cookies != null) {
178                                 int length = _Cookies.Count;
179                                 for (int i = 0; i < length; i++) {
180                                         oHeaders.Add (_Cookies.Get (i).GetCookieHeader ());
181                                 }
182                         }
183
184                         return oHeaders;
185                 }
186
187                 private void SendHeaders ()
188                 {
189                         _WorkerRequest.SendStatus (StatusCode, StatusDescription);
190                         
191                         ArrayList oHeaders = GenerateHeaders ();
192                         foreach (HttpResponseHeader oHeader in oHeaders)
193                                 oHeader.SendContent (_WorkerRequest);
194                         
195                         _bHeadersSent = true;
196                 }
197
198                 public string Status
199                 {
200                         get {
201                                 return String.Format ("{0} {1}", StatusCode, StatusDescription);
202                         }
203
204                         set {
205                                 string sMsg = "OK";
206                                 int iCode = 200;
207
208                                 try {
209                                         iCode = Int32.Parse (value.Substring (0, value.IndexOf (' ')));
210                                         sMsg = value.Substring (value.IndexOf (' ') + 1);
211                                 } catch (Exception) {
212                                         throw new HttpException ("Invalid status string");
213                                 }
214
215                                 StatusCode = iCode;
216                                 StatusDescription = sMsg;
217                         }
218                 }
219
220                 [MonoTODO()]
221                 public void AddCacheItemDependencies (ArrayList cacheKeys)
222                 {
223                         throw new NotImplementedException ();
224                 }
225
226                 [MonoTODO()]
227                 public void AddCacheItemDependency(string cacheKey)
228                 {
229                         throw new NotImplementedException ();
230                 }
231
232                 public void AddFileDependencies (ArrayList filenames)
233                 {
234                         if (filenames == null || filenames.Count == 0)
235                                 return;
236                         
237                         if (fileDependencies == null) {
238                                 fileDependencies = (ArrayList) filenames.Clone ();
239                                 return;
240                         }
241
242                         foreach (string fn in filenames)
243                                 AddFileDependency (fn);
244                 }
245
246                 public void AddFileDependency (string filename)
247                 {
248                         if (fileDependencies == null)
249                                 fileDependencies = new ArrayList ();
250
251                         fileDependencies.Add (filename);
252                 }
253
254                 public void AddHeader (string name, string value)
255                 {
256                         AppendHeader(name, value);
257                 }
258
259                 public void AppendCookie (HttpCookie cookie)
260                 {
261                         if (_bHeadersSent)
262                                 throw new HttpException ("Cannot append cookies after HTTP headers have been sent");
263
264                         Cookies.Add (cookie);
265                 }
266
267                 [MonoTODO()]
268                 public void AppendToLog (string param)
269                 {
270                         throw new NotImplementedException ();
271                 }
272
273                 public string ApplyAppPathModifier (string virtualPath)
274                 {
275                         if (virtualPath == null)
276                                 return null;
277
278                         if (virtualPath == "")
279                                 return _Context.Request.RootVirtualDir;
280
281                         if (UrlUtils.IsRelativeUrl (virtualPath)) {
282                                 virtualPath = UrlUtils.Combine (_Context.Request.RootVirtualDir, virtualPath);
283                         } else if (UrlUtils.IsRooted (virtualPath)) {
284                                 virtualPath = UrlUtils.Reduce (virtualPath);
285                         }
286
287                         return virtualPath;
288                 }
289
290                 public bool Buffer
291                 {
292                         get {
293                                 return BufferOutput;
294                         }
295
296                         set {
297                                 BufferOutput = value;
298                         }
299                 }
300
301                 public bool BufferOutput
302                 {
303                         get {
304                                 return _bBuffering;
305                         }
306                         
307                         set {
308                                 if (_Writer != null)
309                                         _Writer.Update ();
310
311                                 _bBuffering = value;
312                         }
313                 }
314
315                 public HttpCachePolicy Cache
316                 {
317                         get {
318                                 if (null == _CachePolicy)
319                                         _CachePolicy = new HttpCachePolicy ();
320
321                                 return _CachePolicy;
322                         }
323                 }
324
325                 [MonoTODO("Set status in the cache policy")]
326                 public string CacheControl
327                 {
328                         get {
329                                 return _sCacheControl;
330                         }
331
332                         set {
333                                 if (_bHeadersSent)
334                                         throw new HttpException ("Headers has been sent to the client");
335
336                                 _sCacheControl = value;
337                         }
338                 }
339
340                 public string Charset
341                 {
342                         get {
343                                 if (null == _sCharset)
344                                         _sCharset = ContentEncoding.WebName;
345
346                                 return _sCharset;
347                         }
348
349                         set {
350                                 if (_bHeadersSent)
351                                         throw new HttpException ("Headers has been sent to the client");
352
353                                 _sCharset = value;
354                         }
355                 }
356
357                 public Encoding ContentEncoding
358                 {
359                         get {
360                                 if (_ContentEncoding == null)
361                                         _ContentEncoding = WebEncoding.ResponseEncoding;
362
363                                 return _ContentEncoding;
364                         }
365
366                         set {
367                                 if (value == null)
368                                         throw new ArgumentNullException ("Can't set a null as encoding");
369
370                                 _ContentEncoding = value;
371
372                                 if (_Writer != null)
373                                         _Writer.Update ();
374                         }
375                 }
376
377                 public string ContentType
378                 {
379                         get {
380                                 return _sContentType;
381                         }
382
383                         set {
384                                 if (_bHeadersSent)
385                                         throw new HttpException ("Headers has been sent to the client");
386
387                                 _sContentType = value;
388                         }
389                 }
390
391                 public HttpCookieCollection Cookies
392                 {
393                         get {
394                                 if (null == _Cookies)
395                                         _Cookies = new HttpCookieCollection (this, false);
396
397                                 return _Cookies;
398                         }
399                 }
400
401                 [MonoTODO("Set expires in the cache policy")]
402                 public int Expires
403                 {
404                         get {
405                                 throw new NotImplementedException ();
406                         }
407
408                         set {
409                                 throw new NotImplementedException ();
410                         }
411                 }
412
413                 [MonoTODO("Set expiresabsolute in the cache policy")]
414                 public DateTime ExpiresAbsolute
415                 {
416                         get {
417                                 throw new NotImplementedException ();
418                         }
419
420                         set {
421                                 throw new NotImplementedException ();
422                         }
423                 }
424
425                 public Stream Filter
426                 {
427                         get {
428                                 if (_Writer != null)
429                                         return _Writer.GetActiveFilter ();
430
431                                 return null;
432                         }
433
434                         set {
435                                 if (_Writer == null)
436                                         throw new HttpException ("Filtering is not allowed");
437
438                                 _Writer.ActivateFilter (value);
439                         }
440                 }
441
442                 public bool IsClientConnected
443                 {
444                         get {
445                                 if (_ClientDisconnected)
446                                         return false;
447
448                                 if (null != _WorkerRequest && (!_WorkerRequest.IsClientConnected ())) {
449                                         _ClientDisconnected = false;
450                                         return false;
451                                 }
452
453                                 return true;
454                         }
455                 }
456       
457                 public TextWriter Output
458                 {
459                         get {
460                                 return _TextWriter;
461                         }
462                 }
463
464                 public Stream OutputStream
465                 {
466                         get {
467                                 if (_Writer == null)
468                                         throw new HttpException ("an Output stream not available when " +
469                                                                  "running with custom text writer");
470
471                                 return _Writer.OutputStream;
472                         }
473                 }
474
475                 public string StatusDescription
476                 {
477                         get {
478                                 if (null == _sStatusDescription)
479                                         _sStatusDescription =
480                                                 HttpWorkerRequest.GetStatusDescription (_iStatusCode);
481
482                                 return _sStatusDescription;
483                         }
484
485                         set {
486                                 if (_bHeadersSent)
487                                         throw new HttpException ("Headers has been sent to the client");
488
489                                 _sStatusDescription = value;
490                         }
491                 }
492         
493                 public int StatusCode
494                 {
495                         get {
496                                 return _iStatusCode;
497                         }
498
499                         set {
500                                 if (_bHeadersSent)
501                                         throw new HttpException ("Headers has been sent to the client");
502
503                                 _sStatusDescription = null;
504                                 _iStatusCode = value;
505                         }
506                 }
507
508                 public bool SuppressContent
509                 {
510                         get {
511                                 return _bSuppressContent;
512                         }
513                         
514                         set {
515                                 if (_bHeadersSent)
516                                         throw new HttpException ("Headers has been sent to the client");
517
518                                 _bSuppressContent = true;
519                         }
520                 }
521
522                 HttpRequest Request
523                 {
524                         get {
525                                 if (_Context == null)
526                                         return null;
527
528                                 return _Context.Request;
529                         }
530                 }
531
532                 internal void AppendHeader (int iIndex, string value)
533                 {
534                         if (_bHeadersSent)
535                                 throw new HttpException ("Headers has been sent to the client");
536
537                         switch (iIndex) {
538                         case HttpWorkerRequest.HeaderContentLength:
539                                 _lContentLength = Int64.Parse (value);
540                                 break;
541                         case HttpWorkerRequest.HeaderContentEncoding:
542                                 _sContentType = value;
543                                 break;
544                         case HttpWorkerRequest.HeaderTransferEncoding:
545                                 _sTransferEncoding = value;
546                                 if (value.Equals ("chunked")) {
547                                         _bChunked = true;
548                                 } else {
549                                         _bChunked = false;
550                                 }
551                                 break;
552                         case HttpWorkerRequest.HeaderPragma:
553                                 _sCacheControl = value;
554                                 break;
555                         default:
556                                 _Headers.Add (new HttpResponseHeader (iIndex, value));
557                                 break;
558                         }
559                 }
560
561                 public void AppendHeader (string name, string value)
562                 {
563                         if (_bHeadersSent)
564                                 throw new HttpException ("Headers has been sent to the client");
565
566                         switch (name.ToLower ()) {
567                         case "content-length":
568                                 _lContentLength = Int64.Parse (value);
569                                 break;
570                         case "content-type":
571                                 _sContentType = value;
572                                 break;
573                         case "transfer-encoding":
574                                 _sTransferEncoding = value;
575                                 if (value.Equals ("chunked")) {
576                                         _bChunked = true;
577                                 } else {
578                                         _bChunked = false;
579                                 }
580                                 break;
581                         case "pragma":
582                                 _sCacheControl = value;
583                                 break;
584                         default:
585                                 _Headers.Add (new HttpResponseHeader (name, value));
586                                 break;
587                         }
588                 }
589         
590                 internal TextWriter SetTextWriter (TextWriter w)
591                 {
592                         TextWriter prev = _TextWriter;
593                         _TextWriter = w;
594                         return prev;
595                 }
596                 
597                 public void BinaryWrite (byte [] buffer)
598                 {
599                         OutputStream.Write (buffer, 0, buffer.Length);
600                 }
601
602                 public void Clear ()
603                 {
604                         if (_Writer != null)
605                                 _Writer.Clear ();
606                 }
607
608                 public void ClearContent ()
609                 {
610                         Clear();
611                 }
612
613                 public void ClearHeaders ()
614                 {
615                         if (_bHeadersSent)
616                                 throw new HttpException ("Headers has been sent to the client");
617
618                         _sContentType = "text/html";
619
620                         _iStatusCode = 200;
621                         _sCharset = null;
622                         _Headers = new ArrayList ();
623                         _sCacheControl = null;
624                         _sTransferEncoding = null;
625
626                         _lContentLength = 0;
627                         _bSuppressContent = false;
628                         _bSuppressHeaders = false;
629                         _bClientDisconnected = false;
630                 }
631
632                 public void Close ()
633                 {
634                         if (closed && !_bClientDisconnected) {
635                                 _bClientDisconnected = false;
636                                 _WorkerRequest.CloseConnection ();
637                                 _bClientDisconnected = true;
638                         }
639                 }
640
641                 internal void Dispose ()
642                 {
643                         if (_Writer != null) {
644                                 _Writer.Dispose ();
645                                 _Writer = null;
646                         }
647                 }
648
649                 [MonoTODO("Handle callbacks into before done with session, needs to have a non ended flush here")]
650                 internal void FlushAtEndOfRequest () 
651                 {
652                         Flush (true);
653                 }
654
655                 public void End ()
656                 {
657                         if (_bEnded)
658                                 return;
659
660                         Flush ();
661                         _bEnded = true;
662                         _Context.ApplicationInstance.CompleteRequest ();
663                 }
664
665                 public void Flush ()
666                 {
667                         if (closed)
668                                 throw new HttpException ("Response already finished.");
669
670                         Flush (false);
671                 }
672
673                 private void Flush (bool bFinish)
674                 {
675                         if (_bFlushing || closed)
676                                 return;
677
678                         _bFlushing = true;
679
680                         if (_Writer == null) {
681                                 _TextWriter.Flush ();
682                                 _bFlushing = false;
683                                 return;
684                         }
685
686                         try {
687                                 if (_bClientDisconnected)
688                                         return;
689
690                                 long length = _Writer.BufferSize;
691                                 if (!_bHeadersSent && !_bSuppressHeaders) {
692                                         if (bFinish) {
693                                                 if (length == 0 && _lContentLength == 0)
694                                                         _sContentType = null;
695
696                                                 SendHeaders ();
697                                                 length = _Writer.BufferSize;
698                                                 if (length != 0)
699                                                         _WorkerRequest.SendCalculatedContentLength ((int) length);
700                                         } else {
701                                                 if (_lContentLength == 0 && _iStatusCode == 200 &&
702                                                    _sTransferEncoding == null) {
703                                                         // Check we are going todo chunked encoding
704                                                         string sProto = Request.ServerVariables ["SERVER_PROTOCOL"];
705                                                         sProto = "HTTP/1.0"; // Remove this line when we support properly
706                                                                              // chunked content
707
708                                                         if (sProto != null && sProto == "HTTP/1.1") {
709                                                                 AppendHeader (
710                                                                         HttpWorkerRequest.HeaderTransferEncoding,
711                                                                         "chunked");
712                                                         }  else {
713                                                                 // Just in case, the old browsers send a HTTP/1.0
714                                                                 // request with Connection: Keep-Alive
715                                                                 AppendHeader (
716                                                                         HttpWorkerRequest.HeaderConnection,
717                                                                         "Close");
718                                                         }
719                                                 }
720
721                                                 length = _Writer.BufferSize;
722                                                 SendHeaders ();
723                                         }
724                                 }
725
726                                 if (!filtered) {
727                                         _Writer.FilterData (false);
728                                         length = _Writer.BufferSize;
729                                 }
730
731                                 if (length == 0) {
732                                         _WorkerRequest.FlushResponse (bFinish);
733                                         if (!bFinish)
734                                                 _Writer.Clear ();
735                                         return;
736                                 }
737
738                                 if (!_bSuppressContent && Request.HttpMethod == "HEAD")
739                                         _bSuppressContent = true;
740
741                                 if (!_bSuppressContent) {
742                                         _bClientDisconnected = false;
743                                         if (_bChunked) {
744                                                 Encoding oASCII = Encoding.ASCII;
745
746                                                 string chunk = Convert.ToString(_Writer.BufferSize, 16);
747                                                 byte [] arrPrefix = oASCII.GetBytes (chunk + s_sChunkedPrefix);
748
749                                                 _WorkerRequest.SendResponseFromMemory (arrPrefix,
750                                                                                        arrPrefix.Length);
751
752                                                 _Writer.SendContent (_WorkerRequest);
753
754                                                 _WorkerRequest.SendResponseFromMemory (s_arrChunkSuffix,
755                                                                                        s_arrChunkSuffix.Length);
756                                                 if (bFinish)
757                                                         _WorkerRequest.SendResponseFromMemory (
758                                                                         s_arrChunkEnd, s_arrChunkEnd.Length);
759                                         } else {
760                                                 _Writer.SendContent (_WorkerRequest);
761                                         }
762                                 }
763
764                                 _WorkerRequest.FlushResponse (bFinish);
765                                 _Writer.Clear ();
766                         } finally {
767                                 if (bFinish)
768                                         closed = true;
769
770                                 _bFlushing = false;
771                         }
772                 }
773
774                 public void Pics (string value)
775                 {
776                         AppendHeader ("PICS-Label", value);
777                 }
778
779
780                 public void Redirect (string url)
781                 {
782                         Redirect (url, true);
783                 }
784
785                 public void Redirect (string url, bool endResponse)
786                 {
787                         if (_bHeadersSent)
788                                 throw new HttpException ("Headers has been sent to the client");
789
790                         Clear ();
791
792                         url = ApplyAppPathModifier (url);
793                         StatusCode = 302;
794                         AppendHeader (HttpWorkerRequest.HeaderLocation, url);
795
796                         // Text for browsers that can't handle location header
797                         Write ("<html><head><title>Object moved</title></head><body>\r\n");
798                         Write ("<h2>Object moved to <a href='" + url + "'>here</a></h2>\r\n");
799                         Write ("</body><html>\r\n");
800
801                         if (endResponse)
802                                 End ();
803                 }
804
805                 public void Write (char ch)
806                 {
807                         _TextWriter.Write(ch);
808                 }
809
810                 public void Write (object obj)
811                 {
812                         _TextWriter.Write(obj);
813                 }
814
815                 public void Write (string str)
816                 {
817                         _TextWriter.Write (str);
818                 }
819
820                 public void Write (char [] buffer, int index, int count)
821                 {
822                         _TextWriter.Write (buffer, index, count);
823                 }
824
825                 [MonoTODO()]
826                 public static void RemoveOutputCacheItem (string path)
827                 {
828                         throw new NotImplementedException ();
829                 }
830
831                 public void SetCookie (HttpCookie cookie)
832                 {
833                         if (_bHeadersSent)
834                                 throw new HttpException ("Cannot append cookies after HTTP headers have been sent");
835
836                         Cookies.Add (cookie);
837                 }
838
839                 private void WriteFromStream (Stream stream, long offset, long length, long bufsize)
840                 {
841                         if (offset < 0 || length <= 0)
842                                 return;
843                         
844                         long stLength = stream.Length;
845                         if (offset + length > stLength)
846                                 length = stLength - offset;
847
848                         if (offset > 0)
849                                 stream.Seek (offset, SeekOrigin.Begin);
850
851                         byte [] fileContent = new byte [bufsize];
852                         int count = (int) Math.Min (Int32.MaxValue, bufsize);
853                         while (length > 0 && (count = stream.Read (fileContent, 0, count)) != 0) {
854                                 _Writer.WriteBytes (fileContent, 0, count);
855                                 length -= count;
856                                 count = (int) Math.Min (length, fileContent.Length);
857                         }
858                 }
859
860                 public void WriteFile (string filename)
861                 {
862                         WriteFile (filename, false);
863                 }
864
865                 public void WriteFile (string filename, bool readIntoMemory)
866                 {
867                         FileStream fs = null;
868                         try {
869                                 fs = File.OpenRead (filename);
870                                 long size = fs.Length;
871                                 if (readIntoMemory) {
872                                         WriteFromStream (fs, 0, size, size);
873                                 } else {
874                                         WriteFromStream (fs, 0, size, 8192);
875                                 }
876                         } finally {
877                                 if (fs != null)
878                                         fs.Close ();
879                         }
880                 }
881
882                 public void WriteFile (string filename, long offset, long size)
883                 {
884                         FileStream fs = null;
885                         try {
886                                 fs = File.OpenRead (filename);
887                                 WriteFromStream (fs, offset, size, 8192);
888                         } finally {
889                                 if (fs != null)
890                                         fs.Close ();
891                         }
892                 }
893
894                 public void WriteFile (IntPtr fileHandle, long offset, long size)
895                 {
896                         FileStream fs = null;
897                         try {
898                                 fs = new FileStream (fileHandle, FileAccess.Read);
899                                 WriteFromStream (fs, offset, size, 8192);
900                         } finally {
901                                 if (fs != null)
902                                         fs.Close ();
903                         }
904                 }   
905
906                 [MonoTODO()]
907                 internal void OnCookieAdd (HttpCookie cookie)
908                 {
909                 }
910
911                 [MonoTODO("Do we need this?")]
912                 internal void OnCookieChange (HttpCookie cookie)
913                 {
914                 }
915
916                 [MonoTODO()]
917                 internal void GoingToChangeCookieColl ()
918                 {
919                 }
920
921                 [MonoTODO()]
922                 internal void ChangedCookieColl ()
923                 {
924                 }
925         }
926 }