import ballerina/http;
import ballerina/log;

service / on new http:Listener(9090) {

    resource function 'default hello(http:Caller caller, http:Request request)
            returns string|http:InternalServerError|http:ExpectationFailed {
        // [Check if the client expects a 100-continue response](https://docs.central.ballerina.io/ballerina/http/latest/classes/Request#expects100Continue).
        if (request.expects100Continue()) {
            string mediaType = request.getContentType();
            if (mediaType.toLowerAscii() == "text/plain") {

                // Send a 100-continue response to the client.
                var result = caller->continue();
                if (result is error) {
                    log:printError("Error sending response", 'error = result);
                }

            // Send a 417 response to ignore the payload since content type is mismatched
            // with the expected content type.
            } else {
                http:ExpectationFailed resp = {body:"Unprocessable Entity"};
                return resp;
            }
        }

        // The client starts sending the payload once it receives the
        // 100-continue response. Retrieve the payload that is sent by the client.
        var payload = request.getTextPayload();
        if (payload is string) {
            log:printInfo(payload);
            return "Hello World!\n";
        } else {
            http:InternalServerError resp = {body:payload.message()};
            return resp;
        }
    }
}

100 Continue

Convenience functions are provided in the HTTP library for ease of use when handling 100-continue scenarios. 100-continue indicates that the server has received the request headers and the client can proceed with sending the request.

For more information on the underlying module, see the HTTP module.

import ballerina/http;
import ballerina/log;
service / on new http:Listener(9090) {
    resource function 'default hello(http:Caller caller, http:Request request)
            returns string|http:InternalServerError|http:ExpectationFailed {
        if (request.expects100Continue()) {
            string mediaType = request.getContentType();
            if (mediaType.toLowerAscii() == "text/plain") {
                var result = caller->continue();
                if (result is error) {
                    log:printError("Error sending response", 'error = result);
                }

Send a 100-continue response to the client.

            } else {
                http:ExpectationFailed resp = {body:"Unprocessable Entity"};
                return resp;
            }
        }

Send a 417 response to ignore the payload since content type is mismatched with the expected content type.

        var payload = request.getTextPayload();
        if (payload is string) {
            log:printInfo(payload);
            return "Hello World!\n";
        } else {
            http:InternalServerError resp = {body:payload.message()};
            return resp;
        }
    }
}

The client starts sending the payload once it receives the 100-continue response. Retrieve the payload that is sent by the client.

bal run http_expect_header.bal
[ballerina/http] started HTTP/WS listener 0.0.0.0:9090
time = 2021-01-21 20:31:28,347 level = INFO  module = "" message = "TEST 100 CONTINUE"
#Run the cURL command below to run the client.
curl -v -d "TEST 100 CONTINUE" http://localhost:9090/hello -H 'Expect:100-continue' -H 'Content-Type: text/plain'
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9090 (#0)
> POST /hello HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.58.0
> Accept: */*
> Expect:100-continue
> Content-Length: 17
> Content-Type: text/plain
>
< HTTP/1.1 100 Continue
< server: ballerina
< date: Tue, 22 Sep 2020 09:16:18 +0530
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< content-type: text/plain
< content-length: 13
< server: ballerina
< date: Tue, 22 Sep 2020 09:16:18 +0530
<
Hello World!
* Connection #0 to host localhost left intact
# Use the following client to invoke the service using an unsupported media type. Service is supposed to ignore
# the payload if the content type does not matched.
curl -v -d '{"TEST":"100 CONTINUE"}' http://localhost:9090/hello -H 'Expect:100-continue' -H 'Content-Type: application/json'
* Connected to localhost (127.0.0.1) port 9090 (#0)
> POST /hello HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.58.0
> Accept: */*
> Expect:100-continue
> Content-Type: application/json
> Content-Length: 25
>
< HTTP/1.1 417 Expectation Failed
< content-type: text/plain
< content-length: 20
< server: ballerina
< date: Tue, 22 Sep 2020 09:19:53 +0530
* HTTP error before end of send, stop sending
<
* Closing connection 0
Unprocessable Entity