Skip to content

Fix GraphQL operationName parsing when variable values contain ampers…#504

Open
setheclark wants to merge 2 commits intoopenflocon:mainfrom
setheclark:fix_graphql_url_parsing
Open

Fix GraphQL operationName parsing when variable values contain ampers…#504
setheclark wants to merge 2 commits intoopenflocon:mainfrom
setheclark:fix_graphql_url_parsing

Conversation

@setheclark
Copy link

Mapper.kt was using uri.query (Java's URI.getQuery()) which percent-decodes the entire query string before splitting on &. This caused %26 inside encoded JSON values to be decoded to a bare &, which was then misinterpreted as a parameter delimiter — breaking parsing and returning null for the operation name.

  • Fixed by switching to uri.rawQuery and splitting on & first, then decoding each key and value individually. Also replaced destructuring (split("=")) with indexOf("=") to safely handle params with no value.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @setheclark, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in GraphQL operation name extraction that occurred when query parameters contained percent-encoded ampersands. The changes ensure that URI query strings are parsed correctly by handling raw query data and decoding individual components, thereby preventing misinterpretation of parameter delimiters and improving the robustness of GraphQL request processing.

Highlights

  • GraphQL Parsing Fix: Resolved an issue where GraphQL operationName parsing failed when variable values contained encoded ampersands (%26). Previously, uri.query would prematurely decode the entire query string, causing %26 to be misinterpreted as a parameter delimiter.
  • Robust URI Parameter Handling: Switched from uri.query to uri.rawQuery to prevent premature decoding. Parameters are now split by & first, and then individual keys and values are decoded, ensuring correct parsing even with complex encoded values. The parsing logic was also improved to safely handle parameters without values using indexOf("=").
  • New Test Case Added: A new unit test was introduced to specifically cover the scenario where GraphQL variable values contain encoded ampersands, validating the fix.
Changelog
  • FloconDesktop/data/remote/src/commonMain/kotlin/com/flocon/data/remote/network/mapper/Mapper.kt
    • Removed unused import statements for extractDomain and io.ktor.server.util.url.
    • Modified the extractGraphQl function to use uri.rawQuery instead of uri.query for retrieving the query string.
    • Updated the query parameter parsing logic to split the raw query string by & first, then individually decode keys and values using URLDecoder.decode.
    • Replaced split("=") with indexOf("=") for safer parameter key-value separation, accommodating parameters that might not have a value.
  • FloconDesktop/data/remote/src/commonTest/kotlin/com/flocon/data/remote/network/mapper/MapperTest.kt
    • Added a new test case should extract from url when variable value contains ampersand to verify correct GraphQL extraction for URLs with encoded ampersands in variable values.
Activity
  • No human activity (comments, reviews) has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly fixes a bug in GraphQL operation name parsing where ampersands in variable values were misinterpreted. The switch to uri.rawQuery and manual decoding of query parameters is the right approach. The new implementation is also more robust against query parameters without values. I've added one suggestion to make the query parameter parsing slightly more efficient and idiomatic using buildMap. A new test case has been added to cover the fix, which is great.

Comment on lines 140 to 148
val queryParams = uri.rawQuery
?.split("&")
?.associate {
val (k, v) = it.split("=")
k to URLDecoder.decode(v, "UTF-8")
} ?: emptyMap()
?.mapNotNull { param ->
val idx = param.indexOf("=")
if (idx == -1) null
else URLDecoder.decode(param.substring(0, idx), "UTF-8") to
URLDecoder.decode(param.substring(idx + 1), "UTF-8")
}
?.toMap() ?: emptyMap()
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

While this implementation is correct, it can be made more efficient by using buildMap. The current approach creates a few intermediate lists (from split and mapNotNull), whereas buildMap would construct the map directly, which is more memory-efficient.

Suggested change
val queryParams = uri.rawQuery
?.split("&")
?.associate {
val (k, v) = it.split("=")
k to URLDecoder.decode(v, "UTF-8")
} ?: emptyMap()
?.mapNotNull { param ->
val idx = param.indexOf("=")
if (idx == -1) null
else URLDecoder.decode(param.substring(0, idx), "UTF-8") to
URLDecoder.decode(param.substring(idx + 1), "UTF-8")
}
?.toMap() ?: emptyMap()
val queryParams = uri.rawQuery?.let { rawQuery ->
buildMap {
for (param in rawQuery.split('&')) {
val idx = param.indexOf('=')
if (idx != -1) {
val key = URLDecoder.decode(param.substring(0, idx), "UTF-8")
val value = URLDecoder.decode(param.substring(idx + 1), "UTF-8")
put(key, value)
}
}
}
} ?: emptyMap()

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant