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

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

Generated on Thu Oct 6 10:06:34 2005 for OpenMobileIS by  doxygen 1.4.3