mirror of https://github.com/zulip/zulip.git
web: Do not assume error responses are valid, or our, JSON.
Partially fixes #24815.
This commit is contained in:
parent
7efe989a72
commit
ba7492a314
|
@ -80,7 +80,9 @@ export function create_ajax_request(
|
|||
},
|
||||
error(xhr) {
|
||||
$(form_loading).hide();
|
||||
if (xhr.responseJSON?.msg) {
|
||||
$(form_error).show().text(xhr.responseJSON.msg);
|
||||
}
|
||||
$(form_input_section).show();
|
||||
$(zulip_limited_section).show();
|
||||
$(free_trial_alert_message).show();
|
||||
|
|
|
@ -105,20 +105,17 @@ function call(args) {
|
|||
return;
|
||||
}
|
||||
} else if (xhr.status === 403) {
|
||||
try {
|
||||
if (
|
||||
if (xhr.responseJSON === undefined) {
|
||||
blueslip.error("Unexpected 403 response from server", {
|
||||
xhr: xhr.responseText,
|
||||
args,
|
||||
});
|
||||
} else if (
|
||||
xhr.responseJSON.code === "CSRF_FAILED" &&
|
||||
reload_state.csrf_failed_handler !== undefined
|
||||
) {
|
||||
reload_state.csrf_failed_handler();
|
||||
}
|
||||
} catch (error) {
|
||||
blueslip.error(
|
||||
"Unexpected 403 response from server",
|
||||
{xhr: xhr.responseText, args},
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
orig_error(xhr, error_type, xhn);
|
||||
};
|
||||
|
@ -189,7 +186,7 @@ export function patch(options) {
|
|||
}
|
||||
|
||||
export function xhr_error_message(message, xhr) {
|
||||
if (xhr.status.toString().charAt(0) === "4") {
|
||||
if (xhr.status.toString().charAt(0) === "4" && xhr.responseJSON?.msg) {
|
||||
// Only display the error response for 4XX, where we've crafted
|
||||
// a nice response.
|
||||
const server_response_html = _.escape(xhr.responseJSON.msg);
|
||||
|
|
|
@ -583,10 +583,14 @@ export function initialize() {
|
|||
$invite_row.remove();
|
||||
}
|
||||
|
||||
function failure(error_msg) {
|
||||
function xhr_failure(xhr) {
|
||||
let error_message = "Failed to subscribe user!";
|
||||
if (xhr.responseJSON?.msg) {
|
||||
error_message = xhr.responseJSON.msg;
|
||||
}
|
||||
clear_invites();
|
||||
compose_banner.show_error_message(
|
||||
error_msg,
|
||||
error_message,
|
||||
compose_banner.CLASSNAMES.generic_compose_error,
|
||||
$banner_container,
|
||||
$("#compose-textarea"),
|
||||
|
@ -594,11 +598,6 @@ export function initialize() {
|
|||
$(event.target).prop("disabled", true);
|
||||
}
|
||||
|
||||
function xhr_failure(xhr) {
|
||||
const error = xhr.responseJSON;
|
||||
failure(error.msg);
|
||||
}
|
||||
|
||||
const sub = sub_store.get(stream_id);
|
||||
|
||||
subscriber_api.add_user_ids_to_stream([user_id], sub, success, xhr_failure);
|
||||
|
|
|
@ -66,10 +66,13 @@ export function post_hotspot_as_read(hotspot_name) {
|
|||
url: "/json/users/me/hotspots",
|
||||
data: {hotspot: hotspot_name},
|
||||
error(err) {
|
||||
if (err.readyState !== 0) {
|
||||
blueslip.error("Failed to fetch hotspots", {
|
||||
readyState: err.readyState,
|
||||
status: err.status,
|
||||
body: err.responseText,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ function submit_invitation_form() {
|
|||
}
|
||||
},
|
||||
error(xhr) {
|
||||
if (xhr.responseJSON.errors === undefined) {
|
||||
if (xhr.responseJSON?.errors === undefined) {
|
||||
// There was a fatal error, no partial processing occurred.
|
||||
ui_report.error("", xhr, $invite_status);
|
||||
} else {
|
||||
|
|
|
@ -693,6 +693,7 @@ export function toggle_resolve_topic(message_id, old_topic_name, report_errors_i
|
|||
url: "/json/messages/" + message_id,
|
||||
data: request,
|
||||
error(xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
if (xhr.responseJSON.code === "MOVE_MESSAGES_TIME_LIMIT_EXCEEDED") {
|
||||
handle_resolve_topic_failure_due_to_time_limit(topic_is_resolved);
|
||||
return;
|
||||
|
@ -701,6 +702,7 @@ export function toggle_resolve_topic(message_id, old_topic_name, report_errors_i
|
|||
if (report_errors_in_global_banner) {
|
||||
ui_report.generic_embed_error(xhr.responseJSON.msg, 3500);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -842,7 +844,7 @@ export function save_inline_topic_edit($row) {
|
|||
},
|
||||
error(xhr) {
|
||||
const $spinner = $row.find(".topic_edit_spinner");
|
||||
if (xhr.responseJSON.code === "MOVE_MESSAGES_TIME_LIMIT_EXCEEDED") {
|
||||
if (xhr.responseJSON?.code === "MOVE_MESSAGES_TIME_LIMIT_EXCEEDED") {
|
||||
const allowed_message_id = xhr.responseJSON.first_message_id_allowed_to_move;
|
||||
const send_notification_to_old_thread = false;
|
||||
const send_notification_to_new_thread = false;
|
||||
|
@ -1223,7 +1225,7 @@ export function move_topic_containing_message_to_stream(
|
|||
},
|
||||
error(xhr) {
|
||||
reset_modal_ui();
|
||||
if (xhr.responseJSON.code === "MOVE_MESSAGES_TIME_LIMIT_EXCEEDED") {
|
||||
if (xhr.responseJSON?.code === "MOVE_MESSAGES_TIME_LIMIT_EXCEEDED") {
|
||||
const allowed_message_id = xhr.responseJSON.first_message_id_allowed_to_move;
|
||||
function handle_confirm() {
|
||||
move_topic_containing_message_to_stream(
|
||||
|
|
|
@ -196,11 +196,13 @@ function hide_catalog_show_integration() {
|
|||
dataType: "html",
|
||||
success: hide_catalog,
|
||||
error(err) {
|
||||
if (err.readyState !== 0) {
|
||||
blueslip.error(`Integration documentation for '${state.integration}' not found.`, {
|
||||
readyState: err.readyState,
|
||||
status: err.status,
|
||||
responseText: err.responseText,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -180,11 +180,10 @@ function update_url() {
|
|||
|
||||
// API callers: These methods handle communicating with the Python backend API.
|
||||
function handle_unsuccessful_response(response) {
|
||||
try {
|
||||
if (response.responseJSON?.msg) {
|
||||
const status_code = response.statusCode().status;
|
||||
response = JSON.parse(response.responseText);
|
||||
set_results_notice(`Result: (${status_code}) ${response.msg}`, "warning");
|
||||
} catch {
|
||||
set_results_notice(`Result: (${status_code}) ${response.responseJSON.msg}`, "warning");
|
||||
} else {
|
||||
// If the response is not a JSON response, then it is probably
|
||||
// Django returning an HTML response containing a stack trace
|
||||
// with useful debugging information regarding the backend
|
||||
|
|
|
@ -85,6 +85,7 @@ function update_ui_and_send_reaction_ajax(message_id, reaction_info) {
|
|||
},
|
||||
error(xhr) {
|
||||
view.waiting_for_server_request_ids.delete(reaction_request_id);
|
||||
if (xhr.readyState !== 0) {
|
||||
if (
|
||||
xhr.responseJSON?.code === "REACTION_ALREADY_EXISTS" ||
|
||||
xhr.responseJSON?.code === "REACTION_DOES_NOT_EXIST"
|
||||
|
@ -94,6 +95,7 @@ function update_ui_and_send_reaction_ajax(message_id, reaction_info) {
|
|||
} else {
|
||||
blueslip.error(channel.xhr_error_message("Error sending reaction", xhr));
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ function get_events({dont_block = false} = {}) {
|
|||
get_events_xhr = undefined;
|
||||
// If we're old enough that our message queue has been
|
||||
// garbage collected, immediately reload.
|
||||
if (xhr.status === 400 && xhr.responseJSON.code === "BAD_EVENT_QUEUE_ID") {
|
||||
if (xhr.status === 400 && xhr.responseJSON?.code === "BAD_EVENT_QUEUE_ID") {
|
||||
page_params.event_queue_expired = true;
|
||||
reload.initiate({
|
||||
immediate: true,
|
||||
|
|
|
@ -118,9 +118,11 @@ function upload_avatar($file_input) {
|
|||
if (page_params.avatar_source === "G") {
|
||||
$("#user-avatar-source").show();
|
||||
}
|
||||
if (xhr.responseJSON?.msg) {
|
||||
const $error = $("#user-avatar-upload-widget .image_file_input_error");
|
||||
$error.text(xhr.responseJSON.msg);
|
||||
$error.show();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -490,7 +492,9 @@ export function set_up() {
|
|||
$("#api_key_value").text(data.api_key);
|
||||
},
|
||||
error(xhr) {
|
||||
if (xhr.responseJSON?.msg) {
|
||||
$("#user_api_key_error").text(xhr.responseJSON.msg).show();
|
||||
}
|
||||
},
|
||||
});
|
||||
e.preventDefault();
|
||||
|
@ -798,7 +802,7 @@ export function set_up() {
|
|||
},
|
||||
);
|
||||
let rendered_error_msg;
|
||||
if (xhr.responseJSON.code === "CANNOT_DEACTIVATE_LAST_USER") {
|
||||
if (xhr.responseJSON?.code === "CANNOT_DEACTIVATE_LAST_USER") {
|
||||
if (xhr.responseJSON.is_last_owner) {
|
||||
rendered_error_msg = error_last_owner;
|
||||
} else {
|
||||
|
|
|
@ -580,8 +580,10 @@ export function set_up() {
|
|||
$row.find("api_key_error").hide();
|
||||
},
|
||||
error(xhr) {
|
||||
if (xhr.responseJSON?.msg) {
|
||||
const $row = $(e.currentTarget).closest("li");
|
||||
$row.find(".api_key_error").text(xhr.responseJSON.msg).show();
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -73,8 +73,7 @@ function open_linkifier_edit_form(linkifier_id) {
|
|||
},
|
||||
error_continuation(xhr) {
|
||||
$change_linkifier_button.prop("disabled", false);
|
||||
const response_text = xhr.responseJSON;
|
||||
if (response_text.errors !== undefined) {
|
||||
if (xhr.responseJSON?.errors) {
|
||||
handle_linkifier_api_error(
|
||||
xhr,
|
||||
$pattern_status,
|
||||
|
@ -239,12 +238,14 @@ export function build_page() {
|
|||
},
|
||||
error(xhr) {
|
||||
$add_linkifier_button.prop("disabled", false);
|
||||
if (xhr.responseJSON?.errors) {
|
||||
handle_linkifier_api_error(
|
||||
xhr,
|
||||
$pattern_status,
|
||||
$template_status,
|
||||
$linkifier_status,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1101,7 +1101,9 @@ function get_chart_data(data, callback) {
|
|||
update_last_full_update(data.end_times);
|
||||
},
|
||||
error(xhr) {
|
||||
if (xhr.responseJSON?.msg) {
|
||||
$("#id_stats_errors").show().text(xhr.responseJSON.msg);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -280,8 +280,7 @@ function create_stream() {
|
|||
// The rest of the work is done via the subscribe event we will get
|
||||
},
|
||||
error(xhr) {
|
||||
const msg = xhr.responseJSON.msg;
|
||||
if (msg.includes("access")) {
|
||||
if (xhr.responseJSON?.msg?.includes("access")) {
|
||||
// If we can't access the stream, we can safely
|
||||
// assume it's a duplicate stream that we are not invited to.
|
||||
//
|
||||
|
|
|
@ -196,9 +196,12 @@ function subscribe_new_users({pill_user_ids}) {
|
|||
}
|
||||
|
||||
function invite_failure(xhr) {
|
||||
const error = xhr.responseJSON;
|
||||
let message = "Failed to subscribe user!";
|
||||
if (xhr.responseJSON?.msg) {
|
||||
message = xhr.responseJSON.msg;
|
||||
}
|
||||
show_stream_subscription_request_result({
|
||||
message: error.msg,
|
||||
message,
|
||||
add_class: "text-error",
|
||||
remove_class: "text-success",
|
||||
});
|
||||
|
|
|
@ -24,7 +24,9 @@ function send_typing_notification_ajax(user_ids_array, operation) {
|
|||
},
|
||||
success() {},
|
||||
error(xhr) {
|
||||
if (xhr.readyState !== 0) {
|
||||
blueslip.warn("Failed to send typing event: " + xhr.responseText);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ export function error(
|
|||
status_box: JQuery,
|
||||
remove_after?: number,
|
||||
): void {
|
||||
if (xhr && xhr.status >= 400 && xhr.status < 500) {
|
||||
if (xhr && xhr.status >= 400 && xhr.status < 500 && xhr.responseJSON?.msg) {
|
||||
// Only display the error response for 4XX, where we've crafted
|
||||
// a nice response.
|
||||
const server_response_html = _.escape(xhr.responseJSON.msg);
|
||||
|
@ -78,7 +78,7 @@ export function generic_embed_error(error_html: string, remove_after: number): v
|
|||
}
|
||||
|
||||
export function generic_row_button_error(xhr: JQuery.jqXHR, $btn: JQuery): void {
|
||||
if (xhr.status >= 400 && xhr.status < 500) {
|
||||
if (xhr.status >= 400 && xhr.status < 500 && xhr.responseJSON?.msg) {
|
||||
const $error = $("<p>").addClass("text-error").text(xhr.responseJSON.msg);
|
||||
$btn.closest("td").empty().append($error);
|
||||
} else {
|
||||
|
|
|
@ -142,8 +142,10 @@ export function mark_all_as_read(args = {}) {
|
|||
dialog_widget.close_modal();
|
||||
},
|
||||
error(xhr) {
|
||||
if (xhr.readyState === 0) {
|
||||
// client cancelled the request
|
||||
} else if (xhr.responseJSON?.code === "RATE_LIMIT_HIT") {
|
||||
// If we hit the rate limit, just continue without showing any error.
|
||||
if (xhr.responseJSON.code === "RATE_LIMIT_HIT") {
|
||||
const milliseconds_to_wait = 1000 * xhr.responseJSON["retry-after"];
|
||||
setTimeout(() => mark_all_as_read(args), milliseconds_to_wait);
|
||||
} else {
|
||||
|
@ -241,8 +243,10 @@ export function mark_as_unread_from_here(
|
|||
}
|
||||
},
|
||||
error(xhr) {
|
||||
if (xhr.readyState === 0) {
|
||||
// client cancelled the request
|
||||
} else if (xhr.responseJSON?.code === "RATE_LIMIT_HIT") {
|
||||
// If we hit the rate limit, just continue without showing any error.
|
||||
if (xhr.responseJSON.code === "RATE_LIMIT_HIT") {
|
||||
const milliseconds_to_wait = 1000 * xhr.responseJSON["retry-after"];
|
||||
setTimeout(
|
||||
() =>
|
||||
|
|
|
@ -223,9 +223,12 @@ function add_new_members({pill_user_ids}) {
|
|||
}
|
||||
|
||||
function invite_failure(xhr) {
|
||||
const error = xhr.responseJSON;
|
||||
let message = "Failed to subscribe user!";
|
||||
if (xhr.responseJSON?.msg) {
|
||||
message = xhr.responseJSON.msg;
|
||||
}
|
||||
show_user_group_membership_request_result({
|
||||
message: error.msg,
|
||||
message,
|
||||
add_class: "text-error",
|
||||
remove_class: "text-success",
|
||||
});
|
||||
|
|
|
@ -268,7 +268,7 @@ test("sending", ({override, override_rewire}) => {
|
|||
// Since this path calls blueslip.warn, we need to handle it.
|
||||
blueslip.expect("error", "XHR error message.");
|
||||
channel.xhr_error_message = () => "XHR error message.";
|
||||
args.error({responseJSON: {msg: "Some error message"}});
|
||||
args.error({readyState: 4, responseJSON: {msg: "Some error message"}});
|
||||
}
|
||||
emoji_name = "alien"; // not set yet
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue