Conversation
… is set When an INVITE was challenged and the dialog had no credential, process_invite terminated the dialog with ProxyAuthRequired but kept looping without recording the response. The client transaction ends right after the ACK, so do_invite returned (id, None) and the caller lost the status and the challenge. Per RFC 3261 §22.2/§22.3 the UAC may retry with credentials; when it cannot, the 401/407 is the final response. Record it and stop, as the second-challenge branch already does. Applied to both InviteDialog and the deprecated ClientInviteDialog. The authenticated retry path is unchanged.
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.
Bug
When an outbound INVITE is challenged with
401 Unauthorizedor407 Proxy Authentication Requiredand theInviteOptionhas nocredential,do_invitereturns(dialog, None). The caller never sees the challenge. It can't tell "auth required" apart from other failures that return no response, and it can't read the status or theWWW-Authenticate/Proxy-Authenticateheader.The cause is in
InviteDialog::process_invite: the no-credential branch moves the dialog toTerminated(ProxyAuthRequired)and thencontinues without settingfinal_response. The client transaction terminates right after sending the ACK, so the loop ends and the function returnsNone. The branch that handles a second challenge after an authenticated retry already setsfinal_responseandbreaks; the no-credential branch doesn't.The deprecated
ClientInviteDialog::process_invitehas the same copy of this code and the same bug. It is still public, so it is fixed too.Reproduction
New tests in
src/dialog/tests/test_invite_auth_challenge.rsuse real UDP UAC and UAS endpoints on loopback. Onmain:RFC
RFC 3261 §22.2 and §22.3: when a UAC gets a 401/407 it MAY retry with credentials. When it has none, it can't retry, so the challenge is the final response to the INVITE and should reach the application, the same as any other final non-2xx response (§13.2.2.3).
Fix
In the no-credential branch, set
final_response = Some(resp)andbreakinstead ofcontinue, the same as the second-challenge branch. Nothing else changes:TerminatedReason::ProxyAuthRequired, and that state is still emitted;The diff is 7 lines in each of
invite_dialog.rsandclient_dialog.rs. The debug log now says "auth challenge" and includes the status, because it used to say "407" for 401s too.Tests
Six new tests:
ProxyAuthRequired, and no retry is sent.ClientInviteDialog::process_invite.Authorizationfor 401 andProxy-Authorizationfor 407, and the caller gets the 200.Results:
cargo fmt --all -- --checkis clean.cargo buildhas no warnings.cargo testpasses 336 lib tests and 65 doctests (mainpasses 330 + 65). The new tests also passed 20 repeated runs.Compatibility / risk
Low. The only behaviour change: callers that used to get
Nonefor a challenged INVITE with no credential now getSome(401/407).do_inviteanddo_invite_asynconly treat a 2xx as success, so the dialog-layer registry works as before. Code that checkedresp.is_none()to catch this case should check the status code instead, which is what callers already do for other final failures.