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)
reporter, please make a testcase, to ease confirming and testing bugfixes.
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).
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. ��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.
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>
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.
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.
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.
(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.
(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.
Created attachment 5219 [details] proposed fix
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.
Concerning overriding headers via setRequestHeader, see also: 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
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