Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

WebServerConnection.java

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

Generated on Wed Dec 14 21:05:36 2005 for OpenMobileIS by  doxygen 1.4.4