New HTTP-related Features in Helma 1.6
In previous versions of Helma, HTTP parameters, cookies, and selected HTTP headers were all coerced into the req.data collection. Helma 1.6 introduces separate collections for various data, with req.data acting as a combinator of the varous collections to maintain backwards compatibility.
The new collections are:
- Holds parameters passed from a HTTP POST request.
- Holds parameters passed from the HTTP query string.
- Holds parameters combined from the HTTP query string and the HTTP POST request.
- Holds cookies sent by the HTTP client. Access via
req.cookies.cookienameto retrieve the cookie value as string, or
req.cookies.cookiename_cookieto retieve the javax.servlet.http.Cookie instance.
- Backwards compatible collection containing HTTP parameters, cookies, and assorted HTTP headers.
Before version 1.6, Helma only set the req.data.paramname_array array value if a parameter value actually had more than one value. With Helma 1.6, it is always possible to access parameter values as arrays, even if they only have one value. This makes handling multi-valued parameters much easier, because it is no longer necessary to handle the one-value case separately.
Helma allows HTTP parameters to be grouped into objects using a objectid[partid] syntax in the parameter name. For example, a parameter name of foo[bar] will result in a req.data.foo object being created. The actual parameter value will be available at req.data.foo.bar.
This feature can be used recursively, meaning that a parameter named foo[bar][dong] will result in req.data.foo.bar.dong.
Helma 1.6 provides the following new methods to access HTTP headers in the response and request objects:
req.getHeader(name) req.getHeaders(name) req.getIntHeader(name) req.getDateHeader(name) res.setHeader(name, value) res.setDateHeader(name, value) res.addHeader(name, value) res.addDateHeader(name, value)
File uploads in Helma 1.6 have a dramatically impoved memory footprint compared to previous versions by storing uploaded files to a temporary file rather than passing them in memory as byte arrays. With this, it is possible to handle really large files easily.
To preserve the benefit, it is necessary to take some care when dealing with file uploads. There is a new getInputStream() method in helma.util.MimePart which allows to read the content from an input stream rather than loading it into memory all at once using getContent().
To support this, the Helma Image constructor now can take an input stream as argument. The following code snippet shows how it is possible to use this feature in a way that is compatible with previous versions of Helma:
// read image from input stream if available - // otherwise pass content as byte array. var img = new Image(req.data.file.inputStream || req.data.file.content);
If the file is just saved, the MimePart.writeToFile(filename) method will try to just rename the temporary file if it is on the same physical file system as the target file. Bytes are only moved when the target file is on a different file system than the temporary file.
Helma 1.6 supports tracking of file upload progress via a user's session. Upload tracking is activated by adding a
upload_id parameter to the query string. The current upload status can be retrieved by using the
session.getUploadStatus(upload_id) method, which returns null or an instance of helma.framework.UploadStatus, whose toString() method handily returns a JSON representation of itself.
There's a demo available that includes source code.
Before Helma 1.6, there was only an uploadLimit option to allow setting the maximum allowed upload size in apps.properties. However, this applied to both combined and individual upload size, resulting in the per-file upload limit to vary with the number of file input fields per form.
Helma 1.6 introduces the totalUploadLimit property, which allows to set the combined upload size independent from the per-file size.
# upload limit per file gobi.uploadLimit = 2048 # assuming maximum of 5 upload fields per form gobi.totalUploadLimit = 10240
By default, totalUploadLimit is set equal to uploadLimit.