Skip to content

chore(core): HTTP session#6277

Merged
ideoma merged 54 commits intomasterfrom
ia_session_cookie
Oct 24, 2025
Merged

chore(core): HTTP session#6277
ideoma merged 54 commits intomasterfrom
ia_session_cookie

Conversation

@glasstiger
Copy link
Copy Markdown
Contributor

@glasstiger glasstiger commented Oct 15, 2025

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 15, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds HTTP session management support to QuestDB by introducing a new session store interface with implementations, refactoring security context creation to use a PrincipalContext abstraction, refining clock types from generic Clock to specific NanosecondClock/MicrosecondClock, and simplifying HttpServer wiring by moving cookie and header handling into the connection context factory.

Changes

Cohort / File(s) Summary
Session and Cookie Interfaces
core/src/main/java/io/questdb/cutlass/http/HttpSessionStore.java, core/src/main/java/io/questdb/cutlass/http/TokenGenerator.java, core/src/main/java/io/questdb/cutlass/http/HttpCookieHandler.java
New interfaces define session lifecycle (create, destroy, verify, update groups) and token generation; HttpCookieHandler refactored to split cookie parsing, service-account cookies, and session cookies into separate methods with default implementations.
Session and Cookie Implementations
core/src/main/java/io/questdb/cutlass/http/HttpSessionStoreImpl.java, core/src/main/java/io/questdb/cutlass/http/HttpCookieHandlerImpl.java, core/src/main/java/io/questdb/cutlass/http/TokenGeneratorImpl.java, core/src/main/java/io/questdb/cutlass/http/EmptyHttpSessionStore.java
Concrete implementations: session store with rotation/expiry, cookie handler with parsing, token generator with SecureRandom, and empty no-op store.
Security Context Refactoring
core/src/main/java/io/questdb/cairo/security/PrincipalContext.java, core/src/main/java/io/questdb/cairo/security/SecurityContextFactory.java, core/src/main/java/io/questdb/cairo/security/ReadOnlySecurityContextFactory.java, core/src/main/java/io/questdb/cairo/security/AllowAllSecurityContextFactory.java
New PrincipalContext interface consolidates principal, groups, and authType; SecurityContextFactory updated to accept PrincipalContext instead of separate parameters.
Authenticator and Protocol Contexts
core/src/main/java/io/questdb/cutlass/auth/Authenticator.java, core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpConnectionContext.java, core/src/main/java/io/questdb/cutlass/pgwire/PGConnectionContext.java, core/src/main/java/io/questdb/cutlass/pgwire/ReadOnlyUsersAwareSecurityContextFactory.java
Authenticator now extends PrincipalContext; connection contexts updated to pass authenticator/PrincipalContext to security context factory.
HTTP Connection and Constants
core/src/main/java/io/questdb/cutlass/http/HttpConnectionContext.java, core/src/main/java/io/questdb/cutlass/http/HttpConstants.java
HttpConnectionContext wired with session store, cookie parsing, and session lifecycle; new constants for session cookie handling and URL parameters.
HTTP Server and Response
core/src/main/java/io/questdb/cutlass/http/HttpServer.java, core/src/main/java/io/questdb/cutlass/http/HttpResponseSink.java, core/src/main/java/io/questdb/cutlass/http/DefaultHttpCookieHandler.java
HttpServer constructor simplified to remove cookie/header handler dependencies; HttpResponseSink updated to handle multiple cookies via ObjList pairs.
HTTP Configuration Interfaces
core/src/main/java/io/questdb/cutlass/http/HttpContextConfiguration.java, core/src/main/java/io/questdb/cutlass/http/DefaultHttpContextConfiguration.java, core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessorConfiguration.java, core/src/main/java/io/questdb/cutlass/http/processors/LineHttpProcessorConfiguration.java
Configuration interfaces and defaults updated with session timeout; clock return types refined to NanosecondClock and MicrosecondClock.
HTTP Request Processing
core/src/main/java/io/questdb/cutlass/http/HttpRequestProcessor.java, core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessor.java, core/src/main/java/io/questdb/cutlass/http/processors/RejectProcessorImpl.java
Method processCookies renamed to processServiceAccountCookie; session cookie setting added; RejectProcessor updated to handle multiple cookies.
Factory and Configuration
core/src/main/java/io/questdb/DefaultFactoryProvider.java, core/src/main/java/io/questdb/FactoryProvider.java, core/src/main/java/io/questdb/FactoryProviderImpl.java, core/src/main/java/io/questdb/PropertyKey.java
FactoryProvider interface and implementations updated with getHttpSessionStore() method; new helper methods for wiring authentication, cookies, session stores; new HTTP_SESSION_TIMEOUT property key.
Configuration and Services
core/src/main/java/io/questdb/PropServerConfiguration.java, core/src/main/java/io/questdb/PropHttpServerConfiguration.java, core/src/main/java/io/questdb/cutlass/Services.java, core/src/main/java/io/questdb/ServerMain.java
Session timeout configuration added throughout; clock types refined; Services and ServerMain simplified by removing redundant factory methods.
Line TCP and Default Configuration
core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpReceiverConfiguration.java, core/src/main/java/io/questdb/cutlass/line/tcp/DefaultLineTcpReceiverConfiguration.java, core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpReceiverConfigurationWrapper.java, core/src/main/java/io/questdb/cutlass/http/DefaultHttpServerConfiguration.java
Clock types refined from Clock to MicrosecondClock/NanosecondClock; network worker pool configuration exposed.
Configuration Resources
core/src/main/resources/io/questdb/site/conf/server.conf
Added commented example for http.session.timeout configuration.
Test Utilities
core/src/test/java/io/questdb/test/TestServerConfiguration.java, core/src/test/java/io/questdb/test/cutlass/http/HttpQueryTestBuilder.java, core/src/test/java/io/questdb/test/cutlass/http/HttpServerConfigurationBuilder.java, core/src/test/java/io/questdb/test/cutlass/line/tcp/AbstractLineTcpReceiverTest.java, core/src/test/java/io/questdb/test/cutlass/line/tcp/BaseLineTcpContextTest.java
Test builders and helpers updated with clock type refinements and configuration removal (multipart idle spin count).
Test Cases
core/src/test/java/io/questdb/test/ServerMainTest.java, core/src/test/java/io/questdb/test/PropServerConfigurationTest.java, core/src/test/java/io/questdb/test/ServerMainHttpAuthTest.java, core/src/test/java/io/questdb/test/ServerMainHttpAuthConcurrentTest.java, core/src/test/java/io/questdb/test/cutlass/http/HttpErrorHandlingTest.java, core/src/test/java/io/questdb/test/cutlass/http/line/LineHttpSenderLoggingTest.java, utils/src/test/java/io/questdb/cliutil/Table2IlpTest.java
New and updated tests for session management, concurrent auth scenarios, HTTP error handling, and configuration validation.

Sequence Diagram

sequenceDiagram
    participant Client
    participant HttpServer
    participant HttpConnectionContext
    participant SessionStore
    participant Authenticator
    participant SecurityContextFactory

    Client->>HttpServer: HTTP request (auth header)
    HttpServer->>HttpConnectionContext: handleClientRecv()
    HttpConnectionContext->>HttpConnectionContext: parseCookies()
    alt Session Cookie Present
        HttpConnectionContext->>SessionStore: verifySessionId()
        SessionStore-->>HttpConnectionContext: SessionInfo or null
    else No Session Cookie
        HttpConnectionContext->>Authenticator: authenticate()
        Authenticator-->>HttpConnectionContext: PrincipalContext
    end
    HttpConnectionContext->>SecurityContextFactory: getInstance(PrincipalContext)
    SecurityContextFactory-->>HttpConnectionContext: SecurityContext
    HttpConnectionContext->>HttpConnectionContext: configureSecurityContext()
    alt Cookies Enabled and No Valid Session
        HttpConnectionContext->>SessionStore: createSession(PrincipalContext)
        SessionStore-->>HttpConnectionContext: sessionId
        HttpConnectionContext->>HttpConnectionContext: setSessionCookie(sessionId)
    end
    HttpConnectionContext-->>Client: HTTP response with session cookie
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Reasoning: The diff spans 50+ files with significant heterogeneity. Changes include:

  • Dense session management logic with concurrency (HttpSessionStoreImpl, HttpCookieHandlerImpl)
  • Structural refactoring of security context creation (PrincipalContext abstraction)
  • Widespread clock type refinement (many files, but repetitive pattern)
  • HTTP server wiring simplification requiring verification of call sites
  • Multiple test cases validating new session lifecycle and concurrent scenarios
  • Integration of session, cookie, and authentication flows requires understanding cross-module interactions

Possibly related PRs

Suggested labels

Core, Enhancement

Suggested reviewers

  • puzpuzpuz
  • ideoma

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.34% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "chore(core): HTTP session" is clearly and directly related to the main changes in the changeset. The PR introduces a new HTTP session management system with HttpSessionStore, DefaultHttpSessionStore, session cookie handling, and supporting infrastructure like PrincipalContext. The title accurately captures the primary objective of the changes as stated in the PR description "HTTP session with a session cookie." While the changeset also includes supporting refactorings (PrincipalContext introduction, Clock type changes), these are secondary to the core HTTP session management goal, and the title appropriately reflects the main focus without needing to enumerate all details.
Description Check ✅ Passed The pull request description "HTTP session with a session cookie. required by https://github.com/questdb/questdb-enterprise/pull/744" is directly and clearly related to the changeset. The description accurately identifies the core functionality being introduced (HTTP session management with session cookies) and provides context about why the changes are needed. Although brief, the description is not vague or generic—it conveys meaningful information about the changeset and aligns with the actual changes across the multiple files that implement session storage, session cookie handling, and related HTTP request/response processing.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e80bf4f and 5ee9cf5.

📒 Files selected for processing (47)
  • core/src/main/java/io/questdb/DefaultFactoryProvider.java (2 hunks)
  • core/src/main/java/io/questdb/FactoryProviderImpl.java (4 hunks)
  • core/src/main/java/io/questdb/PropHttpServerConfiguration.java (8 hunks)
  • core/src/main/java/io/questdb/PropServerConfiguration.java (7 hunks)
  • core/src/main/java/io/questdb/PropertyKey.java (1 hunks)
  • core/src/main/java/io/questdb/ServerMain.java (0 hunks)
  • core/src/main/java/io/questdb/cairo/security/AllowAllSecurityContextFactory.java (2 hunks)
  • core/src/main/java/io/questdb/cairo/security/PrincipalContext.java (1 hunks)
  • core/src/main/java/io/questdb/cairo/security/ReadOnlySecurityContextFactory.java (1 hunks)
  • core/src/main/java/io/questdb/cairo/security/SecurityContextFactory.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/Services.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/auth/Authenticator.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/DefaultHttpContextConfiguration.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/http/DefaultHttpCookieHandler.java (0 hunks)
  • core/src/main/java/io/questdb/cutlass/http/DefaultHttpServerConfiguration.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/http/EmptyHttpSessionStore.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpConnectionContext.java (13 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpConstants.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpContextConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpCookieHandler.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpCookieHandlerImpl.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpRequestProcessor.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpResponseSink.java (5 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpServer.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpSessionStore.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpSessionStoreImpl.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/TokenGeneratorImpl.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessor.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessorConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/http/processors/LineHttpProcessorConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/line/tcp/DefaultLineTcpReceiverConfiguration.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpConnectionContext.java (5 hunks)
  • core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpReceiverConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpReceiverConfigurationWrapper.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/pgwire/PGConnectionContext.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/pgwire/ReadOnlyUsersAwareSecurityContextFactory.java (2 hunks)
  • core/src/main/resources/io/questdb/site/conf/server.conf (1 hunks)
  • core/src/test/java/io/questdb/test/PropServerConfigurationTest.java (4 hunks)
  • core/src/test/java/io/questdb/test/ServerMainHttpAuthConcurrentTest.java (1 hunks)
  • core/src/test/java/io/questdb/test/ServerMainHttpAuthTest.java (4 hunks)
  • core/src/test/java/io/questdb/test/ServerMainTest.java (1 hunks)
  • core/src/test/java/io/questdb/test/TestServerConfiguration.java (2 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/HttpErrorHandlingTest.java (4 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/HttpQueryTestBuilder.java (3 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/HttpServerConfigurationBuilder.java (5 hunks)
  • core/src/test/java/io/questdb/test/cutlass/line/tcp/AbstractLineTcpReceiverTest.java (2 hunks)
  • core/src/test/java/io/questdb/test/cutlass/line/tcp/BaseLineTcpContextTest.java (2 hunks)

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.39.6)
core/src/main/java/io/questdb/PropServerConfiguration.java

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@glasstiger glasstiger added the DO NOT MERGE These changes should not be merged to main branch label Oct 15, 2025
@bluestreak01
Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 18, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
utils/src/test/java/io/questdb/cliutil/Table2IlpTest.java (1)

199-207: Null‑safe teardown for httpServer

createHttpServer() can return null when HTTP is disabled; tearDown should guard against NPE.

Apply:

-        httpServer.close();
+        if (httpServer != null) {
+            httpServer.close();
+        }
core/src/main/java/io/questdb/cutlass/http/HttpResponseSink.java (1)

604-608: Sanitize cookie name/value to prevent response-splitting/header injection.

Cookie fields are written directly to headers without CR/LF checks. If any value contains \r or \n, a client-controlled header/body split is possible.

Apply a central sanitizer and reuse it for both emitters:

@@ public class HttpResponseHeaderImpl implements Utf8Sink, HttpResponseHeader, Mutable {
-        public void setCookie(CharSequence name, CharSequence value) {
+        public void setCookie(CharSequence name, CharSequence value) {
             if (cookiesEnabled) {
-                put(HEADER_SET_COOKIE).putAscii(": ").put(name).putAscii(COOKIE_VALUE_SEPARATOR).put(value).putEOL();
+                final CharSequence safeName = sanitizeCookieToken(name);
+                final CharSequence safeValue = sanitizeCookieValue(value);
+                put(HEADER_SET_COOKIE).putAscii(": ").put(safeName).putAscii(COOKIE_VALUE_SEPARATOR).put(safeValue).putEOL();
             }
         }
@@ public class SimpleResponseImpl {
-        private void setCookie(CharSequence name, CharSequence value) {
-            if (cookiesEnabled) {
-                headerImpl.put(HEADER_SET_COOKIE).putAscii(": ").put(name).putAscii(COOKIE_VALUE_SEPARATOR).put(!isBlank(value) ? value : "").putEOL();
-            }
-        }
+        private void setCookie(CharSequence name, CharSequence value) {
+            // Delegate to a single implementation to keep behavior consistent
+            headerImpl.setCookie(name, !isBlank(value) ? value : "");
+        }

Add helpers near HttpResponseSink class scope:

+    private static CharSequence sanitizeCookieToken(CharSequence cs) {
+        if (cs == null) return "";
+        for (int i = 0, n = cs.length(); i < n; i++) {
+            char c = cs.charAt(i);
+            if (c <= 0x1F || c == 0x7F || c == '\r' || c == '\n' || c == ';') {
+                throw new IllegalArgumentException("Invalid cookie token character");
+            }
+        }
+        return cs;
+    }
+
+    private static CharSequence sanitizeCookieValue(CharSequence cs) {
+        if (cs == null) return "";
+        for (int i = 0, n = cs.length(); i < n; i++) {
+            char c = cs.charAt(i);
+            if (c == '\r' || c == '\n') {
+                throw new IllegalArgumentException("Invalid cookie value character");
+            }
+        }
+        return cs;
+    }

Also applies to: 842-846

🧹 Nitpick comments (11)
core/src/main/java/io/questdb/cutlass/http/PrincipalContext.java (1)

1-11: Add documentation and nullability annotations.

This new public interface lacks Javadoc and nullability annotations. Consider adding:

  • Interface-level Javadoc explaining the purpose and usage
  • Method-level documentation, especially for getAuthType() to clarify expected values
  • @NotNull or @Nullable annotations on return types per the project's usage of org.jetbrains:annotations:17.0.0

Example documentation:

 package io.questdb.cutlass.http;
 
 import io.questdb.std.ObjList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
+/**
+ * Represents an authenticated principal with associated metadata.
+ * Used for session management and security context creation.
+ */
 public interface PrincipalContext {
+    /**
+     * @return the authentication type identifier
+     */
     byte getAuthType();
 
+    /**
+     * @return the list of groups this principal belongs to, or null if none
+     */
+    @Nullable
     ObjList<CharSequence> getGroups();
 
+    /**
+     * @return the principal name/identifier
+     */
+    @NotNull
     CharSequence getPrincipal();
 }
core/src/main/java/io/questdb/cutlass/http/TokenGenerator.java (1)

1-5: Add documentation and nullability annotations.

This new interface lacks documentation and nullability annotations. Consider adding:

  • Interface-level Javadoc explaining the purpose (e.g., generates session tokens)
  • @NotNull annotation on the return type
  • Copyright header consistent with other project files

Example:

+/*******************************************************************************
+ *     ___                  _   ____  ____
+ *    / _ \ _   _  ___  ___| |_|  _ \| __ )
+ *   | | | | | | |/ _ \/ __| __| | | |  _ \
+ *   | |_| | |_| |  __/\__ \ |_| |_| | |_) |
+ *    \__\_\\__,_|\___||___/\__|____/|____/
+ *
+ *  Copyright (c) 2014-2019 Appsicle
+ *  Copyright (c) 2019-2024 QuestDB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
 package io.questdb.cutlass.http;
 
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Generates unique tokens for HTTP session management.
+ */
 public interface TokenGenerator {
+    /**
+     * @return a newly generated unique token
+     */
+    @NotNull
     CharSequence newToken();
 }
core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessorState.java (1)

1025-1025: Good refactor: prefer isEmpty() over length() == 0.

This change improves code readability by using the more idiomatic isEmpty() method to check for empty strings.

core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpConnectionContext.java (1)

53-53: Consider enum for dummy principal context.

The DummyPrincipalContext is a stateless, immutable singleton. Consider using an enum instead of a static inner class for better clarity and guaranteed singleton semantics:

-    private static final DummyPrincipalContext DUMMY_CONTEXT = new DummyPrincipalContext();
+    private static final PrincipalContext DUMMY_CONTEXT = DummyPrincipal.INSTANCE;

-    private static class DummyPrincipalContext implements PrincipalContext {
+    private enum DummyPrincipal implements PrincipalContext {
+        INSTANCE;
+
         @Override
         public byte getAuthType() {
             return SecurityContext.AUTH_TYPE_NONE;
         }
-
+
         @Override
         public ObjList<CharSequence> getGroups() {
             return null;
         }
-
+
         @Override
         public CharSequence getPrincipal() {
             return null;
         }
     }

Also applies to: 427-442

core/src/main/java/io/questdb/cairo/security/ReadOnlySecurityContextFactory.java (1)

35-37: LGTM: signature aligned with new factory API

Method now matches the PrincipalContext‑based contract and preserves behavior.

If IDE flags the unused parameter, consider @SuppressWarnings("unused") on the method.

core/src/main/java/io/questdb/cutlass/pgwire/PGConnectionContext.java (1)

174-176: Constructor contract: enforce non‑null tasCache

tasCache is required everywhere. Add a non‑null check to fail fast and consider annotating for static analysis.

Apply:

-    private final AssociativeCache<TypesAndSelect> tasCache;
+    private final AssociativeCache<TypesAndSelect> tasCache;
@@
-            AssociativeCache<TypesAndSelect> tasCache
+            AssociativeCache<TypesAndSelect> tasCache
         ) {
@@
-            this.tasCache = tasCache;
+            this.tasCache = java.util.Objects.requireNonNull(tasCache, "tasCache");

Also applies to: 205-210

core/src/main/java/io/questdb/cutlass/http/HttpCookieHandler.java (1)

29-41: Specify non‑null contract for session result

Make the non‑null sentinel explicit to prevent null handling bugs, and document intent for implementors.

Apply:

 package io.questdb.cutlass.http;
 
 import io.questdb.cairo.SecurityContext;
+import org.jetbrains.annotations.NotNull;
 
 public interface HttpCookieHandler {
     boolean parseCookies(HttpConnectionContext context);
 
     boolean processServiceAccountCookie(HttpConnectionContext context, SecurityContext securityContext);
 
-    HttpSessionStore.SessionInfo processSessionCookie(HttpConnectionContext context);
+    @NotNull HttpSessionStore.SessionInfo processSessionCookie(HttpConnectionContext context);
 
     default void setServiceAccountCookie(HttpResponseHeader header, SecurityContext securityContext) {
     }
 
     default void setSessionCookie(HttpResponseHeader header, CharSequence sessionId) {
     }
 }
core/src/main/java/io/questdb/cutlass/http/HttpResponseSink.java (1)

762-770: API polish: collapse cookie overloads around a single path.

sendStatusTextContent(...) and sendStatusWithCookie(...) duplicate intent. Consider keeping only the text method with cookie pairs to avoid future drift.

Also applies to: 788-795

core/src/main/java/io/questdb/cutlass/http/HttpConnectionContext.java (1)

79-82: Avoid duplicating TRUE/FALSE literals.

Prefer a single source (e.g., constants in HttpConstants) to reduce drift and improve discoverability.

core/src/main/java/io/questdb/cutlass/http/HttpSessionStore.java (2)

64-66: Harden the NO_SESSION sentinel against mutation.

Make it final and override mutators to throw to prevent accidental changes during debugging or misuse.

Apply this diff:

-        public static SessionInfo NO_SESSION = new SessionInfo(
-                "NO_SESSION", "NO_SESSION", null, SecurityContext.AUTH_TYPE_NONE, -1L, -1L
-        );
+        public static final SessionInfo NO_SESSION = new SessionInfo(
+                "NO_SESSION", "NO_SESSION", null, SecurityContext.AUTH_TYPE_NONE, -1L, -1L
+        ) {
+            @Override public void rotate(String newSessionId, long nextRotationAt) { throw new UnsupportedOperationException("NO_SESSION"); }
+            @Override public void setExpiresAt(long expiresAt) { throw new UnsupportedOperationException("NO_SESSION"); }
+            @Override public synchronized void setGroups(@Nullable ObjList<CharSequence> source) { throw new UnsupportedOperationException("NO_SESSION"); }
+        };

Also applies to: 113-121, 122-142


95-103: Avoid exposing a mutable groups list.

getGroups() returns a live ObjList that callers can mutate, breaking the double‑buffering assumption.

Consider returning a defensive copy or an unmodifiable view, or document the method as “read‑only” and enforce immutability at the type level if possible.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae812a3 and e80bf4f.

📒 Files selected for processing (36)
  • core/src/main/java/io/questdb/DefaultFactoryProvider.java (2 hunks)
  • core/src/main/java/io/questdb/FactoryProvider.java (2 hunks)
  • core/src/main/java/io/questdb/FactoryProviderImpl.java (2 hunks)
  • core/src/main/java/io/questdb/PropHttpServerConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/PropServerConfiguration.java (1 hunks)
  • core/src/main/java/io/questdb/cairo/security/AllowAllSecurityContextFactory.java (2 hunks)
  • core/src/main/java/io/questdb/cairo/security/ReadOnlySecurityContextFactory.java (1 hunks)
  • core/src/main/java/io/questdb/cairo/security/SecurityContextFactory.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/Services.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/auth/Authenticator.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/DefaultHttpContextConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/http/DefaultHttpCookieHandler.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/DefaultHttpSessionStore.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpConnectionContext.java (14 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpConstants.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpContextConfiguration.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpCookieHandler.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpRequestProcessor.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpResponseSink.java (5 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpServer.java (4 hunks)
  • core/src/main/java/io/questdb/cutlass/http/HttpSessionStore.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/PrincipalContext.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/TokenGenerator.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessor.java (3 hunks)
  • core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessorState.java (1 hunks)
  • core/src/main/java/io/questdb/cutlass/http/processors/RejectProcessorImpl.java (5 hunks)
  • core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpConnectionContext.java (5 hunks)
  • core/src/main/java/io/questdb/cutlass/pgwire/PGConnectionContext.java (2 hunks)
  • core/src/main/java/io/questdb/cutlass/pgwire/ReadOnlyUsersAwareSecurityContextFactory.java (2 hunks)
  • core/src/test/java/io/questdb/test/ServerMainTest.java (1 hunks)
  • core/src/test/java/io/questdb/test/TestServerConfiguration.java (2 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/HttpErrorHandlingTest.java (5 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/HttpQueryTestBuilder.java (4 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/HttpServerConfigurationBuilder.java (4 hunks)
  • core/src/test/java/io/questdb/test/cutlass/http/line/LineHttpSenderLoggingTest.java (1 hunks)
  • utils/src/test/java/io/questdb/cliutil/Table2IlpTest.java (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: New pull request (Coverage Report Coverage Report)
  • GitHub Check: New pull request (SelfHosted Other tests on linux-x64-zfs)
  • GitHub Check: New pull request (SelfHosted Other tests on linux-arm64)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests on linux-arm64)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests on linux-x64-zfs)
  • GitHub Check: New pull request (Rust Test and Lint on linux-jdk17)
  • GitHub Check: New pull request (Hosted Running tests on windows-other)
  • GitHub Check: New pull request (Hosted Running tests on windows-pgwire)
  • GitHub Check: New pull request (Hosted Running tests on windows-cairo)
  • GitHub Check: New pull request (Hosted Running tests on windows-fuzz2)
  • GitHub Check: New pull request (Hosted Running tests on windows-fuzz1)
  • GitHub Check: New pull request (Hosted Running tests on windows-griffin)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-other)
  • GitHub Check: New pull request (Hosted Running tests on mac-other)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-pgwire)
  • GitHub Check: New pull request (Hosted Running tests on mac-pgwire)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-cairo)
  • GitHub Check: New pull request (Hosted Running tests on mac-cairo-fuzz)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-fuzz)
  • GitHub Check: New pull request (Hosted Running tests on mac-cairo)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests Start X64Zfs Agent)
  • GitHub Check: New pull request (SelfHosted Griffin And Fuzz tests Start ARM Agent)
  • GitHub Check: New pull request (Hosted Running tests with cover on linux-griffin)
  • GitHub Check: New pull request (SelfHosted Other tests Start X64Zfs Agent)
  • GitHub Check: New pull request (Hosted Running tests on mac-griffin)
  • GitHub Check: New pull request (SelfHosted Other tests Start ARM Agent)
  • GitHub Check: New pull request (Check Changes Check changes)
🔇 Additional comments (28)
core/src/test/java/io/questdb/test/ServerMainTest.java (1)

727-727: LGTM! HTTP cookie property correctly added to expected parameters.

The addition of http.server.cookies.enabled property aligns with the PR's HTTP session management feature. The format is consistent with existing properties, and the default value of true appropriately enables cookie support by default.

core/src/main/java/io/questdb/PropServerConfiguration.java (2)

1122-1138: Min HTTP context is hardcoded read-only — confirm intent

The constructor passes true for readOnlySecurityContext. If this is intentional for the min server, ignore; otherwise, consider making it configurable (min variant of HTTP_SECURITY_READONLY) for parity with the main server.


1118-1120: Property referenced in suggested fix does not exist; manual verification required

Line 1119 correctly identifies a bug—minHttpServerCookiesEnabled reads HTTP_MIN_SERVER_KEEP_ALIVE (line 1118's property). However, HTTP_MIN_SERVER_COOKIES_ENABLED does not exist in PropertyKey.java. Only HTTP_SERVER_COOKIES_ENABLED (non-min variant) is defined.

Additionally, line 1118 (minHttpMinServerKeepAlive) appears to have an identical bug with a confusing variable name that duplicates the property key.

Clarify the intended behavior:

  • Should HTTP_MIN_SERVER_COOKIES_ENABLED be created as a new property?
  • Or should minHttpServerCookiesEnabled read HTTP_SERVER_COOKIES_ENABLED instead?
core/src/test/java/io/questdb/test/cutlass/http/line/LineHttpSenderLoggingTest.java (1)

126-129: Updated SecurityContextFactory lambda matches new signature

Switch to (principalContext, interfaceId) looks correct and keeps the test focused on auth error handling.

core/src/test/java/io/questdb/test/cutlass/http/HttpQueryTestBuilder.java (1)

196-197: Tests align with new APIs (TextImportProcessor wiring + NanosecondClock)

  • Direct TextImportProcessor(engine, jsonCfg) simplifies the upload route setup.
  • Field and builder now use NanosecondClock; builder call propagated.
    Looks good.

Also applies to: 81-82, 339-342

core/src/main/java/io/questdb/cutlass/auth/Authenticator.java (1)

28-35: Let me verify this finding more thoroughly to ensure no implementations exist:

Now let me run one more comprehensive check to ensure no hidden implementations exist:No actionable breaking changes identified — review comment is incorrect

The comprehensive code search found zero direct implementations of the Authenticator interface in the codebase. All references to classes like AnonymousAuthenticator, EllipticCurveAuthenticator, etc., implement different interfaces (SocketAuthenticator, HttpAuthenticator) rather than Authenticator.

Since the Authenticator interface now extends PrincipalContext (which already defines getPrincipal()), any implementor would automatically inherit this contract without breaking changes. However, no internal implementors exist to break, making the premise of the review comment unfounded.

Likely an incorrect or invalid review comment.

core/src/main/java/io/questdb/cutlass/http/HttpConstants.java (1)

77-77: LGTM!

The new session parameter constant follows the established naming pattern and integrates cleanly with the existing URL parameter constants.

core/src/main/java/io/questdb/FactoryProvider.java (1)

60-61: LGTM!

The new factory method follows the established pattern in the interface and appropriately uses @NotNull annotation.

core/src/main/java/io/questdb/cutlass/http/DefaultHttpContextConfiguration.java (1)

116-118: LGTM!

The return type change aligns with the interface update and the implementation already returns a NanosecondClock instance.

core/src/test/java/io/questdb/test/TestServerConfiguration.java (1)

143-145: LGTM!

Test configuration correctly updated to align with the production interface change.

core/src/main/java/io/questdb/FactoryProviderImpl.java (1)

77-80: No thread-safety concerns—DefaultHttpSessionStore is a stateless no-op implementation.

DefaultHttpSessionStore is a singleton with zero mutable state and all empty method implementations. Its singleton instance is initialized eagerly and safely by Java's static field semantics. No concurrent operations are performed within this class, making thread-safety guarantees unnecessary. Low test coverage is expected for a no-op implementation.

Likely an incorrect or invalid review comment.

core/src/main/java/io/questdb/cutlass/http/HttpContextConfiguration.java (1)

30-30: Type narrowing from Clock to NanosecondClock is correctly implemented and safe.

Verification confirms:

  • Both implementations (DefaultHttpContextConfiguration and PropHttpContextConfiguration) return NanosecondClock
  • NanosecondClock extends Clock, making this a safe subtype narrowing
  • All call sites are compatible with the change (assignments to Clock variables work due to inheritance; no explicit casts found)
  • No breaking changes detected
core/src/main/java/io/questdb/cutlass/http/HttpServer.java (2)

117-117: Session store wiring looks correct.

The session store is properly threaded through HttpContextFactory to HttpConnectionContext construction, maintaining consistency with the existing cookie handler pattern.

Also applies to: 368-373


85-86: API extension is backward-compatible; no breaking change.

The HttpServer constructor has been properly extended with a new parameter (HttpSessionStore) while maintaining backward compatibility through a convenience constructor. All call sites are correctly updated:

  • The 3-parameter convenience constructor (lines 85-92) delegates to the 6-parameter full constructor with DefaultHttpSessionStore.INSTANCE and other defaults
  • All test files correctly use the 3-parameter convenience constructor
  • Production code (Services.java, Table2IlpTest.java) uses the 6-parameter full constructor with explicit values
  • No broken or incomplete constructor calls detected

This is a standard, non-breaking API extension pattern.

Likely an incorrect or invalid review comment.

core/src/main/java/io/questdb/cutlass/line/tcp/LineTcpConnectionContext.java (1)

247-248: SecurityContextFactory API migration looks correct.

The migration from passing individual auth parameters to using PrincipalContext (via authenticator or DUMMY_CONTEXT) maintains the same authentication semantics while improving API cohesion.

Also applies to: 311-312

core/src/main/java/io/questdb/DefaultFactoryProvider.java (1)

70-73: Clean addition following existing patterns.

The getHttpSessionStore() method follows the established factory pattern, returning a singleton instance consistent with other handlers in this provider.

core/src/main/java/io/questdb/cutlass/Services.java (1)

101-111: Session store wiring is consistent.

The session store is properly retrieved from the factory provider and passed to the HttpServer constructor alongside other dependencies.

core/src/main/java/io/questdb/cutlass/http/HttpRequestProcessor.java (1)

86-88: The review comment is incorrect—there is no breaking API change.

The review claims that processCookies() was renamed to processServiceAccountCookie() in HttpRequestProcessor. However, the verification reveals:

  1. processCookies() does not exist in HttpRequestProcessor and never has been renamed.
  2. processCookies() exists in a different, unrelated interface: HttpClientCookieHandler (for HTTP client-side cookie handling).
  3. processServiceAccountCookie() is the current, existing method in HttpRequestProcessor (lines 86-88), already implemented by multiple classes (JsonQueryProcessor, DefaultHttpCookieHandler, etc.).
  4. The method is already being used correctly throughout the codebase (e.g., HttpConnectionContext line 911).

The review conflates two separate APIs. No breaking changes to HttpRequestProcessor have occurred.

Likely an incorrect or invalid review comment.

core/src/main/java/io/questdb/cairo/security/AllowAllSecurityContextFactory.java (1)

38-40: No action needed - API migration is complete and correct.

All implementations of SecurityContextFactory have been properly updated with the new signature requiring PrincipalContext instead of individual authentication parameters. The two call sites in LineTcpConnectionContext are correctly passing compatible types:

  • Line 246-248: authenticator (type SocketAuthenticator, which extends Authenticator which extends PrincipalContext)
  • Line 310-312: DUMMY_CONTEXT (type DummyPrincipalContext implementing PrincipalContext)

All three implementations verified:

  1. ReadOnlySecurityContextFactory - updated
  2. AllowAllSecurityContextFactory - updated
  3. ReadOnlyUsersAwareSecurityContextFactory - updated
core/src/test/java/io/questdb/test/cutlass/http/HttpErrorHandlingTest.java (3)

100-102: LGTM: test calls consolidated helper

Calling assertExecRequest(httpClient) simplifies the test without changing behavior.


166-185: LGTM: deterministic exec error assertion

Hardcoded CREATE TABLE and JSON error assertions are clear and stable. Status 500 check is appropriate.


126-138: Returning null from processSessionCookie() is the correct and supported contract

The code at HttpConnectionContext line 505 explicitly handles null: if (sessionInfo != null && sessionInfo != NO_SESSION). When processSessionCookie() returns null, the authentication flow correctly treats it as "no valid session" and proceeds to the fallback branch (line 507–509). This is the intended design—both the production DefaultHttpCookieHandler and your test mock return null consistently, and the calling code is defensively written to handle this. No changes needed.

core/src/main/java/io/questdb/cutlass/http/processors/JsonQueryProcessor.java (3)

317-319: LGTM: cookie processing rename

processServiceAccountCookie delegation matches the new HttpCookieHandler API.


380-396: LGTM: Java 17 pattern matching

Using if (e instanceof CairoException ce) clarifies logging and avoids redundant casts.


879-883: Review comment is incorrect: CharSequence.isEmpty() is available in Java 17.

The codebase targets Java 17 (<javac.target>17</javac.target> in pom.xml). Java 15 introduced isEmpty() as a default method in the CharSequence interface, making it available in Java 17. Since StringSink implements CharSequence and provides a length() method, the isEmpty() call in the code will work correctly without compilation errors. The suggested diff is unnecessary.

Likely an incorrect or invalid review comment.

utils/src/test/java/io/questdb/cliutil/Table2IlpTest.java (1)

491-501: Session store wiring looks correct

Passing HttpSessionStore into HttpServer and using constant 1 for worker-bound JSON processor in this test is fine.

Also applies to: 503-520

core/src/main/java/io/questdb/cutlass/pgwire/PGConnectionContext.java (1)

596-603: No issues found. The code properly satisfies the PrincipalContext contract.

The review comment's concern is unfounded. SocketAuthenticator extends Authenticator, and Authenticator extends QuietCloseable, Mutable, PrincipalContext. Through this inheritance chain, SocketAuthenticator is a valid PrincipalContext, and Java's type system ensures compatibility at compile time. SecurityContextFactory.getInstance() expects a PrincipalContext parameter, and the authenticator passed at PGConnectionContext.java:598-600 satisfies this contract. Group/role attributes are propagated through the PrincipalContext interface methods (getAuthType(), getGroups()).

core/src/main/java/io/questdb/cutlass/http/processors/RejectProcessorImpl.java (1)

46-48: Migration to multi-cookie looks good.

Lists are cleared on reuse, pairing is consistent, and the new send path is correct.

Also applies to: 58-60, 80-81, 112-115

Copy link
Copy Markdown
Collaborator

@ideoma ideoma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe authenticationNanos should be set to 0 in HttpConnectoinContext.clear(). This is an existing bug; clear() is called when the request is complete, reset() when the connection is closed. We want to reset the auth time for every request, in case the same connection is used for multiple users, like it can happen in case of a proxy

ideoma
ideoma previously approved these changes Oct 23, 2025
@glasstiger
Copy link
Copy Markdown
Contributor Author

[PR Coverage check]

😍 pass : 282 / 332 (84.94%)

file detail

path covered line new line coverage
🔵 io/questdb/cutlass/http/DefaultHttpContextConfiguration.java 0 1 00.00%
🔵 io/questdb/cutlass/line/tcp/DefaultLineTcpReceiverConfiguration.java 0 1 00.00%
🔵 io/questdb/cutlass/http/EmptyHttpSessionStore.java 1 5 20.00%
🔵 io/questdb/cutlass/line/tcp/LineTcpConnectionContext.java 1 4 25.00%
🔵 io/questdb/cutlass/http/HttpSessionStore.java 22 37 59.46%
🔵 io/questdb/cutlass/http/processors/RejectProcessorImpl.java 5 7 71.43%
🔵 io/questdb/cutlass/http/HttpCookieHandler.java 4 5 80.00%
🔵 io/questdb/cutlass/http/HttpResponseSink.java 6 7 85.71%
🔵 io/questdb/cutlass/http/HttpCookieHandlerImpl.java 46 53 86.79%
🔵 io/questdb/cutlass/http/HttpSessionStoreImpl.java 78 90 86.67%
🔵 io/questdb/cutlass/http/HttpConnectionContext.java 35 38 92.11%
🔵 io/questdb/cutlass/http/HttpConstants.java 2 2 100.00%
🔵 io/questdb/PropServerConfiguration.java 2 2 100.00%
🔵 io/questdb/DefaultFactoryProvider.java 1 1 100.00%
🔵 io/questdb/cutlass/line/tcp/LineTcpReceiverConfigurationWrapper.java 1 1 100.00%
🔵 io/questdb/cutlass/http/processors/JsonQueryProcessor.java 7 7 100.00%
🔵 io/questdb/cutlass/http/HttpServer.java 2 2 100.00%
🔵 io/questdb/cutlass/http/TokenGeneratorImpl.java 17 17 100.00%
🔵 io/questdb/FactoryProviderImpl.java 39 39 100.00%
🔵 io/questdb/cutlass/http/processors/JsonQueryProcessorConfiguration.java 1 1 100.00%
🔵 io/questdb/PropertyKey.java 1 1 100.00%
🔵 io/questdb/cutlass/Services.java 3 3 100.00%
🔵 io/questdb/cutlass/pgwire/ReadOnlyUsersAwareSecurityContextFactory.java 6 6 100.00%
🔵 io/questdb/PropHttpServerConfiguration.java 2 2 100.00%

@ideoma ideoma merged commit 00b767b into master Oct 24, 2025
34 checks passed
@ideoma ideoma deleted the ia_session_cookie branch October 24, 2025 11:27
@bluestreak01
Copy link
Copy Markdown
Member

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 24, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO NOT MERGE These changes should not be merged to main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants