2

I am writing a server for handling http requests from a javascript annotation package (annotatorjs.org). The javascript sends an HTTP DELETE request to the server that includes the id of the object in the path, and also sends the annotation in the body of the request in a JSON object.

I've tried implementing the DELETE request both with a Java Web Services object, and a plain servlet. In both cases, when I make the request without a body, it works, but when I add a body, I get a 400 Bad Request.

Here is my servlet

@WebServlet("/api/store/delete/*")
public class AnnotatorServlet extends HttpServlet {  

    @Override protected void doDelete( HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            System.out.println("received DELETE request,requestURI="+request.getRequestURI());        
    }
} 

My curl command, without body succeeds:

curl -i -X DELETE http://localhost:8080/text/api/store/delete/555608203004e74adbf65343 HTTP/1.1 200 OK Server: GlassFish Server Open Source Edition 4.1 X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.1 Java/Oracle Corporation/1.8) Date: Tue, 19 May 2015 19:35:08 GMT Content-Length: 0

My curl command with body fails:

curl -i -X DELETE -d @test.json http://localhost:8080/text/api/store/delete/555608203004e74adbf65343 HTTP/1.1 400 Bad Request Server: GlassFish Server Open Source Edition 4.1 X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.1 Java/Oracle Corporation/1.8) Date: Tue, 19 May 2015 19:35:16 GMT Connection: close Content-Length: 0

Ellen
  • 115
  • 3
  • 13
  • For users of Annotator.js, I just wanted say that I was able to work around this issue with an option in the Store plugin, called emulateHTTP. When this option is set to true, delete and update actions are sent to the server with an HTTP POST, and a request header X-HTTP-Method-Override contains the desired action (PUT or DELETE) – Ellen May 20 '15 at 15:16

3 Answers3

3

DELETE is not supposed to have a body, just like GET.

RFC: https://www.rfc-editor.org/rfc/rfc7231#section-4.3.5

A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.

The best practice is, just don't do it.


One could argue that, this is a bug in the server. But the server could also legitimately claim that, this is a rare situation that it has the right to refuse to serve.

Community
  • 1
  • 1
ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • My code isn't generating the DELETE request, it's coming from the javascript package that I'm using (annotatorjs.org). But I see your point. I was basing my question on this http://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request, where the consensus seemed to by that it is allowed. But in your link it says that it may not be allowed depending on the server implementation. I guess my question is, is there a way to configure this behavior in Glassfish? – Ellen May 19 '15 at 20:11
  • tough luck. you can either file a bug to Glassfish to accept DELETE body; or you can file a bug to annotators.org to not send DELETE body. Or both - both parties are wrong. – ZhongYu May 19 '15 at 20:13
3

Since the DELETE method explicitly does not define a payload (RFC 7231 section 4.3.5), the relevant guideline it should be following is RFC 7230 section 3.3:

The presence of a message body in a request is signaled by a Content-Length or Transfer-Encoding header field. Request message framing is independent of method semantics, even if the method does not define any use for a message body.

The proper standards compliant behaviour for the server is to either consume and ignore the payload, or to act on it in some API specific way. That "API specific way" may be sending 400 or any other status code.

That second curl test you are using does not appear to send any JSON data to the API. When I run it just sends the test string "test.json" as the payload. So it is not clear what the server is rejecting (payload existence? or unknown payload format?).

If you can devise a test which properly demonstrates that the server is rejecting on the mere existence of payload, then you should file a bug against the server.

Community
  • 1
  • 1
  • Amos - this is unlikely a problem with curl usage; the problem was first discovered because of another client, which supposedly sends proper requests. – ZhongYu May 20 '15 at 08:51
  • An origin server needs to understand the meaning of each request. If it receives a DELETE with a body, and it has no idea what the request attempts to mean, it is not wrong to respond 400. Arguably it is safer to reject the request than to accept it sans the body. – ZhongYu May 20 '15 at 08:54
  • Of course, the servlet container, which is not the whole origin server but only a "middleman" that forwards requests to applications, is flawed if it simply rejects any DELETE with body without consulting the application. – ZhongYu May 20 '15 at 08:57
  • Amos, there was a typo in my curl command - I left out the '@' for sending a file named test.json. I fixed it in my original post. – Ellen May 20 '15 at 15:10
0

The Response for the second curl command contains Content-Length:0

I think the request made by the curl, is sending Request property of Content-Length incorrectly.

Mecon
  • 977
  • 1
  • 6
  • 17
  • Some other things to try could be: Create a Filter that accepts this URL pattern, or even a new Servlet that extends "GenericServlet" (instead of HttpServlet). – Mecon May 19 '15 at 20:30