OptionReader fails to parse a parenthesized extension after a regular option path component
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 76/100
Direzione di ricerca
Inizia con wire-schema/src/commonMain/kotlin/com/squareup/wire/schema/internal/parser/OptionReader.kt e SyntaxReader.kt, concentrandoti sul modo in cui i componenti del percorso dell’opzione regolari e tra parentesi consumano i punti. Esamina i test esistenti per le opzioni di estensione annidate, quindi aggiungi la copertura per un’estensione tra parentesi dopo un componente regolare. Il lavoro è completato quando (foo.field).string.(foo.datetime) = true viene analizzato correttamente senza richiedere spazi bianchi.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
Wire's ProtoParser fails to parse a parenthesized extension when it follows a regular field component in a custom option path.
This fails:
(foo.field).string.(foo.datetime) = true
Adding whitespace before the second dot makes the same option parse successfully:
(foo.field).string .(foo.datetime) = true
This occurs in real-world Protovalidate predefined rules, for example:
(buf.validate.field).string.(company.validate.datetime) = true
Protovalidate documents this form of nested extension syntax:
(buf.validate.field).float.(foo.bar.required_with_max)
https://protovalidate.com/schemas/predefined-rules/#applying-predefined-rules
Environment
com.squareup.wire:wire-schema-jvm:5.4.0- Java
21.0.9 - Reproduced by invoking
ProtoParserdirectly - Initially encountered with
confluentinc/cp-schema-registry:8.0.3, which bundles Wire 5.4.0
The failure does not require Schema Registry and can be reproduced by calling Wire directly.
Minimal reproduction
import com.squareup.wire.schema.Location;
import com.squareup.wire.schema.internal.parser.ProtoParser;
public final class WireParseTest {
public static void main(String[] args) {
String schema =
"syntax = \"proto3\";\n" +
"\n" +
"message TestEvent {\n" +
" string started_at = 1 [\n" +
" (foo.field).string.(foo.datetime) = true\n" +
" ];\n" +
"}\n";
var parsed = ProtoParser.Companion.parse(
Location.get("test.proto"),
schema
);
System.out.println(parsed);
}
}
Compile and execute it against Wire 5.4.0:
javac \
-proc:none \
-cp 'wire-schema-jvm-5.4.0.jar:<required-runtime-dependencies>' \
WireParseTest.java
java \
-cp '.:wire-schema-jvm-5.4.0.jar:<required-runtime-dependencies>' \
WireParseTest
It can also be reproduced using the Schema Registry image that contains Wire 5.4.0:
docker run --rm \
--volume "$PWD:/work" \
--workdir /work \
--entrypoint sh \
confluentinc/cp-schema-registry:8.0.3 \
-c '
javac \
-proc:none \
-cp "/usr/share/java/schema-registry/*" \
WireParseTest.java &&
java \
-cp "/work:/usr/share/java/schema-registry/*" \
WireParseTest
'
Actual result
Exception in thread "main" java.lang.IllegalStateException:
Syntax error in test.proto:5:34: expected '=' in option
at com.squareup.wire.schema.internal.parser.SyntaxReader.unexpected(SyntaxReader.kt:425)
at com.squareup.wire.schema.internal.parser.OptionReader.readOption(OptionReader.kt:215)
at com.squareup.wire.schema.internal.parser.OptionReader.readOptions(OptionReader.kt:38)
at com.squareup.wire.schema.internal.parser.ProtoParser.readField(ProtoParser.kt:369)
at com.squareup.wire.schema.internal.parser.ProtoParser.readField(ProtoParser.kt:353)
at com.squareup.wire.schema.internal.parser.ProtoParser.readDeclaration(ProtoParser.kt:168)
at com.squareup.wire.schema.internal.parser.ProtoParser.readMessage(ProtoParser.kt:206)
at com.squareup.wire.schema.internal.parser.ProtoParser.readDeclaration(ProtoParser.kt:150)
at com.squareup.wire.schema.internal.parser.ProtoParser.readProtoFile(ProtoParser.kt:71)
at com.squareup.wire.schema.internal.parser.ProtoParser$Companion.parse(ProtoParser.kt:680)
at WireParseTest.main(WireParseTest.java:15)
Expected result
The option should parse successfully without requiring whitespace before the second dot:
(foo.field).string.(foo.datetime) = true
Whitespace around the dot should not change the meaning or validity of the option path.
Whitespace workaround
Changing only this:
(foo.field).string.(foo.datetime) = true
to this:
(foo.field).string .(foo.datetime) = true
makes Wire parse the schema successfully.
The equivalent Protovalidate message-literal syntax also works:
(buf.validate.field).string = {
[company.validate.datetime]: true
}
Suspected cause
OptionReader.readOption() appears to support nested parenthesized option components:
val subName = reader.readName(retainWrap = true)
if (subName.startsWith("(")) {
subNames.add(subName)
} else {
subNames.addAll(subName.split("."))
}
However, SyntaxReader.readWord() treats . as part of a word:
when (data[pos]) {
in 'a'..'z', in 'A'..'Z', in '0'..'9', '_', '-', '.' -> pos++
else -> break@loop
}
When parsing:
(foo.field).string.(foo.datetime)
the call that should read string appears to consume string. instead. The separator dot before (foo.datetime) therefore never reaches the loop in OptionReader.
OptionReader subsequently encounters ( where it expects =, producing:
expected '=' in option
The successful whitespace workaround supports this analysis: whitespace prevents readWord() from consuming the separator dot as part of string..
Relevant sources:
- https://github.com/square/wire/blob/5.4.0/wire-schema/src/commonMain/kotlin/com/squareup/wire/schema/internal/parser/OptionReader.kt
- https://github.com/square/wire/blob/5.4.0/wire-schema/src/commonMain/kotlin/com/squareup/wire/schema/internal/parser/SyntaxReader.kt
Wire already contains support and tests for some nested extension options, such as:
option (my_message_option_six).(More.more_string) = "foobar";
However, that form does not contain a regular path component between two parenthesized extensions. The failing structure is specifically:
(parenthesized extension).regular field.(parenthesized extension)
- Lingua principale
- Kotlin
- Stelle
- 4.4k
- Fork
- 633
- Merge medio
- 1g 16h
- PR unite (30g)
- 10
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di square/wire
-
GrpcStreamingCall() factory's executeIn() hardcodes Dispatchers.IO instead of using an incoming scopeForse già presa @oldergod l’ha presa 174 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Swift: clear a field's preserved unknown enum value from unknownFields when the field is mutatedAperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 55/100
I maintainer di solito rispondono entro 1 giorno
-
wasmjs on maven repo?Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
square/wire#3604 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
square/wire#3560 · 7 commenti ·
I maintainer di solito rispondono entro 1 giorno
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
nightscout/AndroidAPS#5211 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
commons-app/apps-android-commons#6984 ·
I maintainer di solito rispondono entro 2 giorni
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100