Pull latest into cache update branch#432
Merged
mondain merged 121 commits intoreplace-cachefrom Feb 1, 2026
Merged
Conversation
…lients use data channel to pass messages that the server never handles) [CS-117]
Demote logging about unhandled data channel messages (very loud if c…
…special 2.0.16 branch change
AMF decided to allow negative length strings and arrays. If the client tries these shenanigans, just treat it as a 0 length object instead of believing them. Add a few checks to make sure we aren't reading past the end of the packet if it ends too early. Also don't let a client claim it's going to send a 2 billion arrays to trick us into allocation 2 billion items to store them in.
…he context you're trying to unload does not exist
…meters, return an empty Map instead of Collections.unmodifiableMap throwing an NPE
…tion, if client is somehow null don't registerJMX() because that function needs a working client object.
VINTs that were between 5 and 8 bytes were not being parsed correctly,
causing the parser to get out of sync with the stream.
To reproduce the original bug:
- Take any Matroska element whose size field is encoded with a 7‑byte VINT (legal per EBML). Example: a Cluster element (ID =
0x1F43B675) with a size of 0x20 bytes encoded as:
- ID bytes: 1F 43 B6 75
- Size bytes (7‑byte VINT): 02 00 00 00 00 00 20
- The leading byte 0x02 is 00000010b, which in EBML means “length = 7 bytes, value bits = 0x000000000020”.
- What the code does:
- readVINT reads the first size byte fb = 0x02.
- It sets len = fb >> 4, which is 0x0.
- Because len is 0, it falls into the final else branch (“8‑byte VINT”), sets mask = MASK_BYTE_8, allocates an 8‑byte array,
and reads 7 more bytes for this size.
- The seven bytes it reads are the remaining 6 bytes of the size (00 00 00 00 00 20) plus the first byte of the element
payload (because there were only 6 size bytes left). So the parser consumes one payload byte as if it were part of the
size field.
- Consequences:
- The computed size is wrong (it’s based on 8 bytes instead of 7, and includes one payload byte).
- The stream position is now off by one byte. The next call to parseTag starts in the middle of the element payload, so
subsequent IDs/sizes are garbage. This typically leads to decoding failures, incorrect sizes, and eventually EOF/NPE/assert
failures.
skip() calls InputStream.skip(), which is allowed to return 0, for example if reading from a named pipe or fifo file that's blocked or trying to read past the end of the file. If skip isn't working, try reading one byte to either unstick it or at least advance the file pointer so it doesn't end up with an infinite loop. An alternative would be to just give up if input.skip() returns 0 because I'm not sure recovery is possible.
If inputStream.read has an error, it returns -1. Treat that like an error instead of rewinding the read pointer by 1.
If parseTag fails it can return null. Intentionally throw a meaningful exception instead of an NPE.
Add missing break to co64 to stop it from falling through
getGenericType never maps double or char primitives to their wrappers (checks Double.class/ Character.class instead of double.class/char.class), so those primitives fall through and return the primitive type while other primitives return wrappers.
InputStream readers for uint16/24/32 only checked the last byte for EOF. If the stream ended on the first or middle byte, the methods return a value built from -1 bytes instead of throwing, leading to silent truncation and incorrect protocol parsing (potentially accepting malformed handshakes).
single unmodifiable element containing the values collection, rather than a list of the map’s values. Changed ConversionUtils.convertMapToList in ConversionUtils.java:212-214 to return a list of map values rather than a single values collection entry.
without XML escaping. Any <, &, or " characters in content produced malformed XML and if not handled properly could allow injection of arbitrary markup.
values requiring 5 bytes (>0x0FFFFFFF) overflow and drop the high byte, producing incorrect LEB128 encodings. Fixed by using the byte-array encoder; throws when an encoding needs more than 4 bytes
1) Append mode overwrites instead of appending: WebmWriter never seeks to
the end of the target file in append mode, so writeTag writes from
offset 0 and destroys existing data
2) Existing file not truncated when rewriting: when append is false, the
final copy writes new data to the destination but never truncates the
file first. If the destination already exists and is larger than the
new content, stale bytes remain at the end, producing a corrupted WebM.
Fixed by:
1) Append mode now seeks to the end of the existing file before writing, so
new data no longer overwrites from offset 0.
2) Rewrite mode truncates the destination before copying temporary data,
preventing stale trailing bytes from older, larger files.
…alled correctly, and if processing the results of FLVReader() throws an exception make sure to close the file so it doesn't leak.
…trim the URI down to the base application and room, with the format /app/room and chop off any ?query or #anchor tags. Instead it was converting "/app/room?q=a" to "/app" instead of "/app/room".
…ope for a path. If the path doesn’t match a registered application (typoed URL, unregistered app), don't throw a NoSuchElementException during handshake.
…istener
with listener.getClass().isInstance(clazz), but isInstance expects an
object, not a Class. This always returned false, so listeners were never
detected. As a result, code that relies on this check (e.g., avoiding
duplicate registration or verifying protocol handler availability)
silently failed. Check adjusted to match function return type.
…ecking that it's not null, since it could be client controlled. Fix a similar issue in service/Call.java's read/writeExternal to check serviceName and serviceMethodName before using them. In ReflectionUtils, findMethod now checks that methodName and arguments aren't null before referencing them.
…c and, if negative, only added 256. Negative 24-bit values were not sign-extended correctly, so decoded numbers were wrong. Fixed by sign-extending the high byte.
…ute with the default value instead of fetching it.
…sent (meta.getMetaCue() returns null), the subsequent metaArr.length access throws NullPointerException, so injecting metadata into files without cue points fails.
null, but then would dereference it anyway on the return line. Just return false if it's null.
…olEncoder.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…olEncoder.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…olEncoder.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…olEncoder.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
PlayEngine changes: - Track audio and video base timestamps separately for late subscribers - Both audio and video now start at ts=2 for proper A/V sync - Reorder playLive() to send audio config before keyframe (DTS ordering fix) - Add debug logging for video frame delivery path RTMPConnection changes: - Reduce BytesRead acknowledgement interval from 1MB to 128KB - More frequent acknowledgements improve encoder compatibility - Add debug logging for BytesRead messages RTMP codec improvements: - Enhanced extended timestamp handling for timestamps >= 0xFFFFFF - Per-channel timestamp offset tracking for discontinuity compensation - Improved timestamp delta calculations in encoder Debug logging additions: - ClientBroadcastStream: video reception and livePipe push logging - VideoFrameDropper: state transition and frame drop decision logging - TestRTMPUtils: comprehensive tests for RTMP utility methods
Proposed 2.0.26 release with RTMP encode/decode fixes
- Fix race condition in WebSocketPlugin.setApplication() by using computeIfAbsent for atomic manager creation and initialization - Add getApplication() getter to WebSocketScopeManager to expose appScope - Add null guard in makeScope(IScope) to prevent NPE - Normalize trailing slashes in paths (e.g., "/live/" -> "/live") in both DefaultServerEndpointConfigurator.modifyHandshake() and WebSocketScopeManager.getScope() for consistent scope lookups - Add null checks before putting scope in ConcurrentHashMap user properties - Improve scope lookup to use manager.getApplication() before plugin lookup
…r vs old thread local style
Two issues were causing chunk stream desynchronization in Red5-to-Red5 cluster communication: 1. Type 0 header decoding did not reset extended=false when wire timestamp dropped below MEDIUM_INT_MAX (16777215). This caused the flag to be incorrectly inherited from previous headers, making Type 3 chunks read 4 extra bytes when they shouldn't. 2. A "compatibility check" in Type 3 handling used decoded timestamp values (which include discontinuity offsets) instead of wire values, causing false positives that read extra bytes. Also documented that RTMPProtocolDecoder.decodeBuffer() already calls compact() in its finally block - callers should NOT compact again as double-compact corrupts buffer positions. Fixes: - Add else clause to Type 0 to reset extended=false when timestamp < MEDIUM_INT_MAX - Remove faulty compatibility check from Type 3 that checked adjusted values - Add comments in Mina decoders warning against double-compact - Add debug logging for Type 3 extended timestamp encoding - Add unit test for extended-to-non-extended timestamp transition
Feature/mediabunny
mondain
added a commit
that referenced
this pull request
Feb 1, 2026
Merge pull request #432 from Red5/main
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.