Probleme beim rendern von HTTP Status 207 (Multistatus)

Hallo Leute,
bin derzeit dabei einen Rails basierten CalDAV Server zu entwickeln.
Seit geraumer Zeit sitze ich allerdings an einem Problem, das ich
weder lösen , noch irgendwie eingrenzen kann.

Wie die Meisten sicherlich wissen, setzt CalDAV auf dem WebDAV
Standard auf und nutzt XML zum Informationsaustausch.
In manchen Fällen ist eine Multistatus Response notwendig.
Zu Testzwecken realisiere ich das so:

render :text => my_xml_response, :status => 207

iCal verhält sich aber leider nicht so wie erwartet, sondern liefert
eine Fehlermeldung
Request und Response überwache ich mit dem HTTP Sniffer HTTP Scoop.
Schaut man sich den betreffenden Vorgang an wird deutlich, dass die
TCP Verbindung zwischen iCal und der Rails Anwendung unerwartet
abbricht.
Beim gleichen Vorgang zwischen iCal und dem Apple CalendarServer
verläuft alles wie geplant und die Verbindung wird korrekt terminiert.

Ändere ich nun meinen Code in

render :text => my_xml_response, :status => 200

bekomme ich zwar einen Fehler in iCal (weil die XML Response nicht zum
200er Status passt), aber die TCP Verbindung wird nicht unerwartet
terminiert.
Hat jemand von Euch Erfahrung mit CalDAV oder WebDAV unter Rails?
Gibt es etwas, dass ich bei der Verwendung des 207er Status beachten
muss?
Oder ist dieses Verhalten ein Bug?

Bin für jede Hilfe Dankbar.

ML

Lindhorst Matthias wrote:

Zu Testzwecken realisiere ich das so:
render :text => my_xml_response, :status => 207

wird der Content-Type hier korrekt auf XML gesetzt, oder liefert der
Server das XML als text/plain aus?

Schaut man sich den betreffenden Vorgang an wird deutlich, dass die
TCP Verbindung zwischen iCal und der Rails Anwendung unerwartet
abbricht.

Möglicherweise macht iCal die Verbindung sofort zu, wenn es erkennt,
dass es mit dem Content nichts anfangen kann.

Hat jemand von Euch Erfahrung mit CalDAV oder WebDAV unter Rails?

Nicht mit Rails, aber mit CalDAV/WebDAV :wink:

Gibt es etwas, dass ich bei der Verwendung des 207er Status beachten
muss?

Siehe oben. Am besten du schickst mal den Dump vom HTTP Traffic zwischen
iCal und deinem Server.

Gruss,
Helge

Hi Helge,
vielen Dank für die schnelle Antwort.

wird der Content-Type hier korrekt auf XML gesetzt, oder liefert der
Server das XML als text/plain aus?

Habe den Content-Type explizit auf text/xml gesetzt, iCal zeigt aber
dennoch das gleiche verhalten.

Möglicherweise macht iCal die Verbindung sofort zu, wenn es erkennt,
dass es mit dem Content nichts anfangen kann.

Dann müsste iCal aber auch die Verbindung schließen, wenn es einen
200er Status bekommt, da sich die Daten ja nicht ändern, oder?
Ich bin mir außerdem nicht sicher, warum iCal den Response Body parsen
sollte, bevor dieser vollständig ist.

Hatte vor geraumer Zeit ein ähnliches Szenario aufgebaut, allerdings
nicht mit PROPFIND und iCal, sondern per GET mit Firefox.
Auch hier wurde die Verbindung beendet, bevor die Ãœbertragung zu Ende
war.
Den Body konnte der Browser dann darstellen, aber die Header
Informationen waren teilweise nicht vorhanden.

Am besten du schickst mal den Dump vom HTTP Traffic zwischen
iCal und deinem Server.


Fall 1
(iCal + Apple CalendarServer )


REQUEST

Method: PROPFIND

URL: http://localhost:8008/principals/users/admin/

Headers:

User-Agent: DAVKit/3.0.6 (661); CalendarStore/3.0.7 (858); iCal/3.0.7
(1284); Mac OS X/10.5.7 (9J61)
Host: localhost:8008
Depth: 0
Authorization: Digest username=“admin”, realm=“Test Realm”,
nonce=“100045035610880960381959273727”, uri=“/principals/users/
admin/”, response=“65720e9b3f2c6cf498b8c29e452b62a9”, algorithm=“md5”
Content-Type: text/xml
Content-Length: 374
Connection: keep-alive

Post Data:

<?xml version="1.0" encoding="utf-8"?>

<x0:propfind xmlns:x2=“Calendar and Contacts Server
xmlns:x1="urn:ietf:params:xml:ns:caldav
" xmlns:x0=“DAV:”>
x0:prop
x1:calendar-home-set/
x1:calendar-user-address-set/
x1:schedule-inbox-URL/
x1:schedule-outbox-URL/
x2:dropbox-home-URL/
x2:notifications-URL/
x0:displayname/
</x0:prop>
</x0:propfind>


RESPONSE

Headers:

Accept-Ranges: bytes
Server: Twisted/2.5.0+rUnknown TwistedWeb/[twisted.web2, version 0.2.0
(SVN rUnknown)]
DAV: 1, access-control, calendar-access, calendar-schedule, calendar-
auto-schedule, calendar-availability, inbox-availability, calendar-
proxy, calendarserver-private-events, calendarserver-private-comments,
calendarserver-principal-property-search
Content-Length: 1762
Date: Sun, 28 Jun 2009 12:07:41 GMT
Content-Type: text/xml
Last-Modified: Fri, 26 Jun 2009 16:37:35 GMT

Body:

<?xml version='1.0' encoding='UTF-8'?> /principals/users/admin/ /calendars/__uids__/admin urn:uuid:admin http://Aton:8008/principals/__uids__/admin/ http://Aton:8008/principals/users/admin/ https://Aton:8443/principals/__uids__/admin/ /principals/users/admin/ https://Aton:8443/principals/users/admin/ /principals/__uids__/admin/ /calendars/__uids__/admin/inbox/ /calendars/__uids__/admin/outbox/ /calendars/__uids__/admin/dropbox/ Super User HTTP/1.1 200 OK HTTP/1.1 404 Not Found

Fall 2
(iCal + Rails )


REQUEST

Method: PROPFIND

URL: http://localhost:8008/principals/users/admin/

Headers:

User-Agent: DAVKit/3.0.6 (661); CalendarStore/3.0.7 (858); iCal/3.0.7
(1284); Mac OS X/10.5.7 (9J61)
Content-Type: text/xml
Host: localhost:3000
Depth: 0
Content-Length: 374
Connection: close

Post Data:

<?xml version="1.0" encoding="utf-8"?>

<x0:propfind xmlns:x2=“Calendar and Contacts Server
xmlns:x1="urn:ietf:params:xml:ns:caldav
" xmlns:x0=“DAV:”>
x0:prop
x1:calendar-home-set/
x1:calendar-user-address-set/
x1:schedule-inbox-URL/
x1:schedule-outbox-URL/
x2:dropbox-home-URL/
x2:notifications-URL/
x0:displayname/
</x0:prop>
</x0:propfind>


RESPONSE

Closed by peer

Habe mit Packet Peeper noch 2 TCP Dumps gemacht und diese angehängt.
Die Dateien sollten sich aber auch mit ireshark öffnen lassen.

Könnte es sein, dass Rails einen Bug hat, der beim 207er Status die
Verbindung unterbricht, bevor die Antwort gesendet wurde?

Gruß
Matthias

Hi Helge,
Danke für Deine Hilfe, werde das gleich mal mit curl checken.

Nein, warum? Kommt im Endeffekt auf die Implementierung an. Ich glaube
aber nicht, dass es ein iCal Problem ist, eher ein Rails Problem.

Ich gehe ja auch davon aus, dass es ein Rails Problem ist, deswegen
die Anfrage auf der Rails-ug Liste g.

Und auf Port 8008 läuft deine Rails App. Hinter einem HTTP Server,
oder
ist das direkt ein Rails Prozess? Wie hast du /principals/users/admin/
im Rails auf deinen Controller gemapped?

Nein, auf 8008 läuft der CalendarServer von Apple, meine RailsApp
läuft via Mongrel auf Port 3000.
Das Mapping auf den Principials Controller habe ich mit

ActionController::Routing::HTTP_METHODS << ‘propfind’.to_sym
[…]
‘map.connect /principals/:principal_type/:name/’, :controller =>
‘principals’

realisiert.
Rails lehnt normaler Weise PROPFIND und andere zusätzliche HTTP
Methoden ab, deswegen musste ich ihm diese erst in der environment.rb
“bekannt” machen:

Enable WebDAV HTTP methods

WEBDAV_HTTP_METHODS = %w(propfind report)

WEBDAV_HTTP_METHOD_LOOKUP = WEBDAV_HTTP_METHODS.inject({}) { |h, m|
h[m] = h[m.upcase] = m.to_sym; h}
ActionController::Request::HTTP_METHODS.concat(WEBDAV_HTTP_METHODS)
ActionController::Request::HTTP_METHOD_LOOKUP.merge!
(WEBDAV_HTTP_METHOD_LOOKUP)

Vermutlich hat Rails per Default kein Mapping von 207 auf einen Text.
Bei 200 wird er korrekt “HTTP/1.1 200 OK” generieren.

Was mich bei der Antwort von Rails in Frame 9 auch stutzig macht, ist:

HTTP/1.1 207 …Connection: close <<

Wirkt auf mich, also würde Rails die Verbindung als beendet ansehen,
bevor überhaupt ein Responsebody gesendet wurde.

Gruß
Matthias

Lindhorst Matthias wrote:

Dann müsste iCal aber auch die Verbindung schließen, wenn es einen
200er Status bekommt, da sich die Daten ja nicht ändern, oder?

Nein, warum? Kommt im Endeffekt auf die Implementierung an. Ich glaube
aber nicht, dass es ein iCal Problem ist, eher ein Rails Problem.

Ich würde iCal auch erstmal komplett aussen vor lassen und mit ‘curl’
iCal simulieren bis es klappt, zB:
—snip—
curl --request PROPFIND -v
–insecure --digest
–header “Content-Type: text/xml”
–header “Depth: 0”
–data-binary “@principal-props.xml
–user “test:pwd”
http://railsserver/principals/users/test/
—snap—

In die Datei ‘principal-props.xml’ packst du das XML aus dem iCal
Request.

Ich bin mir außerdem nicht sicher, warum iCal den Response Body parsen
sollte, bevor dieser vollständig ist.

Eigentlich parsen alle vernünftigen Bibliotheken die Daten inkrementell
sobald sie reinkommen (bei XML zB via SAX). Reduziert Speicherverbrauch
und Latenzzeit. Gerade die REPORT Requests auf mehrere Termine können ja
recht gross werden.

Method: PROPFIND
URL: http://localhost:8008/principals/users/admin/

Und auf Port 8008 läuft deine Rails App. Hinter einem HTTP Server, oder
ist das direkt ein Rails Prozess? Wie hast du /principals/users/admin/
im Rails auf deinen Controller gemapped?

RESPONSE
Closed by peer

Hm, im packet dump sieht es so aus, also ob du dem iCal etwas schickst.
Auf den ersten Blick fällt auf, dass die HTTP response Zeile kaputt
scheint (Frame 9). Anscheinend generiert Rails hier sowas:

HTTP/1.1[space]207[space][cr][lf]

Richtig ist eigentlich sowas:

HTTP/1.1[space]207[space]Multistatus[cr][lf]

Eventuell stört dass den HTTP Layer von MacOS schon.

Vermutlich hat Rails per Default kein Mapping von 207 auf einen Text.
Bei 200 wird er korrekt “HTTP/1.1 200 OK” generieren.

Gruss,
Helge

Hi Helge,

habe jetzt mal ein paar Test laufen lassen und fest gestellt, dass HTTP
Scoop anscheinend das Problem ist.
Wenn der Status so aussieht

HTTP/1.1[space]207[space][cr][lf]

erkennt HTTP Scoop diesen fälschlicher Weise nicht als gültigen HTTP Status.
Habe die xml resonse des Apple CalendarServers kopiert und Rails dazu
veranlasst diese mit dem Status 207 zu rendern.
iCal hat darauf wie erwartet reagiert und versucht die angegebenen URLs
von Calendar Home Set etc. zu erreichen
Also lag der Fehler von Anfang an nicht bei Rails oder iCal, sondern an
HTTP Scoop :wink:
Sorry für den Aufwand und vielen Dank für die Hilfe !

Gruß
Matthias

Helge Heß schrieb:

Lindhorst Matthias wrote:

Ich gehe ja auch davon aus, dass es ein Rails Problem ist, deswegen
die Anfrage auf der Rails-ug Liste g.

Yup :wink: Eventuell hilft es ja deine Frage konkreter zu stellen und eine
Rails-Antwort zu bekommen.

Vermutlich hat Rails per Default kein Mapping von 207 auf einen Text.
Bei 200 wird er korrekt “HTTP/1.1 200 OK” generieren.

Ich denke du musst dieses Problem beheben, dann wirds klappen :wink: Sieht
mir nach einem (kleinen) Rails Bug aus.

Was mich bei der Antwort von Rails in Frame 9 auch stutzig macht, ist:

HTTP/1.1 207 …Connection: close <<
Wirkt auf mich, also w�rde Rails die Verbindung als beendet ansehen,
bevor �berhaupt ein Responsebody gesendet wurde.

Nein, das ist OK und üblich. Der Connection ‘close’ header sagt dem
Client, dass er nach dem Lesen der Response die Verbindung kappen soll
(also keine persistenten HTTP Connections verwendet).

Gruss,
Helge

Das ‘CalDAV-on-Rails’ Projekt ist der Grundstein für ein größeres Projekt.
Im derzeitigen. sehr frühen Entwicklungsstadium ist es erstmal nicht
öffentlich.
Da ich aber ein sehr großer Freund von OpenSource bin, wird zumindest
der CalDAV Teil des Projektes in absehbarer Zukunft unter eine
entsprechende Lizenz gestellt und auch öffentlich entwickelt.
Habe mich bis jetzt noch nicht mit dem Parsing des iCalendar Formates
beschäftigt, es scheint aber mehrere Bibliotheken zu geben, die diese
Funktionalität bieten.
Kannst Du mir eine empfehlen, oder lohnt es sich eher über eine
Eigenentwicklung nach zu denken?
Falls Du daran interessiert bist bei der Entwicklung des CalDAV on Rails
Projektes mit zu wirken, können wir uns gerne mal darüber unterhalten.

Matthias

Helge Heß schrieb:

Matthias Lindhorst wrote:

Das ‘CalDAV-on-Rails’ Projekt ist der Grundstein f�r ein gr��eres Projekt.
Im derzeitigen. sehr fr�hen Entwicklungsstadium ist es erstmal nicht
�ffentlich.

OK.

Da ich aber ein sehr gro�er Freund von OpenSource bin, wird zumindest
der CalDAV Teil des Projektes in absehbarer Zukunft unter eine
entsprechende Lizenz gestellt und auch �ffentlich entwickelt.

Klingt gut.

Kannst Du mir eine empfehlen, oder lohnt es sich eher �ber eine
Eigenentwicklung nach zu denken?

Kann ich bzgl Ruby nichts zu sagen.

Falls Du daran interessiert bist bei der Entwicklung des CalDAV on Rails
Projektes mit zu wirken, k�nnen wir uns gerne mal dar�ber unterhalten.

Ich helfe gerne mit sachdienlichen CalDAV Informationen, an der Ruby
Entwicklung selbst werde ich aber nicht mitwirken :wink:

Gruss,
Helge

PS: mehr zum Thema dann wohl am besten via me-at-helgehess-eu.

Ah ja,

prima :wink: Ich bin interessiert an dem ‘CalDAV-on-Rails’ Projekt. Ist das
nur etwas für den internen Gebrauch, oder wird es da auch öffentliche
Software geben?

Was benutzt du unter RoR um iCal/vCard zu generieren / zu parsen?

Gruss,
Helge

vielleicht helfen diese beiden posts ja weiter:

http://blog.funkensturm.de/2008/02/10/finally-railsicalendar-ical-ics-publish-with-ruby-on-rails/
http://blog.funkensturm.de/2009/06/08/funkenrailsdav-webdav-with-rails-eg-for-ical/

Gruß
Manuel

Am 30.06.2009 um 12:20 schrieb Matthias Lindhorst: