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