import ballerina/http;
import ballerina/io;endpoint http:Listener ep {
   port:7090,
   httpVersion:"2.0"
};@http:ServiceConfig {
    basePath:"/http2Service"
}
service<http:Service> http2Service bind ep { @http:ResourceConfig {
    path:"/main"
 }
 http2Resource (endpoint client, http:Request req) {    io:println("Request received");
    http:PushPromise promise1 = new;
    promise1.path = "/resource1";
    promise1.method = "POST";
    _ = client -> promise(promise1);
    http:PushPromise promise2 = new;
    promise2.path = "/resource2";
    promise2.method = "POST";
    _ = client -> promise(promise2);
    http:PushPromise promise3 = new;
    promise3.path = "/resource3";
    promise3.method = "POST";
    _ = client -> promise(promise3);
    http:Response response = new;
    json msg = {"response":{"name":"main resource"}};
    response.setJsonPayload(msg);
    _ = client -> respond(response);
    http:Response push1 = new;
    msg = {"push":{"name":"resource1"}};
    push1.setJsonPayload(msg);
    _ = client -> pushPromisedResponse(promise1, push1);    http:Response push2 = new;
    msg = {"push":{"name":"resource2"}};
    push2.setJsonPayload(msg);
    _ = client -> pushPromisedResponse(promise2, push2);    http:Response push3 = new;
    msg = {"push":{"name":"resource3"}};
    push3.setJsonPayload(msg);
    _ = client -> pushPromisedResponse(promise3, push3);
  }
}endpoint http:Client clientEP {
    targets: [
        {
            url: "http://localhost:7090"
        }
    ],
    httpVersion:"2.0"
};function main (string[] args) {    http:Request serviceReq = new;
    http:HttpFuture httpFuture = new;
    var submissionResult = clientEP -> submit("GET", "/http2Service/main", serviceReq);
    match submissionResult {
        http:HttpConnectorError err => {
            io:println("Error occurred while submitting a request");
            return;
        }
        http:HttpFuture resultantFuture => {
            httpFuture = resultantFuture;
        }
    }    http:PushPromise[] promises = [];
    int promiseCount = 0;
    boolean hasPromise = clientEP -> hasPromise(httpFuture);
    while (hasPromise) {
        http:PushPromise pushPromise = new;
        var nextPromiseResult = clientEP -> getNextPromise(httpFuture);
        match nextPromiseResult {
            http:PushPromise resultantPushPromise => {
                pushPromise = resultantPushPromise;
            }
            http:HttpConnectorError err => {
                io:println("Error occurred while fetching push promise");
                return;
            }
        }
        io:println("Received a promise for " + pushPromise.path);        if (pushPromise.path == "/resource2") {
            _ = clientEP -> rejectPromise(pushPromise);
            io:println("Push promise for resource2 rejected");
        } else {
            promises[promiseCount] = pushPromise;
            promiseCount = promiseCount + 1;
        }
        hasPromise = clientEP -> hasPromise(httpFuture);
    }    http:Response res = new;
    var result = clientEP -> getResponse(httpFuture);
    match result {
        http:Response resultantResponse => {
            res = resultantResponse;
        }
        http:HttpConnectorError err => {
            io:println("Error occurred while fetching response");
            return;
        }
    }    var responsePayload = res.getJsonPayload();
    match responsePayload {
        json resultantJsonPayload => {
            io:println("Response : " + (resultantJsonPayload.toString() but {() => ""}));
        }
        http:PayloadError err => {
            io:println("Expected response not received");
        }
    }
    foreach promise in promises {
        http:Response promisedResponse = new;
        var promisedResponseResult = clientEP -> getPromisedResponse(promise);
        match promisedResponseResult {
            http:Response resultantPromisedResponse => {
                promisedResponse = resultantPromisedResponse;
            }
            http:HttpConnectorError err => {
                io:println("Error occurred while fetching promised response");
                return;
            }
        }        var promisedPayload = promisedResponse.getJsonPayload();
        match promisedPayload {
            json promisedJsonPayload => {
                io:println("Promised resource : " + (promisedJsonPayload.toString() but {() => ""}));
            }
            http:PayloadError err => {
                io:println("Promised response not received");
            }
        }
    }
}

HTTP 2.0 Server Push

This example shows how we can send and receive HTTP/2 Server Push messages in Ballerina HTTP Connector.

import ballerina/http;
import ballerina/io;
endpoint http:Listener ep {
   port:7090,
   httpVersion:"2.0"
};

HTTP version is set to 2.0.

@http:ServiceConfig {
    basePath:"/http2Service"
}
service<http:Service> http2Service bind ep {
 @http:ResourceConfig {
    path:"/main"
 }
 http2Resource (endpoint client, http:Request req) {
    io:println("Request received");
    http:PushPromise promise1 = new;
    promise1.path = "/resource1";
    promise1.method = "POST";
    _ = client -> promise(promise1);

Send a Push Promise.

    http:PushPromise promise2 = new;
    promise2.path = "/resource2";
    promise2.method = "POST";
    _ = client -> promise(promise2);

Send another Push Promise.

    http:PushPromise promise3 = new;
    promise3.path = "/resource3";
    promise3.method = "POST";
    _ = client -> promise(promise3);

Send one more Push Promise.

    http:Response response = new;
    json msg = {"response":{"name":"main resource"}};
    response.setJsonPayload(msg);

Construct requested resource.

    _ = client -> respond(response);

Send the requested resource.

    http:Response push1 = new;
    msg = {"push":{"name":"resource1"}};
    push1.setJsonPayload(msg);

Construct promised resource1.

    _ = client -> pushPromisedResponse(promise1, push1);

Push promised resource1.

    http:Response push2 = new;
    msg = {"push":{"name":"resource2"}};
    push2.setJsonPayload(msg);
    _ = client -> pushPromisedResponse(promise2, push2);

Push promised resource2.

    http:Response push3 = new;
    msg = {"push":{"name":"resource3"}};
    push3.setJsonPayload(msg);
    _ = client -> pushPromisedResponse(promise3, push3);
  }
}

Push promised resource3.

endpoint http:Client clientEP {
    targets: [
        {
            url: "http://localhost:7090"
        }
    ],
    httpVersion:"2.0"
};

HTTP version is set to 2.0.

function main (string[] args) {
    http:Request serviceReq = new;
    http:HttpFuture httpFuture = new;
    var submissionResult = clientEP -> submit("GET", "/http2Service/main", serviceReq);
    match submissionResult {
        http:HttpConnectorError err => {
            io:println("Error occurred while submitting a request");
            return;
        }
        http:HttpFuture resultantFuture => {
            httpFuture = resultantFuture;
        }
    }

Submit a request.

    http:PushPromise[] promises = [];
    int promiseCount = 0;
    boolean hasPromise = clientEP -> hasPromise(httpFuture);
    while (hasPromise) {
        http:PushPromise pushPromise = new;

Check whether promises exists.

        var nextPromiseResult = clientEP -> getNextPromise(httpFuture);
        match nextPromiseResult {
            http:PushPromise resultantPushPromise => {
                pushPromise = resultantPushPromise;
            }
            http:HttpConnectorError err => {
                io:println("Error occurred while fetching push promise");
                return;
            }
        }
        io:println("Received a promise for " + pushPromise.path);

Get the next promise.

        if (pushPromise.path == "/resource2") {
            _ = clientEP -> rejectPromise(pushPromise);
            io:println("Push promise for resource2 rejected");
        } else {

Client is not interested of getting ‘/resource2’, So reject the promise.

            promises[promiseCount] = pushPromise;
            promiseCount = promiseCount + 1;
        }
        hasPromise = clientEP -> hasPromise(httpFuture);
    }

Store required promises.

    http:Response res = new;
    var result = clientEP -> getResponse(httpFuture);
    match result {
        http:Response resultantResponse => {
            res = resultantResponse;
        }
        http:HttpConnectorError err => {
            io:println("Error occurred while fetching response");
            return;
        }
    }

Get the requested resource.

    var responsePayload = res.getJsonPayload();
    match responsePayload {
        json resultantJsonPayload => {
            io:println("Response : " + (resultantJsonPayload.toString() but {() => ""}));
        }
        http:PayloadError err => {
            io:println("Expected response not received");
        }
    }
    foreach promise in promises {
        http:Response promisedResponse = new;
        var promisedResponseResult = clientEP -> getPromisedResponse(promise);
        match promisedResponseResult {
            http:Response resultantPromisedResponse => {
                promisedResponse = resultantPromisedResponse;
            }
            http:HttpConnectorError err => {
                io:println("Error occurred while fetching promised response");
                return;
            }
        }

Fetch required promised responses.

        var promisedPayload = promisedResponse.getJsonPayload();
        match promisedPayload {
            json promisedJsonPayload => {
                io:println("Promised resource : " + (promisedJsonPayload.toString() but {() => ""}));
            }
            http:PayloadError err => {
                io:println("Promised response not received");
            }
        }
    }
}
$ ballerina run http-2.0-server-push.bal -s
ballerina: initiating service(s) in 'http-2.0-server-push.bal'
ballerina: started HTTPS/WSS endpoint http-7090

Run the service.

$ ballerina run http-2.0-server-push.bal
Received a promise for /resource1
Received a promise for /resource2
Push promise for resource2 rejected
Received a promise for /resource3
Response : {"response":{"name":"main resource"}}
Promised resource : {"push":{"name":"resource1"}}
Promised resource : {"push":{"name":"resource3"}}

Run the main function containing ballerina client.