RESOLVED FIXED 3565
Posting data via XMLHttpRequest doesn't work (wrong Content-Type)
https://bugs.webkit.org/show_bug.cgi?id=3565
Summary Posting data via XMLHttpRequest doesn't work (wrong Content-Type)
Ondra Nekola
Reported 2005-06-16 05:25:16 PDT
I have s small XML HTTP Request based webapp. It works fine in all major browsers with exception of Safari. When I go to the particular Webpage I get the "There was a problem retrieving the XML data: undefined" error message. On the server side (several servers with different versions of Jakarta Tomcat servlet container) I can read no data from the request. The key function is this one: function sendRequest(url, data, reqHolder){ if (window.XMLHttpRequest) { req = new XMLHttpRequest(); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } req.onreadystatechange = reqHolder.processRequest; req.open("POST", url, true); reqHolder.setReq(req); //req.setRequestHeader('If-Modified-Since', 'Wed, 15 Nov 1995 00:00:00 GMT'); sent = req.send(data); return req; } reqHolders look like this: function Baz(someData){ var req var toProcess = someData this.setReq = function (aReq) { req = aReq; } this.getReq = function () { return req; } ..... this.toXmlRequest = function() { result = "<foo>\n" for (i in toProcess) { result += "<bar>"+i+"</bar>\n" } result += "</foo>" return result } this.processRequest = function () { if (req && req.readyState == 4) { if (req.status == 200) { elements = req.responseXML.getElementsByTagName("blah") for (q = 0; q < elements.length; q++) { .... } } } ... } Tested in Safari 1.2.4 (v125.12) and 2.0 (412)
Attachments
proposed fix (6.06 KB, patch)
2005-12-22 05:29 PST, Alexey Proskuryakov
eric: review+
Joost de Valk (AlthA)
Comment 1 2005-06-23 10:23:25 PDT
reporter, please make a testcase, to ease confirming and testing bugfixes.
Maciej Stachowiak
Comment 2 2005-06-29 01:57:22 PDT
We need steps to reproduce that we can actually follow, in order to make progress on this bug. Either a site where we can try specific steps that fail, or a standalone test case (could use a tool like tcpflow to see if the POST data is sent or not, or a trivial PHP script or the like could be used to view the post data).
Ondra Nekola
Comment 3 2005-07-11 04:41:55 PDT
Sorry, I was on holiday, so I was not able to make the testcase. The short testcase look like this: File bug.html: <html> <head></head> <body> <script type="text/javascript"> function write(aText) { alert (aText) } function sendRequest(url, data, reqHolder){ if (window.XMLHttpRequest) { req = new XMLHttpRequest() } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP") } req.onreadystatechange = reqHolder.processRequest req.open("POST", url, true) reqHolder.setReq(req) //req.setRequestHeader('If-Modified-Since', 'Wed, 15 Nov 1995 00:00:00 GMT'); sent = req.send(data) return req } function Baz(someData){ var req var toProcess = someData this.setReq = function (aReq) { req = aReq } this.getReq = function () { return req } this.toXmlRequest = function() { result = '<?xml version="1.0"?>\n' result += "<foo>\n" for (i in toProcess) { result += "<bar>"+i+"</bar>\n" } result += "</foo>" write("I will send: " + result) return result } this.processRequest = function () { if (req && req.readyState == 4) { if (req.status == 200) { elements = req.responseXML.getElementsByTagName("bar") write ("Received: " + elements.length + " bar elements") } } } } aReqHolder = new Baz(["1", "2", "three", 4]) sendRequest("http://myserver:8080/servlet/Echo", aReqHolder.toXmlRequest(), aReqHolder) </script> </body> You can run it against any http echo server. I can't make any public for you :( If you want to create a new one as a java servlet, you can use something like this: /* * XmlrpcServlet.java * * Created on 8. &#65533;&#65533;jen 2002, 11:35 */ package gdjweb.servlet; import gdjweb.core.Core; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.misuzilla.text.Punycode; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import domains.Domain; import domains.DomainStatus; public class EchoServlet extends HttpServlet { private static final Log log = LogFactory.getLog(EchoServlet.class); ServletContext app; boolean initialised; Core core; /** Initializes the servlet. */ @Override public void init(ServletConfig config) throws ServletException { super.init(config); app = config.getServletContext(); } /** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response * @throws IOException */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) { response.setHeader("Pragma", "no-cache"); response.setContentType("text/xml"); try { InputStream is = request.getInputStream(); Writer w = response.getWriter(); int aByte; while ((aByte = is.read()) >=0) { w.write(aByte); System.out.write(aByte); } System.out.println(); System.out.flush(); w.flush(); } catch (Throwable e) { log.error("Chyba: " + e, e); } } /** Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { processRequest(request, response); } /** Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { processRequest(request, response); } /** Returns a short description of the servlet. */ @Override public String getServletInfo() { return "Echo"; } } ------------------------------------------- Testing: In other browsers (Fire Fox for example) I will see the message "I will send: <....>" In the log of the server I see the received xml and then a new browser message appears, that tells, that 4 bar elements were received. In Safari no data come to server.
Alexey Proskuryakov
Comment 4 2005-10-27 13:24:15 PDT
This test case works for me in both Safari 2.0.1/10.4.2 and ToT. Here is the captured traffic for ToT (2.0.1 is similar, but includes a weird If-Modified-Since header): POST / HTTP/1.1 Accept: */* Accept-Language: ru-ru Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/420+ (KHTML, like Gecko) Safari/412.5 Content-Type: application/x-www-form-urlencoded Content-Length: 86 Connection: keep-alive Host: server.com <?xml version="1.0"?> <foo> <bar>0</bar> <bar>1</bar> <bar>2</bar> <bar>3</bar> </foo>
Sulka Haro
Comment 5 2005-11-02 00:33:25 PST
Hi! I can confirm the bug exists, and here's data on what's wrong with Safari's behavior. Safari has two bugs related to this: 1) The Content-Type of the request is currently set to "application/x-www-form-urlencoded". All other browsers set it to "text/xml". This causes the parsing behavior of Safari's POST to be quite different from other browsers. 2) The end of line character Safari uses is different from other browsers so parsing for the POST parameters fails. For a discussion about this, see http://jira.atlassian.com/browse/JRA-8354 Please up the priority on this, if the blog post about better AJAX support was indeed true, this is one of the biggest blockers in that regard.
Alexey Proskuryakov
Comment 6 2005-11-02 03:19:14 PST
Confirming the Content-Type difference between Firefox 1.0.6 and Safari 2.0.2. It's pretty easy to work around, though: try { req.setRequestHeader('Content-Type','text/xml'); } catch (error) {}; I am not sure if the end-of-line issue in POSTed parameters is valid, but it appears to be out of scope of this bug. Here, both Firefox and Safari use LF in serialized XML.
Dylan Etkin
Comment 7 2005-11-02 14:31:38 PST
I tried setting the content type of the XMLHTTPRequest with req.setRequestHeader('Content-Type','text/xml'); but is seemed to make no difference, when I examined the Content-Type on the sent request it was still application/x-www-form-urlencoded.
Alexey Proskuryakov
Comment 8 2005-11-02 21:10:32 PST
(In reply to comment #7) Hmm, that's quite strange - worked for me in Safari 2.0.2. Actually, I have now found a hint on Wikipedia advising the same, so it must have worked before, as well.
Alexey Proskuryakov
Comment 9 2005-12-22 02:33:08 PST
(In reply to comment #7) For the workaround to work, setRequestHeader() should be called after open() (and before send()). Still a bug that needs to be fixed, of course.
Alexey Proskuryakov
Comment 10 2005-12-22 05:29:56 PST
Created attachment 5219 [details] proposed fix
Alexey Proskuryakov
Comment 11 2005-12-22 05:32:30 PST
Comment on attachment 5219 [details] proposed fix Default Content-Type to application/xml (match Firefox); encode the request body using a correct codec if a charset was specified.
Alexey Proskuryakov
Comment 12 2005-12-22 06:27:08 PST
Eric Seidel (no email)
Comment 13 2005-12-22 06:36:28 PST
Comment on attachment 5219 [details] proposed fix ap and I talked over IRC. ap noted that there could be security concerns wrt our setRequestHeader support on XMLHTTPRequest. He was able to convince me however that this patch does not introduce any additional security risk, mearly adds support for respecting content-type headers which one was already able to set. ap agreed to file additional bugs on the subject. The patch itself appeared to me to be technically sound. The FireFox bugs in question are: https://bugzilla.mozilla.org/show_bug.cgi?id=302809 https://bugzilla.mozilla.org/show_bug.cgi?id=302263 https://bugzilla.mozilla.org/show_bug.cgi?id=308484
Note You need to log in before you can comment on or make changes to this bug.