简体   繁体   中英

Docker API returns 200 OK then 400 BAD REQUEST

I am writing an API client for Docker. I understood from the documentation that the API is Restful/HTTP, yet if you connect to the local daemon you have to do it over the exposed unix socket .

It all seems to work, I open a socket, send an HTTP request (which respects the specification ), I receive the expected response, but also a 400 BAD REQUEST response follows immediately.

Here is the request:

GET /info HTTP/1.1
Host: localhost
Accept: application/json

And here is what I get:

HTTP/1.1 200 OK
Api-Version: 1.30
Content-Type: application/json
Docker-Experimental: false
Ostype: linux
Server: Docker/17.06.1-ce (linux)
Date: Thu, 01 Feb 2018 18:53:18 GMT
Transfer-Encoding: chunked

892
{"ID":"6MGE:35TO:BI..." ...}

0

HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close

400 Bad Request

First, I figured that there is a bug on my side and I am somehow sending 2 requests, but I enabled debugging and followed the logs with sudo journalctl -fu docker.service and there is exactly one request received... at least one is logged, the GET /info . I've also debugged the code and 1 single request is sent.

Any hint is greatly appreciated!

Edit: here is the client's code:

        final StringBuilder hdrs = new StringBuilder();
        for(final Map.Entry<String, String> header : headers) {
            hdrs.append(header.getKey() + ": " + header.getValue())
                .append("\r\n");
        }
        final String request = String.format(
            this.template(), method, home, hdrs, this.readContent(content)
        );

        final UnixSocketChannel channel = UnixSocketChannel.open(
            new UnixSocketAddress(this.path)
        );
        final PrintWriter writer = new PrintWriter(
            Channels.newOutputStream(channel)
        );
        writer.print(request);
        writer.flush();

        final InputStreamReader reader = new InputStreamReader(
            Channels.newInputStream(channel)
        );
        CharBuffer result = CharBuffer.allocate(1024);
        reader.read(result);
        result.flip();
        System.out.println("read from server: " + result.toString());

It seems like you have an extra CRLF between headers and body.

 private String template() {
            final StringBuilder message = new StringBuilder();
            message
                .append("%s %s HTTP/1.1\r\n")
                .append("Host: localhost").append("\r\n")
                .append("%s")
                .append("\r\n").append("\r\n") //one of these is superfluous, as each header line ends with "\r\n" itself 
                .append("%s");
            return message.toString();
}

Remove one append("\\r\\n") after headers and see what happens.

Fixed. Initially, I thought the problem was with the line endings (that they should have been \\n instead of \\r\\n). Turns out, the 400 BAD REQUEST occured because the Connection: close header was missing, while the Request made was being closed right after receiving the response.

More details here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM