Reading body() before or after form() is not consistent across all servers

Geschlossen
#4,031 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Ein zugehöriger Pull Request wurde bereits gemerged.

  • #4034 von @jknack — gemerged

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
48/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Aktiv
Tech-Stack
java
Bereich
backend

Rechercherichtung

The report identifies ctx.body().value() and ctx.form()/ctx.formMap() in a ServerTest that runs against Undertow and Jetty. Start by tracing how each server handles form parsing and body access, then run the supplied test against both servers. Done means the call order behaves consistently across both servers, or the server difference is documented.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

I was replacing jooby-undertow with jooby-jetty and I am getting different behaviour due to making a call to ctx.body().value() before ctx.form().toMap()

I expected this to be consistent across different servers, or at least for this difference to be documented.

/*
 * Jooby https://jooby.io
 * Apache License Version 2.0 https://jooby.io/LICENSE.txt
 * Copyright 2014 Edgar Espina
 */
package io.jooby.test;

import io.jooby.exception.MissingValueException;
import io.jooby.junit.ServerTest;
import io.jooby.junit.ServerTestRunner;
import java.util.Map;
import okhttp3.FormBody;
import org.junit.jupiter.api.Assertions;

class IssueBodyVsForm {

  @ServerTest
  public void formDataAndQueryParameters(ServerTestRunner runner) {
    runner
        .define(
            app ->
                app.post(
                    "/",
                    ctx -> {
                        try {
                            Assertions.assertAll(() -> {
                                Assertions.assertEquals(1, ctx.form().size(), "form contains one entry");
                                Assertions.assertTrue(ctx.form().isPresent());
                                Assertions.assertFalse(ctx.form().isMissing());
                                Assertions.assertEquals("bar", ctx.form().get("foo").value());
                                Assertions.assertEquals("bar", ctx.form("foo").value());
                                Assertions.assertEquals("bar", ctx.form().toMap().get("foo"));
                                Assertions.assertEquals("bar", ctx.formMap().get("foo"));

                                Assertions.assertEquals("?parameter1=value1", ctx.query().queryString());
                                Assertions.assertEquals("parameter1=value1", ctx.query().value());
                                Assertions.assertEquals("value1", ctx.query("parameter1").value());
                                Assertions.assertEquals("value1", ctx.queryMap().get("parameter1"));
                                Assertions.assertEquals(1, ctx.queryMap().size());
                            });
                            return "OK";
                        } catch (Exception ex){
                            ex.printStackTrace();
                            ctx.setResponseCode(500);
                            return ex.getMessage();
                        }
                    }))
        .ready(
            http ->
                http
                    .post(
                        "/",
                        new FormBody.Builder().add("foo", "bar").build(),
                        Map.of("parameter1", "value1"),
                        rsp -> {
                            Assertions.assertEquals("OK", rsp.body().string());
                            Assertions.assertEquals(200, rsp.code());
                        }));
  }

  @ServerTest
  public void readFormDataBeforeBody(ServerTestRunner runner) {
    runner
        .define(
            app ->
                app.post(
                    "/",
                    ctx -> {
                        try {
                            Assertions.assertAll(() -> {
                                Assertions.assertEquals(1, ctx.form().size(), "form contains one entry");
                                Assertions.assertTrue(ctx.form().isPresent());
                                Assertions.assertFalse(ctx.form().isMissing());
                                Assertions.assertEquals("bar", ctx.form().get("foo").value());
                                Assertions.assertEquals("bar", ctx.form("foo").value());
                                Assertions.assertEquals("bar", ctx.form().toMap().get("foo"));
                                Assertions.assertEquals("bar", ctx.formMap().get("foo"));

                                // get body().value() after calling form methods
                                Assertions.assertThrows(MissingValueException.class, () -> ctx.body().value());
                            });
                            return "OK";
                        } catch (Exception ex){
                            ex.printStackTrace();
                            ctx.setResponseCode(500);
                            return ex.getMessage();
                        }
                    }))
        .ready(
            http ->
                http
                    .post(
                        "/",
                        new FormBody.Builder().add("foo", "bar").build(),
                        rsp -> {
                            Assertions.assertEquals("OK", rsp.body().string());
                            Assertions.assertEquals(200, rsp.code());
                        }));
  }

  @ServerTest
  public void readFormDataAfterBody(ServerTestRunner runner) {
    runner
        .define(
            app ->
                app.post(
                    "/",
                    ctx -> {
                        try {
                            Assertions.assertAll(() -> {
                                // get body().value() before calling form methods
                                Assertions.assertThrows(MissingValueException.class, () -> ctx.body().value());

                                Assertions.assertEquals(1, ctx.form().size(), "form contains one entry");
                                Assertions.assertTrue(ctx.form().isPresent());
                                Assertions.assertFalse(ctx.form().isMissing());
                                Assertions.assertEquals("bar", ctx.form().get("foo").value());
                                Assertions.assertEquals("bar", ctx.form("foo").value());
                                Assertions.assertEquals("bar", ctx.form().toMap().get("foo"));
                                Assertions.assertEquals("bar", ctx.formMap().get("foo"));
                            });
                            return "OK";
                        } catch (Exception ex){
                            ex.printStackTrace();
                            ctx.setResponseCode(500);
                            return ex.getMessage();
                        }
                    }))
        .ready(
            http ->
                http
                    .post(
                        "/",
                        new FormBody.Builder().add("foo", "bar").build(),
                        rsp -> {
                          Assertions.assertEquals("OK", rsp.body().string());
                          Assertions.assertEquals(200, rsp.code());
                        }));
  }
}
Vorherrschende Sprache
Java
Sterne
1.8k
Forks
205
Ø Merge
1 T. 8 Std.
Gemergte PRs (30 T.)
20

Entwicklungsumgebung

  • Enthält ein Dockerfile oder eine Docker-Compose-Datei
  • Keine Pull-Request-Vorlage
  • Kein Beitragsleitfaden

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus jooby-project/jooby

Alle Issues in jooby-project/jooby

Ähnliche Issues

Weitere Issues zu Java

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.