ejabberd icon indicating copy to clipboard operation
ejabberd copied to clipboard

Can't send REST API request when Content-Length header is missing

Open relbraun opened this issue 10 months ago • 3 comments

Environment

  • ejabberd version: 24.12
  • Erlang version: from the docker
  • OS: MAC arm64
  • Installed from: docker

Configuration (only if needed): grep -Ev '^$|^\s*#' ejabberd.yml

loglevel: 4
...

Errors from error.log/crash.log

No errors

Bug description

I am using Spring Boot application that running REST API requests to the Ejabberd service. I have just updated the Spring vertion to the latest one an I see that when I use the RestTemplate to perform the API requests, I receive the following response:

<?xml version='1.0'?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>

<head>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
</head>

<body>
    <h1>400 Bad Request</h1>
</body>

</html>

When I tried to reproduce the request in the Postman I saw the it looks like the header Content-Length is missing. A small reaserch told me the the reason this header is not being sent is that another header is sent: Transfer-Encoding: cunked. The question is how can it be solved? It looks like that the Java RestTemplate doesn't sent the header.

relbraun avatar Apr 16 '25 10:04 relbraun

I think you may be using wrong url, as i think this error is sent if we can't determine what command should be executed from url/payload.

prefiks avatar Apr 16 '25 11:04 prefiks

@prefiks thanks for your response. But, no, the request sent with the correct url (I tried to add manually a wrong Content-Length value and resent the request:

headers.setContentType(MediaType.APPLICATION_JSON);
headers.setContentLength(23);

and the response was:

"I/O error on POST request for "http://localhost:5280/api/v0/create_room_with_opts/v3/":
 too many bytes written"

For the same request without the content-length addition, the response was:

"400 Bad Request on POST request for "http://localhost:5280/api/v0/create_room_with_opts/v3/": 
"<?xml version='1.0'?>
<EOL>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<EOL>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'/></head><body>
<h1>400 Bad Request</h1></body></html>""

relbraun avatar Apr 16 '25 15:04 relbraun

ejabberd includes a minimal HTTP server with those particularities:

That HTTP server doesn't read the content length header, so you can put wrong value or no header at all:

curl -X POST \
     -H  "Content-Length: 3" \
    http://localhost:5280/api/register \
    -d '{"user": "user-3-post-bad-length", "host": "localhost", "password": "asd2"}'

POST /api/register HTTP/1.1
Host: localhost:5280
User-Agent: curl/8.5.0
Accept: */*
Content-Length: 3
Content-Type: application/x-www-form-urlencoded

{"user": "user-3-post-bad-length", "host": "localhost", "password": "asd2"}
HTTP/1.1 200 OK
Content-Length: 63
Access-Control-Allow-Headers: Content-Type, Authorization, X-Admin
Access-Control-Allow-Origin: *
Content-Type: application/json

"User user-3-post-bad-length@localhost successfully registered"

That HTTP server does NOT support content with chunked encoding:

curl -X POST \
     -H  "Content-Length: 3" \
     -H  "Transfer-Encoding: chunked" \
    http://localhost:5280/api/register \
    -d '{"user": "user-4-post-transfer", "host": "localhost", "password": "asd2"}'

POST /api/register HTTP/1.1
Host: localhost:5280
User-Agent: curl/8.5.0
Accept: */*
Content-Length: 3
Transfer-Encoding: chunked
Content-Type: application/x-www-form-urlencoded

49
{"user": "user-4-post-transfer", "host": "localhost", "password": "asd2"}
0

HTTP/1.1 400 Bad Request
Content-Length: 17
Access-Control-Allow-Headers: Content-Type, Authorization, X-Admin
Access-Control-Allow-Origin: *
Content-Type: application/json

"400 Bad Request"

You can use a GET query. Notice that the transfer-encoding header is not read. The only important topic is that the content is not chunked encoded:

curl -X GET \
     -H  "Content-Length: 3" \
     -H  "Transfer-Encoding: chunked" \
    http://localhost:5280/api/register?user=user-5-get-chunked\&host=localhost\&password=asd1

GET /api/register?user=user-5-get-chunked&host=localhost&password=asd1 HTTP/1.1
Host: localhost:5280
User-Agent: curl/8.5.0
Accept: */*
Content-Length: 3
Transfer-Encoding: chunked

HTTP/1.1 200 OK
Content-Length: 59
Access-Control-Allow-Headers: Content-Type, Authorization, X-Admin
Access-Control-Allow-Origin: *
Content-Type: application/json

"User user-5-get-chunked@localhost successfully registered"

badlop avatar Apr 23 '25 09:04 badlop