Skip to content

Conversation

@avazirna
Copy link
Contributor

@avazirna avazirna commented May 28, 2025

Product Description

During the first login a full data pull is triggered, HQ now responds with a 406 when the restore file contains at least one mobile report with more 100K records, more info on this HQ PR. This PR adds a new user message and ensures parsing of XML-formatted response bodies.

Message type Current behavior (Without HQ and Mobile changes) With HQ changes only (CC mobile version 2.59 and below) With both HQ and Mobile changes
Mobile report exceeds limit
Restore rate limiting

Ticket: https://dimagi.atlassian.net/browse/SAAS-16814

Safety Assurance

Safety story

Successfully tested locally. This shouldn't cause any crash, worse case scenario the user will see an Unknown issue message or an inconveniently JSON/XML-formatted text.

Labels and Review

  • Do we need to enhance the manual QA test coverage ? If yes, the "QA Note" label is set correctly
  • Does the PR introduce any major changes worth communicating ? If yes, the "Release Note" label is set and a "Release Note" is specified in PR description.
  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@avazirna avazirna force-pushed the show-error-message-when-mobile-report-exceeds-limit branch from 9c2a955 to d3f625f Compare May 28, 2025 12:47
@coderabbitai
Copy link

coderabbitai bot commented May 28, 2025

📝 Walkthrough

Walkthrough

The changes introduce a new error message string key, restore.failed.error, to the Android translatable strings file for user-facing error reporting. In the HttpUtils class, the parseUserVisibleError method is updated to handle error response bodies in both JSON and XML formats, rather than just JSON. Two new helper methods, parseJsonErrorResponseBody and parseXmlErrorResponseBody, are added to parse the respective formats and extract error details. Exception handling in the error parsing logic is also expanded to cover XML parsing exceptions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant HttpUtils
    participant Server

    Client->>Server: Send HTTP request
    Server-->>Client: Return error response (JSON or XML)
    Client->>HttpUtils: parseUserVisibleError(response)
    alt Response is JSON
        HttpUtils->>HttpUtils: parseJsonErrorResponseBody(responseStr)
        HttpUtils-->>Client: Extracted error message
    else Response is XML
        HttpUtils->>HttpUtils: parseXmlErrorResponseBody(responseStr)
        HttpUtils-->>Client: Extracted error message
    end
Loading

Suggested reviewers

  • shubham1g5
  • OrangeAndGreen

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c7b703 and d3f625f.

📒 Files selected for processing (2)
  • app/assets/locales/android_translatable_strings.txt (1 hunks)
  • app/src/org/commcare/network/HttpUtils.java (2 hunks)
🔇 Additional comments (3)
app/assets/locales/android_translatable_strings.txt (1)

452-452: LGTM! Clear and actionable error message.

The new error message key follows the established naming conventions and provides users with clear guidance on what to do when encountering this issue.

app/src/org/commcare/network/HttpUtils.java (2)

13-25: LGTM! Appropriate imports for the enhanced functionality.

The new imports support the XML parsing capabilities and improved error handling. All imports are necessary and properly organized.


108-111: Review exception handling and potential information leakage.

The broad exception catching and fallback to responseStr might expose sensitive server information to users. Consider whether the raw response should be shown or if a generic error message would be more appropriate.

Should raw server error responses be displayed to end users, or would it be better to show a generic error message to avoid potential information leakage?

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@avazirna avazirna force-pushed the show-error-message-when-mobile-report-exceeds-limit branch from d3f625f to 2487da6 Compare May 28, 2025 12:50
Copy link

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

🧹 Nitpick comments (1)
app/src/org/commcare/network/HttpUtils.java (1)

123-123: Consider making helper methods package-private.

The new helper methods parseJsonErrorResponseBody and parseXmlErrorResponseBody are currently public but appear to be implementation details that don't need external access.

-    public static Map<String, String> parseJsonErrorResponseBody(String responseStr) throws JSONException {
+    static Map<String, String> parseJsonErrorResponseBody(String responseStr) throws JSONException {
🛑 Comments failed to post (3)
app/src/org/commcare/network/HttpUtils.java (3)

123-131: 🛠️ Refactor suggestion

Enhance JSON parsing error handling and remove redundant null check.

The current implementation has several issues:

  1. The null check on jsonObject is redundant since the constructor throws an exception for invalid input
  2. getString() calls will throw JSONException if keys don't exist, which should be handled gracefully
 public static Map<String, String> parseJsonErrorResponseBody(String responseStr) throws JSONException {
     Map<String, String> map = new HashMap<>();
     JSONObject jsonObject = new JSONObject(responseStr);
-    if (jsonObject != null) {
-        map.put("error", jsonObject.getString("error"));
-        map.put("default_response", jsonObject.getString("default_response"));
-    }
+    map.put("error", jsonObject.optString("error", ""));
+    map.put("default_response", jsonObject.optString("default_response", ""));
     return map;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    public static Map<String, String> parseJsonErrorResponseBody(String responseStr) throws JSONException {
        Map<String, String> map = new HashMap<>();
        JSONObject jsonObject = new JSONObject(responseStr);
        map.put("error", jsonObject.optString("error", ""));
        map.put("default_response", jsonObject.optString("default_response", ""));
        return map;
    }
🤖 Prompt for AI Agents
In app/src/org/commcare/network/HttpUtils.java around lines 123 to 131, remove
the redundant null check on jsonObject since the constructor throws
JSONException on invalid input. Instead, enhance error handling by checking if
the keys "error" and "default_response" exist in the JSONObject before calling
getString(), and handle missing keys gracefully to avoid throwing exceptions.

99-104: 🛠️ Refactor suggestion

Improve content type checking robustness.

The current content type comparison using .equals() may fail if the response includes additional parameters like charset (e.g., "application/json; charset=utf-8").

-            if (response.errorBody().contentType().equals("application/json")) {
+            if (response.errorBody().contentType().toString().contains("application/json")) {

Alternatively, use a more robust approach:

-            if (response.errorBody().contentType().equals("application/json")) {
+            if ("application".equals(response.errorBody().contentType().type()) && 
+                "json".equals(response.errorBody().contentType().subtype())) {
🤖 Prompt for AI Agents
In app/src/org/commcare/network/HttpUtils.java around lines 99 to 104, the
content type check uses equals() which fails if the content type has parameters
like charset. Replace the equals() check with a more robust approach such as
using startsWith("application/json") or parsing the media type properly to
handle additional parameters, ensuring the content type check correctly
identifies JSON responses even with charset or other parameters.

147-168: 🛠️ Refactor suggestion

Add input validation and consider making the method package-private.

The XML parsing method needs input validation and the rigid XML structure parsing might fail with slight variations.

-    public static Map<String, String> parseXmlErrorResponseBody(String responseStr)
+    static Map<String, String> parseXmlErrorResponseBody(String responseStr)
             throws IOException, InvalidStructureException, UnfullfilledRequirementsException,
             XmlPullParserException {
+        if (responseStr == null || responseStr.trim().isEmpty()) {
+            return new HashMap<>();
+        }

Consider adding more flexible XML parsing that can handle structure variations, or add better error messages when the expected structure is not found.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    static Map<String, String> parseXmlErrorResponseBody(String responseStr)
            throws IOException, InvalidStructureException, UnfullfilledRequirementsException,
            XmlPullParserException {
        if (responseStr == null || responseStr.trim().isEmpty()) {
            return new HashMap<>();
        }

        KXmlParser baseParser = ElementParser.instantiateParser(
                new ByteArrayInputStream(responseStr.getBytes(StandardCharsets.UTF_8)));
        ElementParser<Map<String, String>> responseParser = new ElementParser<>(baseParser) {
            @Override
            public Map<String, String> parse() throws InvalidStructureException, IOException,
                    XmlPullParserException {
                Map<String, String> map = new HashMap<>();
                checkNode("OpenRosaResponse");
                nextTag("message");
                nextTag("error");
                map.put("error", parser.nextText());
                nextTag("default_response");
                map.put("default_response", parser.nextText());
                return map;
            }
        };
        return responseParser.parse();
    }
🤖 Prompt for AI Agents
In app/src/org/commcare/network/HttpUtils.java around lines 147 to 168, the
parseXmlErrorResponseBody method lacks input validation and assumes a rigid XML
structure that may cause failures with slight variations. Add input validation
to check if responseStr is null or empty before parsing. Modify the XML parsing
logic to be more flexible by checking for the presence of expected tags before
accessing them, and provide clear error messages if the structure is not as
expected. Also, consider changing the method's visibility to package-private if
it is not used outside the package.

@avazirna avazirna marked this pull request as ready for review May 28, 2025 13:57
@avazirna
Copy link
Contributor Author

@damagatchi retest this please

@avazirna avazirna added the skip-integration-tests Skip android tests. label Jun 2, 2025
@avazirna
Copy link
Contributor Author

avazirna commented Jun 2, 2025

@damagatchi retest this please

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

Labels

skip-integration-tests Skip android tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants