diff --git a/ballerina-tests/http-interceptor-tests/tests/http2_interceptors_basic_tests.bal b/ballerina-tests/http-interceptor-tests/tests/http2_interceptors_basic_tests.bal index ec2696e97b..5b25c3d3cd 100644 --- a/ballerina-tests/http-interceptor-tests/tests/http2_interceptors_basic_tests.bal +++ b/ballerina-tests/http-interceptor-tests/tests/http2_interceptors_basic_tests.bal @@ -416,7 +416,7 @@ function tesHttp2RequestInterceptorPathAndVerb() returns error? { res = check http2InterceptorsBasicTestsClientEP3->get("/interceptorPathAndVerb/bar"); test:assertEquals(res.statusCode, 404); - common:assertTextPayload(res.getTextPayload(), "no matching resource found for path"); + common:assertTextPayload(res.getTextPayload(), "no matching resource found for path : /interceptorPathAndVerb/bar , method : GET"); common:assertHeaderValue(check res.getHeader("last-interceptor"), "default-response-error-interceptor"); common:assertHeaderValue(check res.getHeader("default-response-error-interceptor"), "true"); common:assertHeaderValue(check res.getHeader("last-response-interceptor"), "true"); diff --git a/ballerina-tests/http-interceptor-tests/tests/interceptors_error_handling_tests.bal b/ballerina-tests/http-interceptor-tests/tests/interceptors_error_handling_tests.bal index c0c395a5a8..9077e90a89 100644 --- a/ballerina-tests/http-interceptor-tests/tests/interceptors_error_handling_tests.bal +++ b/ballerina-tests/http-interceptor-tests/tests/interceptors_error_handling_tests.bal @@ -87,7 +87,7 @@ function testNoMatchingServiceRegistered() returns error? { function testNoMatchingResourceFound() returns error? { http:Response res = check serviceErrorHandlingClientEP->get("/foo/new"); test:assertEquals(res.statusCode, 404); - common:assertTextPayload(res.getTextPayload(), "no matching resource found for path"); + common:assertTextPayload(res.getTextPayload(), "no matching resource found for path : /foo/new , method : GET"); common:assertHeaderValue(check res.getHeader("last-interceptor"), "default-response-error-interceptor"); common:assertHeaderValue(check res.getHeader("default-response-error-interceptor"), "true"); common:assertHeaderValue(check res.getHeader("last-response-interceptor"), "true"); @@ -331,7 +331,7 @@ function testInvalidPathWithSingleService() returns error? { http:Client singleServiceRegisteredClientEP = check new("http://localhost:" + singleServiceRegisteredTestPort.toString(), httpVersion = http:HTTP_1_1); http:Response res = check singleServiceRegisteredClientEP->get("/path2"); test:assertEquals(res.statusCode, 404); - test:assertEquals(res.getTextPayload(), "no matching service found for path"); + test:assertEquals(res.getTextPayload(), "no matching service found for path: /path2"); common:assertHeaderValue(check res.getHeader("last-interceptor"), "default-response-error-interceptor"); common:assertHeaderValue(check res.getHeader("default-response-error-interceptor"), "true"); common:assertHeaderValue(check res.getHeader("last-response-interceptor"), "true"); @@ -403,7 +403,7 @@ function testInvalidPathWithRootService() returns error? { http:Client rootServiceRegisteredClientEP = check new("http://localhost:" + rootServiceRegisteredTestPort.toString(), httpVersion = http:HTTP_1_1); http:Response res = check rootServiceRegisteredClientEP->get("/path2"); test:assertEquals(res.statusCode, 404); - test:assertEquals(res.getTextPayload(), "no matching resource found for path"); + test:assertEquals(res.getTextPayload(), "no matching resource found for path : /path2 , method : GET"); common:assertHeaderValue(check res.getHeader("last-interceptor"), "default-response-error-interceptor"); common:assertHeaderValue(check res.getHeader("default-response-error-interceptor"), "true"); common:assertHeaderValue(check res.getHeader("last-response-interceptor"), "true"); diff --git a/ballerina-tests/http-test-common/utils.bal b/ballerina-tests/http-test-common/utils.bal index df88bb885b..b260646fd9 100644 --- a/ballerina-tests/http-test-common/utils.bal +++ b/ballerina-tests/http-test-common/utils.bal @@ -57,7 +57,7 @@ public isolated function assertJsonPayloadtoJsonString(json|error payload, json } public isolated function assertJsonErrorPayload(json payload, string message, string reason, int statusCode, string path, string method) returns error? { - test:assertEquals(payload.message, message); + test:assertTrue((check payload.message).toString().startsWith(message)); test:assertEquals(payload.reason, reason); test:assertEquals(payload.status, statusCode); test:assertEquals(payload.path, path); diff --git a/ballerina/http_errors.bal b/ballerina/http_errors.bal index 6e320f6470..7a17a457d6 100644 --- a/ballerina/http_errors.bal +++ b/ballerina/http_errors.bal @@ -38,6 +38,8 @@ public type LoadBalanceActionErrorData record { # Defines the common error type for the module. public type Error distinct error; +type InternalError distinct Error; + // Level 2 # Defines the possible listener error types. public type ListenerError distinct Error; @@ -64,42 +66,56 @@ public type GenericListenerError distinct ListenerError; # Represents an error, which occurred due to a failure in interceptor return. public type InterceptorReturnError distinct ListenerError & httpscerr:InternalServerErrorError; +type InternalInterceptorReturnError InterceptorReturnError & InternalError; + # Represents an error, which occurred due to a header binding. public type HeaderBindingError distinct ListenerError & httpscerr:BadRequestError; +type InternalHeaderBindingError HeaderBindingError & InternalError; + // TODO: Change the error type as HeaderBindingError once this issue is fixed: // https://github.com/ballerina-platform/ballerina-lang/issues/40273 # Represents an error, which occurred due to a header constraint validation. public type HeaderValidationError distinct HeaderBindingError & httpscerr:BadRequestError; +type InternalHeaderValidationError HeaderValidationError & InternalError; + # Represents an error, which occurred due to the absence of the payload. public type NoContentError distinct ClientError; type PayloadBindingClientError ClientError & PayloadBindingError; -type PayloadBindingListenerError distinct ListenerError & PayloadBindingError & httpscerr:BadRequestError; +type InternalPayloadBindingListenerError distinct ListenerError & PayloadBindingError & httpscerr:BadRequestError & InternalError; # Represents an error, which occurred due to payload constraint validation. public type PayloadValidationError distinct PayloadBindingError; type PayloadValidationClientError ClientError & PayloadValidationError; -type PayloadValidationListenerError distinct ListenerError & PayloadValidationError & httpscerr:BadRequestError; +type InternalPayloadValidationListenerError distinct ListenerError & PayloadValidationError & httpscerr:BadRequestError & InternalError; # Represents an error, which occurred due to a query parameter binding. public type QueryParameterBindingError distinct ListenerError & httpscerr:BadRequestError; +type InternalQueryParameterBindingError QueryParameterBindingError & InternalError; + // TODO: Change the error type as QueryParameterBindingError once this issue is fixed: // https://github.com/ballerina-platform/ballerina-lang/issues/40273 # Represents an error, which occurred due to a query parameter constraint validation. public type QueryParameterValidationError distinct QueryParameterBindingError & httpscerr:BadRequestError; +type InternalQueryParameterValidationError QueryParameterValidationError & InternalError; + # Represents an error, which occurred due to a path parameter binding. public type PathParameterBindingError distinct ListenerError & httpscerr:BadRequestError; +type InternalPathParameterBindingError PathParameterBindingError & InternalError; + # Represents an error, which occurred during the request dispatching. public type RequestDispatchingError distinct ListenerError; +type InternalRequestDispatchingError RequestDispatchingError & InternalError; + # Represents an error, which occurred during the service dispatching. public type ServiceDispatchingError distinct RequestDispatchingError; @@ -242,23 +258,39 @@ public type InvalidCookieError distinct OutboundResponseError; # Represents Service Not Found error. public type ServiceNotFoundError httpscerr:NotFoundError & ServiceDispatchingError; +type InternalServiceNotFoundError ServiceNotFoundError & InternalError; + # Represents Bad Matrix Parameter in the request error. public type BadMatrixParamError httpscerr:BadRequestError & ServiceDispatchingError; +type InternalBadMatrixParamError BadMatrixParamError & InternalError; + # Represents an error, which occurred when the resource is not found during dispatching. public type ResourceNotFoundError httpscerr:NotFoundError & ResourceDispatchingError; +type InternalResourceNotFoundError ResourceNotFoundError & InternalError; + # Represents an error, which occurred due to a path parameter constraint validation. public type ResourcePathValidationError httpscerr:BadRequestError & ResourceDispatchingError; +type InternalResourcePathValidationError ResourcePathValidationError & InternalError; + # Represents an error, which occurred when the resource method is not allowed during dispatching. public type ResourceMethodNotAllowedError httpscerr:MethodNotAllowedError & ResourceDispatchingError; +type InternalResourceMethodNotAllowedError ResourceMethodNotAllowedError & InternalError; + # Represents an error, which occurred when the media type is not supported during dispatching. public type UnsupportedRequestMediaTypeError httpscerr:UnsupportedMediaTypeError & ResourceDispatchingError; +type InternalUnsupportedRequestMediaTypeError UnsupportedRequestMediaTypeError & InternalError; + # Represents an error, which occurred when the payload is not acceptable during dispatching. public type RequestNotAcceptableError httpscerr:NotAcceptableError & ResourceDispatchingError; +type InternalRequestNotAcceptableError RequestNotAcceptableError & InternalError; + # Represents other internal server errors during dispatching. public type ResourceDispatchingServerError httpscerr:InternalServerErrorError & ResourceDispatchingError; + +type InternalResourceDispatchingServerError ResourceDispatchingServerError & InternalError; diff --git a/ballerina/http_interceptors.bal b/ballerina/http_interceptors.bal index ddddeaf4dd..ac4d02a8c8 100644 --- a/ballerina/http_interceptors.bal +++ b/ballerina/http_interceptors.bal @@ -15,6 +15,7 @@ // under the License. import ballerina/jwt; +import ballerina/log; # The HTTP request interceptor service object type public type RequestInterceptor distinct service object { @@ -57,6 +58,9 @@ service class DefaultErrorInterceptor { *ResponseErrorInterceptor; remote function interceptResponseError(error err, Request request) returns Response { + if err !is InternalError { + log:printError("unhandled error returned from the service", err, path = request.rawPath, method = request.method); + } return getErrorResponseForInterceptor(err, request); } } diff --git a/changelog.md b/changelog.md index 27f41de3df..65db555093 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - [Remove unused import from Http2StateUtil](https://github.com/ballerina-platform/ballerina-library/issues/5966) - [Fix client getting hanged when server closes connection in the ALPN handshake](https://github.com/ballerina-platform/ballerina-library/issues/6003) - [Fix client getting hanged when multiple requests are sent which exceed `maxHeaderSize`](https://github.com/ballerina-platform/ballerina-library/issues/6000) +- [Fix inconsistencies with error logging](https://github.com/ballerina-platform/ballerina-library/issues/5877) ## [2.10.5] - 2023-12-06 diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/BallerinaHTTPConnectorListener.java b/native/src/main/java/io/ballerina/stdlib/http/api/BallerinaHTTPConnectorListener.java index f9860fb8aa..0bdac2a974 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/BallerinaHTTPConnectorListener.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/BallerinaHTTPConnectorListener.java @@ -87,7 +87,7 @@ public void onMessage(HttpCarbonMessage inboundMessage) { } catch (Exception ex) { HttpRequestInterceptorUnitCallback callback = new HttpRequestInterceptorUnitCallback(inboundMessage, httpServicesRegistry.getRuntime(), this); - callback.invokeErrorInterceptors(HttpUtil.createError(ex), false); + callback.invokeErrorInterceptors(HttpUtil.createError(ex), true); return; } @@ -101,7 +101,7 @@ public void onMessage(HttpCarbonMessage inboundMessage) { } catch (Exception ex) { HttpCallableUnitCallback callback = new HttpCallableUnitCallback(inboundMessage, httpServicesRegistry.getRuntime()); - callback.invokeErrorInterceptors(HttpUtil.createError(ex), false); + callback.invokeErrorInterceptors(HttpUtil.createError(ex), true); } } } @@ -285,7 +285,7 @@ protected void executeMainResourceOnMessage(HttpCarbonMessage inboundMessage) { } catch (BallerinaConnectorException ex) { HttpCallableUnitCallback callback = new HttpCallableUnitCallback(inboundMessage, httpServicesRegistry.getRuntime()); - callback.invokeErrorInterceptors(HttpUtil.createError(ex), false); + callback.invokeErrorInterceptors(HttpUtil.createError(ex), true); } } @@ -319,7 +319,7 @@ private void setTargetServiceToInboundMsg(HttpCarbonMessage inboundMessage) { } catch (Exception e) { if (((BArray) listenerLevelInterceptors).size() == 1 && e instanceof BError && ((BError) e).getType().getName() - .equals(HttpErrorType.SERVICE_NOT_FOUND_ERROR.getErrorName())) { + .equals(HttpErrorType.INTERNAL_SERVICE_NOT_FOUND_ERROR.getErrorName())) { HttpService singleService = HttpDispatcher.findSingleService(httpServicesRegistry); if (singleService != null && singleService.hasInterceptors()) { inboundMessage.setProperty(INTERCEPTORS, singleService.getBalInterceptorServicesArray()); diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java index 09a58b2be9..3eedc79796 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpCallableUnitCallback.java @@ -92,7 +92,7 @@ public void notifySuccess(Object result) { return; } if (result instanceof BError) { - invokeErrorInterceptors((BError) result, true); + invokeErrorInterceptors((BError) result, false); return; } if (isLastService) { @@ -130,7 +130,6 @@ public void invokeBalMethod(Object[] paramFeed, String methodName) { @Override public void notifySuccess(Object result) { stopObserverContext(); - printStacktraceIfError(result); } @Override @@ -166,17 +165,19 @@ public void notifyFailure(BError error) { // handles panic and check_panic System.exit(1); } - public void invokeErrorInterceptors(BError error, boolean printError) { - requestMessage.setProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR, error); - if (printError) { - error.printStackTrace(); + public void invokeErrorInterceptors(BError error, boolean isInternalError) { + if (isInternalError) { + requestMessage.setProperty(HttpConstants.INTERNAL_ERROR, true); + } else { + requestMessage.removeProperty(HttpConstants.INTERNAL_ERROR); } + requestMessage.setProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR, error); returnErrorResponse(error); } public void sendFailureResponse(BError error) { stopObserverContext(); - HttpUtil.handleFailure(requestMessage, error, true); + HttpUtil.handleFailure(requestMessage, error); } public void cleanupRequestMessage() { @@ -186,19 +187,13 @@ public void cleanupRequestMessage() { private boolean alreadyResponded(Object result) { try { HttpUtil.methodInvocationCheck(requestMessage, HttpConstants.INVALID_STATUS_CODE, ILLEGAL_FUNCTION_INVOKED); - } catch (BError e) { + } catch (BError bError) { if (result != null) { // handles nil return and end of resource exec - printStacktraceIfError(result); - err.println(HttpConstants.HTTP_RUNTIME_WARNING_PREFIX + e.getMessage()); + bError.printStackTrace(); + err.println(HttpConstants.HTTP_RUNTIME_WARNING_PREFIX + bError.getMessage()); } return true; } return false; } - - private void printStacktraceIfError(Object result) { - if (result instanceof BError) { - ((BError) result).printStackTrace(); - } - } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java index c491ba9b8e..233f3e2312 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java @@ -382,6 +382,7 @@ public final class HttpConstants { public static final String REQUEST_INTERCEPTOR_INDEX = "REQUEST_INTERCEPTOR_INDEX"; public static final String RESPONSE_INTERCEPTOR_INDEX = "RESPONSE_INTERCEPTOR_INDEX"; public static final String INTERCEPTOR_SERVICE_ERROR = "INTERCEPTOR_SERVICE_ERROR"; + public static final String INTERNAL_ERROR = "INTERNAL_ERROR"; public static final String WAIT_FOR_FULL_REQUEST = "WAIT_FOR_FULL_REQUEST"; public static final String HTTP_NORMAL = "Normal"; public static final String REQUEST_INTERCEPTOR = "RequestInterceptor"; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpDispatcher.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpDispatcher.java index dba6f94b81..89ca9d40e6 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpDispatcher.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpDispatcher.java @@ -62,7 +62,7 @@ import static io.ballerina.stdlib.http.api.HttpConstants.QUERY_STRING_SEPARATOR; import static io.ballerina.stdlib.http.api.HttpConstants.REQUEST_CTX_MEMBERS; import static io.ballerina.stdlib.http.api.HttpConstants.WHITESPACE; -import static io.ballerina.stdlib.http.api.HttpErrorType.SERVICE_NOT_FOUND_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_SERVICE_NOT_FOUND_ERROR; import static io.ballerina.stdlib.http.api.HttpUtil.getParameterTypes; /** @@ -90,7 +90,7 @@ public static HttpService findService(HTTPServicesRegistry servicesRegistry, Htt } else { String localAddress = inboundReqMsg.getProperty(HttpConstants.LOCAL_ADDRESS).toString(); String message = "no service has registered for listener : " + localAddress; - throw HttpUtil.createHttpStatusCodeError(SERVICE_NOT_FOUND_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_SERVICE_NOT_FOUND_ERROR, message); } String rawUri = (String) inboundReqMsg.getProperty(HttpConstants.TO); @@ -103,8 +103,8 @@ public static HttpService findService(HTTPServicesRegistry servicesRegistry, Htt servicesOnInterface, sortedServiceURIs); if (basePath == null) { - String message = "no matching service found for path"; - throw HttpUtil.createHttpStatusCodeError(SERVICE_NOT_FOUND_ERROR, message); + String message = "no matching service found for path: " + rawPathAndQuery[0]; + throw HttpUtil.createHttpStatusCodeError(INTERNAL_SERVICE_NOT_FOUND_ERROR, message); } HttpService service = servicesOnInterface.get(basePath); @@ -117,7 +117,7 @@ public static HttpService findService(HTTPServicesRegistry servicesRegistry, Htt return service; } catch (Exception e) { if (!(e instanceof BError)) { - throw HttpUtil.createHttpStatusCodeError(SERVICE_NOT_FOUND_ERROR, e.getMessage()); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_SERVICE_NOT_FOUND_ERROR, e.getMessage()); } throw e; } @@ -154,7 +154,7 @@ public static InterceptorService findInterceptorService(HTTPInterceptorServicesR } else { String localAddress = inboundReqMsg.getProperty(HttpConstants.LOCAL_ADDRESS).toString(); String message = "no service has registered for listener : " + localAddress; - throw HttpUtil.createHttpStatusCodeError(SERVICE_NOT_FOUND_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_SERVICE_NOT_FOUND_ERROR, message); } if (isResponsePath) { @@ -177,8 +177,8 @@ public static InterceptorService findInterceptorService(HTTPInterceptorServicesR servicesOnInterface, sortedServiceURIs); if (basePath == null) { - String message = "no matching service found for path"; - throw HttpUtil.createHttpStatusCodeError(SERVICE_NOT_FOUND_ERROR, message); + String message = "no matching service found for path: " + rawPathAndQuery[0]; + throw HttpUtil.createHttpStatusCodeError(INTERNAL_SERVICE_NOT_FOUND_ERROR, message); } InterceptorService service = servicesOnInterface.get(basePath); @@ -186,7 +186,7 @@ public static InterceptorService findInterceptorService(HTTPInterceptorServicesR return service; } catch (Exception e) { if (!(e instanceof BError)) { - throw HttpUtil.createHttpStatusCodeError(SERVICE_NOT_FOUND_ERROR, e.getMessage()); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_SERVICE_NOT_FOUND_ERROR, e.getMessage()); } throw e; } @@ -231,14 +231,14 @@ public static HttpResource findResource(HTTPServicesRegistry servicesRegistry, H String protocol = (String) inboundMessage.getProperty(HttpConstants.PROTOCOL); if (protocol == null) { throw HttpUtil.createHttpError("protocol not defined in the incoming request", - HttpErrorType.REQ_DISPATCHING_ERROR); + HttpErrorType.INTERNAL_REQ_DISPATCHING_ERROR); } // Find the Service TODO can be improved HttpService service = HttpDispatcher.findService(servicesRegistry, inboundMessage, false); if (service == null) { throw HttpUtil.createHttpError("no Service found to handle the service request", - HttpErrorType.REQ_DISPATCHING_ERROR); + HttpErrorType.INTERNAL_REQ_DISPATCHING_ERROR); // Finer details of the errors are thrown from the dispatcher itself, Ideally we shouldn't get here. } @@ -251,14 +251,14 @@ public static InterceptorResource findInterceptorResource(HTTPInterceptorService String protocol = (String) inboundMessage.getProperty(HttpConstants.PROTOCOL); if (protocol == null) { throw HttpUtil.createHttpError("protocol not defined in the incoming request", - HttpErrorType.REQ_DISPATCHING_ERROR); + HttpErrorType.INTERNAL_REQ_DISPATCHING_ERROR); } // Find the Service TODO can be improved InterceptorService service = HttpDispatcher.findInterceptorService(servicesRegistry, inboundMessage, false); if (service == null) { throw HttpUtil.createHttpError("no Service found to handle the service request", - HttpErrorType.REQ_DISPATCHING_ERROR); + HttpErrorType.INTERNAL_REQ_DISPATCHING_ERROR); // Finer details of the errors are thrown from the dispatcher itself, Ideally we shouldn't get here. } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpErrorType.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpErrorType.java index a616afb567..3353093ab0 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpErrorType.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpErrorType.java @@ -63,26 +63,26 @@ public enum HttpErrorType { INVALID_CONTENT_LENGTH("InvalidContentLengthError"), HEADER_NOT_FOUND_ERROR("HeaderNotFoundError"), CLIENT_ERROR("ClientError"), - PAYLOAD_BINDING_LISTENER_ERROR("PayloadBindingListenerError"), - PAYLOAD_VALIDATION_LISTENER_ERROR("PayloadValidationListenerError"), - HEADER_BINDING_ERROR("HeaderBindingError"), - QUERY_PARAM_BINDING_ERROR("QueryParameterBindingError"), - PATH_PARAM_BINDING_ERROR("PathParameterBindingError"), - INTERCEPTOR_RETURN_ERROR("InterceptorReturnError"), - REQ_DISPATCHING_ERROR("RequestDispatchingError"), - RESOURCE_NOT_FOUND_ERROR("ResourceNotFoundError"), - RESOURCE_METHOD_NOT_ALLOWED_ERROR("ResourceMethodNotAllowedError"), - UNSUPPORTED_REQUEST_MEDIA_TYPE_ERROR("UnsupportedRequestMediaTypeError"), - REQUEST_NOT_ACCEPTABLE_ERROR("RequestNotAcceptableError"), - SERVICE_NOT_FOUND_ERROR("ServiceNotFoundError"), - BAD_MATRIX_PARAMS_ERROR("BadMatrixParamError"), - RESOURCE_DISPATCHING_SERVER_ERROR("ResourceDispatchingServerError"), + INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR("InternalPayloadBindingListenerError"), + INTERNAL_PAYLOAD_VALIDATION_LISTENER_ERROR("InternalPayloadValidationListenerError"), + INTERNAL_HEADER_BINDING_ERROR("InternalHeaderBindingError"), + INTERNAL_QUERY_PARAM_BINDING_ERROR("InternalQueryParameterBindingError"), + INTERNAL_PATH_PARAM_BINDING_ERROR("InternalPathParameterBindingError"), + INTERNAL_INTERCEPTOR_RETURN_ERROR("InternalInterceptorReturnError"), + INTERNAL_REQ_DISPATCHING_ERROR("InternalRequestDispatchingError"), + INTERNAL_RESOURCE_NOT_FOUND_ERROR("InternalResourceNotFoundError"), + INTERNAL_RESOURCE_METHOD_NOT_ALLOWED_ERROR("InternalResourceMethodNotAllowedError"), + INTERNAL_UNSUPPORTED_REQUEST_MEDIA_TYPE_ERROR("InternalUnsupportedRequestMediaTypeError"), + INTERNAL_REQUEST_NOT_ACCEPTABLE_ERROR("InternalRequestNotAcceptableError"), + INTERNAL_SERVICE_NOT_FOUND_ERROR("InternalServiceNotFoundError"), + INTERNAL_BAD_MATRIX_PARAMS_ERROR("InternalBadMatrixParamError"), + INTERNAL_RESOURCE_DISPATCHING_SERVER_ERROR("InternalResourceDispatchingServerError"), INTERNAL_LISTENER_AUTHZ_ERROR("InternalListenerAuthzError"), INTERNAL_LISTENER_AUTHN_ERROR("InternalListenerAuthnError"), CLIENT_CONNECTOR_ERROR("ClientConnectorError"), - RESOURCE_PATH_VALIDATION_ERROR("ResourcePathValidationError"), - HEADER_VALIDATION_ERROR("HeaderValidationError"), - QUERY_PARAM_VALIDATION_ERROR("QueryParameterValidationError"); + INTERNAL_RESOURCE_PATH_VALIDATION_ERROR("InternalResourcePathValidationError"), + INTERNAL_HEADER_VALIDATION_ERROR("InternalHeaderValidationError"), + INTERNAL_QUERY_PARAM_VALIDATION_ERROR("InternalQueryParameterValidationError"); private final String errorName; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java index 76cc1302c3..dc10dc7a43 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpRequestInterceptorUnitCallback.java @@ -29,7 +29,7 @@ import io.ballerina.stdlib.http.api.nativeimpl.ModuleUtils; import io.ballerina.stdlib.http.transport.message.HttpCarbonMessage; -import static io.ballerina.stdlib.http.api.HttpErrorType.INTERCEPTOR_RETURN_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_INTERCEPTOR_RETURN_ERROR; /** * {@code HttpRequestInterceptorUnitCallback} is the responsible for acting on notifications received from Ballerina @@ -61,7 +61,7 @@ public void notifySuccess(Object result) { if (!result.equals(requestCtx.getNativeData(HttpConstants.TARGET_SERVICE))) { requestMessage.setHttpStatusCode(500); } - invokeErrorInterceptors((BError) result, true); + invokeErrorInterceptors((BError) result, false); return; } validateResponseAndProceed(result); @@ -74,11 +74,13 @@ public void notifyFailure(BError error) { // handles panic and check_panic System.exit(1); } - public void invokeErrorInterceptors(BError error, boolean printError) { - requestMessage.setProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR, error); - if (printError) { - error.printStackTrace(); + public void invokeErrorInterceptors(BError error, boolean isInternalError) { + if (isInternalError) { + requestMessage.setProperty(HttpConstants.INTERNAL_ERROR, true); + } else { + requestMessage.removeProperty(HttpConstants.INTERNAL_ERROR); } + requestMessage.setProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR, error); ballerinaHTTPConnectorListener.onMessage(requestMessage); } @@ -101,12 +103,6 @@ private boolean alreadyResponded() { return false; } - private void printStacktraceIfError(Object result) { - if (result instanceof BError) { - ((BError) result).printStackTrace(); - } - } - private void sendRequestToNextService() { ballerinaHTTPConnectorListener.onMessage(requestMessage); } @@ -152,7 +148,7 @@ private void validateServiceReturnType(Object result, int interceptorId, BArray sendRequestToNextService(); } else { String message = "next interceptor service did not match with the configuration"; - BError err = HttpUtil.createHttpStatusCodeError(INTERCEPTOR_RETURN_ERROR, message); + BError err = HttpUtil.createHttpStatusCodeError(INTERNAL_INTERCEPTOR_RETURN_ERROR, message); invokeErrorInterceptors(err, true); } } else { @@ -161,7 +157,7 @@ private void validateServiceReturnType(Object result, int interceptorId, BArray sendRequestToNextService(); } else { String message = "target service did not match with the configuration"; - BError err = HttpUtil.createHttpStatusCodeError(INTERCEPTOR_RETURN_ERROR, message); + BError err = HttpUtil.createHttpStatusCodeError(INTERNAL_INTERCEPTOR_RETURN_ERROR, message); invokeErrorInterceptors(err, true); } } @@ -186,13 +182,12 @@ public void invokeBalMethod(Object[] paramFeed, String methodName) { Callback returnCallback = new Callback() { @Override public void notifySuccess(Object result) { - printStacktraceIfError(result); } @Override public void notifyFailure(BError result) { cleanupRequestMessage(); - HttpUtil.handleFailure(requestMessage, result, false); + HttpUtil.handleFailure(requestMessage, result); } }; runtime.invokeMethodAsyncSequentially( diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java index 00f5d223c2..f9e8d76fff 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpResponseInterceptorUnitCallback.java @@ -64,7 +64,7 @@ public HttpResponseInterceptorUnitCallback(HttpCarbonMessage requestMessage, BOb public void notifySuccess(Object result) { if (result instanceof BError) { requestMessage.setHttpStatusCode(500); - invokeErrorInterceptors((BError) result, true); + invokeErrorInterceptors((BError) result, false); return; } if (possibleLastInterceptor) { @@ -80,20 +80,16 @@ public void notifyFailure(BError error) { // handles panic and check_panic System.exit(1); } - public void invokeErrorInterceptors(BError error, boolean printError) { - requestMessage.setProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR, error); - if (printError) { - error.printStackTrace(); + public void invokeErrorInterceptors(BError error, boolean isInternalError) { + if (isInternalError) { + requestMessage.setProperty(HttpConstants.INTERNAL_ERROR, true); + } else { + requestMessage.removeProperty(HttpConstants.INTERNAL_ERROR); } + requestMessage.setProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR, error); returnErrorResponse(error); } - private void printStacktraceIfError(Object result) { - if (result instanceof BError) { - ((BError) result).printStackTrace(); - } - } - private void sendResponseToNextService() { Respond.nativeRespondWithDataCtx(environment, caller, response, dataContext); } @@ -142,8 +138,8 @@ private void validateServiceReturnType(Object result, int interceptorId, BArray if (result.equals(interceptor)) { sendResponseToNextService(); } else { - String message = "next interceptor service did not match with the configuration"; - BError err = HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERCEPTOR_RETURN_ERROR, message); + BError err = HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_INTERCEPTOR_RETURN_ERROR, + "next interceptor service did not match with the configuration"); invokeErrorInterceptors(err, true); } } @@ -171,7 +167,6 @@ public void invokeBalMethod(Object[] paramFeed, String methodName) { public void notifySuccess(Object result) { stopObserverContext(); dataContext.notifyOutboundResponseStatus(null); - printStacktraceIfError(result); } @Override diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java index 0e983ed339..f70bc10db2 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpUtil.java @@ -493,12 +493,10 @@ public static void handleFailure(HttpCarbonMessage requestMessage, String errorM PipeliningHandler.sendPipelinedResponse(requestMessage, createErrorMessage(errorMsg, statusCode)); } - public static void handleFailure(HttpCarbonMessage requestMessage, BError error, Boolean printStackTrace) { + public static void handleFailure(HttpCarbonMessage requestMessage, BError error) { String errorMsg = getErrorMessage(error); int statusCode = getStatusCode(requestMessage, errorMsg); - if (printStackTrace) { - error.printStackTrace(); - } + error.printStackTrace(); PipeliningHandler.sendPipelinedResponse(requestMessage, createErrorMessage(errorMsg, statusCode)); } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDataElement.java b/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDataElement.java index 101ba541a6..e189775e0b 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDataElement.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDataElement.java @@ -31,9 +31,9 @@ import java.util.stream.Collectors; import static io.ballerina.stdlib.http.api.HttpErrorType.GENERIC_LISTENER_ERROR; -import static io.ballerina.stdlib.http.api.HttpErrorType.REQUEST_NOT_ACCEPTABLE_ERROR; -import static io.ballerina.stdlib.http.api.HttpErrorType.RESOURCE_METHOD_NOT_ALLOWED_ERROR; -import static io.ballerina.stdlib.http.api.HttpErrorType.UNSUPPORTED_REQUEST_MEDIA_TYPE_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_REQUEST_NOT_ACCEPTABLE_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_RESOURCE_METHOD_NOT_ALLOWED_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_UNSUPPORTED_REQUEST_MEDIA_TYPE_ERROR; /** * Http Node Item for URI template tree. @@ -136,8 +136,7 @@ private Resource validateHTTPMethod(List resources, HttpCarbonMessage return httpResource; } if (!isOptionsRequest) { - String message = "Method not allowed"; - throw HttpUtil.createHttpStatusCodeError(RESOURCE_METHOD_NOT_ALLOWED_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_RESOURCE_METHOD_NOT_ALLOWED_ERROR, "Method not allowed"); } return null; } @@ -189,7 +188,7 @@ private void validateConsumes(Resource resource, HttpCarbonMessage cMsg) { } } String message = "content-type : " + contentMediaType + " is not supported"; - throw HttpUtil.createHttpStatusCodeError(UNSUPPORTED_REQUEST_MEDIA_TYPE_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_UNSUPPORTED_REQUEST_MEDIA_TYPE_ERROR, message); } private String extractContentMediaType(String header) { @@ -231,7 +230,7 @@ private void validateProduces(Resource resource, HttpCarbonMessage cMsg) { return; } } - throw HttpUtil.createHttpStatusCodeError(REQUEST_NOT_ACCEPTABLE_ERROR, "Request is not acceptable"); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_REQUEST_NOT_ACCEPTABLE_ERROR, "Request is not acceptable"); } private List extractAcceptMediaTypes(String header) { diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDispatcher.java b/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDispatcher.java index ca3ebacf07..a03322782b 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDispatcher.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/ResourceDispatcher.java @@ -27,8 +27,8 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; -import static io.ballerina.stdlib.http.api.HttpErrorType.RESOURCE_DISPATCHING_SERVER_ERROR; -import static io.ballerina.stdlib.http.api.HttpErrorType.RESOURCE_NOT_FOUND_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_RESOURCE_DISPATCHING_SERVER_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_RESOURCE_NOT_FOUND_ERROR; /** * Resource level dispatchers handler for HTTP protocol. @@ -55,13 +55,14 @@ public static Resource findResource(Service service, HttpCarbonMessage inboundRe if (method.equals(HttpConstants.HTTP_METHOD_OPTIONS)) { handleOptionsRequest(inboundRequest, service); } else { - String message = "no matching resource found for path"; - throw HttpUtil.createHttpStatusCodeError(RESOURCE_NOT_FOUND_ERROR, message); + String message = "no matching resource found for path : " + + inboundRequest.getProperty(HttpConstants.TO) + " , method : " + method; + throw HttpUtil.createHttpStatusCodeError(INTERNAL_RESOURCE_NOT_FOUND_ERROR, message); } return null; } } catch (URITemplateException e) { - throw HttpUtil.createHttpStatusCodeError(RESOURCE_DISPATCHING_SERVER_ERROR, e.getMessage()); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_RESOURCE_DISPATCHING_SERVER_ERROR, e.getMessage()); } } @@ -85,8 +86,9 @@ private static void handleOptionsRequest(HttpCarbonMessage cMsg, Service service response.setHeader(HttpHeaderNames.ALLOW.toString(), DispatcherUtil.concatValues(service.getAllAllowedMethods(), false)); } else { - String message = "no matching resource found for path"; - throw HttpUtil.createHttpStatusCodeError(RESOURCE_NOT_FOUND_ERROR, message); + String message = "no matching resource found for path : " + cMsg.getProperty(HttpConstants.TO) + + " , method : OPTIONS"; + throw HttpUtil.createHttpStatusCodeError(INTERNAL_RESOURCE_NOT_FOUND_ERROR, message); } CorsHeaderGenerator.process(cMsg, response, false); String introspectionResourcePathHeaderValue = service.getIntrospectionResourcePathHeaderValue(); diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequestContext.java b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequestContext.java index a59d559fb4..fe0daded1f 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequestContext.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequestContext.java @@ -28,7 +28,7 @@ import io.ballerina.stdlib.http.api.HttpUtil; import org.ballerinalang.langlib.value.EnsureType; -import static io.ballerina.stdlib.http.api.HttpErrorType.INTERCEPTOR_RETURN_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_INTERCEPTOR_RETURN_ERROR; /** * Utilities related to HTTP request context. @@ -61,13 +61,14 @@ public static Object next(BObject requestCtx) { if (!isInterceptorService(requestCtx)) { // TODO : After introducing response interceptors, calling ctx.next() should return "illegal function // invocation : next()" if there is a response interceptor service in the pipeline - return HttpUtil.createHttpStatusCodeError(INTERCEPTOR_RETURN_ERROR, "no next service to be returned"); + return HttpUtil.createHttpStatusCodeError(INTERNAL_INTERCEPTOR_RETURN_ERROR, + "no next service to be returned"); } requestCtx.addNativeData(HttpConstants.REQUEST_CONTEXT_NEXT, true); return getNextInterceptor(requestCtx, interceptors); } else { String message = "request context object does not contain the configured interceptors"; - return HttpUtil.createHttpStatusCodeError(INTERCEPTOR_RETURN_ERROR, message); + return HttpUtil.createHttpStatusCodeError(INTERNAL_INTERCEPTOR_RETURN_ERROR, message); } } @@ -90,7 +91,8 @@ private static Object getNextInterceptor(BObject requestCtx, BArray interceptors } } if (interceptorIndex > interceptors.size()) { - return HttpUtil.createHttpStatusCodeError(INTERCEPTOR_RETURN_ERROR, "no next service to be returned"); + return HttpUtil.createHttpStatusCodeError(INTERNAL_INTERCEPTOR_RETURN_ERROR, + "no next service to be returned"); } if (interceptorIndex < 0) { return null; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java index 03242c8c95..71e30ceaf8 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/connection/Respond.java @@ -206,6 +206,11 @@ public static boolean invokeResponseInterceptor(Environment env, HttpCarbonMessa throw new BallerinaConnectorException("no Interceptor Service found to handle the response"); } + if (interceptorServiceIndex == 0 && inboundMessage.isInterceptorInternalError()) { + BError bError = (BError) inboundMessage.getProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR); + bError.printStackTrace(); + } + interceptorServiceIndex -= 1; inboundMessage.setProperty(HttpConstants.RESPONSE_INTERCEPTOR_INDEX, interceptorServiceIndex); startInterceptResponseMethod(inboundMessage, outboundResponseObj, callerObj, service, env, @@ -215,6 +220,7 @@ public static boolean invokeResponseInterceptor(Environment env, HttpCarbonMessa throw HttpUtil.createHttpError(e.getMessage(), HttpErrorType.GENERIC_LISTENER_ERROR); } } + // Handling error panics if (inboundMessage.isInterceptorError()) { HttpResponseInterceptorUnitCallback callback = new HttpResponseInterceptorUnitCallback(inboundMessage, callerObj, outboundResponseObj, env, dataContext, null, false); diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllHeaderParams.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllHeaderParams.java index 76d3a0d469..68ebac151a 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllHeaderParams.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllHeaderParams.java @@ -33,7 +33,7 @@ import java.util.ArrayList; import java.util.List; -import static io.ballerina.stdlib.http.api.HttpErrorType.HEADER_BINDING_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_HEADER_BINDING_ERROR; import static io.ballerina.stdlib.http.api.service.signature.ParamUtils.castParam; import static io.ballerina.stdlib.http.api.service.signature.ParamUtils.castParamArray; @@ -45,6 +45,8 @@ public class AllHeaderParams implements Parameter { private final List allHeaderParams = new ArrayList<>(); + private static final String NO_HEADER_VALUE_ERROR_MSG = "no header value found for '%s'"; + private static final String HEADER_BINDING_FAILED_ERROR_MSG = "header binding failed for parameter: '%s'"; @Override public String getTypeName() { @@ -78,8 +80,8 @@ public void populateFeed(HttpCarbonMessage httpCarbonMessage, Object[] paramFeed try { castedHeader = ValueUtils.convert(parsedHeader, headerParam.getOriginalType()); } catch (Exception ex) { - String message = "header binding failed for parameter: '" + headerParam.getHeaderName() + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message, null, + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(HEADER_BINDING_FAILED_ERROR_MSG, headerParam.getHeaderName()), null, HttpUtil.createError(ex)); } paramFeed[index++] = headerParam.validateConstraints(castedHeader); @@ -94,8 +96,8 @@ public void populateFeed(HttpCarbonMessage httpCarbonMessage, Object[] paramFeed paramFeed[index] = true; continue; } else { - String message = "no header value found for '" + token + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(NO_HEADER_VALUE_ERROR_MSG, token)); } } if (headerValues.size() == 1 && headerValues.get(0).isEmpty()) { @@ -104,8 +106,8 @@ public void populateFeed(HttpCarbonMessage httpCarbonMessage, Object[] paramFeed paramFeed[index] = true; continue; } else { - String message = "no header value found for '" + token + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(NO_HEADER_VALUE_ERROR_MSG, token)); } } int typeTag = headerParam.getEffectiveTypeTag(); @@ -119,9 +121,8 @@ public void populateFeed(HttpCarbonMessage httpCarbonMessage, Object[] paramFeed } castedHeaderValue = ValueUtils.convert(parsedHeaderValue, headerParam.getOriginalType()); } catch (Exception ex) { - String message = "header binding failed for parameter: '" + token + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message, null, - HttpUtil.createError(ex)); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(HEADER_BINDING_FAILED_ERROR_MSG, token), null, HttpUtil.createError(ex)); } paramFeed[index++] = headerParam.validateConstraints(castedHeaderValue); @@ -146,8 +147,8 @@ private BMap processHeaderRecord(HeaderParam headerParam, HttpH } else if (headerParam.isNilable()) { return null; } else { - String message = "no header value found for '" + key + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(NO_HEADER_VALUE_ERROR_MSG, key)); } } if (headerValues.size() == 1 && headerValues.get(0).isEmpty()) { @@ -157,8 +158,8 @@ private BMap processHeaderRecord(HeaderParam headerParam, HttpH } else if (headerParam.isNilable()) { return null; } else { - String message = "no header value found for '" + key + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(NO_HEADER_VALUE_ERROR_MSG, key)); } } try { @@ -170,9 +171,8 @@ private BMap processHeaderRecord(HeaderParam headerParam, HttpH recordValue.put(StringUtils.fromString(key), castParam(fieldTypeTag, headerValues.get(0))); } } catch (Exception ex) { - String message = "header binding failed for parameter: '" + key + "'"; - throw HttpUtil.createHttpStatusCodeError(HEADER_BINDING_ERROR, message, null, - HttpUtil.createError(ex)); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_BINDING_ERROR, + String.format(HEADER_BINDING_FAILED_ERROR_MSG, key), null, HttpUtil.createError(ex)); } } return recordValue; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllPathParams.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllPathParams.java index a591af5c6c..3e5f94045c 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllPathParams.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllPathParams.java @@ -39,7 +39,7 @@ import static io.ballerina.stdlib.http.api.HttpConstants.PERCENTAGE_ENCODED; import static io.ballerina.stdlib.http.api.HttpConstants.PLUS_SIGN; import static io.ballerina.stdlib.http.api.HttpConstants.PLUS_SIGN_ENCODED; -import static io.ballerina.stdlib.http.api.HttpErrorType.RESOURCE_NOT_FOUND_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_RESOURCE_NOT_FOUND_ERROR; import static io.ballerina.stdlib.http.api.service.signature.ParamUtils.castParam; import static io.ballerina.stdlib.http.api.service.signature.ParamUtils.castParamArray; @@ -95,10 +95,12 @@ public void populateFeed(Object[] paramFeed, HttpCarbonMessage httpCarbonMessage } catch (Exception ex) { String message = "error in casting path parameter : '" + paramToken + "'"; if (ParamUtils.isFiniteType(paramType)) { - message = "no matching resource found for path"; - throw HttpUtil.createHttpStatusCodeError(RESOURCE_NOT_FOUND_ERROR, message); + message = "no matching resource found for path : " + + httpCarbonMessage.getProperty(HttpConstants.TO) + + " , method : " + httpCarbonMessage.getHttpMethod(); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_RESOURCE_NOT_FOUND_ERROR, message); } else { - throw HttpUtil.createHttpStatusCodeError(HttpErrorType.PATH_PARAM_BINDING_ERROR, message, + throw HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_PATH_PARAM_BINDING_ERROR, message, null, HttpUtil.createError(ex)); } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllQueryParams.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllQueryParams.java index 9dea4d049b..c24734128f 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllQueryParams.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/AllQueryParams.java @@ -30,7 +30,7 @@ import java.util.ArrayList; import java.util.List; -import static io.ballerina.stdlib.http.api.HttpErrorType.QUERY_PARAM_BINDING_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_QUERY_PARAM_BINDING_ERROR; import static io.ballerina.stdlib.http.api.service.signature.ParamUtils.castParam; import static io.ballerina.stdlib.http.api.service.signature.ParamUtils.castParamArray; @@ -76,7 +76,7 @@ public void populateFeed(HttpCarbonMessage httpCarbonMessage, ParamHandler param continue; } else { String message = "no query param value found for '" + token + "'"; - throw HttpUtil.createHttpStatusCodeError(QUERY_PARAM_BINDING_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_QUERY_PARAM_BINDING_ERROR, message); } } Object castedQueryValue; @@ -93,7 +93,7 @@ public void populateFeed(HttpCarbonMessage httpCarbonMessage, ParamHandler param castedQueryValue = ValueUtils.convert(parsedQueryValue, queryParam.getOriginalType()); } catch (Exception ex) { String message = "error in casting query param : '" + token + "'"; - throw HttpUtil.createHttpStatusCodeError(QUERY_PARAM_BINDING_ERROR, message, null, + throw HttpUtil.createHttpStatusCodeError(INTERNAL_QUERY_PARAM_BINDING_ERROR, message, null, HttpUtil.createError(ex)); } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/HeaderParam.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/HeaderParam.java index e182aabdd8..bd29b95806 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/HeaderParam.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/HeaderParam.java @@ -31,7 +31,7 @@ import static io.ballerina.runtime.api.TypeTags.RECORD_TYPE_TAG; import static io.ballerina.stdlib.http.api.HttpConstants.HEADER_PARAM; -import static io.ballerina.stdlib.http.api.HttpErrorType.HEADER_VALIDATION_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_HEADER_VALIDATION_ERROR; /** * {@code {@link HeaderParam }} represents a inbound request header parameter details. @@ -98,7 +98,7 @@ public Object validateConstraints(Object headerValue) { Object result = Constraints.validateAfterTypeConversion(headerValue, getOriginalType()); if (result instanceof BError) { String message = "header validation failed: " + HttpUtil.getPrintableErrorMsg((BError) result); - throw HttpUtil.createHttpStatusCodeError(HEADER_VALIDATION_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_HEADER_VALIDATION_ERROR, message); } } return headerValue; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/ParamUtils.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/ParamUtils.java index 6ad7bf9acc..3fdd17b173 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/ParamUtils.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/ParamUtils.java @@ -20,6 +20,7 @@ import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.TypeTags; +import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.types.ArrayType; @@ -33,6 +34,7 @@ import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.utils.ValueUtils; import io.ballerina.runtime.api.values.BArray; +import io.ballerina.runtime.api.values.BError; import io.ballerina.stdlib.http.api.BallerinaConnectorException; import io.ballerina.stdlib.http.api.HttpUtil; @@ -64,20 +66,28 @@ public class ParamUtils { public static Object castParam(int targetParamTypeTag, String argValue) { - switch (targetParamTypeTag) { - case INT_TAG: - return Long.parseLong(argValue); - case FLOAT_TAG: - return Double.parseDouble(argValue); - case BOOLEAN_TAG: - return Boolean.parseBoolean(argValue); - case DECIMAL_TAG: - return ValueCreator.createDecimalValue(argValue); - case MAP_TAG: - case RECORD_TYPE_TAG: - return JsonUtils.parse(argValue); - default: - return StringUtils.fromString(argValue); + try { + switch (targetParamTypeTag) { + case INT_TAG: + return Long.parseLong(argValue); + case FLOAT_TAG: + return Double.parseDouble(argValue); + case BOOLEAN_TAG: + return Boolean.parseBoolean(argValue); + case DECIMAL_TAG: + return ValueCreator.createDecimalValue(argValue); + case MAP_TAG: + case RECORD_TYPE_TAG: + return JsonUtils.parse(argValue); + default: + return StringUtils.fromString(argValue); + } + } catch (Exception exp) { + String errorMessage = "error occurred while converting '" + argValue + "' to the target type"; + if (exp instanceof BError) { + throw ErrorCreator.createError(StringUtils.fromString(errorMessage), exp); + } + throw ErrorCreator.createError(StringUtils.fromString(errorMessage)); } } @@ -90,7 +100,16 @@ public static BArray castParamArray(Type elementType, String[] argValueArr) { case DECIMAL_TAG: case MAP_TAG: case RECORD_TYPE_TAG: - return getBArray(argValueArr, TypeCreator.createArrayType(elementType), elementType); + try { + return getBArray(argValueArr, TypeCreator.createArrayType(elementType), elementType); + } catch (Exception exp) { + String errorMessage = "error occurred while converting '" + argValueArr + + "' to the target array type"; + if (exp instanceof BError) { + throw ErrorCreator.createError(StringUtils.fromString(errorMessage), exp); + } + throw ErrorCreator.createError(StringUtils.fromString(errorMessage)); + } default: return StringUtils.fromStringArray(argValueArr); } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PathParam.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PathParam.java index 01c58063b1..de1fafc69a 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PathParam.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PathParam.java @@ -24,7 +24,7 @@ import io.ballerina.stdlib.http.api.HttpUtil; import static io.ballerina.stdlib.http.api.HttpConstants.PATH_PARAM; -import static io.ballerina.stdlib.http.api.HttpErrorType.QUERY_PARAM_VALIDATION_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_QUERY_PARAM_VALIDATION_ERROR; /** * {@code {@link PathParam }} represents a path parameter details. @@ -40,7 +40,7 @@ public Object validateConstraints(Object pathValue) { Object result = Constraints.validateAfterTypeConversion(pathValue, getOriginalType()); if (result instanceof BError) { String message = "path validation failed: " + HttpUtil.getPrintableErrorMsg((BError) result); - throw HttpUtil.createHttpStatusCodeError(QUERY_PARAM_VALIDATION_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_QUERY_PARAM_VALIDATION_ERROR, message); } } return pathValue; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PayloadParam.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PayloadParam.java index 72da491ab2..6b6b57de6f 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PayloadParam.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/PayloadParam.java @@ -40,8 +40,8 @@ import java.util.List; import static io.ballerina.runtime.api.TypeTags.ARRAY_TAG; -import static io.ballerina.stdlib.http.api.HttpErrorType.PAYLOAD_BINDING_LISTENER_ERROR; -import static io.ballerina.stdlib.http.api.HttpErrorType.PAYLOAD_VALIDATION_LISTENER_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_PAYLOAD_VALIDATION_LISTENER_ERROR; import static io.ballerina.stdlib.http.api.service.signature.builder.AbstractPayloadBuilder.getBuilder; import static io.ballerina.stdlib.mime.util.MimeConstants.REQUEST_ENTITY_FIELD; @@ -168,7 +168,7 @@ private int populateFeedWithAlreadyBuiltPayload(Object[] paramFeed, BObject inRe } } catch (BError ex) { String message = "data binding failed: " + HttpUtil.getPrintableErrorMsg(ex); - throw HttpUtil.createHttpStatusCodeError(PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } return index; } @@ -188,11 +188,11 @@ private int populateFeedWithFreshPayload(HttpCarbonMessage inboundMessage, Objec paramFeed[index] = null; return ++index; } - if (PAYLOAD_VALIDATION_LISTENER_ERROR.getErrorName().equals(typeName)) { + if (INTERNAL_PAYLOAD_VALIDATION_LISTENER_ERROR.getErrorName().equals(typeName)) { throw ex; } String message = "data binding failed: " + HttpUtil.getPrintableErrorMsg(ex); - throw HttpUtil.createHttpStatusCodeError(PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } } @@ -202,7 +202,7 @@ private Object validateConstraints(Object payloadBuilderValue) { ValueCreator.createTypedescValue(this.customParameterType)); if (result instanceof BError) { String message = "payload validation failed: " + HttpUtil.getPrintableErrorMsg((BError) result); - throw HttpUtil.createHttpStatusCodeError(PAYLOAD_VALIDATION_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_PAYLOAD_VALIDATION_LISTENER_ERROR, message); } } return payloadBuilderValue; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/QueryParam.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/QueryParam.java index 262c927019..579f629438 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/QueryParam.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/QueryParam.java @@ -24,7 +24,7 @@ import io.ballerina.stdlib.http.api.HttpUtil; import static io.ballerina.stdlib.http.api.HttpConstants.QUERY_PARAM; -import static io.ballerina.stdlib.http.api.HttpErrorType.QUERY_PARAM_VALIDATION_ERROR; +import static io.ballerina.stdlib.http.api.HttpErrorType.INTERNAL_QUERY_PARAM_VALIDATION_ERROR; /** * {@code {@link QueryParam }} represents a query parameter details. @@ -54,7 +54,7 @@ public Object validateConstraints(Object queryValue) { Object result = Constraints.validateAfterTypeConversion(queryValue, getOriginalType()); if (result instanceof BError) { String message = "query validation failed: " + HttpUtil.getPrintableErrorMsg((BError) result); - throw HttpUtil.createHttpStatusCodeError(QUERY_PARAM_VALIDATION_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(INTERNAL_QUERY_PARAM_VALIDATION_ERROR, message); } } return queryValue; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/BinaryPayloadBuilder.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/BinaryPayloadBuilder.java index 10cf301b06..2c5b19037b 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/BinaryPayloadBuilder.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/BinaryPayloadBuilder.java @@ -62,7 +62,7 @@ public Object getValue(BObject entity, boolean readonly) { } } String message = "incompatible type found: '" + payloadType.toString() + "'"; - throw HttpUtil.createHttpStatusCodeError(HttpErrorType.PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } private Object createValue(BObject entity, boolean readonly) { diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/StringPayloadBuilder.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/StringPayloadBuilder.java index a1653bafef..90e963d6ac 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/StringPayloadBuilder.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/StringPayloadBuilder.java @@ -72,6 +72,6 @@ private Object createValue(Type payloadType, boolean readonly, BString dataSourc } } String message = "incompatible type found: '" + payloadType.toString() + "'"; - throw HttpUtil.createHttpStatusCodeError(HttpErrorType.PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/XmlPayloadBuilder.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/XmlPayloadBuilder.java index cc5ee01069..e7f024d754 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/XmlPayloadBuilder.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/builder/XmlPayloadBuilder.java @@ -55,6 +55,6 @@ public Object getValue(BObject entity, boolean readonly) { return bxml; } String message = "incompatible type found: '" + payloadType.toString() + "'"; - throw HttpUtil.createHttpStatusCodeError(HttpErrorType.PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/StringToByteArrayConverter.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/StringToByteArrayConverter.java index aceb3577c1..b1169dd0d0 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/StringToByteArrayConverter.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/StringToByteArrayConverter.java @@ -44,7 +44,7 @@ public static Object convert(ArrayType type, BString dataSource, boolean readonl return readonly ? createReadonlyArrayValue(values) : createArrayValue(values); } String message = "incompatible array element type found: '" + elementType.toString() + "'"; - throw HttpUtil.createHttpStatusCodeError(HttpErrorType.PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } private StringToByteArrayConverter() { diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/UrlEncodedStringToMapConverter.java b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/UrlEncodedStringToMapConverter.java index 6c311834f1..018009ebd4 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/UrlEncodedStringToMapConverter.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/service/signature/converter/UrlEncodedStringToMapConverter.java @@ -57,7 +57,7 @@ public static Object convert(MapType type, BString dataSource, boolean readonly) return formParamMap; } String message = "incompatible type found: '" + type.toString() + "'"; - throw HttpUtil.createHttpStatusCodeError(HttpErrorType.PAYLOAD_BINDING_LISTENER_ERROR, message); + throw HttpUtil.createHttpStatusCodeError(HttpErrorType.INTERNAL_PAYLOAD_BINDING_LISTENER_ERROR, message); } private static BMap getFormParamMap(Object stringDataSource) { diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpCarbonMessage.java b/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpCarbonMessage.java index be989305b6..c2d0e47f48 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpCarbonMessage.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/message/HttpCarbonMessage.java @@ -675,6 +675,11 @@ public boolean isInterceptorError() { return this.getProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR) != null; } + public boolean isInterceptorInternalError() { + return this.getProperty(HttpConstants.INTERNAL_ERROR) != null && + this.getProperty(HttpConstants.INTERCEPTOR_SERVICE_ERROR) != null; + } + public String getRequestInterceptorServiceState() { if (isInterceptorError()) { return HttpConstants.REQUEST_ERROR_INTERCEPTOR; diff --git a/native/src/main/java/io/ballerina/stdlib/http/uri/URIUtil.java b/native/src/main/java/io/ballerina/stdlib/http/uri/URIUtil.java index e53c0717e8..34dd76400d 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/uri/URIUtil.java +++ b/native/src/main/java/io/ballerina/stdlib/http/uri/URIUtil.java @@ -128,7 +128,7 @@ public static String extractMatrixParams(String path, Map