merge -r 53370:58178
[mono.git] / mcs / class / System.Web / System.Web.Hosting / ServletWorkerRequest.jvm.cs
1 //
2 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
3 //
4
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //
25 using System;
26 using System.IO;
27 using System.Text;
28 using System.Runtime.InteropServices;
29 using System.Web.Util;
30 using vmw.common;
31 using System.Web.J2EE;
32 using System.Collections;
33 using System.Web;
34 using javax.servlet;
35 using javax.servlet.http;
36
37 namespace System.Web.Hosting
38 {
39         [MonoTODO("Implement security demands on the path usage functions (and review)")]
40         [ComVisible (false)]
41         internal class ServletWorkerRequest : HttpWorkerRequest
42         {
43                 private string _Page;
44                 private string _Query;
45                 private string _PathInfo = String.Empty;
46                 private string _AppVirtualPath;
47                 private string _AppPhysicalPath;
48                 private string _AppInstallPath;
49                 private bool _HasInstallInfo;
50                 
51                 private static string SLASH = "/";
52
53                 private ServletOutputStream _ServletOutputStream;
54                 private HttpServlet _HttpServlet;
55                 private HttpServletRequest _HttpServletRequest;
56                 private HttpServletResponse _HttpServletResponse;
57                 private string [][] unknownHeaders;
58
59                 private HttpWorkerRequest.EndOfSendNotification _endOfSendCallback;
60                 private object _endOfSendArgs;
61
62
63                 private ServletWorkerRequest ()
64                 {
65                 }
66
67                 public ServletWorkerRequest (HttpServlet servlet, HttpServletRequest req, HttpServletResponse resp, ServletOutputStream output)
68                         :this(String.Empty, String.Empty ,String.Empty, String.Empty ,null)
69                 {
70 #if DEBUG
71                         Console.WriteLine("Constructor 1 of ServletWorkerRequest!! -->");
72 #endif
73                         _HttpServlet = servlet;
74                         _HttpServletRequest = req;
75                         _HttpServletResponse = resp;
76                         _ServletOutputStream = output;
77
78                         string contextPath = req.getContextPath();
79                         string requestURI = req.getRequestURI();
80                         if (requestURI.Equals(contextPath) ||
81                                 ((requestURI.Length - contextPath.Length) == 1) && requestURI[requestURI.Length-1] == '/' && requestURI.StartsWith(contextPath))
82                                 requestURI = contextPath + req.getServletPath();
83                 
84                         _Page = requestURI.Substring(contextPath.Length);
85                         
86                         if (_Page.StartsWith("/"))
87                                 _Page = _Page.Substring(1);
88
89                         _Query = req.getQueryString();
90                         //_PathInfo = req.getPathInfo();
91                         _AppVirtualPath = req.getContextPath();
92                         _AppPhysicalPath = J2EEUtils.GetApplicationRealPath(servlet.getServletConfig());
93 #if DEBUG
94                         LogCurrentPageLocation();
95 #endif
96                 }
97
98                 public ServletWorkerRequest (string Page, string Query, ServletOutputStream output)
99                         :this(Page, Query)
100                 {
101 #if DEBUG
102                         Console.WriteLine("Constructor 2 of ServletWorkerRequest!! -->");
103 #endif
104                         //_Page = Page;
105                         ParsePathInfo ();
106
107                         //_Query = Query;
108                         AppDomain current = AppDomain.CurrentDomain;
109                         object o = current.GetData (".appPath");
110                         if (o == null)
111                                 throw new HttpException ("Cannot get .appPath");
112                         _AppPhysicalPath = (string)current.GetData(IAppDomainConfig.WEB_APP_DIR);
113
114                         o = current.GetData (".hostingVirtualPath");
115                         if (o == null)
116                                 throw new HttpException ("Cannot get .hostingVirtualPath");
117                         _AppVirtualPath = CheckAndAddVSlash (o.ToString ());
118
119                         o = current.GetData (".hostingInstallDir");
120                         if (o == null)
121                                 throw new HttpException ("Cannot get .hostingInstallDir");
122                         _AppInstallPath = o.ToString ();
123                         _ServletOutputStream = output;
124
125                         if (_AppPhysicalPath == null)
126                                 throw new HttpException ("Invalid app domain");
127
128                         _HasInstallInfo = true;
129 #if DEBUG
130                         LogCurrentPageLocation();
131 #endif
132                 }
133
134                 public ServletWorkerRequest (string AppVirtualPath,
135                                           string AppPhysicalPath,
136                                           string Page,
137                                           string Query,
138                                           ServletOutputStream output) : this (Page, Query)
139                 {
140 #if DEBUG
141                         Console.WriteLine("Constructor 3 of ServletWorkerRequest!! -->");
142 #endif
143                         if (AppDomain.CurrentDomain.GetData (".appPath") == null)
144                                 throw new HttpException ("Invalid app domain");
145
146                         //_Page = Page;
147                         ParsePathInfo ();
148                         //_Query = Query;
149                         _AppVirtualPath = AppVirtualPath;
150                         _AppPhysicalPath = CheckAndAddSlash (AppPhysicalPath);
151                         _ServletOutputStream = output;
152                         _HasInstallInfo = false;
153 #if DEBUG
154                         LogCurrentPageLocation();
155 #endif
156                 }
157
158                 public ServletWorkerRequest (string Page, string Query)
159                 {
160                         _Page = Page;
161
162                         _Query = Query;
163                         AppDomain current = AppDomain.CurrentDomain;
164                         object o = current.GetData (".appPath");
165                         if (o == null)
166                                 throw new HttpException ("Cannot get .appPath");
167                         _AppPhysicalPath = o.ToString ();
168
169                         o = current.GetData (".hostingVirtualPath");
170                         if (o == null)
171                                 throw new HttpException ("Cannot get .hostingVirtualPath");
172                         _AppVirtualPath = o.ToString ();
173
174                         o = current.GetData (".hostingInstallDir");
175                         if (o == null)
176                                 throw new HttpException ("Cannot get .hostingInstallDir");
177                         _AppInstallPath = o.ToString ();
178
179                         if (_AppPhysicalPath == null)
180                                 throw new HttpException ("Invalid app domain");
181
182                         _HasInstallInfo = true;
183
184                         ExtractPagePathInfo();
185                 }
186
187                 public ServletOutputStream ServletOutputStream
188                 {
189                         get     
190                         {
191                                 return _ServletOutputStream;
192                         }
193                 }
194
195                 public HttpServlet Servlet
196                 {
197                         get {
198                                 return _HttpServlet;
199                         }
200                 }
201                 
202                 public HttpServletRequest ServletRequest
203                 {
204                         get{
205                                 return _HttpServletRequest;
206                         }
207                 }
208
209                 public HttpServletResponse ServletResponse
210                 {
211                         get{
212                                 return _HttpServletResponse;
213                         }
214                 }
215                 
216                 [MonoTODO("Implement security")]
217                 public override string MachineInstallDirectory
218                 {
219                         get {
220                                 if (_HasInstallInfo)
221                                         return _AppInstallPath;
222
223                                 return ICalls.GetMachineInstallDirectory ();
224                         }
225                 }
226
227                 public override string MachineConfigPath
228                 {
229                         get { return ICalls.GetMachineConfigPath (); }
230                 }
231
232                 public override void EndOfRequest ()
233                 {
234                         _ServletOutputStream = null;
235                         _HttpServlet = null;
236                         _HttpServletRequest = null;
237                         _HttpServletResponse = null;
238                         if (_endOfSendCallback != null)
239                                 _endOfSendCallback(this, _endOfSendArgs);
240                 }
241
242                 public override void FlushResponse (bool finalFlush)
243                 {
244                         _ServletOutputStream.flush();
245                         if (finalFlush)
246                                 _ServletOutputStream.close();
247                 }
248
249                 public override string GetAppPath ()
250                 {
251                         return _AppVirtualPath;
252                 }
253
254                 public override string GetAppPathTranslated ()
255                 {
256                         return _AppPhysicalPath;
257                 }
258
259                 public override string GetFilePath ()
260                 {
261                         return CreatePath (false);
262                 }
263
264                 public override string GetFilePathTranslated ()
265                 {
266                         string page = _Page;
267
268                         if (Path.DirectorySeparatorChar != '/')
269                                 page = _Page.Replace ('/', Path.DirectorySeparatorChar);
270
271                         if (page [0] == Path.DirectorySeparatorChar)
272                                 page = page.Substring (1);
273                         
274                         return (Path.Combine (_AppPhysicalPath, page));
275                 }
276
277                 public override string GetHttpVerbName ()
278                 {
279                         return _HttpServletRequest.getMethod();
280                 }
281
282                 public override string GetHttpVersion ()
283                 {
284                         return _HttpServletRequest.getProtocol();
285                 }
286
287                 public override string GetLocalAddress ()
288                 {
289                         return _HttpServletRequest.getServerName();
290                 }
291
292                 public override int GetLocalPort ()
293                 {
294                         return _HttpServletRequest.getServerPort();
295                 }
296
297                 public override string GetPathInfo ()
298                 {
299                         return (null != _PathInfo) ? _PathInfo : String.Empty;
300                 }
301
302                 public override string GetQueryString ()
303                 {
304                         return _Query;
305                 }
306
307                 public override string GetRawUrl ()
308                 {
309                         string path = CreatePath (true);
310                         if (null != _Query && _Query.Length > 0)
311                                 return path + "?" + _Query;
312
313                         return path;
314                 }
315
316                 public override string GetRemoteAddress()
317                 {
318                         return _HttpServletRequest.getRemoteAddr();
319                 }
320
321                 public override int GetRemotePort()
322                 {
323                         try
324                         {
325                                 return _HttpServletRequest.getRemotePort();
326                         }
327                         catch(Exception e) //should catch also java.lang.Throwable
328                         {
329                                 //if servlet API is 2.3 and below - there is no
330                                 //method getRemotePort in ServletRequest interface...
331                                 //should be described as limitation.
332                                 return 0;
333                         }
334                 }
335
336                 public override string GetServerVariable(string name)
337                 {
338                         return String.Empty;
339                 }
340
341                 public override string GetUriPath()
342                 {
343                         return CreatePath (true);
344                 }
345
346                 public override IntPtr GetUserToken()
347                 {
348                         return IntPtr.Zero;
349                 }
350
351                 public override string MapPath (string path)
352                 {
353                         if (path.StartsWith(_AppVirtualPath))
354                         {
355                                 path = path.Remove(0,_AppVirtualPath.Length);
356                                 if (path.StartsWith("/"))
357                                         path = path.Remove(0,1);
358                         }
359                         //string realPath = Servlet.getServletContext().getRealPath(path);
360 //                      if (Path.IsPathRooted(path))
361 //                              return path;
362 //                      if (!path.StartsWith(IAppDomainConfig.WAR_ROOT_SYMBOL)&& 
363 //                              !path.StartsWith("/") && !path.StartsWith("\\")&& !Path.IsPathRooted(path))            
364 //                              return IAppDomainConfig.WAR_ROOT_SYMBOL + "/" + path;
365 //                      else if (!path.StartsWith(IAppDomainConfig.WAR_ROOT_SYMBOL)&& !Path.IsPathRooted(path))
366 //                              return IAppDomainConfig.WAR_ROOT_SYMBOL + path;
367 //                      else 
368 //                              return path;
369
370                         if (path.StartsWith(IAppDomainConfig.WAR_ROOT_SYMBOL))
371                         {
372                                 return path;
373                         }
374
375                         string retVal =  IAppDomainConfig.WAR_ROOT_SYMBOL;
376
377                         if (!path.StartsWith("/") && !path.StartsWith("\\"))
378                                 retVal += "/";
379
380                         retVal += path;
381
382                         return retVal;
383                 }
384
385                 public override void SendResponseFromFile (IntPtr handle, long offset, long length)
386                 {
387                 }
388
389                 public override void SendResponseFromFile (string filename, long offset, long length)
390                 {
391                         using (FileStream fs = File.OpenRead (filename)) {
392                                 byte [] buffer = new byte [4 * 1024];
393
394                                 if (offset != 0)
395                                         fs.Position = offset;
396
397                                 long remain = length;
398                                 int n;
399                                 while (remain > 0 && (n = fs.Read (buffer, 0, (int) Math.Min (remain, buffer.Length))) != 0){
400                                         remain -= n;
401                                         SendResponseFromMemory(buffer, n);
402                                 }
403                         }
404                 }
405
406                 public override void SendResponseFromMemory (byte [] data, int length)
407                 {
408                         sbyte [] sdata = vmw.common.TypeUtils.ToSByteArray(data);
409                         _ServletOutputStream.write(sdata, 0 , length);
410                 }
411
412                 public override void SendStatus(int statusCode, string statusDescription)
413                 {
414                         _HttpServletResponse.setStatus(statusCode, statusDescription);
415                 }
416
417                 public override void SendUnknownResponseHeader(string name, string value)
418                 {
419                         _HttpServletResponse.addHeader(name, value);
420                 }
421
422                 public override bool HeadersSent ()
423                 {
424                         return false;
425                 }
426
427                 public override void SendCalculatedContentLength (int contentLength)
428                 {
429                         //FIXME: Should we ignore this for apache2?
430                         SendUnknownResponseHeader ("Content-Length", contentLength.ToString ());
431                 }
432
433                 public override void SendKnownResponseHeader (int index, string value)
434                 {
435                         if (HeadersSent ())
436                                 return;
437
438                         string headerName = HttpWorkerRequest.GetKnownResponseHeaderName (index);
439                         SendUnknownResponseHeader (headerName, value);
440                 }
441                 
442                 // Create's a path string
443                 private string CheckAndAddSlash(string sPath)
444                 {
445                         if (null == sPath)
446                                 return null;
447
448                         if (String.Empty == sPath)
449                                 return SLASH;
450                                 
451                         if (!sPath.EndsWith ("" + Path.DirectorySeparatorChar))
452                                 return sPath + Path.DirectorySeparatorChar;
453
454                         return sPath;
455                 }
456
457                 // Creates a path string
458                 private string CheckAndAddVSlash(string sPath)
459                 {
460                         if (null == sPath)
461                                 return null;
462
463                         if (!sPath.EndsWith ("/"))
464                                 return sPath + "/";
465
466                         return sPath;
467                 }
468
469                 // Create's a path string
470                 private string CreatePath (bool bIncludePathInfo)
471                 {
472                         string sPath = Path.Combine (_AppVirtualPath, _Page);
473
474                         if (bIncludePathInfo && null != _PathInfo)
475                         {
476                                 sPath += _PathInfo;
477                         }
478
479                         return sPath;
480                 }
481
482                 //  "The extra path information, as given by the client. In
483                 //  other words, scripts can be accessed by their virtual
484                 //  pathname, followed by extra information at the end of this
485                 //  path. The extra information is sent as PATH_INFO."
486                 private void ExtractPagePathInfo ()
487                 {
488                         if (_Page == null || _Page == String.Empty)
489                                 return;
490
491                         string FullPath = GetFilePathTranslated ();
492                         int PathInfoLength = 0;
493                         string LastFile = String.Empty;
494
495                         while (PathInfoLength < _Page.Length) {
496                                 if (LastFile.Length > 0) {
497                                         // increase it by the length of the file plus 
498                                         // a "/"
499                                         //
500                                         PathInfoLength += LastFile.Length + 1;
501                                 }
502
503                                 if (File.Exists (FullPath) == true)
504                                         break;
505
506                                 if (Directory.Exists (FullPath) == true) {
507                                         PathInfoLength -= (LastFile.Length + 1);
508                                         break;
509                                 }
510
511                                 LastFile = Path.GetFileName (FullPath);
512                                 FullPath = Path.GetDirectoryName (FullPath);
513                         }
514
515                         if (PathInfoLength <= 0 || PathInfoLength > _Page.Length)
516                                 return;
517
518                         _PathInfo = _Page.Substring (_Page.Length - PathInfoLength);
519                         _Page = _Page.Substring (0, _Page.Length - PathInfoLength);
520                 }
521                 
522                 // Parses out the string after / known as the "path info"
523                 private void ParsePathInfo ()
524                 {
525                         int iPos = _Page.LastIndexOf("/");
526                         if (iPos >= 0) {
527                                 _PathInfo = _Page.Substring (iPos);
528                                 _Page = _Page.Substring (0, iPos);
529                         }
530                 }
531
532                 public override string GetKnownRequestHeader (int index)
533                 {
534                         if (_HttpServletRequest == null)
535                                 return null;
536
537                         string headerName = HttpWorkerRequest.GetKnownRequestHeaderName (index);
538                         
539                         return _HttpServletRequest.getHeader(headerName);
540                 }
541
542                 public override string GetUnknownRequestHeader (string name)
543                 {
544                         if (_HttpServletRequest == null)
545                                 return null;
546
547                         return _HttpServletRequest.getHeader(name);
548                 }
549
550                 public override string [][] GetUnknownRequestHeaders ()
551                 {
552                         if (unknownHeaders == null) {
553                                 ArrayList pairs = new ArrayList ();
554                                 for (java.util.Enumeration he = _HttpServletRequest.getHeaderNames(); he.hasMoreElements() ;) {
555                                         string key = (string) he.nextElement();
556                                         int index = HttpWorkerRequest.GetKnownRequestHeaderIndex (key);
557                                         if (index != -1)
558                                                 continue;
559                                         pairs.Add (new string [] {key, _HttpServletRequest.getHeader(key)});
560                                 }
561                                 
562                                 if (pairs.Count != 0) {
563                                         unknownHeaders = new string [pairs.Count][];
564                                         for (int i = 0; i < pairs.Count; i++)
565                                                 unknownHeaders [i] = (string []) pairs [i];
566                                 }
567                         }
568                         if (unknownHeaders == null) unknownHeaders = new string [0][];
569
570                         return unknownHeaders;
571                 }
572
573                 public override int ReadEntityBody (byte [] buffer, int size)
574                 {
575                         if (buffer == null || size == 0)
576                                 return 0;
577                         sbyte [] sbuffer = new sbyte [size];
578                         int r = _HttpServletRequest.getInputStream().read(sbuffer, 0, size);
579                         for (int i=0; i < r; i++) buffer[i] = (byte) sbuffer[i];                        
580                         return (r==-1)?0:r;
581                 }
582
583                 public override void SetEndOfSendNotification(System.Web.HttpWorkerRequest.EndOfSendNotification callback, object extraData)
584                 {
585                         _endOfSendCallback = callback;
586                         _endOfSendArgs = extraData;
587                 }
588                 
589                 // Prints some stats about the current _Page.
590                 private void LogCurrentPageLocation()
591                 {
592 #if DEBUG
593                         Console.WriteLine(" relpath=" + _AppVirtualPath);
594                         Console.WriteLine(" physical path=" + _AppPhysicalPath);
595                         Console.WriteLine(" page=" + _Page);
596 #endif
597                 }
598                 
599         }
600 }
601