/*
* $Id: AnyRequest.java,v 1.31 2002/09/16 08:05:03 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.core.net;
import anvil.core.Any;
import anvil.core.AnyAbstractClass;
import anvil.core.AnyString;
import anvil.core.AnyTuple;
import anvil.core.AnyList;
import anvil.core.Array;
import anvil.Log;
import anvil.script.Context;
import anvil.session.Session;
import anvil.session.SessionContainer;
import anvil.session.HttpSessionAdapter;
import anvil.java.util.BindingEnumeration;
import anvil.java.util.Holder;
import com.oreilly.servlet.MultipartRequest;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Cookie;
///
/// @class Request
/// The HTTP request from the client terminal/browser.
/// <p>
/// All request parameters (URL parameters and FORM parameters)
/// appear as request's fields. For example, if the query string
/// contains "a=1&b=2", there will be two fields available in
/// the request: <i>request.a</i> and <i>request.b</i>
/// </p>
///
/// <p>
/// If parameter names contains "keys" enclosed into angle brackets
/// corresponding array structures are created onto request. For example:
/// <pre>
/// <input type="person[name]" value="john doe">
/// <input type="person[age]" value="50">
/// </pre>
/// When submitted will yield to attribute person to request
/// with value <code>["name"=>"john doe", "age"=>"50"]</code>.
/// </p>
///
/// <p>
/// Handles also file uploads. For example:
/// <pre>
/// <form method="post" ENCTYPE="multipart/form-data">
/// <input type="file" name="file1">
/// </form>
/// </pre>
/// Here the <i>request.file1</i> field will contain a
/// File datatype, which represents an uploaded file.
/// </p>
/**
* AnyRequest combines HttpServletRequest and MultipartRequest.
* It handles also file uploads.
*
* @author: Jani Lehtim�ki
* @author: Jaripekka Salminen
*/
public class AnyRequest extends AnyAbstractClass
{
private HttpServletRequest _request;
private SessionContainer _container;
private MultipartRequest _multi;
private Array _parameters = new Array();
public AnyRequest(HttpServletRequest request, SessionContainer container)
{
this(request);
_container = container;
}
public AnyRequest(HttpServletRequest request)
{
_request = request;
Enumeration enu = _request.getHeaderNames();
while (enu.hasMoreElements()) {
String headerName = (String)enu.nextElement();
//anvil.Log.log().debug(headerName+"="+_request.getHeader(headerName));
}
/* handle POST ENCTYPE="multipart/form-data" */
String contentType = _request.getContentType();
if (contentType != null) {
try {
if (contentType.toLowerCase().startsWith("multipart/form-data")) {
File tmpFile = File.createTempFile("tmp_anvil_","_upload");
String tmpDirName = tmpFile.toString();
tmpFile.delete();
File tmpDir = new File(tmpDirName);
tmpDir.mkdir();
tmpDir.deleteOnExit();
//anvil.Log.log().debug("tmpDir="+tmpDir.toString());
_multi = new MultipartRequest(request, tmpDir.toString(), 32*1024*1024);
enu = _multi.getParameterNames();
while(enu.hasMoreElements()) {
String name = (String)enu.nextElement();
parseParameter(_parameters, name, _multi.getParameterValues(name));
}
enu = _multi.getFileNames();
while(enu.hasMoreElements()) {
String name = (String)enu.nextElement();
_parameters.remove(Any.create(name));
parseParameter(_parameters, name, _multi.getFile(name));
}
return;
}
} catch (IOException e) {
anvil.Log.log().error("AnyRequest multipart/form-data exception ", e);
}
}
enu = _request.getParameterNames();
while(enu.hasMoreElements()) {
String name = (String)enu.nextElement();
parseParameter(_parameters, name, request.getParameterValues(name));
}
}
private Any createKey(String key)
{
if (key.length() > 0) {
char ch = key.charAt(0);
if (Character.isDigit(ch) || ch == '-') {
try {
return Any.create(Integer.valueOf(key));
} catch (NumberFormatException e) {
}
}
}
return Any.create(key);
}
private void parseParameter(Array base, String name, Object value)
{
int start = name.indexOf('[');
if (start > 0) {
int end;
int new_start;
int length = name.length();
Any key;
Any any;
Array array;
key = new AnyString(name.substring(0, start).trim());
any = base.get(key);
if ((any == null) || !any.isArray()) {
array = new Array();
base.put(key, array);
} else {
array = any.toArray();
}
base = array;
do {
end = name.indexOf(']', start + 1);
if (end == -1) {
end = length;
}
new_start = name.indexOf('[', end+1);
key = createKey(name.substring(start+1, end).trim());
if (new_start > 0) {
any = base.get(key);
if ((any == null) || !any.isArray()) {
array = new Array();
base.put(key, array);
} else {
array = any.toArray();
}
base = array;
} else {
putParameter(base, key, value);
}
start = new_start;
} while (start>=0 && start<length);
} else {
putParameter(base, new AnyString(name), value);
}
}
protected void putParameter(Array base, Any key, Object value)
{
if (value instanceof String[]) {
String[] strarray = (String[])value;
int length = strarray.length;
if (length == 1) {
base.put(key, Any.create(strarray[0]));
} else {
Any[] tuple = new Any[length];
for(int i=0; i<length; i++) {
tuple[i] = Any.create(strarray[i]);
}
base.put(key, new AnyTuple(tuple));
}
} else {
base.put(key, Any.create(value));
}
}
public final anvil.script.ClassType classOf() {
return __class__;
}
public int sizeOf()
{
return _parameters.size();
}
public Object toObject()
{
return _request;
}
/// @attribute parameter
/// Parameter from request. For ordinary parameters
/// string is returned, for uploads anvil.io.File is returned
/// and for parameters containing list of angle bracketed keys
/// an array is returned.
/// @synopsis object <i>request</i>.<i>parameter</i>
public Any getAttribute(Context context, String attribute)
{
Any value = (Any)_parameters.get(Any.create(attribute));
return (value != null) ? value : UNDEFINED;
}
public Any setAttribute(Context context, String attribute, Any value)
{
_parameters.put(Any.create(attribute), value);
return value;
}
public Any checkAttribute(Context context, String attribute)
{
Any value = (Any)_parameters.get(Any.create(attribute));
return (value != null) ? value : UNDEFINED;
}
public boolean deleteAttribute(Context context, String attribute)
{
return false;
}
/// @reference "object <i>request</i>[<i>parameter</i>]"
/// Parameter from request. For ordinary parameters
/// string is returned, for uploads anvil.io.File is returned
/// and for parameters containing list of angle bracketed keys
/// an array is returned.
public Any getReference(Context context, Any index)
{
return getAttribute(context, index.toString());
}
public Any setReference(Context context, Any index, Any value)
{
return setAttribute(context, index.toString(), value);
}
public Any setReference(Context context, Any value)
{
return this;
}
public Any checkReference(Context context, Any index)
{
return checkAttribute(context, index.toString());
}
public boolean deleteReference(Context context, Any index)
{
return deleteAttribute(context, index.toString());
}
public BindingEnumeration enumeration()
{
return _parameters.keysAndElements();
}
/// @method getAuthType
/// Returns the name of the authentication scheme.
/// Used to protect the "site servlet", for example, "BASIC" or "SSL,"
/// or null if the servlet was not protected.
/// @synopsis string getAuthType()
/// @return the name of the authentication scheme
public Any m_getAuthType()
{
return Any.create(_request.getAuthType());
}
/// @method getContentLength
/// Returns the length, in bytes, of the request body and
/// made available by the input stream, or -1 if the length is not
/// known.
/// @synopsis string getContentLength()
/// @return content length
public Any m_getContentLength()
{
return Any.create(_request.getContentLength());
}
/// @method getContentType
/// Returns the MIME type of the body of the request, or
/// null if the type is not known.
/// @synopsis string getContentType()
/// @return content type
public Any m_getContentType()
{
return Any.create(_request.getContentType());
}
/// @method getHeaderNames
/// Returns an array of all the header names this request contains.
/// @synopsis array getHeaderNames()
/// @return header names
public Any m_getHeaderNames()
{
Array array = new Array();
Enumeration enu = _request.getHeaderNames();
while (enu.hasMoreElements()) {
array.append(Any.create((String)enu.nextElement()));
}
return array;
}
/// @method getHeader
/// Returns the value of the specified request header as a string.
/// If the request did not include a header of the specified name,
/// this method returns null. The header name is case insensitive.
/// Some useful headers for detecting the client type are
/// "User-Agent" and "Accept".
/// @synopsis string getHeader(string headerName)
/// @param headerName header name
/// @return header
public static final Object[] p_getHeader = { "headerName" };
public Any m_getHeader(String headerName)
{
return Any.create(_request.getHeader(headerName));
}
/// @method getMethod
/// Returns the name of the HTTP method with which this
/// request was made, for example, GET, POST, or PUT.
/// @synopsis string getMethod()
/// @return the HTTP method
public Any m_getMethod()
{
return Any.create(_request.getMethod());
}
/// @method getPathInfo
/// Returns any extra path information associated with the
/// URL the client sent when it made this request.
/// @synopsis string getPathInfo()
/// @return path info
public Any m_getPathInfo()
{
return Any.create(_request.getPathInfo());
}
/// @method getQueryString
/// Returns the query string that is contained in the request
/// URL after the path.
/// @synopsis string getQueryString()
/// @return query string
public Any m_getQueryString()
{
return Any.create(_request.getQueryString());
}
/// @method getRemoteUser
/// Returns the login of the user making this request, if the
/// user has been authenticated, or null if the user has not been
/// authenticated.
/// @synopsis string getRemoteUser()
/// @return remote user
public Any m_getRemoteUser()
{
return Any.create(_request.getRemoteUser());
}
/// @method getRequestURI
/// Returns the part of this request's URL from the
/// protocol name up to the query string in the first line of the
/// HTTP request.
/// @synopsis string getRequestURI()
/// @return request URI
public Any m_getRequestURI()
{
return Any.create(_request.getRequestURI());
}
/// @method getServletPath
/// Returns the part of this request's URL that calls the servlet.
/// @synopsis string getServletPath()
/// @return servlet path
public Any m_getServletPath()
{
return Any.create(_request.getServletPath());
}
/// @method getRemoteAddr
/// Returns the Internet Protocol (IP) address of the client that sent the request.
/// @synopsis string getRemoteAddr()
/// @return remote address
public Any m_getRemoteAddr()
{
return Any.create(_request.getRemoteAddr());
}
/// @method getRemoteHost
/// Returns the fully qualified name of the client that sent
/// the request, or the IP address of the client if the name cannot
/// be determined.
/// @synopsis string getRemoteHost()
/// @return remote host
public Any m_getRemoteHost()
{
return Any.create(_request.getRemoteHost());
}
/// @method getServerName
/// Returns the host name of the server that received the request.
/// @synopsis string getServerName()
/// @return server name
public Any m_getServerName()
{
return Any.create(_request.getServerName());
}
/// @method getServerPort
/// Returns the port number on which this request was received.
/// @synopsis string getServerPort()
/// @return server port
public Any m_getServerPort()
{
return Any.create(_request.getServerPort());
}
/// @method getProtocol
/// Returns the name and version of the protocol the request
/// uses in the form protocol/majorVersion.minorVersion, for
/// example, HTTP/1.1.
/// @synopsis string getProtocol()
/// @return protocol
public Any m_getProtocol()
{
return Any.create(_request.getProtocol());
}
/// @method getCookies
/// Returns list containing all cookies that browser
/// sent with this request.
/// @synopsis list getCookies()
public Any m_getCookies()
{
Cookie[] cookies = _request.getCookies();
if (cookies == null) {
return new AnyList(Any.ARRAY0);
} else {
int n = cookies.length;
Any[] list = new Any[n];
for(int i=0; i<n; i++) {
list[i] = new AnyCookie(cookies[i]);
}
return new AnyList(list);
}
}
/// @method getSession
/// Returns the current session associated with this request.
/// Session returned by this method is independent from
/// Anvil's session handling mechanism as it is provided
/// by enclosing servlet container.
/// @synopsis Session getSession()
/// @synopsis Session getSession(boolean create)
/// @param create If true and there is no session, returns a new session
public static final Object[] p_getSession = { "create" };
public Any m_getSession(Any create)
{
HttpSession session;
if (create != null) {
session = _request.getSession(create.toBoolean());
} else {
session = _request.getSession();
}
if (session != null) {
return new AnySession(new HttpSessionAdapter(session));
} else {
return UNDEFINED;
}
}
/// @method getRequestedSessionId
/// Returns the session ID specified by the client.
/// @synopsis string getRequestedSessionId()
public Any m_getRequestedSessionId()
{
return Any.create(_request.getRequestedSessionId());
}
/// @method isRequestedSessionIdFromCookie
/// Checks whether the requested session ID came in as a cookie.
/// @synopsis boolean isRequestSessionIdFromCookie()
public Any m_isRequestedSessionIdFromCookie()
{
return _request.isRequestedSessionIdFromCookie() ? TRUE : FALSE;
}
/// @method isRequestedSessionIdFromURL
/// Checks whether the requested session ID came in as part of the request URL.
/// @synopsis boolean isRequestedSessionIdFromURL()
public Any m_isRequestedSessionIdFromURL()
{
return _request.isRequestedSessionIdFromURL() ? TRUE : FALSE;
}
/// @method isRequestedSessionValid
/// Checks whether the requested session ID is still valid.
/// @synopsis boolean isRequestedSessionValid()
public Any m_isRequestedSessionValid()
{
return _request.isRequestedSessionIdValid() ? TRUE : FALSE;
}
public static final anvil.script.compiler.NativeClass __class__ =
new anvil.script.compiler.NativeClass("Request", AnyRequest.class,
//DOC{{
""+
"\n" +
" @class Request\n" +
" The HTTP request from the client terminal/browser.\n" +
" <p>\n" +
" All request parameters (URL parameters and FORM parameters)\n" +
" appear as request's fields. For example, if the query string\n" +
" contains \"a=1&b=2\", there will be two fields available in\n" +
" the request: <i>request.a</i> and <i>request.b</i>\n" +
" </p>\n" +
"\n" +
" <p>\n" +
" If parameter names contains \"keys\" enclosed into angle brackets \n" +
" corresponding array structures are created onto request. For example:\n" +
" <pre>\n" +
" <input type=\"person[name]\" value=\"john doe\">\n" +
" <input type=\"person[age]\" value=\"50\">\n" +
" </pre>\n" +
" When submitted will yield to attribute person to request\n" +
" with value <code>[\"name\"=>\"john doe\", \"age\"=>\"50\"]</code>.\n" +
" </p>\n" +
"\n" +
" <p>\n" +
" Handles also file uploads. For example:\n" +
" <pre>\n" +
" <form method=\"post\" ENCTYPE=\"multipart/form-data\">\n" +
" <input type=\"file\" name=\"file1\">\n" +
" </form>\n" +
" </pre>\n" +
" Here the <i>request.file1</i> field will contain a\n" +
" File datatype, which represents an uploaded file.\n" +
" </p>\n" +
" @attribute parameter\n" +
" Parameter from request. For ordinary parameters\n" +
" string is returned, for uploads anvil.io.File is returned\n" +
" and for parameters containing list of angle bracketed keys\n" +
" an array is returned.\n" +
" @synopsis object <i>request</i>.<i>parameter</i>\n" +
" @reference \"object <i>request</i>[<i>parameter</i>]\"\n" +
" Parameter from request. For ordinary parameters\n" +
" string is returned, for uploads anvil.io.File is returned\n" +
" and for parameters containing list of angle bracketed keys\n" +
" an array is returned.\n" +
" @method getAuthType\n" +
" Returns the name of the authentication scheme.\n" +
" Used to protect the \"site servlet\", for example, \"BASIC\" or \"SSL,\" \n" +
" or null if the servlet was not protected.\n" +
" @synopsis string getAuthType()\n" +
" @return the name of the authentication scheme\n" +
" @method getContentLength\n" +
" Returns the length, in bytes, of the request body and\n" +
" made available by the input stream, or -1 if the length is not\n" +
" known.\n" +
" @synopsis string getContentLength()\n" +
" @return content length\n" +
" @method getContentType\n" +
" Returns the MIME type of the body of the request, or\n" +
" null if the type is not known.\n" +
" @synopsis string getContentType()\n" +
" @return content type\n" +
" @method getHeaderNames\n" +
" Returns an array of all the header names this request contains.\n" +
" @synopsis array getHeaderNames()\n" +
" @return header names\n" +
" @method getHeader\n" +
" Returns the value of the specified request header as a string.\n" +
" If the request did not include a header of the specified name,\n" +
" this method returns null. The header name is case insensitive.\n" +
" Some useful headers for detecting the client type are\n" +
" \"User-Agent\" and \"Accept\".\n" +
" @synopsis string getHeader(string headerName)\n" +
" @param headerName header name\n" +
" @return header\n" +
" @method getMethod\n" +
" Returns the name of the HTTP method with which this\n" +
" request was made, for example, GET, POST, or PUT.\n" +
" @synopsis string getMethod()\n" +
" @return the HTTP method\n" +
" @method getPathInfo\n" +
" Returns any extra path information associated with the\n" +
" URL the client sent when it made this request.\n" +
" @synopsis string getPathInfo()\n" +
" @return path info\n" +
" @method getQueryString\n" +
" Returns the query string that is contained in the request\n" +
" URL after the path.\n" +
" @synopsis string getQueryString()\n" +
" @return query string\n" +
" @method getRemoteUser\n" +
" Returns the login of the user making this request, if the\n" +
" user has been authenticated, or null if the user has not been\n" +
" authenticated.\n" +
" @synopsis string getRemoteUser()\n" +
" @return remote user\n" +
" @method getRequestURI \n" +
" Returns the part of this request's URL from the\n" +
" protocol name up to the query string in the first line of the\n" +
" HTTP request.\n" +
" @synopsis string getRequestURI()\n" +
" @return request URI\n" +
" @method getServletPath\n" +
" Returns the part of this request's URL that calls the servlet.\n" +
" @synopsis string getServletPath()\n" +
" @return servlet path\n" +
" @method getRemoteAddr \n" +
" Returns the Internet Protocol (IP) address of the client that sent the request.\n" +
" @synopsis string getRemoteAddr()\n" +
" @return remote address\n" +
" @method getRemoteHost \n" +
" Returns the fully qualified name of the client that sent\n" +
" the request, or the IP address of the client if the name cannot\n" +
" be determined.\n" +
" @synopsis string getRemoteHost()\n" +
" @return remote host\n" +
" @method getServerName \n" +
" Returns the host name of the server that received the request.\n" +
" @synopsis string getServerName()\n" +
" @return server name\n" +
" @method getServerPort \n" +
" Returns the port number on which this request was received.\n" +
" @synopsis string getServerPort()\n" +
" @return server port\n" +
" @method getProtocol \n" +
" Returns the name and version of the protocol the request\n" +
" uses in the form protocol/majorVersion.minorVersion, for\n" +
" example, HTTP/1.1.\n" +
" @synopsis string getProtocol()\n" +
" @return protocol\n" +
" @method getCookies\n" +
" Returns list containing all cookies that browser \n" +
" sent with this request.\n" +
" @synopsis list getCookies()\n" +
" @method getSession\n" +
" Returns the current session associated with this request.\n" +
" Session returned by this method is independent from \n" +
" Anvil's session handling mechanism as it is provided\n" +
" by enclosing servlet container.\n" +
" @synopsis Session getSession()\n" +
" @synopsis Session getSession(boolean create)\n" +
" @param create If true and there is no session, returns a new session\n" +
" @method getRequestedSessionId\n" +
" Returns the session ID specified by the client.\n" +
" @synopsis string getRequestedSessionId()\n" +
" @method isRequestedSessionIdFromCookie\n" +
" Checks whether the requested session ID came in as a cookie.\n" +
" @synopsis boolean isRequestSessionIdFromCookie()\n" +
" @method isRequestedSessionIdFromURL\n" +
" Checks whether the requested session ID came in as part of the request URL.\n" +
" @synopsis boolean isRequestedSessionIdFromURL()\n" +
" @method isRequestedSessionValid\n" +
" Checks whether the requested session ID is still valid.\n" +
" @synopsis boolean isRequestedSessionValid()\n"
//}}DOC
);
static {
NetModule.class.getName();
}
}