fix GetFilePath.
[mono.git] / mcs / class / Mainsoft.Web / Mainsoft.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 System.Web.J2EE;
31 using System.Collections;
32 using System.Web;
33 using javax.servlet;
34 using javax.servlet.http;
35 using System.Collections.Specialized;
36 using System.Globalization;
37 using System.Web.Hosting;
38 using vmw.common;
39 using InputStream=java.io.InputStream;
40 using java.security;
41
42 namespace Mainsoft.Web.Hosting {
43         [MonoTODO("Implement security demands on the path usage functions (and review)")]
44         [ComVisible (false)]
45         public abstract class BaseWorkerRequest : HttpWorkerRequest, IServiceProvider {
46                 OutputStreamWrapper _OutputStream;
47
48                 readonly string _contextPath;
49                 readonly string _requestUri;
50                 readonly string _pathInfo;
51
52                 static readonly StringDictionary _srvVarsToHeaderMap;
53
54                 private string [][] unknownHeaders;
55                 string _rawUrl;
56
57                 private HttpWorkerRequest.EndOfSendNotification _endOfSendCallback;
58                 private object _endOfSendArgs;
59
60                 enum KnownServerVariable {
61                         AUTH_TYPE,
62                         CONTENT_LENGTH,
63                         CONTENT_TYPE,
64                         QUERY_STRING,
65                         REMOTE_ADDR,
66                         REMOTE_HOST,
67                         REMOTE_USER,
68                         REQUEST_METHOD,
69                         REQUEST_URI,
70                         SCRIPT_NAME,
71                         SERVER_NAME,
72                         SERVER_PORT,
73                         SERVER_PROTOCOL,
74                         SERVER_SOFTWARE,
75                         PATH_INFO
76                 };
77
78                 static readonly Hashtable KnownServerVariableMap;
79
80                 static BaseWorkerRequest() {
81                         _srvVarsToHeaderMap = new StringDictionary();
82                         _srvVarsToHeaderMap.Add("HTTP_ACCEPT", "Accept");
83                         _srvVarsToHeaderMap.Add("HTTP_REFERER", "Referer");
84                         _srvVarsToHeaderMap.Add("HTTP_ACCEPT_LANGUAGE", "Accept-Language");
85                         _srvVarsToHeaderMap.Add("HTTP_ACCEPT_ENCODING", "Accept-Encoding");
86                         _srvVarsToHeaderMap.Add("HTTP_CONNECTION", "Connection");
87                         _srvVarsToHeaderMap.Add("HTTP_HOST", "Host");
88                         _srvVarsToHeaderMap.Add("HTTP_USER_AGENT", "User-Agent");
89                         _srvVarsToHeaderMap.Add("HTTP_SOAPACTION", "SOAPAction");
90
91                         string[] knownServerVariableNames = Enum.GetNames(typeof(KnownServerVariable));
92                         KnownServerVariableMap = CollectionsUtil.CreateCaseInsensitiveHashtable(knownServerVariableNames.Length);
93                         for (int i = 0; i < knownServerVariableNames.Length; i++)
94                                 KnownServerVariableMap[knownServerVariableNames[i]] = (KnownServerVariable)i;
95                 }
96
97                 public BaseWorkerRequest (string contextPath, string servletPath, string requestURI) {
98
99
100                         _contextPath = contextPath;
101
102                         //string contextPath = req.getContextPath();
103                         //string servletPath = req.getServletPath ();
104                         //string requestURI = req.getRequestURI ();
105                         // servletPath - Returns the part of this request's URL that calls the servlet.
106                         //              so it contains default page.
107                         // requestURI - Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request.
108                         //              so it contains what the user passed.
109                         //
110                         // the one containing more information wins.
111                         if (contextPath.Length + servletPath.Length > requestURI.Length)
112                                 requestURI = contextPath + servletPath;
113                         else { 
114                                 int contextPos = requestURI.IndexOf(contextPath, StringComparison.Ordinal);
115                                 if (contextPos > 0)
116                                         requestURI = requestURI.Substring (contextPos);
117                         }
118
119                         _requestUri = Uri.UnescapeDataString(requestURI);
120                         const int dotInvokeLength = 7; //".invoke".Length
121                         if (_requestUri.Length > dotInvokeLength &&
122                                 String.CompareOrdinal(".invoke", 0, _requestUri, 
123                                 _requestUri.Length - dotInvokeLength, dotInvokeLength) == 0) {
124
125                                 _requestUri = _requestUri.Substring(0, _requestUri.Length - dotInvokeLength);
126                                 
127                                 int paramNameStart = _requestUri.LastIndexOf('/');
128                                 _pathInfo = _requestUri.Substring(paramNameStart, _requestUri.Length - paramNameStart);
129                         }
130
131                         const int aspnetconfigLength = 12; //"aspnetconfig".Length
132                         int endingSlash = _requestUri [_requestUri.Length - 1] == '/' ? 1 : 0;
133                         if (_requestUri.Length > aspnetconfigLength &&
134                                 String.CompareOrdinal ("aspnetconfig", 0, _requestUri,
135                                 _requestUri.Length - aspnetconfigLength - endingSlash, aspnetconfigLength) == 0) {
136
137                                 if (endingSlash == 0)
138                                         _requestUri += "/";
139                                 _requestUri += "Default.aspx";
140                         }
141                 }
142
143                 static readonly Type typeOfWriter = typeof (java.io.Writer);
144                 public virtual object GetService (Type serviceType)
145                 {
146                         if (serviceType == typeOfWriter)
147                                 return CreateOutputStream (false);
148                         return null;
149                 }
150                 
151                 [MonoTODO("Implement security")]
152                 public override string MachineInstallDirectory {
153                         get {
154                                 return ".";
155                         }
156                 }
157
158                 public override string MachineConfigPath {
159                         get { return "."; }
160                 }
161
162                 public override void EndOfRequest () {
163                         if (_endOfSendCallback != null)
164                                 _endOfSendCallback(this, _endOfSendArgs);
165                         _OutputStream = null;
166                 }
167
168                 public override void FlushResponse (bool finalFlush) {
169                         //kostat
170                         //IPortletActionResponse resp =_HttpServletResponse as IPortletActionResponse;
171                         //if (_OutputStream == null || resp != null && resp.isRedirected())
172                         //      return;
173                         if (_OutputStream == null)
174                                 return;
175
176                         _OutputStream.flush();
177                         if (finalFlush)
178                                 _OutputStream.close();
179                 }
180
181                 public override string GetAppPath () {
182                         return _contextPath;
183                 }
184
185                 public override string GetFilePath () {
186                         string uri = GetUriPath();
187                         string pathInfo = GetPathInfo();
188                         if (pathInfo != null && pathInfo.Length > 0)
189                                 uri = uri.Substring (0, uri.Length - pathInfo.Length);
190
191                         return uri;
192                 }
193
194                 public override string GetFilePathTranslated () {
195                         string page = GetFilePath ();
196
197                         if (Path.DirectorySeparatorChar != '/')
198                                 page = page.Replace ('/', Path.DirectorySeparatorChar);
199
200                         if (page [0] == Path.DirectorySeparatorChar)
201                                 page = page.Substring (1);
202                         
203                         return Path.Combine (GetAppPathTranslated (), page);
204                 }
205
206                 public override string GetPathInfo () {
207                         return _pathInfo;
208                 }               
209
210                 public override string GetRawUrl () {
211                         if (_rawUrl == null) {
212                                 StringBuilder builder = new StringBuilder();
213                                 builder.Append(GetUriPath());
214                                 string pathInfo = GetPathInfo();
215                                 string query = GetQueryString();
216                                 if (query != null && query.Length > 0) {
217                                         builder.Append('?');
218                                         builder.Append(query);
219                                 }
220
221                                 _rawUrl = builder.ToString();
222                         }
223
224                         return _rawUrl;
225                 }
226
227                 public override string GetServerVariable(string name) {
228                         // FIXME: We need to make a proper mapping between the standard server
229                         // variables and java equivalent. probably we have to have a configuration file 
230                         // which associates between the two. Pay a special attention on GetUnknownRequestHeader/s
231                         // while implementing. Ensure that system web "common" code correctly calls each method.
232
233                         string headerName = _srvVarsToHeaderMap[name];
234
235                         if (headerName != null)
236                                 return getHeader( headerName );
237
238                         object knownVariable = KnownServerVariableMap[name];
239                         if (knownVariable != null)
240                                 return GetKnownServerVariable((KnownServerVariable)knownVariable);
241
242                         return getHeader( name );
243                 }
244
245                 public abstract string GetAuthType ();
246                 protected abstract int getContentLength ();
247                 protected abstract string getContentType ();
248                 public abstract string GetRemoteUser ();
249                 protected abstract string getHeader (string name);
250                 protected abstract java.util.Enumeration getHeaderNames ();
251                 protected abstract InputStream getInputStream ();
252                 public abstract ServletContext GetContext ();
253                 protected abstract OutputStreamWrapper CreateOutputStream (bool binary);
254
255                 public abstract HttpSession GetSession (bool create);
256                 public abstract bool IsRequestedSessionIdValid ();
257                 public abstract string GetRequestedSessionId ();
258                 public abstract bool IsUserInRole (string name);
259                 public abstract Principal GetUserPrincipal ();
260
261                 string GetKnownServerVariable(KnownServerVariable index) {
262                         switch (index) {
263                                 case KnownServerVariable.AUTH_TYPE : return GetAuthType();
264                                 case KnownServerVariable.CONTENT_LENGTH : return Convert.ToString(getContentLength());
265                                 case KnownServerVariable.CONTENT_TYPE : return getContentType();
266                                 case KnownServerVariable.QUERY_STRING : return GetQueryString();
267                                 case KnownServerVariable.REMOTE_ADDR : return GetRemoteAddress();
268                                 case KnownServerVariable.REMOTE_HOST : return GetRemoteName();
269                                 case KnownServerVariable.REMOTE_USER : return GetRemoteUser();
270                                 case KnownServerVariable.REQUEST_METHOD : return GetHttpVerbName ();
271                                 case KnownServerVariable.REQUEST_URI : return GetUriPath();
272                                 case KnownServerVariable.SCRIPT_NAME : return GetFilePath ();
273                                 case KnownServerVariable.SERVER_NAME : return GetServerName();
274                                 case KnownServerVariable.SERVER_PORT : return Convert.ToString(GetLocalPort());
275                                 case KnownServerVariable.SERVER_PROTOCOL : return GetHttpVersion ();
276                                 case KnownServerVariable.SERVER_SOFTWARE : return GetContext().getServerInfo();
277                                 case KnownServerVariable.PATH_INFO : return GetPathInfo();
278                                 default: throw new IndexOutOfRangeException("index");
279                         }
280                 }
281
282                 public override string GetUriPath() {
283                         return _requestUri;
284                 }
285
286                 public override IntPtr GetUserToken() {
287                         return IntPtr.Zero;
288                 }
289
290                 public override string GetAppPathTranslated () {
291                         return J2EEUtils.GetApplicationRealPath (GetContext ());
292                 }
293
294                 public override string MapPath (string virtualPath) {
295                         if (virtualPath == null)
296                                 throw new ArgumentNullException ("virtualPath");
297
298                         ServletContext context = GetContext ();
299
300                         string contextPath = GetAppPath ();
301                         if ((virtualPath.Length > contextPath.Length && virtualPath [contextPath.Length] != '/') ||
302                                 string.Compare (contextPath, 0, virtualPath, 0, contextPath.Length, StringComparison.OrdinalIgnoreCase) != 0) {
303
304                                 for (int appVirtualPathIndex = 0; appVirtualPathIndex > 0 && virtualPath.Length > appVirtualPathIndex; ) {
305                                         appVirtualPathIndex = virtualPath.IndexOf ('/', appVirtualPathIndex + 1);
306                                         string crossContextPath = appVirtualPathIndex > 0 ?
307                                                 virtualPath.Remove (appVirtualPathIndex) : virtualPath;
308                                         ServletContext other = context.getContext (crossContextPath);
309                                         if (other != null) {
310                                                 string appVirtualPath = appVirtualPathIndex > 0 ?
311                                                         virtualPath.Substring (appVirtualPathIndex) : String.Empty;
312                                                 return other.getRealPath (appVirtualPath);
313                                         }
314                                 }
315
316                                 throw new HttpException (
317                                         String.Format ("MapPath: Mapping across applications is not allowed. ApplicationPath is '{0}', VirtualPath is '{1}'.",
318                                         contextPath, virtualPath));
319                         }
320
321                         string thisAppVirtualPath = virtualPath.Length > contextPath.Length ? virtualPath.Substring (contextPath.Length) : String.Empty;
322                         return J2EEUtils.GetApplicationRealPath (context, thisAppVirtualPath);
323
324                 }
325
326                 public override void SendResponseFromFile (IntPtr handle, long offset, long length) {
327                         throw new NotSupportedException();
328                 }
329
330                 public override void SendResponseFromFile (string filename, long offset, long length) {
331                         using (FileStream fs = File.OpenRead (filename)) {
332                                 byte [] buffer = new byte [4 * 1024];
333
334                                 if (offset != 0)
335                                         fs.Position = offset;
336
337                                 long remain = length;
338                                 int n;
339                                 while (remain > 0 && (n = fs.Read (buffer, 0, (int) Math.Min (remain, buffer.Length))) != 0){
340                                         remain -= n;
341                                         SendResponseFromMemory(buffer, n);
342                                 }
343                         }
344                 }
345
346                 //kostat
347                 //private OutputStreamWrapper CreateOutputStream (bool binary)
348                 //{
349                 //    IPortletActionResponse resp = _HttpServletResponse as IPortletActionResponse;
350                 //    if (resp != null)
351                 //        return null; // no output stream while processAction
352
353                 //    if (_OutputStream != null)
354                 //        return _OutputStream;
355
356                 //    if (_HttpServletResponse != null) {
357                 //        if (binary)
358                 //            _OutputStream = new OutputStreamWrapper (_HttpServletResponse.getOutputStream ());
359                 //        else
360                 //            _OutputStream = new OutputStreamWrapper (_HttpServletResponse.getWriter ());
361                 //    }
362
363                 //    return _OutputStream;
364                 //}
365
366                 public override void SendResponseFromMemory (byte [] data, int length) {
367                         _OutputStream = CreateOutputStream (true);
368
369                         if (_OutputStream == null)
370                                 return;
371
372                         sbyte [] sdata = vmw.common.TypeUtils.ToSByteArray(data);
373                         _OutputStream.write(sdata, 0 , length);
374                 }
375
376                 public override void SendKnownResponseHeader (int index, string value) {
377                         SendUnknownResponseHeader (GetKnownResponseHeaderName (index), value);
378                 }
379
380                 public override string GetKnownRequestHeader (int index) {      
381                         return GetUnknownRequestHeader(GetKnownRequestHeaderName (index));
382                 }
383
384                 public override string GetUnknownRequestHeader (string name) {
385                         return getHeader(name);
386                 }
387
388                 public override string [][] GetUnknownRequestHeaders () {
389                         if (unknownHeaders == null) {
390                                 ArrayList pairs = new ArrayList ();
391                                 for (java.util.Enumeration he = getHeaderNames(); he.hasMoreElements() ;) {
392                                         string key = (string) he.nextElement();
393                                         int index = HttpWorkerRequest.GetKnownRequestHeaderIndex (key);
394                                         if (index != -1)
395                                                 continue;
396                                         pairs.Add (new string [] {key, getHeader(key)});
397                                 }
398                                 
399                                 if (pairs.Count != 0) {
400                                         unknownHeaders = new string [pairs.Count][];
401                                         for (int i = 0; i < pairs.Count; i++)
402                                                 unknownHeaders [i] = (string []) pairs [i];
403                                 }
404                         }
405                         if (unknownHeaders == null) unknownHeaders = new string [0][];
406
407                         return unknownHeaders;
408                 }
409
410                 public override int ReadEntityBody (byte [] buffer, int size) {
411                         if (buffer == null || size == 0)
412                                 return 0;
413                         sbyte [] sbuffer = vmw.common.TypeUtils.ToSByteArray(buffer);
414                         InputStream inp = getInputStream();
415                         if (inp == null)
416                                 return 0;
417                         int r = inp.read (sbuffer, 0, size);
418                         return r < 0 ? 0 : r;
419                 }
420
421                 public override void SetEndOfSendNotification(System.Web.HttpWorkerRequest.EndOfSendNotification callback, object extraData) {
422                         _endOfSendCallback = callback;
423                         _endOfSendArgs = extraData;
424                 }
425
426                 public abstract BaseHttpContext CreateContext (HttpContext context);
427         }
428 }
429