From 048289afc22e6fdc010d0a6d0fab7ed1af7c434c Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Tue, 30 Jul 2024 11:05:00 +0530 Subject: [PATCH 1/4] Fix path calculation for cookie --- ballerina/cookie_cookieStore.bal | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/ballerina/cookie_cookieStore.bal b/ballerina/cookie_cookieStore.bal index 156e4d610f..ce451eab87 100644 --- a/ballerina/cookie_cookieStore.bal +++ b/ballerina/cookie_cookieStore.bal @@ -16,6 +16,7 @@ import ballerina/log; import ballerina/time; +import ballerina/lang.regexp; # Represents the cookie store. # @@ -47,7 +48,7 @@ public isolated class CookieStore { return error CookieHandlingError("Number of total cookies for the domain: " + domain + " in the cookie store can not exceed the maximum amount per domain"); } - string path = requestPath; + string path = getReqPath(url, requestPath); int? index = requestPath.indexOf("?"); if index is int { path = requestPath.substring(0, index); @@ -114,7 +115,7 @@ public isolated class CookieStore { public isolated function getCookies(string url, string requestPath) returns Cookie[] { Cookie[] cookiesToReturn = []; string domain = getDomain(url); - string path = requestPath; + string path = getReqPath(url, requestPath); int? index = requestPath.indexOf("?"); if index is int { path = requestPath.substring(0,index); @@ -382,21 +383,37 @@ const string URL_TYPE_2 = "http://www."; const string URL_TYPE_3 = "http://"; const string URL_TYPE_4 = "https://"; +final regexp:RegExp SLASH_REGEX = re `/`; + // Extracts domain name from the request URL. isolated function getDomain(string url) returns string { string domain = url; if url.startsWith(URL_TYPE_1) { - domain = url.substring(URL_TYPE_1.length(), url.length()); + domain = SLASH_REGEX.split(url.substring(URL_TYPE_1.length(), url.length()))[0]; } else if url.startsWith(URL_TYPE_2) { - domain = url.substring(URL_TYPE_2.length(), url.length()); + domain = SLASH_REGEX.split(url.substring(URL_TYPE_2.length(), url.length()))[0]; } else if url.startsWith(URL_TYPE_3) { - domain = url.substring(URL_TYPE_3.length(), url.length()); + domain = SLASH_REGEX.split(url.substring(URL_TYPE_3.length(), url.length()))[0]; } else if url.startsWith(URL_TYPE_4) { - domain = url.substring(URL_TYPE_4.length(), url.length()); + domain = SLASH_REGEX.split(url.substring(URL_TYPE_4.length(), url.length()))[0]; } return domain.toLowerAscii(); } +// Construct the request path from client url and the path from client method invocation. +isolated function getReqPath(string url, string path) returns string { + string urlWithoutScheme = url; + if url.startsWith(URL_TYPE_3) { + urlWithoutScheme = url.substring(URL_TYPE_3.length(), url.length()); + } else if url.startsWith(URL_TYPE_4) { + urlWithoutScheme = url.substring(URL_TYPE_4.length(), url.length()); + } + + int? indexOfSlash = urlWithoutScheme.indexOf("/"); + string basePath = indexOfSlash is int ? urlWithoutScheme.substring(indexOfSlash, urlWithoutScheme.length()) : ""; + return basePath + path; +} + // Returns true if the cookie domain matches with the request domain according to [RFC-6265](https://tools.ietf.org/html/rfc6265#section-5.1.3). isolated function matchDomain(Cookie cookie, string domain, CookieConfig cookieConfig) returns Cookie? { From a49049f925bed2dc7a9b499f3e844e7cff968a74 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Tue, 30 Jul 2024 16:36:54 +0530 Subject: [PATCH 2/4] Add test case --- .../tests/http_cookies_test.bal | 203 ++++++++++++++---- .../tests/test_service_ports.bal | 3 + 2 files changed, 162 insertions(+), 44 deletions(-) diff --git a/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal b/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal index f72c4fee80..e24c457715 100644 --- a/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal +++ b/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal @@ -15,27 +15,37 @@ // under the License. import ballerina/file; -// import ballerina/log; import ballerina/test; import ballerina/http; import ballerina/http_test_common as common; -listener http:Listener CookieTestserverEP = new (9253, httpVersion = http:HTTP_1_1); +listener http:Listener CookieTestServerEP = new (cookieTestPort1, httpVersion = http:HTTP_1_1); -service /cookie on CookieTestserverEP { +http:ListenerConfiguration http2SslServiceConf = { + secureSocket: { + key: { + path: common:KEYSTORE_PATH, + password: "ballerina" + } + } +}; + +listener http:Listener CookieTestHTTPSServerEP = new (cookieTestPort2, http2SslServiceConf); + +service /cookie on CookieTestServerEP { resource function get addPersistentAndSessionCookies(http:Caller caller, http:Request req) returns error? { http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34", path = "/cookie/addPersistentAndSessionCookies", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false, expires = "2030-06-26 05:46:22"); http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34", path = "/cookie/addPersistentAndSessionCookies", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false, expires = "2030-07-15 05:46:22"); @@ -43,7 +53,7 @@ service /cookie on CookieTestserverEP { http:Cookie cookie3 = new("SID003", "895gd4dmnmsddd34", path = "/cookie/addPersistentAndSessionCookies", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false); @@ -68,12 +78,12 @@ service /cookie on CookieTestserverEP { // Creates the cookies. http:Cookie cookie1 = new("SID002", "239d4dmnmsddd34", path = "/cookie", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true); http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34", path = "/cookie", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = false); http:Response res = new; @@ -94,12 +104,12 @@ service /cookie on CookieTestserverEP { // Creates the cookies. http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34", path = "/cookie", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true); http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34", path = "/cookie/removeSessionCookie", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false); @@ -123,14 +133,14 @@ service /cookie on CookieTestserverEP { resource function get sendSimilarPersistentCookies(http:Caller caller, http:Request req) returns error? { http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34", path = "/cookie/sendSimilarPersistentCookies", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = false, secure = false, expires = "2030-06-26 05:46:22"); http:Cookie cookie3 = new("SID001", "895gd4dmnmsddd34", path = "/cookie/sendSimilarPersistentCookies", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false, expires = "2030-06-26 05:46:22"); @@ -153,13 +163,13 @@ service /cookie on CookieTestserverEP { returns error? { http:Cookie cookie2 = new("SID003", "895gd4dmnmsddd34", path = "/cookie/sendSimilarPersistentAndSessionCookies_1", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false); http:Cookie cookie3 = new("SID003", "aeaa895gd4dmnmsddd34", path = "/cookie/sendSimilarPersistentAndSessionCookies_1", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = false, secure = false, expires = "2030-07-15 05:46:22"); @@ -182,14 +192,14 @@ service /cookie on CookieTestserverEP { returns error? { http:Cookie cookie2 = new("SID003", "aeaa895gd4dmnmsddd34", path = "/cookie/sendSimilarPersistentAndSessionCookies_2", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = false, secure = false, expires = "2030-07-15 05:46:22"); http:Cookie cookie3 = new("SID003", "895gd4dmnmsddd34", path = "/cookie/sendSimilarPersistentAndSessionCookies_2", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false); @@ -211,13 +221,13 @@ service /cookie on CookieTestserverEP { // Creates the cookies. http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34", path = "/cookie/removePersistentCookieByServer", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, expires = "2030-07-15 05:46:22"); http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34", path = "/cookie/removePersistentCookieByServer", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false); @@ -253,21 +263,21 @@ service /cookie on CookieTestserverEP { returns error? { http:Cookie cookie1 = new("SID001", "239d4dmnmsddd34", path = "/cookie/addPersistentAndSessionCookiesDefault", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false, expires = "2030-06-26 05:46:22"); http:Cookie cookie2 = new("SID002", "178gd4dmnmsddd34", path = "/cookie/addPersistentAndSessionCookiesDefault", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false, expires = "2030-07-15 05:46:22"); http:Cookie cookie3 = new("SID003", "895gd4dmnmsddd34", path = "/cookie/addPersistentAndSessionCookiesDefault", - domain = "localhost:9253", + domain = string `localhost:${cookieTestPort1}`, httpOnly = true, secure = false); @@ -289,7 +299,7 @@ service /cookie on CookieTestserverEP { } } -service /cookieDemo on CookieTestserverEP { +service /cookieDemo on CookieTestServerEP { resource function post login(http:Request req) returns http:Response|http:BadRequest { json|error details = req.getJsonPayload(); if details is json { @@ -329,11 +339,73 @@ service /cookieDemo on CookieTestserverEP { } } +service /cookies on CookieTestServerEP { + + resource function get path(http:Request req) returns http:Response|string { + http:Cookie[] userCookie = from http:Cookie cookie in req.getCookies() + where cookie.name == "user" + limit 1 + select cookie; + if userCookie.length() == 0 { + http:Cookie cookie = new ("user", "ballerina", {path: "/cookies"}); + http:Response res = new; + res.addCookie(cookie); + return res; + } + return userCookie[0].value; + } + + resource function get .(http:Request req) returns http:Response|string { + http:Cookie[] userCookie = from http:Cookie cookie in req.getCookies() + where cookie.name == "user" + limit 1 + select cookie; + if userCookie.length() == 0 { + http:Cookie cookie = new ("user", "ballerina", {path: "/cookies"}); + http:Response res = new; + res.addCookie(cookie); + return res; + } + return userCookie[0].value; + } +} + +service /cookies on CookieTestHTTPSServerEP { + + resource function get path(http:Request req) returns http:Response|string { + http:Cookie[] userCookie = from http:Cookie cookie in req.getCookies() + where cookie.name == "user" + limit 1 + select cookie; + if userCookie.length() == 0 { + http:Cookie cookie = new ("user", "ballerina", {path: "/cookies"}); + http:Response res = new; + res.addCookie(cookie); + return res; + } + return userCookie[0].value; + } + + resource function get .(http:Request req) returns http:Response|string { + http:Cookie[] userCookie = from http:Cookie cookie in req.getCookies() + where cookie.name == "user" + limit 1 + select cookie; + if userCookie.length() == 0 { + http:Cookie cookie = new ("user", "ballerina", {path: "/cookies"}); + http:Response res = new; + res.addCookie(cookie); + return res; + } + return userCookie[0].value; + } +} + // Test to send requests by cookie client for first, second and third times @test:Config {} public isolated function testSendRequestsByCookieClient() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-1.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/addPersistentAndSessionCookies"); @@ -353,7 +425,7 @@ public isolated function testSendRequestsByCookieClient() returns error? { @test:Config {} public isolated function testRemoveSessionCookieByClient() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-2.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/addPersistentAndSessionCookies"); @@ -361,7 +433,7 @@ public isolated function testRemoveSessionCookieByClient() returns error? { http:CookieStore? myCookieStore = cookieClientEndpoint.getCookieStore(); if myCookieStore is http:CookieStore { http:CookieHandlingError? removeResult = - myCookieStore.removeCookie("SID003", "localhost:9253", "/cookie/addPersistentAndSessionCookies"); + myCookieStore.removeCookie("SID003", string `localhost:${cookieTestPort1}`, "/cookie/addPersistentAndSessionCookies"); if removeResult is http:CookieHandlingError { // log:printError("Error retrieving", 'error = removeResult); } @@ -380,7 +452,7 @@ public isolated function testRemoveSessionCookieByClient() returns error? { // cookie in the cookie store @test:Config {} public isolated function testAddSimilarSessionCookies() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends similar session cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/addSimilarSessionCookie"); @@ -397,7 +469,7 @@ public isolated function testAddSimilarSessionCookies() returns error? { @test:Config {} public isolated function testRemoveSessionCookieByServer() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookies-test-data/client-4.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends the session cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/removeSessionCookie"); @@ -416,7 +488,7 @@ public isolated function testRemoveSessionCookieByServer() returns error? { @test:Config {} public isolated function testSendRequestsByClient() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-6.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, retryConfig = { interval: 3, @@ -453,7 +525,7 @@ public isolated function testSendRequestsByClient() returns error? { @test:Config {} public function testRemovePersistentCookieByClient() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-7.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/addPersistentAndSessionCookies"); @@ -461,7 +533,7 @@ public function testRemovePersistentCookieByClient() returns error? { http:CookieStore? myCookieStore = cookieClientEndpoint.getCookieStore(); if myCookieStore is http:CookieStore { http:CookieHandlingError? removeResult = - myCookieStore.removeCookie("SID001", "localhost:9253", "/cookie/addPersistentAndSessionCookies"); + myCookieStore.removeCookie("SID001", string `localhost:${cookieTestPort1}`, "/cookie/addPersistentAndSessionCookies"); if removeResult is http:CookieHandlingError { // log:printError("Error retrieving", 'error = removeResult); } @@ -481,7 +553,7 @@ public function testRemovePersistentCookieByClient() returns error? { @test:Config {} public function testAddSimilarPersistentCookies() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-8.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends similar persistent cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/sendSimilarPersistentCookies"); @@ -500,7 +572,7 @@ public function testAddSimilarPersistentCookies() returns error? { @test:Config {} public function testSendSimilarPersistentAndSessionCookies_1() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-9.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends a session cookie and a similar persistent cookie in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/sendSimilarPersistentAndSessionCookies_1"); @@ -519,7 +591,7 @@ public function testSendSimilarPersistentAndSessionCookies_1() returns error? { @test:Config {} public function testSendSimilarPersistentAndSessionCookies_2() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-10.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends a persistent cookie and a similar session cookie in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/sendSimilarPersistentAndSessionCookies_2"); @@ -537,7 +609,7 @@ public function testSendSimilarPersistentAndSessionCookies_2() returns error? { @test:Config {} public function testRemovePersistentCookieByServer() returns error? { http:CsvPersistentCookieHandler myPersistentStore = new("./cookie-test-data/client-11.csv"); - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true, persistentCookieHandler: myPersistentStore }); // Server sends cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/removePersistentCookieByServer"); @@ -556,7 +628,7 @@ public function testRemovePersistentCookieByServer() returns error? { // Test to send persistent cookies when the persistentCookieHandler is not configured @test:Config {} public function testSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->get("/cookie/addPersistentAndSessionCookies"); @@ -574,7 +646,7 @@ public function testSendPersistentCookiesWithoutPersistentCookieHandler() return // Test the cookie validation when using the getCookies() @test:Config {} public function testCookieValidation() returns error? { - http:Client clientEP = check new("http://localhost:9253", httpVersion = http:HTTP_1_1); + http:Client clientEP = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1); http:Response|error response = clientEP->get("/cookie/validateCookie", {"Cookie":"user=John; asd=; =sdsdfsf; =gffg; "}); if response is http:Response { common:assertTextPayload(response.getTextPayload(), "Valid cookies: user=John,asd=,"); @@ -587,7 +659,7 @@ public function testCookieValidation() returns error? { // Test to send persistent cookies when the persistentCookieHandler is not configured @test:Config {} public function testPostSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->post("/cookie/addPersistentAndSessionCookiesDefault", ""); @@ -604,7 +676,7 @@ public function testPostSendPersistentCookiesWithoutPersistentCookieHandler() re @test:Config {} public function testPutSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->put("/cookie/addPersistentAndSessionCookiesDefault", ""); @@ -621,7 +693,7 @@ public function testPutSendPersistentCookiesWithoutPersistentCookieHandler() ret @test:Config {} public function testPatchSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->patch("/cookie/addPersistentAndSessionCookiesDefault", ""); @@ -638,7 +710,7 @@ public function testPatchSendPersistentCookiesWithoutPersistentCookieHandler() r @test:Config {} public function testDeleteSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->delete("/cookie/addPersistentAndSessionCookiesDefault", ""); @@ -655,7 +727,7 @@ public function testDeleteSendPersistentCookiesWithoutPersistentCookieHandler() @test:Config {} public function testHeadSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->head("/cookie/addPersistentAndSessionCookiesDefault"); @@ -670,7 +742,7 @@ public function testHeadSendPersistentCookiesWithoutPersistentCookieHandler() re @test:Config {} public function testOptionsSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->options("/cookie/addPersistentAndSessionCookiesDefault"); @@ -687,7 +759,7 @@ public function testOptionsSendPersistentCookiesWithoutPersistentCookieHandler() @test:Config {} public function testExecuteSendPersistentCookiesWithoutPersistentCookieHandler() returns error? { - http:Client cookieClientEndpoint = check new("http://localhost:9253", + http:Client cookieClientEndpoint = check new(string `http://localhost:${cookieTestPort1}`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); // Server sends the cookies in the response for the first request. http:Response|error response = cookieClientEndpoint->execute("GET", @@ -705,7 +777,7 @@ public function testExecuteSendPersistentCookiesWithoutPersistentCookieHandler() @test:Config {} public function testCaseSensitiveDomain() returns error? { - http:Client httpClient = check new("http://localhost:9253/cookieDemo", + http:Client httpClient = check new(string `http://localhost:${cookieTestPort1}/cookieDemo`, httpVersion = http:HTTP_1_1, cookieConfig = { enabled: true }); http:Request request = new; json jsonPart = { @@ -723,3 +795,46 @@ public function testCaseSensitiveDomain() returns error? { } return; } + +@test:Config {} +public function testCookieWithEmptyPath() returns error? { + http:Client httpClient = check new (string `http://localhost:${cookieTestPort1}/cookies`, cookieConfig = {enabled: true}); + http:Response _ = check httpClient->get(""); + string result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `http://localhost:${cookieTestPort1}/cookies/path`, cookieConfig = {enabled: true}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `localhost:${cookieTestPort1}/cookies`, cookieConfig = {enabled: true}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `localhost:${cookieTestPort1}/cookies/path`, cookieConfig = {enabled: true}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `https://localhost:${cookieTestPort2}/cookies`, cookieConfig = {enabled: true}, secureSocket = {enable: false}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `https://localhost:${cookieTestPort2}/cookies/path`, cookieConfig = {enabled: true}, secureSocket = {enable: false}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `localhost:${cookieTestPort2}/cookies`, cookieConfig = {enabled: true}, secureSocket = {enable: false}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); + + httpClient = check new (string `localhost:${cookieTestPort2}/cookies/path`, cookieConfig = {enabled: true}, secureSocket = {enable: false}); + http:Response _ = check httpClient->get(""); + result = check httpClient->get(""); + test:assertEquals(result, "ballerina"); +} \ No newline at end of file diff --git a/ballerina-tests/http-advanced-tests/tests/test_service_ports.bal b/ballerina-tests/http-advanced-tests/tests/test_service_ports.bal index 7176d4045f..4c3934fe70 100644 --- a/ballerina-tests/http-advanced-tests/tests/test_service_ports.bal +++ b/ballerina-tests/http-advanced-tests/tests/test_service_ports.bal @@ -42,3 +42,6 @@ const int statusCodeErrorUseCasePort = 9090; const int statusCodeErrorPort = 9092; const int identicalCookiePort = 9093; + +const int cookieTestPort1 = 9253; +const int cookieTestPort2 = 9254; From d1baef576678ea87458c7edefa1a1e972a52e526 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Tue, 30 Jul 2024 16:39:40 +0530 Subject: [PATCH 3/4] Update changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index fb7241eee4..73ea84a6d9 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Fixed - [Fix number format exception with decimal values for cache configuration](https://github.com/ballerina-platform/ballerina-library/issues/6765) +- [Fix cookie path resolution logic](https://github.com/ballerina-platform/ballerina-library/issues/6788) ## [2.11.2] - 2024-06-14 From 0ae35c346e351278c50a5c9e32c7b32393a4c1c5 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Wed, 31 Jul 2024 13:40:43 +0530 Subject: [PATCH 4/4] Add suggestions from review --- .../http-advanced-tests/tests/http_cookies_test.bal | 2 +- ballerina/cookie_cookieStore.bal | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal b/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal index e24c457715..3b38edeb37 100644 --- a/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal +++ b/ballerina-tests/http-advanced-tests/tests/http_cookies_test.bal @@ -837,4 +837,4 @@ public function testCookieWithEmptyPath() returns error? { http:Response _ = check httpClient->get(""); result = check httpClient->get(""); test:assertEquals(result, "ballerina"); -} \ No newline at end of file +} diff --git a/ballerina/cookie_cookieStore.bal b/ballerina/cookie_cookieStore.bal index ce451eab87..2eda6161ab 100644 --- a/ballerina/cookie_cookieStore.bal +++ b/ballerina/cookie_cookieStore.bal @@ -402,16 +402,11 @@ isolated function getDomain(string url) returns string { // Construct the request path from client url and the path from client method invocation. isolated function getReqPath(string url, string path) returns string { - string urlWithoutScheme = url; - if url.startsWith(URL_TYPE_3) { - urlWithoutScheme = url.substring(URL_TYPE_3.length(), url.length()); - } else if url.startsWith(URL_TYPE_4) { - urlWithoutScheme = url.substring(URL_TYPE_4.length(), url.length()); + regexp:Groups? groups = re `^(?:https?://)?[^/]+(/.*)?$`.findGroups(url); + if groups is () || groups.length() == 1 || groups[1] is () { + return path; } - - int? indexOfSlash = urlWithoutScheme.indexOf("/"); - string basePath = indexOfSlash is int ? urlWithoutScheme.substring(indexOfSlash, urlWithoutScheme.length()) : ""; - return basePath + path; + return (groups[1]).substring() + path; }