Bug 1906077 - ICS calendar subscriptions should use the original URI for temporary redirects. r=aleca

To test, subscribe to https://github.com/othyn/go-calendar/releases/latest/download/gocal__community_day.ics

Also
* don't fail for cases there content-type is null
* accept for content-type=application/octet-stream where the Content-Disposition says it's an .ics

Differential Revision: https://phabricator.services.mozilla.com/D220872

--HG--
extra : rebase_source : a3e7e2cc8f56bdf7e7968b1a2863bbfa8002b9a2
extra : absorb_source : 3e9d607dfd459e5ad8f87348838f9667711f8cd8
This commit is contained in:
Magnus Melin 2024-09-05 13:42:16 +03:00
Родитель 885e42ebd1
Коммит 03004531ab
7 изменённых файлов: 73 добавлений и 14 удалений

Просмотреть файл

@ -98,7 +98,7 @@ export var detection = {
* @param {ProviderFilter[]} aPreDetectFilters - Functions for filtering out providers. * @param {ProviderFilter[]} aPreDetectFilters - Functions for filtering out providers.
* @param {object} aExtraProperties - Extra properties to pass on to the * @param {object} aExtraProperties - Extra properties to pass on to the
* providers. * providers.
* @returns {Promise<Map<string,calICalendar[]>>} a Map of provider type to calendars found. * @returns {Promise<Map<calICalendarProvider,calICalendar[]>>} a Map of provider type to calendars found.
*/ */
async detect( async detect(
aUsername, aUsername,

Просмотреть файл

@ -99,8 +99,6 @@ CalDavCalendar.prototype = {
return this != this.superCalendar; return this != this.superCalendar;
}, },
mLastRedirectStatus: null,
ensureTargetCalendar() { ensureTargetCalendar() {
if (!this.isCached && !this.mOfflineStorage) { if (!this.isCached && !this.mOfflineStorage) {
// If this is a cached calendar, the actual cache is taken care of // If this is a cached calendar, the actual cache is taken care of

Просмотреть файл

@ -307,7 +307,7 @@ class CalDavDetector {
// `request.commit()` can throw; errors should be caught by calling functions. // `request.commit()` can throw; errors should be caught by calling functions.
const response = await request.commit(); const response = await request.commit();
const homeSets = response.firstProps["C:calendar-home-set"]; const homeSets = response.firstProps ? response.firstProps["C:calendar-home-set"] : null;
const target = response.uri; const target = response.uri;
if (response.authError) { if (response.authError) {

Просмотреть файл

@ -277,14 +277,19 @@ class ICSDetector {
// The content type header may include a charset, so use 'string.includes'. // The content type header may include a charset, so use 'string.includes'.
if (response.ok) { if (response.ok) {
const header = response.getHeader("Content-Type"); const contentType = response.getHeader("Content-Type");
const contentDisposition = response.getHeader("Content-Disposition");
if ( if (
header.includes("text/calendar") || contentType?.includes("text/calendar") ||
header.includes("application/ics") || contentType?.includes("application/ics") ||
/\.ics\b/i.test(contentDisposition) ||
(response.text && response.text.includes("BEGIN:VCALENDAR")) (response.text && response.text.includes("BEGIN:VCALENDAR"))
) { ) {
const target = response.uri; let target = response.uri;
// Set up calendar for original URI for temporal redirects.
if (response.lastRedirectStatus == 302 || response.lastRedirectStatus == 307) {
target = response.nsirequest.originalURI;
}
cal.LOG(`[calICSProvider] ${target.spec} has valid content type (via ${method} request)`); cal.LOG(`[calICSProvider] ${target.spec} has valid content type (via ${method} request)`);
return [this.handleCalendar(target)]; return [this.handleCalendar(target)];
} }
@ -410,8 +415,8 @@ class ICSDetector {
* Set up and return a new ICS calendar object. * Set up and return a new ICS calendar object.
* *
* @param {nsIURI} uri - The location of the calendar. * @param {nsIURI} uri - The location of the calendar.
* @param {Set} [props] - For CalDav calendars, these are the props * @param {Set} [props] - For CalDav calendars, these are the props parsed
* parsed from the response. * from the response.
* @returns {calICalendar} A new calendar. * @returns {calICalendar} A new calendar.
*/ */
handleCalendar(uri, props = new Set()) { handleCalendar(uri, props = new Set()) {

Просмотреть файл

@ -2,8 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
import { Assert } from "resource://testing-common/Assert.sys.mjs";
import { CommonUtils } from "resource://services-common/utils.sys.mjs"; import { CommonUtils } from "resource://services-common/utils.sys.mjs";
import { HttpServer } from "resource://testing-common/httpd.sys.mjs"; import { HttpServer } from "resource://testing-common/httpd.sys.mjs";
@ -21,6 +19,7 @@ export var ICSServer = {
this.username = username; this.username = username;
this.password = password; this.password = password;
this.server.registerPathHandler("/ping", this.ping); this.server.registerPathHandler("/ping", this.ping);
this.server.registerPathHandler("/http302", this.http302);
this.server.registerPathHandler(this.path, this.handleICS.bind(this)); this.server.registerPathHandler(this.path, this.handleICS.bind(this));
this.reset(); this.reset();
@ -98,6 +97,15 @@ export var ICSServer = {
response.write("pong"); response.write("pong");
}, },
http302(request, response) {
const params = new URLSearchParams(request.queryString);
const path = params.get("path");
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", `${ICSServer.origin}/${path}`);
response.setHeader("Content-Type", "text/plain; charset=UTF-8");
response.setHeader("Content-Length", "0");
},
handleICS(request, response) { handleICS(request, response) {
if (!this.checkAuth(request, response)) { if (!this.checkAuth(request, response)) {
return; return;
@ -115,7 +123,6 @@ export var ICSServer = {
return; return;
} }
Assert.report(true, undefined, undefined, "Should not have reached here");
response.setStatusLine("1.1", 405, "Method Not Allowed"); response.setStatusLine("1.1", 405, "Method Not Allowed");
response.setHeader("Content-Type", "text/plain"); response.setHeader("Content-Type", "text/plain");
response.write(`Method not allowed: ${request.method}`); response.write(`Method not allowed: ${request.method}`);

Просмотреть файл

@ -0,0 +1,48 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
var { ICSServer } = ChromeUtils.importESModule(
"resource://testing-common/calendar/ICSServer.sys.mjs"
);
var { detection } = ChromeUtils.importESModule(
"resource:///modules/calendar/utils/calProviderDetectionUtils.sys.mjs"
);
add_setup(async () => {
ICSServer.open();
ICSServer.putICSInternal(
CalendarTestUtils.dedent`
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:6714b781-920f-46f8-80ec-3d3995e2e9ce
SUMMARY:some event
DTSTART:20210401T120000Z
DTEND:20210401T130000Z
END:VEVENT
END:VCALENDAR
`
);
registerCleanupFunction(() => ICSServer.close());
});
add_task(async function testIcsDetection() {
const url = `${ICSServer.origin}/test.ics`;
const detectedCals = await detection.detect("", "", url, false, [], {});
Assert.ok(detectedCals, "should find calendars");
Assert.equal(detectedCals.size, 1, "should find one calendar");
const icsCal = detectedCals.values().next().value[0];
Assert.equal(icsCal.uri.spec, url, "should have expected uri");
});
add_task(async function testIcsDetection302() {
// This url will redirect to test.ics for the actual content.
// We still want to subscribe to the original url.
const url = `${ICSServer.origin}/http302?path=test.ics`;
const detectedCals = await detection.detect("", "", url, false, [], {});
Assert.ok(detectedCals, "should find calendars");
Assert.equal(detectedCals.size, 1, "should find one calendar");
const icsCal = detectedCals.values().next().value[0];
Assert.equal(icsCal.uri.spec, url, "should have expected uri");
});

Просмотреть файл

@ -4,6 +4,7 @@ prefs =
calendar.timezone.local=UTC calendar.timezone.local=UTC
calendar.timezone.useSystemTimezone=false calendar.timezone.useSystemTimezone=false
[test_cal_detection.js]
[test_caldavCalendar_cached.js] [test_caldavCalendar_cached.js]
[test_caldavCalendar_uncached.js] [test_caldavCalendar_uncached.js]
[test_icsCalendar_cached.js] [test_icsCalendar_cached.js]