<!-- This file specifies a spotbugs filter for excluding reports that
     should not be considered errors.

     The format of this file is documented at:

       https://spotbugs.readthedocs.io/en/latest/filter.html

     When possible, please specify the full names of the bug codes,
     using the pattern attribute, to make it clearer what reports are
     being suppressed.  You can find a listing of codes at:

       https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html
  -->

<FindBugsFilter>

    <Match>
        <Or>
            <!-- Ignore checking for generated JMH benchmarking classes -->
            <Package name="io.undertow.benchmarks.generated"/>
        </Or>
    </Match>

    <!-- Ignore spotbugs reports from incomplete detectors -->
    <Match>
        <Bug pattern="TESTING"/>
    </Match>

    <!-- We don't mind having redundant checks for null, it is more error prone to later changes -->
    <Match>
        <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/>
    </Match>

    <!-- Ignore negating result of compareTo -->
    <Match>
        <Bug pattern="RV_NEGATING_RESULT_OF_COMPARETO"/>
    </Match>

    <!-- Ignore class naming convention issues -->
    <Match>
        <Bug pattern="NM_CLASS_NAMING_CONVENTION"/>
    </Match>

    <!-- Ignore unread public and protected fields as someone may depend on Undertow and use them in their app -->
    <Match>
        <Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"/>
    </Match>

    <!-- False positives => ignoring, the field is read in tests -->
    <Match>
        <Bug pattern="URF_UNREAD_FIELD"/>
        <Or>
            <And>
                <Class name="io.undertow.server.protocol.ajp.AjpRequestParseState"/>
                <Field name="dataSize"/>
            </And>
        </Or>
    </Match>

    <!-- False positives => ignoring, the field is regular boolean, no complex bitwise operation is in place here -->
    <Match>
        <Bug pattern="BIT_IOR"/>
        <Or>
            <And>
                <Class name="io.undertow.conduits.AbstractFixedLengthStreamSinkConduit"/>
            </And>
        </Or>
    </Match>

    <!-- field is always incremented/decremented inside synchronized blocks using the same lock -->
    <Match>
        <Bug pattern="VO_VOLATILE_INCREMENT"/>
        <Or>
            <And>
                <Class name="io.undertow.server.protocol.framed.AbstractFramedStreamSinkChannel"/>
                <Field name="waiterCount"/>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.proxy.mod_cluster.NodeLbStatus"/>
                <Field name="elected"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ssl.SslConduit"/>
                <Field name="outstandingTasks"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ssl.SslConduit$5"/>
                <Field name="outstandingTasks"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ssl.SslConduit$5$1"/>
                <Field name="outstandingTasks"/>
            </And>
            <And>
                <Class name="io.undertow.server.session.InMemorySessionManager$SessionImpl"/>
                <Field name="expiredSessionCount"/>
            </And>
        </Or>
    </Match>

    <!--Stream id in HTTP/2 is always unsigned int per spec -->
    <Match>
        <Bug pattern="IM_BAD_CHECK_FOR_ODD"/>
        <Class name="io.undertow.protocols.http2.Http2Channel"/>
        <Method name="isClient"/>
    </Match>

    <!-- Even per javadoc of Object.wait(), this should be always used in loop. It is on purpose -->
    <Match>
        <Bug pattern="WA_NOT_IN_LOOP"/>
        <Or>
            <And>
                <Class name="io.undertow.protocols.ssl.SslConduit"/>
                <Method name="~await.*"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.framed.AbstractFramedStreamSourceChannel"/>
                <Method name="awaitReadable"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.framed.AbstractFramedStreamSinkChannel"/>
                <Method name="awaitWritable"/>
            </And>
        </Or>
    </Match>

    <!-- Ignore returning references to internal representations of objects -->
    <Match>
        <Bug pattern="EI_EXPOSE_REP"/>
    </Match>

    <!-- Ignoring when internal representation stores reference to external representation -->
    <Match>
        <Bug pattern="EI_EXPOSE_REP2"/>
    </Match>

    <!-- Intentional switch case follow through -->
    <Match>
        <Bug pattern="SF_SWITCH_FALLTHROUGH"/>
        <Or>
            <And>
                <Class name="io.undertow.protocols.ajp.AjpResponseParser"/>
                <Method name="parse" params="java.nio.ByteBuffer" returns="void"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.ajp.AjpRequestParser"/>
                <Method name="parse"/>
            </And>
            <And>
                <Class name="io.undertow.util.Cookies"/>
                <Method name="parseCookies"/>
            </And>
            <And>
                <Class name="io.undertow.util.Cookies"/>
                <Method name="parseCookie"/>
            </And>
            <And>
                <Class name="io.undertow.util.PathTemplate"/>
                <Method name="create"/>
            </And>
        </Or>
    </Match>

    <!-- Path has always some elements in our cases => ignoring -->
    <Match>
        <Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
        <Class name="io.undertow.server.handlers.resource.PathResource"/>
    </Match>

    <!-- The PathTemplate equivalent always exist, checked already by the contains method -->
    <Match>
        <Bug pattern="NP_NULL_ON_SOME_PATH"/>
        <Class name="io.undertow.util.PathTemplateMatcher"/>
    </Match>

    <!-- Ignoring switch cases with no default, all cases which can occur are covered -->
    <!-- TODO: Discuss with developer, whether not to add there some exception being thrown in such cases -->
    <Match>
        <Bug pattern="SF_SWITCH_NO_DEFAULT"/>
    </Match>


    <!-- Intentional throwing RuntimeException instead of checked exception -->
    <Match>
        <Bug pattern="REC_CATCH_EXCEPTION"/>
        <Or>
            <!-- Intentional throwing RuntimeException instead of checked exception -->
            <And>
                <Class name="io.undertow.Undertow"/>
                <Method name="start"/>
            </And>

            <!-- Intentional throwing RuntimeException instead of checked exception -->
            <And>
                <Class name="io.undertow.server.handlers.proxy.mod_cluster.MCMPHandler"/>
                <Method name="processConfig"/>
            </And>

            <!-- Intentional not throwing exception -->
            <And>
                <Class name="io.undertow.util.FlexBase64$Encoder"/>
                <Method name="encodeString"/>
            </And>
        </Or>
    </Match>

    <!-- The SQL is created based on configuration of the Handler => when proper configuration is created,
    then the risk of SQL injection is evaded -->
    <Match>
        <Bug pattern="SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING"/>
        <Class name="io.undertow.server.handlers.JDBCLogHandler"/>
        <Method name="prepareStatement"/>
    </Match>

    <!--Some inner subclasses of the AjpClientChannel class require to be non static, we want all of the same type inner -->
    <!--classes to be the same -->
    <Match>
        <Bug pattern="SIC_INNER_SHOULD_BE_STATIC"/>
        <Class name="~io\.undertow\.protocols\.ajp\.AjpClientChannel\$.*"/>
    </Match>

    <!-- Is done actually only once, no harm in it -->
    <Match>
        <Bug pattern="DMI_RANDOM_USED_ONLY_ONCE"/>
        <Class name="io.undertow.security.impl.SimpleNonceManager" />
    </Match>

    <Match>
        <Bug pattern="EQ_COMPARETO_USE_OBJECT_EQUALS"/>
        <Or>
            <Class name="io.undertow.server.handlers.encoding.EncodingMapping"/>
            <Class name="~.*AlpnOpenListener\$ListenerEntry"/>
        </Or>
    </Match>

    <!-- MCMPAdvertiseTask is used only as single background thread for doing advertising -->
    <Match>
        <Bug pattern="STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE"/>
        <Class name="io.undertow.server.handlers.proxy.mod_cluster.MCMPAdvertiseTask"/>
    </Match>

    <!--Ignoring checking for examples-->
    <Match>
        <Package name="~io\.undertow\.examples.*"/>
    </Match>

    <Match>
        <Bug pattern="RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT"/>
    </Match>

    <Match>
        <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
        <Class name="io.undertow.predicate.PredicatesHandler$RestartHandlerBuilder$1$1"/>
        <Method name="handleRequest"/>
    </Match>

    <!-- Method is actually fine-->
    <Match>
        <Bug pattern="NP_NONNULL_PARAM_VIOLATION"/>
        <Class name="io.undertow.server.protocol.http.AlpnOpenListener$AlpnConnectionListener"/>
    </Match>
    <!-- UNDERTOW-1839: we don't want to increase contention to synchronize all blocks that access the fields:
         engine, invokingReadListenerHandshake, readListenerInvocationCount. The less contention the better,
         the goal of the new synchronized blocks is to prevent writing to buffers that are being released
         by another thread -->
    <Match>
        <Bug pattern="IS2_INCONSISTENT_SYNC"/>
        <Class name="io.undertow.protocols.ssl.SslConduit"/>
    </Match>

    <!-- SslConduit needs to update the expanded buffer pool (static field) taking
    in consideration the buffer size needed for wrapping (instance lock context) -->
    <Match>
        <Bug pattern="SSD_DO_NOT_USE_INSTANCE_LOCK_ON_SHARED_STATIC_DATA"/>
        <Class name="io.undertow.protocols.ssl.SslConduit"/>
    </Match>

    <Match>
        <Bug pattern="THROWS_METHOD_THROWS_CLAUSE_THROWABLE"/>
        <Or>
            <!-- throws Throwable declared by finalize -->
            <Class name="io.undertow.server.DefaultByteBufferPool"/>
            <Class name="io.undertow.server.DefaultByteBufferPool$LeakDetector"/>
            <Class name="io.undertow.server.DefaultByteBufferPool$ThreadLocalData"/>
        </Or>
    </Match>

    <Match>
        <!-- At least for now, we don't mind throwing runtime exception, as this is a framework
        and currently several internal errors are wrapped in a RuntimeException whenever
        it is an internal error caller cannot handle or an external superclass signature
        does not contain a throw class-->
        <Bug pattern="THROWS_METHOD_THROWS_RUNTIMEEXCEPTION"/>
        <Or>
            <And>
                <Class name="io.undertow.annotationprocessor.HttpParserAnnotationProcessor"/>
                <Method name="process"/>
            </And>
            <And>
                <Class name="io.undertow.Undertow$ListenerInfo"/>
                <Method name="suspend"/>
            </And>
            <And>
                <Or>
                    <Class name="io.undertow.attribute.ExchangeAttributeParser"/>
                    <Class name="io.undertow.protocols.http2.Http2PushBackParser"/>
                    <Class name="io.undertow.util.URLUtils$QueryStringParser"/>
                    <Class name="io.undertow.server.handlers.builder.PredicatedHandlersParser"/>
                </Or>
                <Method name="parse"/>
            </And>
            <And>
                <Class name="io.undertow.client.http.ResponseParser"/>
                <Method name="httpStrings"/>
            </And>
            <And>
                <Or>
                    <Class name="io.undertow.conduits.DebuggingStreamSinkConduit"/>
                    <Class name="io.undertow.conduits.DebuggingStreamSourceConduit"/>
                </Or>
                <Method name="dump"/>
            </And>
            <And>
                <Class name="io.undertow.conduits.InflatingStreamSourceConduit"/>
                <Method name="read"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ajp.AjpClientChannel"/>
                <Method name="createChannel"/>
            </And>
            <And>
                <Or>
                    <Class name="io.undertow.protocols.alpn.JDK9AlpnProvider"/>
                    <Class name="io.undertow.protocols.alpn.OpenSSLAlpnProvider"/>
                </Or>
                <Or>
                    <Method name="setProtocols"/>
                    <Method name="getSelectedProtocol"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.protocols.http2.Http2DataStreamSinkChannel"/>
                <Method name="createFrameHeaderImpl"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.http2.Http2StreamSourceChannel"/>
                <Method name="handleHeaderData"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ssl.ALPNHackSSLEngine"/>
                <Method name="regenerateHashes"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ssl.ALPNHackServerByteArrayOutputStream"/>
                <Method name="write"/>
            </And>
            <And>
                <Class name="io.undertow.protocols.ssl.ALPNHackServerHelloExplorer"/>
                <Method name="exploreServerHello"/>
            </And>
            <And>
                <Class name="io.undertow.security.impl.FormAuthenticationMechanism"/>
                <Method name="runFormAuth"/>
            </And>
            <And>
                <Class name="io.undertow.server.Connectors"/>
                <Method name="setExchangeRequestPath"/>
            </And>
            <And>
                <Class name="io.undertow.server.DirectByteBufferDeallocator"/>
                <Or>
                    <Method name="getUnsafe0"/>
                    <Method name="getDeclaredMethod0"/>
                    <Method name="getAccesibleMethod0"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.RequestDumpingHandler"/>
                <Method name="dumpRequestBody"/>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.SetAttributeHandler$1"/>
                <Method name="beforeCommit"/>
            </And>
            <And>
                <Or>
                    <Class name="io.undertow.server.handlers.error.FileErrorPageHandler$2"/>
                    <Class name="io.undertow.util.Headers$1"/>
                </Or>
                <Method name="run"/>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.form.FormData"/>
                <Or>
                    <Method name="add"/>
                    <Method name="put"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler"/>
                <Or>
                    <Method name="parseBlocking"/>
                    <Method name="beginPart"/>
                    <Method name="data"/>
                    <Method name="endPart"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.proxy.HostTable"/>
                <Or>
                    <Method name="addHost"/>
                    <Method name="addRoute"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.proxy.ProxyConnectionPool"/>
                <Or>
                    <Method name="closeCurrentConnections"/>
                    <Method name="openConnection"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.proxy.ProxyHandlerBuilder"/>
                <Method name="build"/>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.proxy.mod_cluster.MCMPHandler"/>
                <Method name="checkStringForSuspiciousCharacters"/>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.resource.PathResource"/>
                <Or>
                    <Method name="list"/>
                    <Method name="getLastModified"/>
                    <Method name="getContentLength"/>
                    <Method name="getUrl"/>
                    <Method name="serveImpl"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.resource.URLResource"/>
                <Method name="list"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.ajp.AjpServerRequestConduit"/>
                <Method name="doRead"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.framed.AbstractFramedChannel"/>
                <Method name="flushSenders"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.http.RequestParser"/>
                <Or>
                    <Method name="instance"/>
                    <Method name="handlePath"/>
                    <Method name="handleQueryParameters"/>
                    <Method name="handlePathParameters"/>
                    <Method name="httpStrings"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.http2.Http2UpgradeHandler$1"/>
                <Method name="onComplete"/>
            </And>
            <And>
                <Or>
                    <Class name="io.undertow.util.MultipartParser$Base64Encoding"/>
                    <Class name="io.undertow.server.protocol.http2.Http2UpgradeHandler$3"/>
                </Or>
                <Method name="handle"/>
            </And>
            <And>
                <Class name="io.undertow.server.session.InMemorySessionManager"/>
                <Method name="createAndSaveNewID"/>
            </And>
            <And>
                <Class name="io.undertow.util.FileUtils"/>
                <Method name="readFile"/>
            </And>
            <And>
                <Class name="io.undertow.util.Headers"/>
                <Method name="extractQuotedValueFromHeaderWithEncoding"/>
            </And>
            <And>
                <Class name="io.undertow.Undertow"/>
                <Or>
                    <Method name="start"/>
                    <Method name="stop"/>
                </Or>
            </And>
            <And>
                <Class name="io.undertow.util.PathTemplate"/>
                <Method name="create"/>
            </And>
            <And>
                <Class name="io.undertow.util.RedirectBuilder"/>
                <Method name="redirect"/>
            </And>
            <And>
                <Or>
                    <!-- TODO: figure out static{} block reference -->
                    <Class name="io.undertow.client.http.ResponseParser"/>
                    <!-- TODO: figure constructor reference -->
                    <Class name="io.undertow.protocols.http2.Http2Channel"/>
                    <!-- TODO: figure constructor reference -->
                    <Class name="io.undertow.protocols.ssl.ALPNHackServerByteArrayOutputStream"/>
                    <!-- TODO: figure static reference -->
                    <Class name="io.undertow.security.impl.GSSAPIAuthenticationMechanism"/>
                    <!-- TODO: figure constructor reference -->
                    <Class name="io.undertow.server.handlers.proxy.mod_cluster.MCMPAdvertiseTask"/>
                    <!-- TODO: figure constructor reference -->
                    <Class name="io.undertow.server.handlers.resource.PathResourceManager"/>
                    <!-- TODO: figure static reference -->
                    <Class name="io.undertow.server.protocol.http.RequestParser"/>
                    <!-- TODO: figure static reference -->
                    <Class name="io.undertow.server.session.SecureRandomSessionIdGenerator"/>
                </Or>
            </And>
        </Or>
    </Match>
    <Match>
        <Bug pattern="THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION"/>
        <Or>
            <And>
                <Or>
                    <Class name="io.undertow.predicate.PredicatesHandler$DoneHandlerBuilder$1$1"/>
                    <Class name="io.undertow.predicate.PredicatesHandler$RestartHandlerBuilder$1$1"/>
                    <!-- False positive? -->
                    <Class name="io.undertow.security.impl.GSSAPIAuthenticationMechanism$AcceptSecurityContext"/>
                    <Class name="io.undertow.util.FlexBase64$1"/>
                </Or>
            </And>
                <!-- HttpHandler.handleEvent throws Exception, and so do all of its subclasses
                (there are tons of those) - as well as JDK classes -->
            <And>
                <Or>
                    <Class name="io.undertow.server.HttpHandler"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$2$1"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$2$2"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$2$3"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$3$1"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$3$2"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$3$3"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$4$1"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$4$2"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$4$3"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$5$1"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$5$2"/>
                    <Class name="io.undertow.io.AsyncReceiverImpl$5$3"/>
                    <Class name="io.undertow.predicate.PredicatesHandler"/>
                    <Class name="io.undertow.predicate.PredicatesHandler$DoneHandlerBuilder$1$1"/>
                    <Class name="io.undertow.predicate.PredicatesHandler$RestartHandlerBuilder$1$1"/>
                    <Class name="io.undertow.security.handlers.AbstractConfidentialityHandler"/>
                    <Class name="io.undertow.security.handlers.AbstractSecurityContextAssociationHandler"/>
                    <Class name="io.undertow.security.handlers.AuthenticationCallHandler"/>
                    <Class name="io.undertow.security.handlers.AuthenticationConstraintHandler"/>
                    <Class name="io.undertow.security.handlers.AuthenticationMechanismsHandler"/>
                    <Class name="io.undertow.security.handlers.CachedAuthenticatedSessionHandler"/>
                    <Class name="io.undertow.security.handlers.NotificationReceiverHandler"/>
                    <Class name="io.undertow.server.JvmRouteHandler"/>
                    <Class name="io.undertow.server.RoutingHandler"/>
                    <Class name="~io.undertow.server.handlers.*"/>
                    <Class name="io.undertow.server.handlers.resource.ResourceHandler"/>
                    <Class name="io.undertow.server.protocol.http.HttpContinue$3$1"/>
                    <Class name="io.undertow.server.protocol.http.HttpContinue$4$1"/>
                    <Class name="io.undertow.server.protocol.http2.Http2UpgradeHandler"/>
                    <Class name="io.undertow.server.protocol.http2.Http2UpgradeHandler$4$1"/>
                    <Class name="io.undertow.server.session.SessionAttachmentHandler"/>
                </Or>
                <Method name="handleRequest"/>
            </And>
            <And>
                <Class name="io.undertow.server.protocol.http2.Http2UpgradeHandler"/>
                <Method name="handleUpgradeBody"/>
            </And>
            <And>
                <Class name="io.undertow.server.RoutingHandler"/>
                <Method name="handleNoMatch"/>
            </And>
            <And>
                <Or>
                    <Class name="io.undertow.server.handlers.form.FormDataParser"/>
                    <Class name="io.undertow.server.handlers.form.FormEncodedDataDefinition$FormEncodedDataParser"/>
                    <Class name="io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler"/>
                </Or>
                <Method name="parse"/>
            </And>
            <And>
                <Class name="io.undertow.server.handlers.resource.ResourceHandler"/>
                <Method name="serveResource"/>
            </And>
        </Or>
    </Match>
    <Match>
        <Or>
            <!-- apparently a false positive associated with the try with resources -->
            <!-- see https://github.com/spotbugs/spotbugs/issues/647 -->
            <Bug pattern="NP_LOAD_OF_KNOWN_NULL_VALUE"/>
            <!-- apparently a false positive associated with the try with resources -->
            <!-- see https://github.com/spotbugs/spotbugs/issues/647 -->
            <Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"/>
        </Or>
        <Class name="io.undertow.security.impl.SingleSignOnAuthenticationMechanism"/>
        <Method name="authenticate"/>
    </Match>
    <Match>
        <Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE"/>
        <And>
            <Class name="io.undertow.client.http.HttpClientConnection$ClientReadListener"/>
            <Method name="handleEvent"/>
        </And>
    </Match>
    <!-- ignore benchmarks -->
    <Match>
        <Package name="io.undertow.benchmarks"/>
    </Match>
</FindBugsFilter>
