From 524028da3a11036be4ccd36df5abdf4b60b59c44 Mon Sep 17 00:00:00 2001 From: hns Date: Fri, 15 Jun 2007 10:58:25 +0000 Subject: [PATCH] * Major reshuffling of servlet/request code. * Implement req.cookies, req.params, req.postParams and req.queryParams collections * Improve access to parameter values as array: param_array is always available even with just one value * Implement req.getHeader(name), req.getHeaders(name), req.getIntHeader(name), req.getDateHeader(name) * Implement res.setHeader(name), res.setDateHeader(name), res.addHeader(name), res.addDateHeader(name) --- src/helma/framework/RequestBean.java | 93 ++++- src/helma/framework/RequestTrans.java | 349 +++++++++++++++++-- src/helma/framework/ResponseBean.java | 37 ++ src/helma/framework/ResponseTrans.java | 44 +++ src/helma/servlet/AbstractServletClient.java | 241 ++++--------- 5 files changed, 550 insertions(+), 214 deletions(-) diff --git a/src/helma/framework/RequestBean.java b/src/helma/framework/RequestBean.java index f5e7c176..44ac9636 100644 --- a/src/helma/framework/RequestBean.java +++ b/src/helma/framework/RequestBean.java @@ -82,59 +82,114 @@ public class RequestBean implements Serializable { } /** - * - * - * @return ... + * Proxy to HttpServletRequest.getHeader(). + * @param name the header name + * @return the header value, or null + */ + public String getHeader(String name) { + return req.getHeader(name); + } + + /** + * Proxy to HttpServletRequest.getHeaders(), returns header values as string array. + * @param name the header name + * @return the header values as string array + */ + public String[] getHeaders(String name) { + return req.getHeaders(name); + } + + /** + * Proxy to HttpServletRequest.getIntHeader(), fails silently by returning -1. + * @param name the header name + * @return the header parsed as integer or -1 + */ + public int getIntHeader(String name) { + return req.getIntHeader(name); + } + + /** + * Proxy to HttpServletRequest.getDateHeader(), fails silently by returning -1. + * @param name the header name + * @return the date in milliseconds, or -1 + */ + public long getDateHeader(String name) { + return req.getDateHeader(name); + } + + /** + * @return A string representation of this request */ public String toString() { return "[Request]"; } - // property related methods: + /** + * @return the invoked action + */ public String getAction() { return req.getAction(); } /** - * - * - * @return ... + * @return The req.data map containing request parameters, cookies and + * assorted HTTP headers */ public Map getData() { return req.getRequestData(); } /** - * - * - * @return ... + * @return the req.params map containing combined query and post parameters + */ + public Map getParams() { + return req.getParams(); + } + + /** + * @return the req.queryParams map containing parameters parsed from the query string + */ + public Map getQueryParams() { + return req.getQueryParams(); + } + + /** + * @return the req.postParams map containing params parsed from post data + */ + public Map getPostParams() { + return req.getPostParams(); + } + + /** + * @return the req.cookies map containing request cookies + */ + public Map getCookies() { + return req.getCookies(); + } + + /** + * @return the time this request has been running, in milliseconds */ public long getRuntime() { return (System.currentTimeMillis() - req.getStartTime()); } /** - * - * - * @return ... + * @return the password if using HTTP basic authentication */ public String getPassword() { return req.getPassword(); } /** - * - * - * @return ... + * @return the request path */ public String getPath() { return req.getPath(); } /** - * - * - * @return ... + * @return the username if using HTTP basic authentication */ public String getUsername() { return req.getUsername(); diff --git a/src/helma/framework/RequestTrans.java b/src/helma/framework/RequestTrans.java index ea7910d9..b74024de 100644 --- a/src/helma/framework/RequestTrans.java +++ b/src/helma/framework/RequestTrans.java @@ -18,9 +18,11 @@ package helma.framework; import helma.util.Base64; import helma.util.SystemMap; +import helma.util.StringUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.Cookie; import java.io.*; import java.util.*; import java.util.regex.Pattern; @@ -58,7 +60,9 @@ public class RequestTrans implements Serializable { private String session; // the map of form and cookie data - private final Map values = new SystemMap(); + private final Map values = new DataComboMap(); + + private Map params, queryParams, postParams, cookies; // the HTTP request method private String method; @@ -100,6 +104,51 @@ public class RequestTrans implements Serializable { this.response = response; this.path = path; startTime = System.currentTimeMillis(); + + // do standard HTTP variables + String header = request.getHeader("Host"); + if (header != null) { + values.put("http_host", header.toLowerCase()); + } + + header = request.getHeader("Referer"); + if (header != null) { + values.put("http_referer", header); + } + + try { + long ifModifiedSince = request.getDateHeader("If-Modified-Since"); + if (ifModifiedSince > -1) { + setIfModifiedSince(ifModifiedSince); + } + } catch (IllegalArgumentException ignore) { + // not a date header + } + + header = request.getHeader("If-None-Match"); + if (header != null) { + setETags(header); + } + + header = request.getRemoteAddr(); + if (header != null) { + values.put("http_remotehost", header); + } + + header = request.getHeader("User-Agent"); + if (header != null) { + values.put("http_browser", header); + } + + header = request.getHeader("Accept-Language"); + if (header != null) { + values.put("http_language", header); + } + + header = request.getHeader("authorization"); + if (header != null) { + values.put("authorization", header); + } } /** @@ -122,41 +171,96 @@ public class RequestTrans implements Serializable { return XMLRPC.equals(method); } + /** + * Set a cookie + * @param name the cookie name + * @param cookie the cookie + */ + public void setCookie(String name, Cookie cookie) { + if (cookies == null) { + cookies = new ParameterMap(); + } + cookies.put(name, cookie); + } + + /** + * @return a map containing the cookies sent with this request + */ + public Map getCookies() { + if (cookies == null) { + cookies = new ParameterMap(); + } + return cookies; + } + + /** + * @return the combined query and post parameters for this request + */ + public Map getParams() { + if (params == null) { + params = new ParamComboMap(); + } + return params; + } + + /** + * @return get the query parameters for this request + */ + public Map getQueryParams() { + if (queryParams == null) { + queryParams = new ParameterMap(); + } + return queryParams; + } + + /** + * @return get the post parameters for this request + */ + public Map getPostParams() { + if (postParams == null) { + postParams = new ParameterMap(); + } + return postParams; + } + + /** + * set the request parameters + */ + public void setParameters(Map parameters, boolean isPost) { + if (isPost) { + postParams = new ParameterMap(parameters); + } else { + queryParams = new ParameterMap(parameters); + } + } + + /** + * Add a post parameter to the request + * @param name the parameter name + * @param value the parameter value + */ + public void addPostParam(String name, Object value) { + if (postParams == null) { + postParams = new ParameterMap(); + } + Object previous = postParams.get(name); + if (previous instanceof Object[]) { + Object[] array = (Object[]) previous; + Object[] values = new Object[array.length + 1]; + System.arraycopy(array, 0, values, 0, array.length); + values[array.length] = value; + postParams.put(name, values); + } else if (previous == null) { + postParams.put(name, new Object[] {value}); + } + } + /** * Set a parameter value in this request transmitter. This * parses foo[bar][baz] as nested objects/maps. */ public void set(String name, Object value) { - int bracket = name.indexOf('['); - Object previousValue; - if (bracket > -1 && name.endsWith("]")) { - Matcher m = paramPattern.matcher(name); - String partName = name.substring(0, bracket); - Map map = values; - while (m.find()) { - previousValue = map.get(partName); - Map partMap; - if (previousValue == null) { - partMap = new SystemMap(); - map.put(partName, partMap); - } else if (previousValue instanceof Map) { - partMap = (Map) previousValue; - } else { - throw new RuntimeException("Conflicting HTTP Parameters for '" + name + "'"); - } - partName = m.group(1); - map = partMap; - } - previousValue = map.put(partName, value); - if (previousValue != null && - (!(previousValue instanceof Object[]) || ! partName.endsWith("_array"))) - throw new RuntimeException("Conflicting HTTP Parameters for '" + name + "'"); - } else { - previousValue = values.put(name, value); - if (previousValue != null && - (!(previousValue instanceof Object[]) || !name.endsWith("_array"))) - throw new RuntimeException("Conflicting HTTP Parameters for '" + name + "'"); - } + values.put(name, value); } /** @@ -185,6 +289,51 @@ public class RequestTrans implements Serializable { return request; } + /** + * Proxy to HttpServletRequest.getHeader(). + * @param name the header name + * @return the header value, or null + */ + public String getHeader(String name) { + return request == null ? null : request.getHeader(name); + } + + /** + * Proxy to HttpServletRequest.getHeaders(), returns header values as string array. + * @param name the header name + * @return the header values as string array + */ + public String[] getHeaders(String name) { + return request == null ? + null : StringUtils.collect(request.getHeaders(name)); + } + + /** + * Proxy to HttpServletRequest.getIntHeader(), fails silently by returning -1. + * @param name the header name + * @return the header parsed as integer or -1 + */ + public int getIntHeader(String name) { + try { + return request == null ? -1 : getIntHeader(name); + } catch (NumberFormatException nfe) { + return -1; + } + } + + /** + * Proxy to HttpServletRequest.getDateHeader(), fails silently by returning -1. + * @param name the header name + * @return the date in milliseconds, or -1 + */ + public long getDateHeader(String name) { + try { + return request == null ? -1 : getDateHeader(name); + } catch (NumberFormatException nfe) { + return -1; + } + } + /** * Returns the Servlet response for this request. * Returns null for internal and XML-RPC requests. @@ -425,4 +574,142 @@ public class RequestTrans implements Serializable { httpPassword = null; } } + + class ParameterMap extends SystemMap { + + public ParameterMap() { + super(); + } + + public ParameterMap(Map map) { + super((int) (map.size() / 0.75f) + 1); + for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) { + Map.Entry e = (Map.Entry) i.next(); + put(e.getKey(), e.getValue()); + } + } + + public Object put(Object key, Object value) { + if (key instanceof String) { + String name = (String) key; + int bracket = name.indexOf('['); + if (bracket > -1 && name.endsWith("]")) { + Matcher matcher = paramPattern.matcher(name); + String partName = name.substring(0, bracket); + return putInternal(partName, matcher, value); + } + } + Object previous = super.get(key); + if (previous != null && (!(previous instanceof Object[]) || !(value instanceof Object[]))) + throw new RuntimeException("Conflicting HTTP Parameters for '" + key + "'"); + return super.put(key, value); + } + + private Object putInternal(String name, Matcher matcher, Object value) { + Object previous = super.get(name); + if (matcher.find()) { + ParameterMap map = null; + if (previous instanceof ParameterMap) { + map = (ParameterMap) previous; + } else if (previous == null) { + map = new ParameterMap(); + super.put(name, map); + } else { + throw new RuntimeException("Conflicting HTTP Parameters for '" + name + "'"); + } + String partName = matcher.group(1); + return map.putInternal(partName, matcher, value); + } + if (previous != null && (!(previous instanceof Object[]) || !(value instanceof Object[]))) + throw new RuntimeException("Conflicting HTTP Parameters for '" + name + "'"); + return super.put(name, value); + } + + public Object get(Object key) { + if (key instanceof String) { + Object value = super.get(key); + String name = (String) key; + if (name.endsWith("_array") && value == null) { + value = super.get(name.substring(0, name.length() - 6)); + return value instanceof Object[] ? value : null; + } else if (name.endsWith("_cookie") && value == null) { + System.err.println(" *** *** *** " + name.substring(0, name.length() - 7)); + value = super.get(name.substring(0, name.length() - 7)); + return value instanceof Cookie ? value : null; + } else if (value instanceof Object[]) { + Object[] values = ((Object[]) value); + return values.length > 0 ? values[0] : null; + } else if (value instanceof Cookie) { + Cookie cookie = (Cookie) value; + return cookie.getValue(); + } + } + return super.get(key); + } + } + + class DataComboMap extends SystemMap { + + public Object get(Object key) { + Object value = super.get(key); + if (value != null) + return value; + if (postParams != null && (value = postParams.get(key)) != null) + return value; + if (queryParams != null && (value = queryParams.get(key)) != null) + return value; + if (cookies != null && (value = cookies.get(key)) != null) + return value; + return null; + } + + public boolean containsKey(Object key) { + return get(key) != null; + } + + public Set entrySet() { + Set entries = new HashSet(super.entrySet()); + if (postParams != null) entries.addAll(postParams.entrySet()); + if (queryParams != null) entries.addAll(queryParams.entrySet()); + if (cookies != null) entries.addAll(cookies.entrySet()); + return entries; + } + + public Set keySet() { + Set keys = new HashSet(super.keySet()); + if (postParams != null) keys.addAll(postParams.keySet()); + if (queryParams != null) keys.addAll(queryParams.keySet()); + if (cookies != null) keys.addAll(cookies.keySet()); + return keys; + } + } + + class ParamComboMap extends SystemMap { + public Object get(Object key) { + Object value; + if (postParams != null && (value = postParams.get(key)) != null) + return value; + if (queryParams != null && (value = queryParams.get(key)) != null) + return value; + return null; + } + + public boolean containsKey(Object key) { + return get(key) != null; + } + + public Set entrySet() { + Set entries = new HashSet(); + if (postParams != null) entries.addAll(postParams.entrySet()); + if (queryParams != null) entries.addAll(queryParams.entrySet()); + return entries; + } + + public Set keySet() { + Set keys = new HashSet(); + if (postParams != null) keys.addAll(postParams.keySet()); + if (queryParams != null) keys.addAll(queryParams.keySet()); + return keys; + } + } } diff --git a/src/helma/framework/ResponseBean.java b/src/helma/framework/ResponseBean.java index 6939902c..e961c407 100644 --- a/src/helma/framework/ResponseBean.java +++ b/src/helma/framework/ResponseBean.java @@ -296,6 +296,43 @@ public class ResponseBean implements Serializable { res.setContentType(contentType); } + /** + * Proxy to HttpServletResponse.addHeader() + * @param name the header name + * @param value the header value + */ + public void addHeader(String name, String value) { + res.addHeader(name, value); + } + + /** + * Proxy to HttpServletResponse.addDateHeader() + * @param name the header name + * @param value the header value + */ + public void addDateHeader(String name, Date value) { + res.addDateHeader(name, value); + } + + /** + * Proxy to HttpServletResponse.setHeader() + * @param name the header name + * @param value the header value + */ + public void setHeader(String name, String value) { + res.setHeader(name, value); + } + + /** + * Proxy to HttpServletResponse.setDateHeader() + * @param name the header name + * @param value the header value + */ + public void setDateHeader(String name, Date value) { + res.setDateHeader(name, value); + } + + /** * Get the data map for the response * diff --git a/src/helma/framework/ResponseTrans.java b/src/helma/framework/ResponseTrans.java index 64c0bc00..687a7e7b 100644 --- a/src/helma/framework/ResponseTrans.java +++ b/src/helma/framework/ResponseTrans.java @@ -484,6 +484,50 @@ public final class ResponseTrans extends Writer implements Serializable { response = what; } + /** + * Proxy to HttpServletResponse.addHeader() + * @param name the header name + * @param value the header value + */ + public void addHeader(String name, String value) { + HttpServletResponse res = getServletResponse(); + if (res != null) + res.addHeader(name, value); + } + + /** + * Proxy to HttpServletResponse.addDateHeader() + * @param name the header name + * @param value the header value + */ + public void addDateHeader(String name, Date value) { + HttpServletResponse res = getServletResponse(); + if (res != null) + res.addDateHeader(name, value.getTime()); + } + + /** + * Proxy to HttpServletResponse.setHeader() + * @param name the header name + * @param value the header value + */ + public void setHeader(String name, String value) { + HttpServletResponse res = getServletResponse(); + if (res != null) + res.setHeader(name, value); + } + + /** + * Proxy to HttpServletResponse.setDateHeader() + * @param name the header name + * @param value the header value + */ + public void setDateHeader(String name, Date value) { + HttpServletResponse res = getServletResponse(); + if (res != null) + res.setDateHeader(name, value.getTime()); + } + /** * Write a vanilla error report. Callers should make sure the ResponeTrans is * new or has been reset. diff --git a/src/helma/servlet/AbstractServletClient.java b/src/helma/servlet/AbstractServletClient.java index 101aaafd..022781ca 100644 --- a/src/helma/servlet/AbstractServletClient.java +++ b/src/helma/servlet/AbstractServletClient.java @@ -27,11 +27,8 @@ import java.util.*; import javax.servlet.*; import javax.servlet.http.*; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.FileUpload; -import org.apache.commons.fileupload.ProgressListener; +import org.apache.commons.fileupload.*; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload.servlet.ServletRequestContext; @@ -162,55 +159,20 @@ public abstract class AbstractServletClient extends HttpServlet { Cookie[] reqCookies = request.getCookies(); if (reqCookies != null) { - for (int i = 0; i < reqCookies.length; i++) + for (int i = 0; i < reqCookies.length; i++) { try { // get Cookies - String nextKey = reqCookies[i].getName(); - String nextPart = reqCookies[i].getValue(); + String key = reqCookies[i].getName(); - if (sessionCookieName.equals(nextKey)) { - reqtrans.setSession(nextPart); + if (sessionCookieName.equals(key)) { + reqtrans.setSession(reqCookies[i].getValue()); } else { - reqtrans.set(nextKey, nextPart); + reqtrans.setCookie(key, reqCookies[i]); } } catch (Exception badCookie) { - // ignore + log("Error setting cookie", badCookie); } - } - - // do standard HTTP variables - String host = request.getHeader("Host"); - - if (host != null) { - host = host.toLowerCase(); - reqtrans.set("http_host", host); - } - - String referer = request.getHeader("Referer"); - - if (referer != null) { - reqtrans.set("http_referer", referer); - } - - try { - long ifModifiedSince = request.getDateHeader("If-Modified-Since"); - - if (ifModifiedSince > -1) { - reqtrans.setIfModifiedSince(ifModifiedSince); } - } catch (IllegalArgumentException ignore) { - } - - String ifNoneMatch = request.getHeader("If-None-Match"); - - if (ifNoneMatch != null) { - reqtrans.setETags(ifNoneMatch); - } - - String remotehost = request.getRemoteAddr(); - - if (remotehost != null) { - reqtrans.set("http_remotehost", remotehost); } // get the cookie domain to use for this response, if any. @@ -222,11 +184,11 @@ public abstract class AbstractServletClient extends HttpServlet { // check for x-forwarded-for header, fix for bug 443 String proxiedHost = request.getHeader("x-forwarded-host"); if (proxiedHost != null) { - if (proxiedHost.toLowerCase().indexOf(cookieDomain) == -1) { + if (proxiedHost.toLowerCase().indexOf(resCookieDomain) == -1) { resCookieDomain = null; } } else if ((host != null) && - host.toLowerCase().indexOf(cookieDomain) == -1) { + host.toLowerCase().indexOf(resCookieDomain) == -1) { resCookieDomain = null; } } @@ -234,93 +196,23 @@ public abstract class AbstractServletClient extends HttpServlet { // check if session cookie is present and valid, creating it if not. checkSessionCookie(request, response, reqtrans, resCookieDomain); - String browser = request.getHeader("User-Agent"); - - if (browser != null) { - reqtrans.set("http_browser", browser); - } - - String language = request.getHeader("Accept-Language"); - - if (language != null) { - reqtrans.set("http_language", language); - } - - String authorization = request.getHeader("authorization"); - - if (authorization != null) { - reqtrans.set("authorization", authorization); - } - // read and set http parameters - Map parameters = parseParameters(request, encoding); - - if (parameters != null) { - for (Iterator i = parameters.entrySet().iterator(); i.hasNext();) { - Map.Entry entry = (Map.Entry) i.next(); - String key = (String) entry.getKey(); - String[] values = (String[]) entry.getValue(); - - if ((values != null) && (values.length > 0)) { - // set to single string value - reqtrans.set(key, values[0]); - - if (values.length > 1) { - // set string array - reqtrans.set(key + "_array", values); - } - } - } - } + parseParameters(request, reqtrans, encoding); + // read file uploads List uploads = null; ServletRequestContext reqcx = new ServletRequestContext(request); if (ServletFileUpload.isMultipartContent(reqcx)) { // get session for upload progress monitoring - final UploadStatus uploadStatus = getApplication().getUploadStatus(reqtrans); + UploadStatus uploadStatus = getApplication().getUploadStatus(reqtrans); try { - // handle file upload - DiskFileItemFactory factory = new DiskFileItemFactory(); - FileUpload upload = new FileUpload(factory); - // use upload limit for individual file size, but also set a limit on overall size - upload.setFileSizeMax(uploadLimit * 1024); - upload.setSizeMax(totalUploadLimit * 1024); - - // register upload tracker with user's session - if (uploadStatus != null) { - upload.setProgressListener(new ProgressListener() { - public void update(long bytesRead, long contentLength, int itemsRead) { - uploadStatus.update(bytesRead, contentLength, itemsRead); - } - }); - } - - uploads = upload.parseRequest(reqcx); - Iterator it = uploads.iterator(); - - while (it.hasNext()) { - FileItem item = (FileItem) it.next(); - String name = item.getFieldName(); - Object value; - // check if this is an ordinary HTML form element or a file upload - if (item.isFormField()) { - value = item.getString(encoding); - } else { - value = new MimePart(item); - } - // if multiple values exist for this name, append to _array - if (reqtrans.get(name) != null) { - appendFormValue(reqtrans, name, value); - } else { - reqtrans.set(name, value); - } - } - + uploads = parseUploads(reqcx, reqtrans, uploadStatus, encoding); } catch (Exception upx) { log("Error in file upload", upx); String message; - if (upx instanceof FileUploadBase.SizeLimitExceededException) { + boolean tooLarge = (upx instanceof FileUploadBase.SizeLimitExceededException); + if (tooLarge) { message = "File upload size exceeds limit of " + uploadLimit + " kB"; } else { message = upx.getMessage(); @@ -334,13 +226,11 @@ public abstract class AbstractServletClient extends HttpServlet { if (uploadSoftfail || uploadStatus != null) { reqtrans.set("helma_upload_error", message); - } else if (upx instanceof FileUploadBase.SizeLimitExceededException) { - sendError(response, HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, - "Error in file upload: " + message); - return; } else { - sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Error in file upload: " + message); + int errorCode = tooLarge ? + HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE: + HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + sendError(response, errorCode, "Error in file upload: " + message); return; } } @@ -412,13 +302,15 @@ public abstract class AbstractServletClient extends HttpServlet { } else { if (!hopres.isCacheable() || !caching) { // Disable caching of response. - // for HTTP 1.0 - res.setDateHeader("Expires", System.currentTimeMillis() - 10000); - res.setHeader("Pragma", "no-cache"); - - // for HTTP 1.1 - res.setHeader("Cache-Control", - "no-cache, no-store, must-revalidate, max-age=0"); + if (isOneDotOne(req.getProtocol())) { + // for HTTP 1.1 + res.setHeader("Cache-Control", + "no-cache, no-store, must-revalidate, max-age=0"); + } else { + // for HTTP 1.0 + res.setDateHeader("Expires", System.currentTimeMillis() - 10000); + res.setHeader("Pragma", "no-cache"); + } } if (hopres.getRealm() != null) { @@ -609,30 +501,6 @@ public abstract class AbstractServletClient extends HttpServlet { return false; } - /** - * Used to build the form value array when a multipart (file upload) form has - * multiple values for one form element name. - * - * @param reqtrans - * @param name - * @param value - */ - private void appendFormValue(RequestTrans reqtrans, String name, Object value) { - String arrayName = name + "_array"; - try { - Object[] values = (Object[]) reqtrans.get(arrayName); - if (values == null) { - reqtrans.set(arrayName, new Object[] {reqtrans.get(name), value}); - } else { - Object[] newValues = new Object[values.length + 1]; - System.arraycopy(values, 0, newValues, 0, values.length); - newValues[values.length] = value; - reqtrans.set(arrayName, newValues); - } - } catch (ClassCastException x) { - // name_array is defined as something else in the form - don't overwrite it - } - } /** * Check if the session cookie is set and valid for this request. @@ -726,7 +594,46 @@ public abstract class AbstractServletClient extends HttpServlet { map.put(name, newValues); } - protected Map parseParameters(HttpServletRequest request, String encoding) + protected List parseUploads(ServletRequestContext reqcx, RequestTrans reqtrans, + final UploadStatus uploadStatus, String encoding) + throws FileUploadException, UnsupportedEncodingException { + // handle file upload + DiskFileItemFactory factory = new DiskFileItemFactory(); + FileUpload upload = new FileUpload(factory); + // use upload limit for individual file size, but also set a limit on overall size + upload.setFileSizeMax(uploadLimit * 1024); + upload.setSizeMax(totalUploadLimit * 1024); + + // register upload tracker with user's session + if (uploadStatus != null) { + upload.setProgressListener(new ProgressListener() { + public void update(long bytesRead, long contentLength, int itemsRead) { + uploadStatus.update(bytesRead, contentLength, itemsRead); + } + }); + } + + List uploads = upload.parseRequest(reqcx); + Iterator it = uploads.iterator(); + + while (it.hasNext()) { + FileItem item = (FileItem) it.next(); + String name = item.getFieldName(); + Object value; + // check if this is an ordinary HTML form element or a file upload + if (item.isFormField()) { + value = item.getString(encoding); + } else { + value = new MimePart(item); + } + // if multiple values exist for this name, append to _array + reqtrans.addPostParam(name, value); + } + return uploads; + } + + protected void parseParameters(HttpServletRequest request, RequestTrans reqtrans, + String encoding) throws IOException { // check if there are any parameters before we get started String queryString = request.getQueryString(); @@ -736,7 +643,7 @@ public abstract class AbstractServletClient extends HttpServlet { && contentType.toLowerCase().startsWith("application/x-www-form-urlencoded"); if (queryString == null && !isFormPost) { - return null; + return; } HashMap parameters = new HashMap(); @@ -744,6 +651,10 @@ public abstract class AbstractServletClient extends HttpServlet { // Parse any query string parameters from the request if (queryString != null) { parseParameters(parameters, queryString.getBytes(), encoding, false); + if (!parameters.isEmpty()) { + reqtrans.setParameters(parameters, false); + parameters.clear(); + } } // Parse any posted parameters in the input stream @@ -765,9 +676,11 @@ public abstract class AbstractServletClient extends HttpServlet { // is.close(); parseParameters(parameters, buf, encoding, true); + if (!parameters.isEmpty()) { + reqtrans.setParameters(parameters, true); + parameters.clear(); + } } - - return parameters; } /**