Skip to content

[Inference API] Prevent trailing slashes from being included in URLs#141692

Merged
DonalEvans merged 4 commits intoelastic:mainfrom
DonalEvans:fix-eis-url-trailing-slash
Feb 9, 2026
Merged

[Inference API] Prevent trailing slashes from being included in URLs#141692
DonalEvans merged 4 commits intoelastic:mainfrom
DonalEvans:fix-eis-url-trailing-slash

Conversation

@DonalEvans
Copy link
Contributor

Update ElasticInferenceService and AzureAiStudio model classes to prevent trailing slashes in the base URL causing errors when sending requests

Update ElasticInferenceService and AzureAiStudio model classes to
prevent trailing slashes in the base URL causing errors when sending
requests
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/search-inference-team (Team:Search - Inference)

@DonalEvans DonalEvans enabled auto-merge (squash) February 4, 2026 00:44
}

return new URI(this.target + COMPLETIONS_URI_PATH);
return new URIBuilder(this.target).setPath(COMPLETIONS_URI_PATH).build();
Copy link
Contributor

Choose a reason for hiding this comment

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

Ugh, after looking at how azure does this I think we might need to do more work here. For example I'm able to build an azure deployment with a path like this:

https://ai753146444935.services.ai.azure.com/models

My understanding is that setPath will overwrite any path that was there, which means we'd lose the models portion.

Apache http 5.x luckily has appendPath which is exactly what we need. Sadly we're still on 4.x 😢

I think we'l'l need something like this:

https://github.com/elastic/elasticsearch/blob/main/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/common/http/HttpClient.java#L357-L390

var a = new URIBuilder(this.target)
a.getPath()

Then split it and combine with COMPLETIONS_URI_PATH.

I could be wrong about the behavior though. Let's add a test where the this.target has a path already on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At this point, until we can upgrade to Apache http 5.x and use appendPath(), would it be simpler to just check for trailing slashes in the target and strip them out before concatenating the path constant as a String? It's not pretty, but it's simpler than doing all of the splitting and combining in that static helper method.

* @param url
* @return
*/
public static String stripTrailingSlash(String url) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree in general that it'd be much easier to use a library. The problem is that we should probably handle multiple slashes at the end (probably overkill but might as well).

Since we can't easily do that this is what gemini generated for me 😄

import java.net.URI;
import java.net.URISyntaxException;
import java.util.regex.Pattern;

public class UriUtils {

    // Compiling these once saves significant CPU cycles in high-throughput apps
    private static final Pattern TRAILING_SLASHES = Pattern.compile("/+$");
    private static final Pattern LEADING_SLASHES = Pattern.compile("^/+");

    /**
     * Combines a base URL with a sub-path, collapsing multiple slashes at the join point.
     * * @param baseUrl   The base (e.g., "http://google.com//")
     * @param extraPath The segment to append (e.g., "///hello")
     * @return A URI with exactly one slash at the junction: "http://google.com/hello"
     */
    public static URI combineUri(String baseUrl, String extraPath) {
        if (baseUrl == null) {
            throw new IllegalArgumentException("baseUrl cannot be null");
        }

        try {
            URI baseUri = new URI(baseUrl);
            
            // Extract the existing path from the base URI
            String basePath = (baseUri.getPath() == null) ? "" : baseUri.getPath();
            
            // 1. Strip trailing slashes from the existing base path
            String cleanBase = TRAILING_SLASHES.matcher(basePath).replaceAll("");
            
            // 2. Strip leading slashes from the new segment
            String cleanExtra = (extraPath == null) ? "" : LEADING_SLASHES.matcher(extraPath).replaceAll("");
            
            // 3. Join with exactly one separator
            String joinedPath = cleanBase + "/" + cleanExtra;
            
            // Reconstruct the URI using the multi-arg constructor.
            // This ensures the path is handled correctly without double-escaping.
            return new URI(
                baseUri.getScheme(),
                baseUri.getAuthority(),
                joinedPath,
                baseUri.getQuery(),
                baseUri.getFragment()
            );
            
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("Failed to construct URI: " + e.getMessage(), e);
        }
    }
}

How do you feel about incorporating something like that? We can probably use the UriBuilder instead of

            return new URI(
                baseUri.getScheme(),
                baseUri.getAuthority(),
                joinedPath,
                baseUri.getQuery(),
                baseUri.getFragment()
            );

But URI is probably fine too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that there's a limit to how much sanitization of user input we should do here. A trailing slash at the end of a URL is a reasonable thing to expect and deal with, but multiple trailing slashes is just an incorrect input. If a user passed a URL like https://ai753146444935.services.ai.azure.com//models (a double slash in the path instead of at the end) we'd still return an error even with the more complex method described in your comment, so I don't think handling double slashes is something we should try to do. We just want to make sure that if a user provides a valid URL, we don't muck it up by accidentally adding one too many slashes.

Copy link
Contributor

Choose a reason for hiding this comment

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

++

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah fair point 👍

@DonalEvans DonalEvans merged commit 8db18bb into elastic:main Feb 9, 2026
35 checks passed
@elasticsearchmachine
Copy link
Collaborator

💔 Backport failed

Status Branch Result
9.3 Commit could not be cherrypicked due to conflicts
8.19 Commit could not be cherrypicked due to conflicts
9.2 Commit could not be cherrypicked due to conflicts

You can use sqren/backport to manually backport by running backport --upstream elastic/elasticsearch --pr 141692

DonalEvans added a commit to DonalEvans/elasticsearch that referenced this pull request Feb 9, 2026
…lastic#141692)

Update ElasticInferenceService and AzureAiStudio model classes to
prevent trailing slashes in the base URL causing errors when sending
requests

(cherry picked from commit 8db18bb)

# Conflicts:
#	x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/densetextembeddings/ElasticInferenceServiceDenseTextEmbeddingsModel.java
#	x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/completion/ElasticInferenceServiceCompletionModelTests.java
#	x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/denseembeddings/ElasticInferenceServiceDenseEmbeddingsModelTests.java
DonalEvans added a commit to DonalEvans/elasticsearch that referenced this pull request Feb 9, 2026
…lastic#141692)

Update ElasticInferenceService and AzureAiStudio model classes to
prevent trailing slashes in the base URL causing errors when sending
requests

(cherry picked from commit 8db18bb)

# Conflicts:
#	x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceModel.java
#	x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/densetextembeddings/ElasticInferenceServiceDenseTextEmbeddingsModel.java
#	x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/completion/ElasticInferenceServiceCompletionModelTests.java
#	x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/denseembeddings/ElasticInferenceServiceDenseEmbeddingsModelTests.java
@DonalEvans
Copy link
Contributor Author

💔 Some backports could not be created

Status Branch Result
9.3
9.2
8.19 An unhandled error occurred. Please see the logs for details

Manual backport

To create the backport manually run:

backport --pr 141692

Questions ?

Please refer to the Backport tool documentation

DonalEvans added a commit that referenced this pull request Feb 9, 2026
…141692) (#142153)

Update ElasticInferenceService and AzureAiStudio model classes to
prevent trailing slashes in the base URL causing errors when sending
requests

(cherry picked from commit 8db18bb)
DonalEvans added a commit that referenced this pull request Feb 9, 2026
…141692) (#142156)

Update ElasticInferenceService and AzureAiStudio model classes to
prevent trailing slashes in the base URL causing errors when sending
requests

(cherry picked from commit 8db18bb)
DonalEvans added a commit that referenced this pull request Feb 9, 2026
…141692) (#142167)

Update ElasticInferenceService and AzureAiStudio model classes to
prevent trailing slashes in the base URL causing errors when sending
requests

(cherry picked from commit 8db18bb)
@DonalEvans DonalEvans deleted the fix-eis-url-trailing-slash branch February 9, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-backport Automatically create backport pull requests when merged backport pending >bug Feature:GenAI Features around GenAI :SearchOrg/Inference Label for the Search Inference team Team:Search - Inference v8.19.12 v9.2.6 v9.3.1 v9.4.0

4 participants