There is a bug in WO 5.4 with how HTTP headers are handled when
deployed in a servlet container. I reported this (5711936) and it has
been marked as resolved in 'the latest seed release of Xcode 3.1,
Developer preview 2. So perhaps this is the bug you are running in to.
Here's how it manifested itself to me:
When WebObjects applications are deployed in servlet containers, the
WebObjects application does not receive requests or generate
responses directly. Instead, the WOServletAdaptor sits in between
the WebObjects application and the servlet container. All requests
and responses are sent to the servlet container, which then
dispatches them to the WOServletAdaptor, which dispatches them to
the underlying WebObjects application. Responses are handled in the
same way, but in the opposite direction.
A bug exists in how the WOServletAdaptor and the WOMessage and
WORequest classes handle HTTP headers. It seems that WOMessage and
WORequest expect all headers to be lower-case - and that the
WOServletAdaptor does not make sure all headers are lower-case.
This results in posts from a form whose enctype is "multipart/form-
data" failing to update any of the variables bound to form fields.
Steps to Reproduce:
1. Create a new WebObjects project
2. Modify the main component as follows:
HTML:
<wo:WOForm>
<wo:WOTextField value =
"[message]"></wo:WOTextField>
<wo:WOSubmitButton action =
"[sayHello]"></wo:WOSubmitButton>
</wo:WOForm>
<wo:WOForm enctype = "multipart/form-data">
<wo:WOTextField value =
"[message]"></wo:WOTextField>
<wo:WOSubmitButton action =
"[sayHello]"></wo:WOSubmitButton>
</wo:WOForm>
<wo:WOString value = "[message]"></wo:WOString>
Java:
public String message;
public Main(WOContext context) {
super(context);
}
public WOComponent sayHello() {
message = "hello, " + message + "!";
NSDictionary headers = this.context().request().headers();
for(int i=0;i<headers.allKeys().count();i++) {
String header = (String)
headers.allKeys().objectAtIndex(i);
System.out.println(header + ": ");
System.out.println(headers.valueForKey(header));
System.out.println(this.context().request().headerForKey(header));
}
return(this);
}
3. Build the application as both a .woa and a .war
4. Deploy the applications.
Expected Results:
Type something in the forms and click on sumbit. Both forms should
behave in the same way and you should see "hello, " plus whatever
you typed.
The console should show all the headers with the values repeated.
Actual Results:
When a WebObjects application is deployed in a servlet container,
the following rather strange situation occurs:
When this is deployed as a .woa, it produces the following correct
output:
<snip>
content-type:
( multipart/form-data; boundary=----
WebKitFormBoundaryZdrwLAre6TArzAid )
multipart/form-data; boundary=----WebKitFormBoundaryZdrwLAre6TArzAid
</snip>
But when it is run in a servlet container, it produces the
following, obviously incorrect output:
<snip>
Content-Type:
( multipart/form-data; boundary=----
WebKitFormBoundaryonU48QK5I46+pA1T )
null
</snip>
A problem exists because the valueForHeader() method in WOMessage
assumes all headers are lower-case, so when WORequest attempts to
determine if the request isMultipartFormData(), it does so by asking
for the contentType() - which results in a call to valueForHeader(),
which in turn calls the get() method of the underlying TreeMap of
_httpHeaders, but mistakenly does so with a lower-case version of
the key:
(List)_httpHeaders.get(aKey.toString().toLowerCase())
The result of all of this is that if you specify the "enctype" of
your form as "multipart/form-data" none of the bindings for your
form will get values.
Whilst this is reported as fixed, I'm still using a work-around in my
app (as I haven't upgraded it to a fixed version of WO yet) - so if
this is the bug you're encountering, the work-around might help you too.
I wrote a subclass of WOServletAdaptor that converts all the header
keys to lowercase before calling 'super'. You just need to include
this class in your project and modify the web.xml that is created to
reference your WOServletAdaptor subclass instead of the default one.
MyServletAdaptor.java:
package au.id.jmacmullin;
import java.io.IOException;
import javax.servlet.ServletException;
import com.webobjects.jspservlet.WOServletAdaptor;
public class MyServletAdaptor extends WOServletAdaptor {
public MyServletAdaptor() throws ServletException {
super();
}
// over-rides the default implementation to first convert all the
header keys to lower-case, before calling super
public void doPost(javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response) throws
IOException, javax.servlet.ServletException {
LowercaseHeaderKeysWrapper requestWrapper = new
LowercaseHeaderKeysWrapper(request);
super.doPost(requestWrapper, response);
}
}
LowercaseHeaderKeysWrapper.java:
package au.id.jmacmullin;
import java.util.Enumeration;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class LowercaseHeaderKeysWrapper extends
HttpServletRequestWrapper {
public LowercaseHeaderKeysWrapper(HttpServletRequest request) {
super(request);
}
public Enumeration getHeaderNames() {
Vector headerNames = new Vector();
Enumeration existingNames = super.getHeaderNames();
while(existingNames.hasMoreElements()) {
headerNames.add(((String)
existingNames.nextElement()).toLowerCase());
}
return(headerNames.elements());
}
public Enumeration getHeaders(String name) {
Enumeration returnVals;
// try and find a header with the exact name
Enumeration existingHeaders = super.getHeaders(name);
if(existingHeaders!=null && existingHeaders.hasMoreElements()) {
returnVals = existingHeaders;
} else {
StringBuilder sb = new StringBuilder();
// try and find a header with different capitalisation
String[] words = name.split("-");
for(int i=0;i<words.length;i++) {
sb.append(words[i].substring(0,
1).toUpperCase());
sb.append(words[i].substring(1));
if(i<words.length-1) {
sb.append("-");
}
}
String camelCaseHeaderKey = sb.toString();
returnVals = super.getHeaders(camelCaseHeaderKey);
}
return(returnVals);
}
}
web.xml:
...
<!-- The WebObjects Servlet that interfaces between the Servlet
container
world and the WebObjects world. -->
<servlet>
<servlet-name>MyServletAdaptor</servlet-name>
<servlet-class>au.id.jmacmullin.MyServletAdaptor</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
...
Hope this helps,
Jake
On 31/10/2008, at 8:11 AM, Chuck Hill wrote:
On Oct 30, 2008, at 12:30 PM, William Hatch wrote:
5.4.3, using a pretty recent Wonder build. Deployed under either
tomcat or as regular .woa, development in Eclipse....
Nothing happens when I click "Upload".
Meaning no request to the server? A request to the server but no
data sent? Data is sent but the component does not see it?
Something else?
I came across a thread by Mike discussing the perils of not binding
filePath along with data, and that's not the case here; both are
bound, although filePath is completely not used. This same exact
component worked fine in 5.3. I also came across some other scary
posts regarding encoding, and one regarding WOServeletAdaptor
issues with WOFileUpload under 5.4 So what's the new new trick for
getting this to fly again?
I don't recall having problems with uploads moving an app from 5.3.3
to 5.4.3.
Chuck
--
Chuck Hill Senior Consultant / VP Development
Practical WebObjects - for developers who want to increase their
overall knowledge of WebObjects or who are trying to solve specific
problems.
http://www.global-village.net/products/practical_webobjects
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list ([email protected])
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/webobjects-dev/jmacmullin%40mac.com
This email sent to [EMAIL PROTECTED]
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list ([email protected])
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com
This email sent to [EMAIL PROTECTED]