1. Invocations of the setHttpURL() method made from constructors lead to generation of a PROPFIND request with a missing body. Moreover, the "Content- Type" header is not set for that request as well. As a result, a WebdavResource constructor throws an exception: public void test() throws Exception { HttpURL url = new HttpURL("http://localhost:8080/slide/"); WebdavResource webdav = new WebdavResource(url, 1, true); } generates (Apache Tomcat/5.5.9) PROPFIND /slide/ HTTP/1.1 Content-Type: text/xml; charset=utf-8 User-Agent: Jakarta Commons-HttpClient/3.0 Host: 127.0.0.1:8081 Depth: 1 which leads to org.apache.commons.httpclient.HttpException at org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource. java:3467) at org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource. java:3423) at org.apache.webdav.lib.WebdavResource.setNamedProp(WebdavResource.java: 967) at org.apache.webdav.lib.WebdavResource.setBasicProperties(WebdavResource. java:912) at org.apache.webdav.lib.WebdavResource.setProperties(WebdavResource.java: 1894) at org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java: 1301) at org.apache.webdav.lib.WebdavResource.<init>(WebdavResource.java:275) because of HTTP/1.1 400 Bad Request: Request content missing Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=7006BD8F1AE1863B56B86D1C79276E8D; Path=/slide Content-Type: text/html;charset=utf-8 Content-Length: 1077 Date: Thu, 06 Apr 2006 08:50:30 GMT Connection: close 2. There is a typo in a constructor (there should not be "this." prefix!) public WebdavResource(HttpURL httpURL, int action, int depth, boolean followRedirects)throws HttpException, IOException { setFollowRedirects(this.followRedirects); }
The issue lies in method HttpRequestBodyMethodBase#writeRequestBody where the bytes are not properly written to the underlying ChunkedOutputStream stream when using chunked contents. The corrected method is shown below. Additionally, please also note the wrong comment in the method comment and in the class header. protected boolean writeRequestBody(HttpState state, HttpConnection conn) throws IOException, HttpException { OutputStream out = conn.getRequestOutputStream(); if (isHttp11() && (null == getRequestHeader("Content-Length"))) { out = new ChunkedOutputStream(out); } InputStream inputStream = null; if (file != null && file.exists()) { inputStream = new FileInputStream(file); } else if (url != null) { inputStream = url.openConnection().getInputStream(); } else if(data != null){ inputStream = new ByteArrayInputStream(data); } else { return true; } byte[] buffer = new byte[4096]; int nb = 0; while (true) { nb = inputStream.read(buffer); if (nb == -1) { break; } out.write(buffer, 0, nb); } if (out instanceof ChunkedOutputStream){ ((ChunkedOutputStream)out).finish(); } out.flush(); return true; }
You also need to override the inherited method #addRequestHeaders otherwise there is no Content-Length nor Transfer-Encoding header, and some server does not like that. /** * Overrides the inherited method to add a header "Transfer-Encoding: * chunked" if the content-length has not been already set, as expected by * the method writeRequestBody. * * @see #writeRequestBody */ protected void addRequestHeaders(HttpState state, HttpConnection conn) throws IOException, HttpException { super.addRequestHeaders(state, conn); if (isHttp11() && getRequestHeader("Content-Length")==null) { int len = getRequestContentLength(); if (len>=0){ setRequestHeader("Content-Length", String.valueOf(len)); } else setRequestHeader("Transfer-Encoding", "chunked"); } }
Very similar patch from the bug #35213 was applied to the trunk by antoine. *** This bug has been marked as a duplicate of 35213 ***