grails-core icon indicating copy to clipboard operation
grails-core copied to clipboard

Grails application reachable before fully deployed

Open mcepar opened this issue 3 years ago • 1 comments

Expected Behavior

The Grails application should not allow users to make HTTP requests before the application is fully deployed.

Actual Behaviour

The application accepts and actually processes HTTP requests before 'com.valsight.BootStrap#init' has finished executing.

This is especially problematic in relation to the "org.grails.plugins:database-migration" plugin, because the app processes HTTP requests, before the migrations are done.

Here is an example project that adds a delay to 'com.valsight.BootStrap#init' you can use to easily create HTTP requests before the app is deployed. app-accessible-too-early-bug-report-27092022.zip

Steps To Reproduce

  1. In any environment
  2. Start the application (use the attached project to make it easier)
  3. fire an HTTP request to the application while 'com.valsight.BootStrap#init' is executing
  4. the actual error: the HTTP request is fully processed before 'com.valsight.BootStrap#init' is finished

Environment Information

Operating system: Ubuntu 22.04 Java version: openjdk version "1.8.0_342" OpenJDK Runtime Environment (build 1.8.0_342-8u342-b07-0ubuntu1~22.04-b07) OpenJDK 64-Bit Server VM (build 25.342-b07, mixed mode)

Example Application

No response

Version

5.2.4

mcepar avatar Sep 28 '22 11:09 mcepar

I know this is an old question but i just got hit by the same bug. Grails 5.3.6

No filters are applied so all requests are running, even protected db access.

Found a patch for now: Service:

class WaitForBootstrapService {
    static lazy = false

    Boolean bootstrapDone = false
}

Interceptor:

class WaitForBootstrapInterceptor implements Interceptor {
    int order = HIGHEST_PRECEDENCE + 50

    WaitForBootstrapService waitForBootstrapService

    WaitForBootstrapInterceptor() {
        matchAll()
    }

    boolean before() {
        if(!waitForBootstrapService.bootstrapDone) {
            response.status = 503
        }
        return waitForBootstrapService.bootstrapDone
    }

    boolean after() { true }

    void afterView() {
        // no-op
    }
}

In Bootstrap

class BootStrap {

    WaitForBootstrapService waitForBootstrapService

    def init = { servletContext ->
        log.info("Start Bootstrap")
        // All normal bootstrap code
        waitForBootstrapService.bootstrapDone = true
        log.info("Finish Bootstrap")
    }
    def destroy = {
    }
}

jaudette790 avatar Apr 11 '24 20:04 jaudette790