WebServerConnection.java

00001 /*
00002  * OpenMobileIS - a free Java(TM) Framework for mobile applications Java(TM)
00003  * Copyright (C) 2004-2006 Philippe Delrieu
00004  * All rights reserved.
00005  * Contact: pdelrieu@openmobileis.org
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00020  * USA
00021  *
00022  *  Author : Philippe Delrieu
00023  *  
00024  *  Modifications :
00025  *  2004 Creation P.Delrieu
00026  *  2004 Modified by Romain Beaugrand
00027  * 
00028  */
00029 
00030 package org.openmobileis.embedded.webserver;
00031 
00032 import java.io.BufferedReader;
00033 import java.io.IOException;
00034 import java.io.InputStreamReader;
00035 import java.io.OutputStreamWriter;
00036 import java.io.PrintWriter;
00037 import java.io.UnsupportedEncodingException;
00038 import java.net.InetAddress;
00039 import java.net.Socket;
00040 import java.security.Principal;
00041 import java.text.SimpleDateFormat;
00042 import java.util.Date;
00043 import java.util.Enumeration;
00044 import java.util.Hashtable;
00045 import java.util.Locale;
00046 import java.util.StringTokenizer;
00047 import java.util.Vector;
00048 
00049 import javax.servlet.RequestDispatcher;
00050 import javax.servlet.ServletException;
00051 import javax.servlet.ServletInputStream;
00052 import javax.servlet.ServletOutputStream;
00053 import javax.servlet.ServletRequest;
00054 import javax.servlet.ServletResponse;
00055 import javax.servlet.SingleThreadModel;
00056 import javax.servlet.http.Cookie;
00057 import javax.servlet.http.HttpServlet;
00058 import javax.servlet.http.HttpServletRequest;
00059 import javax.servlet.http.HttpServletResponse;
00060 import javax.servlet.http.HttpSession;
00061 import javax.servlet.http.HttpUtils;
00062 
00063 import org.openmobileis.common.context.SessionContext;
00064 import org.openmobileis.common.context.SessionContextManager;
00065 import org.openmobileis.common.util.log.LogManager;
00066 import org.openmobileis.common.util.log.LogServices;
00067 
00068 
00069 public class WebServerConnection implements HttpServletRequest, HttpServletResponse {
00070 
00071     public final static String WWWFORMURLENCODE = "application/x-www-form-urlencoded";
00072     public final static String TRANSFERENCODING = "Transfer-Encoding";
00073     public final static String CHUNKED = "chunked";
00074     public final static String CONTENTLENGTH = "Content-Length";
00075     public final static String CONTENTTYPE = "Content-Type";
00076 
00077     private Socket socket;
00078     private WebServer webserver;
00079 
00080     private String reqMethod; // == null by default
00081 
00082     private String reqUriPath;
00083 
00084     private boolean oneOne; // HTTP/1.1 or better
00085 
00086     String reqQuery = null;
00087 
00088     private Vector reqHeaderNames = new Vector();
00089     private Vector reqHeaderValues = new Vector();
00090     private Locale locale; // = java.util.Locale.getDefault();
00091 
00092     private int uriLen;
00093     private static final Hashtable EMPTYHASHTABLE = new Hashtable();
00094 
00095     protected long connexionLifeTime = 0;
00096 
00097     private ServletInputStream in;
00098 
00099     private ServletOutputStream out;
00100 
00101     private boolean reqMime;
00102 
00103     private String reqProtocol;
00104     private String reqCharEncoding;
00105 
00106     private Hashtable formParameters;
00107 
00108     private Hashtable attributes = new Hashtable();
00109 
00110     private int resCode = -1;
00111 
00112     private String resMessage = null;
00113 
00114     private Hashtable resHeaderNames = new Hashtable();
00115 
00116     private boolean headersWritten = false;
00117 
00118     protected static final SimpleDateFormat expdatefmt = new SimpleDateFormat(
00119             "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'");
00120 
00121     protected static final SimpleDateFormat headerdateformat = new SimpleDateFormat(
00122             "EEE, dd MMM yyyy HH:mm:ss z");
00123     
00124     private PrintWriter printWriter = null;
00125     
00126     public void init(WebServer webserver, Socket socket)        {
00127     // Save arguments.
00128     this.webserver = webserver;
00129     this.socket = socket;
00130     out = null;
00131     in = null;
00132     oneOne = false;
00133     reqMethod = null;
00134     reqUriPath = null;
00135     reqQuery = null;
00136     reqProtocol = null;
00137     reqCharEncoding = null;
00138     reqHeaderNames = new Vector();
00139     reqHeaderValues = new Vector();
00140     formParameters = null;
00141     attributes = new Hashtable();
00142     locale = null;
00143     uriLen = -1;
00144     resCode = -1;
00145     connexionLifeTime = 0;
00146     reqMime = false;
00147     resMessage = "";
00148     resHeaderNames = new Hashtable();
00149     headersWritten = false;
00150     printWriter = null;
00151   }
00152 
00153     // Methods from Runnable.
00154     public void run() {
00155       SessionContextManager.getManager().joinSessionContext("OPENMOBILEISSESSION");
00156         try {
00157             // Get the streams.
00158             in = new ServeInputStream(socket.getInputStream());
00159             out = new ServeOutputStream(socket.getOutputStream(), this);
00160         } catch (IOException e) {
00161             problem("Getting streams: " + e.getMessage(), SC_BAD_REQUEST);
00162             LogManager.traceError(0, e);
00163             try {
00164                 socket.close();
00165             } catch (Exception ex){}
00166             return;
00167         }
00168 
00169         // parse the request
00170         parseRequest();
00171 
00172  //       LogManager.traceDebug(LogServices.WEBSERVICE, socket.getInetAddress().toString()
00173  //              + ' ' + reqMethod + ' ' + reqUriPath + ' ' + resCode
00174         /*
00175          * + (serve.isShowReferer() ? "| " + getHeader("Referer") : "") +
00176          * (serve.isShowUserAgent() ? "| " + getHeader("User-Agent") : "")
00177          */
00178  //       );
00179 
00180         try {
00181             this.execURI(this.reqUriPath);
00182         } catch (Exception e) {
00183             problem("Getting streams: " + e.getMessage(), SC_BAD_REQUEST);
00184             LogManager.traceError(0, e);
00185         } finally {
00186             try {
00187                 //socket.getOutputStream().write(byteOut.toByteArray());
00188                 socket.close();
00189             } catch (IOException e) {
00190                 org.openmobileis.common.util.log.LogManager
00191                         .traceError(
00192                                 org.openmobileis.common.util.log.LogServices.WEBSERVICE,
00193                                 "Impossible to close socket : WebServerConnection");
00194                 org.openmobileis.common.util.log.LogManager
00195                         .traceError(
00196                                 org.openmobileis.common.util.log.LogServices.WEBSERVICE,
00197                                 e);
00198             }
00199         }
00200     }
00201 
00202     private void parseRequest() {
00203         byte[] lineBytes = new byte[4096];
00204         int len;
00205         String line;
00206 
00207         try {
00208             // Read the first line of the request.
00209             len = in.readLine(lineBytes, 0, lineBytes.length);
00210             if (len == -1 || len == 0) {
00211                 problem("Empty request", SC_BAD_REQUEST);
00212                 return;
00213             }
00214             line = new String(lineBytes, 0, len);
00215             StringTokenizer ust = new StringTokenizer(line);
00216             reqProtocol = null;
00217             if (ust.hasMoreTokens()) {
00218                 reqMethod = ust.nextToken();
00219                 if (ust.hasMoreTokens()) {
00220                     reqUriPath = Acme.Utils.urlDecoder(ust.nextToken());
00221                     if (ust.hasMoreTokens()) {
00222                         reqProtocol = ust.nextToken();
00223                         oneOne = !reqProtocol.toUpperCase().equals("HTTP/1.0");
00224                         reqMime = true;
00225                         // Read the rest of the lines.
00226                         String s;
00227                         while ((s = ((ServeInputStream) in).readLine()) != null) {
00228                             if (s.length() == 0)
00229                                 break;
00230 
00231                             int c = s.indexOf(':', 0);
00232                             if (c > 0) {
00233                                 String key = s.substring(0, c).trim();
00234                                 String value = s.substring(c + 1, s.length())
00235                                         .trim();
00236                                 reqHeaderNames.addElement(key.toLowerCase());
00237                                 reqHeaderValues.addElement(value);
00238                             } else {
00239                                 LogManager.traceError(LogServices.WEBSERVICE, "header field without ':'");
00240                             }
00241                         }
00242                     } else {
00243                         reqProtocol = "HTTP/0.9";
00244                         oneOne = false;
00245                         reqMime = false;
00246                     }
00247                 }
00248             }
00249             if (reqProtocol == null) {
00250                 problem("Malformed request line", SC_BAD_REQUEST);
00251                 return;
00252             }
00253             // Check Host: header in HTTP/1.1 requests.
00254             if (oneOne) {
00255                 String host = getHeader("host");
00256                 if (host == null) {
00257                     problem("Host header missing on HTTP/1.1 request",
00258                             SC_BAD_REQUEST);
00259                     return;
00260                 }
00261             }
00262 
00263             // Decode %-sequences.
00264             //reqUriPath = decode( reqUriPath );
00265             // Split off query string, if any.
00266             int qmark = reqUriPath.indexOf('?');
00267             if (qmark > -1) {
00268                 reqQuery = reqUriPath.substring(qmark + 1);
00269                 reqUriPath = reqUriPath.substring(0, qmark);
00270             }
00271             if (CHUNKED.equals(getHeader(TRANSFERENCODING))) {
00272                 setHeader(CONTENTLENGTH, null);
00273                 ((ServeInputStream) in).chunking(true);
00274             }
00275 
00276         } catch (IOException e) {
00277             problem("Reading request: " + e.getMessage(), SC_BAD_REQUEST);
00278         }
00279     }
00280 
00281     private void execURI(String URI) throws ServletException {
00282         //manage /index for index servlet
00283         if (URI.equals("/index")) {
00284             URI = "/services/index";
00285             reqUriPath = URI;
00286         }
00287         Object[] os = webserver.getServletByURLorClassName(URI);
00288         if (os[0] == null) {
00289             os = webserver.getServletByURLorClassName("defaultServlet");
00290             if (os[0] == null) {
00291                 throw new ServletException(
00292                         "WebServerConnection::execUri Unable to find file servlet");
00293             }
00294             //uriLen = ((Integer) os[1]).intValue();
00295             uriLen = 0;
00296             runServlet((HttpServlet) os[0]);
00297         } else {
00298             uriLen = ((Integer) os[1]).intValue();
00299             runServlet((HttpServlet) os[0]);
00300         }
00301     }
00302 
00304     // output stream.
00305     // @exception IOException if an I/O error has occurred
00306     void writeHeaders() throws IOException {
00307         synchronized (this) {
00308             if (headersWritten)
00309                 return;
00310 
00311             headersWritten = true;
00312         }
00313         if (reqMime) {
00314             //boolean chunked_out = false;
00315             out.println(reqProtocol + " " + resCode + " " + resMessage);
00316 
00317             Enumeration he = resHeaderNames.keys();
00318             while (he.hasMoreElements()) {
00319                 String name = (String) he.nextElement();
00320                 Object o = resHeaderNames.get(name);
00321                 if (o instanceof String) {
00322                     String value = (String) o;
00323                     if (value != null) // just in case
00324                         out.println(name + ": " + value);
00325                     /*
00326                      * moved to servlet if (TRANSFERENCODING.equals(name) &&
00327                      * CHUNKED.equals(value)) chunked_out = true;
00328                      */
00329                 } else if (o instanceof String[]) {
00330                     String[] values = (String[]) o;
00331                     out.println(name + ": " + values[0]);
00332                     for (int i = 0; i < values.length; i++)
00333                         out.print("," + values[i]);
00334                     out.println();
00335                 }
00336             }
00337             //add specific header to remove page from cache
00338             out.println("Pragma: no-cache");
00339                         out.println("Cache-Control: no-cache, must-revalidate");
00340                         out.println("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
00341                         out.println("Date: Mon, 26 Jul 1997 05:00:00 GMT");
00342                         
00343                         out.println("Last-Modified: Mon, 26 Jul 1997 05:00:00 GMT");
00344                         out.println("Connection: close" );
00345             // Marks the beginning of body-content.
00346             out.println();
00347             out.flush();
00348             //if (chunked_out) ((ServeOutputStream)out).setChunked(true);
00349         }
00350     }
00351 
00352     private void runServlet(HttpServlet servlete) {
00353         // Set default response fields.
00354         setStatus(SC_OK);
00355         /*
00356          * setDateHeader("Date", System.currentTimeMillis());
00357          * setHeader("Server", Serve.Identification.serverName + "/" +
00358          * Serve.Identification.serverVersion); setHeader("MIME-Version",
00359          * "1.0");
00360          */
00361         try {
00362                 authenticate();
00363             if (servlete instanceof SingleThreadModel)
00364                 synchronized (servlete) {
00365                     servlete.service((ServletRequest) this,
00366                             (ServletResponse) this);
00367                 }
00368             else {
00369                 servlete.service((ServletRequest) this, (ServletResponse) this);
00370             }
00371             if (((ServeOutputStream)out).isReturnedAsWriter() && printWriter != null) {
00372                 printWriter.flush();
00373             } else {
00374                 out.flush();
00375             }
00376         } catch (IOException e) {
00377             e.printStackTrace();
00378             problem("IO problem running servlet: " + e.toString(),
00379                     SC_BAD_REQUEST);
00380         } catch (ServletException e) {
00381             e.printStackTrace();
00382             problem("problem running servlet: " + e.toString(), SC_BAD_REQUEST);
00383         } catch (Exception e) {
00384             e.printStackTrace();
00385             problem("unexpected problem running servlet: " + e.toString(),
00386                     SC_INTERNAL_SERVER_ERROR);
00387         }
00388     }
00389     
00390     private boolean authenticate() throws IOException {
00391         // We don't use any authentification
00392         return true;
00393     }
00394     
00395     // send an error page
00396     private void problem(String logMessage, int resCode) {
00397         LogManager.traceError(LogServices.WEBSERVICE, logMessage);
00398         try {
00399           sendError(resCode);
00400         } catch (IllegalStateException e) { /* ignore */
00401         } catch (IOException e) { /* ignore */
00402         }
00403     }
00404 
00405     private Hashtable getParametersFromRequest() {
00406         Hashtable result = null;
00407         //System.out.println("Req:"+reqMethod+" con:"+getContentType()+" eq
00408         // "+WWWFORMURLENCODE.equals(getContentType()));
00409         if ("GET".equals(reqMethod)) {
00410             if (reqQuery != null)
00411                 try {
00412                     result = HttpUtils.parseQueryString(reqQuery);
00413                 } catch (IllegalArgumentException ex) {
00414                 }
00415         } else if ("POST".equals(reqMethod))
00416             if (WWWFORMURLENCODE.equals(getContentType()))
00417                 try {
00418                     result = HttpUtils.parsePostData(getContentLength(), getInputStream());
00419                     if (reqQuery != null && reqQuery.length() > 0) {
00420                         Acme.Utils.putAll(result, HttpUtils.parseQueryString(reqQuery));
00421                     }
00422                 } catch (Exception ex) {
00423                     LogManager.traceError(0, ex);
00424                     LogManager.traceError(LogServices.WEBSERVICE, "Exception " + ex + " at parsing post data of length " + getContentLength());
00425                 }
00426             else
00427                 try {
00428                     if (reqQuery != null)
00429                         result = HttpUtils.parseQueryString(reqQuery);
00430                 } catch (Exception ex) {
00431                 }
00432         return result != null ? result : EMPTYHASHTABLE;
00433     }
00434     
00435     private void realSendError() throws IOException {
00436         if (isCommitted())
00437             throw new IllegalStateException(
00438                     "Can not send error, headers have been already written");
00439         synchronized (out) {
00440             // no more out after error
00441             ((ServeOutputStream) out).setReturnedAsStream(true);
00442             ((ServeOutputStream) out).setReturnedAsWriter(true);
00443         }
00444         setContentType("text/html");
00445         StringBuffer sb = new StringBuffer(100);
00446         sb.append("<HTML><HEAD>").append(
00447                 "<TITLE>" + resCode + " " + resMessage + "</TITLE>").append(
00448                 "</HEAD><BODY BGCOLOR=\"#F1D0F2\">").append(
00449                 "<H2>" + resCode + " " + resMessage + "</H2>").append("<HR>");
00450         Identification.writeAddress(sb);
00451         sb.append("</BODY></HTML>");
00452         setContentLength(sb.length());
00453         out.print(sb.toString());
00454         out.flush();
00455     }
00456 
00457 
00458 
00459 
00460      
00461      
00462      
00463      
00464      
00465      
00466      
00467      
00468      
00469      
00470      
00471      
00472      
00473      
00474      
00475      
00476      
00477      
00478      // HttpServletRequest METHODS
00479      // ***************************************************************************************************************
00480     
00482     // the attribute does not exist. This method allows access to request
00483     // information not already provided by the other methods in this interface.
00484     public Object getAttribute(String name) {
00485         return attributes.get(name);
00486     }
00487 
00488     // from ServletRequest
00489     public Enumeration getAttributeNames() {
00490         return attributes.keys();
00491     }
00492      
00493      public String getAuthType() {
00494          //return HttpServletRequest.BASIC_AUTH;
00495          return null;
00496      }
00497      
00499      // Same as the CGI variable CONTENT_LENGTH.
00500      public int getContentLength() {
00501          try {
00502              return this.getIntHeader(CONTENTLENGTH);
00503          } catch (Exception ex) {
00504              return -1;
00505          }
00506      }
00507      
00509      // not known.
00510      // Same as the CGI variable CONTENT_TYPE.
00511      public String getContentType() {
00512          return getHeader(CONTENTTYPE);
00513      }
00514      
00515      public String getContextPath() {
00516          return "";
00517      }
00518      
00519      public Cookie[] getCookies() {
00520          // We don't use cookies
00521          return null;
00522      }
00523      
00524      public long getDateHeader(String name) {
00525          String val = getHeader(name);
00526          if (val == null)
00527              return 0;
00528          try {
00529              return headerdateformat.parse(val).getTime();
00530          } catch (Exception e) {
00531              throw new IllegalArgumentException("Value " + val
00532                      + " can't be converted to Date using "
00533                      + headerdateformat.toPattern());
00534          }
00535      }
00536      
00537      public String getHeader(String name) {
00538          int i = reqHeaderNames.indexOf(name.toLowerCase());
00539          if (i == -1)
00540              return null;
00541          return (String) reqHeaderValues.elementAt(i);
00542      }
00543      
00544      public Enumeration getHeaderNames() {
00545          return reqHeaderNames.elements();
00546      }
00547      
00548      public Enumeration getHeaders(String header) {
00549          Vector result = new Vector();
00550          int i = -1;
00551          while ((i = reqHeaderNames.indexOf(header.toLowerCase(), i + 1)) >= 0)
00552              result.addElement(reqHeaderValues.elementAt(i));
00553          return result.elements();
00554      }
00555      
00557      // @exception IllegalStateException if getReader has already been called
00558      // @exception IOException on other I/O-related errors
00559      public ServletInputStream getInputStream() throws IOException {
00560          synchronized (in) {
00561              if (((ServeInputStream) in).isReturnedAsReader())
00562                  throw new IllegalStateException("Already returned as a reader.");
00563              ((ServeInputStream) in).setReturnedAsReader(true);
00564          }
00565          return in;
00566      }
00567 
00569      // @param name the header field name
00570      public int getIntHeader(String name) {
00571          String val = getHeader(name);
00572          if (val == null)
00573              return -1;
00574          
00575          // We don't use any try catch, as this method must return
00576          // a NumberFormatException in case of problem
00577          // (According to the Servlet 2.4 specifications)
00578          return Integer.parseInt(val);
00579      }
00580      
00591      public String getLocalAddr() {
00592        return null; // TODO:
00593      }
00594      
00595      // should decide about supported locales and charsets, no a good decision yet
00596      public Enumeration getLocales() {
00597        // TODO: get locales from Accept-Language (RFC 2616)
00598        //Locale.getAvailableLocales() 
00599        return null;
00600      }
00601      
00611      public String getLocalName() {
00612        return null; // TODO: get bind address
00613      }
00614      
00623      public int getLocalPort() {
00624          return webserver.port;
00625      }
00626      
00627      public String getMethod() {
00628          return reqMethod;
00629      }
00630      
00632      // if not found.
00633      // @param name the parameter name
00634      public String getParameter(String name) {
00635          String[] params = getParameterValues(name);
00636          if (params == null || params.length == 0)
00637              return null;
00638 
00639          return params[0];
00640      }
00641      
00651      public java.util.Map getParameterMap() {
00652        return (java.util.Map) formParameters;
00653      }
00654      
00656      public Enumeration getParameterNames() {
00657          if (formParameters == null)
00658              formParameters = getParametersFromRequest();
00659          return formParameters.keys();
00660      }
00661      
00663      // array of strings, or null if the named parameter does not exist.
00664      public String[] getParameterValues(String name) {
00665          if (formParameters == null)
00666              getParameterNames();
00667 
00668          return (String[]) formParameters.get(name);
00669      }
00670      
00671      public String getPathInfo() {
00672          // In this server, the entire path is regexp-matched against the
00673          // servlet pattern, so there's no good way to distinguish which
00674          // part refers to the servlet.
00675          return uriLen >= reqUriPath.length() ? null : reqUriPath.substring(uriLen);
00676      }
00677      
00678      public String getPathTranslated() {
00679          // In this server, the entire path is regexp-matched against the
00680          // servlet pattern, so there's no good way to distinguish which
00681          // part refers to the servlet.
00682          return getRealPath(getPathInfo());
00683      }
00684      
00686      // the form <protocol>/<major version>.<minor version>.
00687      // Same as the CGI variable SERVER_PROTOCOL.
00688      public String getProtocol() {
00689        return reqProtocol;
00690      }
00691      
00692      // Returns the query string part of the servlet URI, or null if not known.
00693      // Same as the CGI variable QUERY_STRING.
00694      public String getQueryString() {
00695          return reqQuery;
00696      }
00697      
00699      // @exception UnsupportedEncodingException if the character set encoding isn't supported
00700      // @exception IllegalStateException if getInputStream has already been called
00701      // @exception IOException on other I/O-related errors
00702      public BufferedReader getReader() throws IOException {
00703        synchronized (in) {
00704          if (((ServeInputStream) in).isReturnedAsStream())
00705            throw new IllegalStateException("Already returned as a stream.");
00706          ((ServeInputStream) in).setReturnedAsStream(true);
00707        }
00708        if (reqCharEncoding != null)
00709          try {
00710            return new BufferedReader(new InputStreamReader(in, reqCharEncoding));
00711          } catch (UnsupportedEncodingException uee) {
00712          }
00713        return new BufferedReader(new InputStreamReader(in));
00714      }
00715      
00717      // corresponding real path, or null if the translation can not be
00718      // performed for any reason.  For example, an HTTP servlet would
00719      // resolve the path using the virtual docroot, if virtual hosting is
00720      // enabled, and with the default docroot otherwise.  Calling this
00721      // method with the string "/" as an argument returns the document root.
00722      public String getRealPath(String path) {
00723        return webserver.getRealPath(path);
00724      }
00725      
00727      // Same as the CGI variable REMOTE_ADDR.
00728      public String getRemoteAddr() {
00729        return socket.getInetAddress().getHostAddress().toString();
00730      }
00731 
00733      // request.
00734      // Same as the CGI variable REMOTE_HOST.
00735      public String getRemoteHost() {
00736        String result = socket.getInetAddress().getHostName();
00737        return result != null ? result : getRemoteAddr();
00738      }
00739      
00748      public int getRemotePort() {
00749          // TODO : Actually returns local port
00750          return webserver.port;
00751      }
00752      
00754      // Same as the CGI variable REMOTE_USER.
00755      public String getRemoteUser() {
00756          // We don't use user authentification.
00757          return null;
00758      }
00759      
00760      public RequestDispatcher getRequestDispatcher(String urlpath) {
00761          // TODO: calculate dispacter relatively the current path
00762          return null; // we don't provide resource dispatching in this way
00763        }
00764      
00765      public String getRequestedSessionId() {
00766          // This WEB server only handles one session.
00767          return this.getSession().getId();
00768      }
00769      
00770      public String getRequestURI() {
00771          return reqUriPath;
00772      }
00773      
00774      public void setRequestURI(String uri) {
00775          reqUriPath = uri;
00776      }
00777 
00778      public StringBuffer getRequestURL() {
00779          return new StringBuffer().append(getScheme()).append("://").append(this.getServerName())
00780                         .append(webserver.port == 80 ? "" : ":"+String.valueOf(webserver.port)).append(getRequestURI());
00781      }
00782      
00784      // "http", "https", or "ftp".  Different schemes have different rules
00785      // for constructing URLs, as noted in RFC 1738.  The URL used to create
00786      // a request may be reconstructed using this scheme, the server name
00787      // and port, and additional information such as URIs.
00788      public String getScheme() {
00789        if (socket.getClass().getName().toUpperCase().indexOf("SSL") < 0)
00790          return "http";
00791        else
00792          return "https";
00793      }
00794      
00796      // the request URI.
00797      // Same as the CGI variable SERVER_NAME.
00798      public String getServerName() {
00799        String serverName;
00800        serverName = getHeader("Host");
00801        if (serverName != null && serverName.length() > 0) {
00802          int colon = serverName.indexOf(':');
00803          if (colon >= 0) {
00804            if (colon < serverName.length()) serverName = serverName.substring(0, colon);
00805          }
00806        }
00807 
00808        if (serverName == null) {
00809          try {
00810            serverName = InetAddress.getLocalHost().getHostName();
00811          } catch (java.net.UnknownHostException ignore) {
00812            serverName = "127.0.0.0";
00813          }
00814        }
00815 
00816        int slash = serverName.indexOf("/");
00817        if (slash >= 0)
00818          serverName = serverName.substring(slash + 1);
00819        return serverName;
00820      }
00821 
00823      // the <port> part of the request URI.
00824      // Same as the CGI variable SERVER_PORT.
00825      public int getServerPort() {
00826        return socket.getLocalPort();
00827      }
00828      
00829      public String getServletPath() {
00830          // In this server, the entire path is regexp-matched against the
00831          // servlet pattern, so there's no good way to distinguish which
00832          // part refers to the servlet.
00833          return uriLen > 0 ? reqUriPath.substring(0, uriLen) : "";
00834      }
00835      
00836      public HttpSession getSession() {
00837          return this.getSession(true);
00838      }
00839 
00840      public HttpSession getSession(boolean create) {
00841          // Only one seesion context
00842        SessionContext session = SessionContextManager.getManager().getSessionContext("OPENMOBILEISSESSION");
00843        if (session == null)  {
00844          synchronized (SessionContextManager.getManager()) {
00845            session = SessionContextManager.getManager().getSessionContext("OPENMOBILEISSESSION");
00846            if (session == null)  {
00847              session = SessionContextManager.getManager().createSessionContext("OPENMOBILEISSESSION");
00848            }
00849          }
00850        }
00851        SessionContextManager.getManager().joinSessionContext(session.getId());
00852        return SessionContextManager.getManager().getSessionContext();
00853      }
00854      
00855      public Principal getUserPrincipal() {
00856          // We don't use user authentification.
00857          return null;
00858      }
00859      
00860      public boolean isRequestedSessionIdFromCookie() {
00861          // We don't use cookies.
00862          return false;
00863      }
00864      
00865      public boolean isRequestedSessionIdFromURL() {
00866          // We only use on session for this web browser.
00867          return false;
00868      }
00869 
00870      public boolean isRequestedSessionIdFromUrl() {
00871          // We only use on session for this web browser.
00872          return false;
00873      }
00874      
00875      public boolean isRequestedSessionIdValid() {
00876          HttpSession session = this.getSession();
00877          if (session != null) {
00878              return true;
00879          }
00880          return false;
00881      }
00882      
00883      public boolean isSecure() {
00884          return false;
00885        }
00886      
00887      public boolean isUserInRole(String arg0) {
00888          // We don't use authentification.
00889          return false;
00890      }
00891      
00892      public void removeAttribute(String name) {
00893          attributes.remove(name);
00894      }
00895      
00896      public void setAttribute(String key, Object o) {
00897          attributes.put(key, o);
00898        }
00899      
00907      public void setCharacterEncoding(String _enc) {
00908        reqCharEncoding = _enc;
00909      }
00910      
00911      
00912      
00913      
00914      
00915      
00916      
00917      
00918      
00919      
00920      
00921      
00922      
00923      
00924      
00925      // HttpServletRequest AND HttpServletResponse METHODS
00926      // ***************************************************************************************************************
00927      
00929      // character encoding is either the one specified in the assigned
00930      // content type, or one which the client understands. If no content
00931      // type has yet been assigned, it is implicitly set to text/plain.
00932      public String getCharacterEncoding() {
00933          String ct = (String) resHeaderNames.get(CONTENTTYPE);
00934          if (ct != null) {
00935              int scp = ct.indexOf(';');
00936              if (scp > 0) {
00937                  scp = ct.toLowerCase().indexOf("charset=", scp);
00938                  if (scp >= 0) {
00939                      ct = ct.substring(scp + 8);
00940                      scp = ct.indexOf(' ');
00941                      if (scp > 0)
00942                          ct = ct.substring(0, scp);
00943                      scp = ct.indexOf(';');
00944                      if (scp > 0)
00945                          ct = ct.substring(0, scp);
00946                      return ct;
00947                  }
00948              }
00949          }
00950          return null;
00951      }
00952      
00953      public Locale getLocale() {
00954          return locale;
00955      }
00956       
00957 
00958      
00959      
00960      
00961      
00962      
00963      
00964      
00965      
00966      
00967      
00968      
00969      
00970      
00971      
00972      
00973      
00974      
00975      
00976      
00977      
00978      
00979      
00980      
00981      
00982      
00983      
00984      
00985      // HttpServletResponse METHODS
00986      // ***************************************************************************************************************
00987      
00989      // multiple times to set more than one cookie.
00990      public void addCookie(Cookie cookie) {
00991          // We don't use cookies.
00992      }
00993      
00994      public void addDateHeader(String header, long date) {
00995          addHeader(header, expdatefmt.format(new Date(date)));
00996      }
00997      
00998      public void addHeader(String header, String value) {
00999          Object o = resHeaderNames.get(header);
01000          if (o == null)
01001              setHeader(header, value);
01002          else {
01003              if (o instanceof String[]) {
01004                  String[] oldVal = (String[]) o;
01005                  String[] newVal = new String[oldVal.length + 1];
01006                  System.arraycopy(oldVal, 0, newVal, 0, oldVal.length);
01007                  newVal[oldVal.length] = value;
01008                  resHeaderNames.put(header, newVal);
01009              } else if (o instanceof String) {
01010                  String[] newVal = new String[2];
01011                  newVal[0] = (String) o;
01012                  newVal[1] = value;
01013                  resHeaderNames.put(header, newVal);
01014              } else
01015                  throw new RuntimeException("Invalid content of header hash - "
01016                          + o.getClass().getName());
01017          }
01018      }
01019      
01020      public void addIntHeader(String header, int value) {
01021          addHeader(header, Integer.toString(value));
01022      }
01023      
01025      // specified name.
01026      public boolean containsHeader(String name) {
01027          return resHeaderNames.contains(name);
01028      }
01029      
01031      // encoding is not needed, returns the URL unchanged. The
01032      // implementation of this method should include the logic to determine
01033      // whether the session ID needs to be encoded in the URL. Because the
01034      // rules for making this determination differ from those used to
01035      // decide whether to encode a normal link, this method is seperate
01036      // from the encodeUrl method.
01037      // <P>
01038      // All URLs sent to the HttpServletResponse.sendRedirect method should be
01039      // run through this method. Otherwise, URL rewriting cannot be used with
01040      // browsers which do not support cookies.
01041      public String encodeRedirectUrl(String url) {
01042          return url;
01043      }
01044      
01045      public String encodeRedirectURL(String url) {
01046          return url; // as is
01047      }
01048      
01049      // URL session-encoding stuff. Not implemented, but the API is here
01050      // for compatibility.
01051 
01053      // encoding is not needed, returns the URL unchanged. The
01054      // implementation of this method should include the logic to determine
01055      // whether the session ID needs to be encoded in the URL. For example,
01056      // if the browser supports cookies, or session tracking is turned off,
01057      // URL encoding is unnecessary.
01058      // <P>
01059      // All URLs emitted by a Servlet should be run through this method.
01060      // Otherwise, URL rewriting cannot be used with browsers which do not
01061      // support cookies.
01062      public String encodeUrl(String url) {
01063          return url;
01064      }
01065      
01066      // JSDK 2.1 extension
01067      public String encodeURL(String url) {
01068          return url; // as is
01069      }
01070      
01071      // 2.2
01072      // do not use buffer
01073      public void flushBuffer() {
01074      }
01075      
01076         public int getBufferSize() {
01077          return 0;
01078         }
01079         
01081     public ServletOutputStream getOutputStream() throws IOException {
01082       synchronized (out) {
01083         if (((ServeOutputStream) out).isReturnedAsWriter())
01084           throw new IllegalStateException("Already returned as a writer");
01085         ((ServeOutputStream) out).setReturnedAsStream(true);
01086       }
01087       return out;
01088     }
01089     
01091     // the response will be modified, if necessary, to reflect the character
01092     // encoding used, through the charset=... property.  This means that the
01093     // content type must be set before calling this method.
01094     // @exception UnsupportedEncodingException if no such encoding can be provided
01095     // @exception IllegalStateException if getOutputStream has been called
01096     // @exception IOException on other I/O errors
01097     public PrintWriter getWriter() throws IOException {
01098       synchronized (out) {
01099         if (((ServeOutputStream) out).isReturnedAsStream())
01100           throw new IllegalStateException("Already was returned as servlet output stream");
01101         ((ServeOutputStream) out).setReturnedAsWriter(true);
01102       }
01103       String encoding = getCharacterEncoding();
01104       if (encoding != null) {
01105         //return new PrintWriter(new OutputStreamWriter(out, encoding));
01106           printWriter = new PrintWriter(new OutputStreamWriter(out, encoding));
01107       } else {
01108         //return new PrintWriter(out);
01109           printWriter = new PrintWriter(out);
01110       }
01111       return printWriter;
01112     }
01113     
01122      // a caller should think about syncronization 
01123      public boolean isCommitted() {
01124        return headersWritten;
01125      }
01126      
01133      public void reset() {
01134        if (!isCommitted()) {
01135          resHeaderNames.clear();
01136        } else
01137          throw new IllegalStateException("Header have already been committed.");
01138      }
01139      
01140      public void resetBuffer() {
01141          throw new IllegalStateException("The method not implemented");
01142      }
01143         
01145      // @param resCode the status code
01146      // @param resMessage the status message
01147      // @exception IOException if an I/O error has occurred
01148      public void sendError(int resCode, String resMessage) throws IOException {
01149          setStatus(resCode, resMessage);
01150          realSendError();
01151      }
01152 
01154      // message.
01155      // @param resCode the status code
01156      // @exception IOException if an I/O error has occurred
01157      public void sendError(int resCode) throws IOException {
01158          setStatus(resCode);
01159          realSendError();
01160      }
01161 
01163      // location URL.
01164      // @param location the redirect location URL
01165      // @exception IOException if an I/O error has occurred
01166      public void sendRedirect(String location) throws IOException {
01167          if (isCommitted())
01168              throw new IllegalStateException(
01169                      "Can not redirect, headers have been already written");
01170          synchronized (out) {
01171              // no more out after redirect
01172              ((ServeOutputStream) out).setReturnedAsStream(true);
01173              ((ServeOutputStream) out).setReturnedAsWriter(true);
01174          }
01175          setHeader("Location", location);
01176          setStatus(SC_MOVED_TEMPORARILY);
01177          setContentType("text/html");
01178          StringBuffer sb = new StringBuffer(200);
01179          sb.append("<HTML><HEAD>" + "<TITLE>" + SC_MOVED_TEMPORARILY
01180                  + " Moved</TITLE>" + "</HEAD><BODY BGCOLOR=\"#F1D0F2\">"
01181                  + "<H2>" + SC_MOVED_TEMPORARILY + " Moved</H2>"
01182                  + "This document has moved <a href=" + location + ">here.<HR>");
01183          Identification.writeAddress(sb);
01184          sb.append("</BODY></HTML>");
01185          setContentLength(sb.length());
01186          // to avoid further out
01187          out.print(sb.toString());
01188          out.flush();
01189      }
01190      
01191      // 2.2
01192      // do not use buffer
01193      public void setBufferSize(int size) {
01194      }
01195      
01197      // @param length the content length
01198      public void setContentLength(int length) {
01199        setIntHeader(CONTENTLENGTH, length);
01200      }
01201      
01203      // @param type the content type
01204      public void setContentType(String type) {
01205        setHeader(CONTENTTYPE, type != null ? type : "Unknown");
01206      }
01207      
01209      // @param name the header field name
01210      // @param value the header field date value
01211      public void setDateHeader(String name, long value) {
01212          setHeader(name, expdatefmt.format(new Date(value)));
01213      }
01214      
01216      // @param name the header field name
01217      // @param value the header field value
01218      public void setHeader(String name, String value) {
01219          resHeaderNames.put(name, value);
01220      }
01221      
01223      // @param name the header field name
01224      // @param value the header field integer value
01225      public void setIntHeader(String name, int value) {
01226          setHeader(name, Integer.toString(value));
01227      }
01228      
01237      public void setLocale(Locale locale) {
01238        this.locale = locale;
01239      }
01240      
01242      // @param resCode the status code
01243      public void setStatus(int resCode) {
01244          switch (resCode) {
01245          case SC_CONTINUE:
01246              setStatus(resCode, "Continue");
01247              break;
01248          case SC_SWITCHING_PROTOCOLS:
01249              setStatus(resCode, "Switching protocols");
01250              break;
01251          case SC_OK:
01252              setStatus(resCode, "Ok");
01253              break;
01254          case SC_CREATED:
01255              setStatus(resCode, "Created");
01256              break;
01257          case SC_ACCEPTED:
01258              setStatus(resCode, "Accepted");
01259              break;
01260          case SC_NON_AUTHORITATIVE_INFORMATION:
01261              setStatus(resCode, "Non-authoritative");
01262              break;
01263          case SC_NO_CONTENT:
01264              setStatus(resCode, "No content");
01265              break;
01266          case SC_RESET_CONTENT:
01267              setStatus(resCode, "Reset content");
01268              break;
01269          case SC_PARTIAL_CONTENT:
01270              setStatus(resCode, "Partial content");
01271              break;
01272          case SC_MULTIPLE_CHOICES:
01273              setStatus(resCode, "Multiple choices");
01274              break;
01275          case SC_MOVED_PERMANENTLY:
01276              setStatus(resCode, "Moved permanentently");
01277              break;
01278          case SC_MOVED_TEMPORARILY:
01279              setStatus(resCode, "Moved temporarily");
01280              break;
01281          case SC_SEE_OTHER:
01282              setStatus(resCode, "See other");
01283              break;
01284          case SC_NOT_MODIFIED:
01285              setStatus(resCode, "Not modified");
01286              break;
01287          case SC_USE_PROXY:
01288              setStatus(resCode, "Use proxy");
01289              break;
01290          case SC_BAD_REQUEST:
01291              setStatus(resCode, "Bad request");
01292              break;
01293          case SC_UNAUTHORIZED:
01294              setStatus(resCode, "Unauthorized");
01295              break;
01296          case SC_PAYMENT_REQUIRED:
01297              setStatus(resCode, "Payment required");
01298              break;
01299          case SC_FORBIDDEN:
01300              setStatus(resCode, "Forbidden");
01301              break;
01302          case SC_NOT_FOUND:
01303              setStatus(resCode, "Not found");
01304              break;
01305          case SC_METHOD_NOT_ALLOWED:
01306              setStatus(resCode, "Method not allowed");
01307              break;
01308          case SC_NOT_ACCEPTABLE:
01309              setStatus(resCode, "Not acceptable");
01310              break;
01311          case SC_PROXY_AUTHENTICATION_REQUIRED:
01312              setStatus(resCode, "Proxy auth required");
01313              break;
01314          case SC_REQUEST_TIMEOUT:
01315              setStatus(resCode, "Request timeout");
01316              break;
01317          case SC_CONFLICT:
01318              setStatus(resCode, "Conflict");
01319              break;
01320          case SC_GONE:
01321              setStatus(resCode, "Gone");
01322              break;
01323          case SC_LENGTH_REQUIRED:
01324              setStatus(resCode, "Length required");
01325              break;
01326          case SC_PRECONDITION_FAILED:
01327              setStatus(resCode, "Precondition failed");
01328              break;
01329          case SC_REQUEST_ENTITY_TOO_LARGE:
01330              setStatus(resCode, "Request entity too large");
01331              break;
01332          case SC_REQUEST_URI_TOO_LONG:
01333              setStatus(resCode, "Request URI too large");
01334              break;
01335          case SC_UNSUPPORTED_MEDIA_TYPE:
01336              setStatus(resCode, "Unsupported media type");
01337              break;
01338          case SC_INTERNAL_SERVER_ERROR:
01339              setStatus(resCode, "Internal server error");
01340              break;
01341          case SC_NOT_IMPLEMENTED:
01342              setStatus(resCode, "Not implemented");
01343              break;
01344          case SC_BAD_GATEWAY:
01345              setStatus(resCode, "Bad gateway");
01346              break;
01347          case SC_SERVICE_UNAVAILABLE:
01348              setStatus(resCode, "Service unavailable");
01349              break;
01350          case SC_GATEWAY_TIMEOUT:
01351              setStatus(resCode, "Gateway timeout");
01352              break;
01353          case SC_HTTP_VERSION_NOT_SUPPORTED:
01354              setStatus(resCode, "HTTP version not supported");
01355              break;
01356          default:
01357              setStatus(resCode, "");
01358              break;
01359          }
01360      }
01361      
01363      // @param resCode the status code
01364      // @param resMessage the status message
01365      public void setStatus(int resCode, String resMessage) {
01366          //     if (this.resCode > 0 && this.resCode != SC_OK)
01367          //             throw new IllegalStateException("Result code "+this.resCode+" was
01368          // already set.");
01369          this.resCode = resCode;
01370          this.resMessage = resMessage;
01371      }
01372 
01373 
01374      
01375      
01376 }

Generated on Tue May 22 23:01:13 2007 for OpenMobileIS by  doxygen 1.5.1-p1