403 response from Fastmail when syncing phone contacts



  • Hi,

    I've been trying to sync my contacts to Fastmail. Installing DAVDroid worked fine. Syncing from Fastmail to the phone worked fine. Creating a "Testing" contact on the phone and syncing to Fastmail worked. Then I copied all my Google contacts into the Fastmail group (on the phone). DAVDroid then crashes because it gets a 403 response.

    D/HttpClient(29355): Secure session established
    D/HttpClient(29355):  negotiated protocol: TLSv1.2
    D/HttpClient(29355):  negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
    D/HttpClient(29355):  peer principal: CN=*.messagingengine.com, O=FastMail Pty Ltd, L=Melbourne, ST=Victoria, C=AU
    D/HttpClient(29355):  peer alternative names: [*.messagingengine.com, messagingengine.com, mail.messagingengine.com, dav.messagingengine.com, caldav.messagingengine.com, carddav.messagingengine.com]
    D/HttpClient(29355):  issuer principal: CN=DigiCert SHA2 High Assurance Server CA, OU=www.digicert.com, O=DigiCert Inc, C=US
    D/HttpClient(29355): Connection established 192.168.1.230:40466<->66.111.4.58:443
    D/HttpClient(29355): Executing request PROPFIND /dav/addressbooks/user/user@fastmail.fm/Default/ HTTP/1.1
    D/HttpClient(29355): Target auth state: CHALLENGED
    D/HttpClient(29355): Proxy auth state: UNCHALLENGED
    D/Wire    (29355): http-outgoing-1 >> "PROPFIND /dav/addressbooks/user/user@fastmail.fm/Default/ HTTP/1.1[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Content-Type: text/xml; charset=UTF-8[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Accept: text/xml[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Depth: 0[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Content-Length: 299[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Host: carddav-d49.messagingengine.com[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Connection: Keep-Alive[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "User-Agent: DAVdroid/0.8.4[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Authorization: Basic somethingsomething[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "<propfind xmlns="DAV:">[\n]"
    D/Wire    (29355): http-outgoing-1 >> "   <prop>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "      <A:calendar-color xmlns:A="http://apple.com/ns/ical/"/>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "      <displayname/>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "      <CS:getctag xmlns:CS="http://calendarserver.org/ns/"/>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "      <resourcetype/>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "      <CD:supported-address-data xmlns:CD="urn:ietf:params:xml:ns:carddav"/>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "   </prop>[\n]"
    D/Wire    (29355): http-outgoing-1 >> "</propfind>"
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    D/Wire    (29355): http-outgoing-1 << "HTTP/1.1 207 Multi-Status[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Server: nginx[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Date: Fri, 28 Aug 2015 16:34:41 GMT[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Content-Type: application/xml; charset=utf-8[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Content-Length: 879[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Connection: keep-alive[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Vary: Accept-Encoding, Brief, Prefer[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "<?xml version="1.0" encoding="utf-8"?>[\n]"
    D/Wire    (29355): http-outgoing-1 << "<multistatus xmlns="DAV:" xmlns:A="http://apple.com/ns/ical/" xmlns:CS="http://calendarserver.org/ns/" xmlns:CD="urn:ietf:params:xml:ns:carddav">[\n]"
    D/Wire    (29355): http-outgoing-1 << "  <response>[\n]"
    D/Wire    (29355): http-outgoing-1 << "    <href>/dav/addressbooks/user/user@fastmail.fm/Default/</href>[\n]"
    D/Wire    (29355): http-outgoing-1 << "    <propstat>[\n]"
    /Wire    (29355): http-outgoing-1 << "      <prop>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        <displayname><![CDATA[Default]]></displayname>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        <CS:getctag>data:,1419071798-65529</CS:getctag>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        <resourcetype>[\n]"
    D/Wire    (29355): http-outgoing-1 << "          <collection/>[\n]"
    D/Wire    (29355): http-outgoing-1 << "          <CD:addressbook/>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        </resourcetype>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        <CD:supported-address-data>[\n]"
    D/Wire    (29355): http-outgoing-1 << "          <CD:address-data-type content-type="text/vcard" version="3.0"/>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        </CD:supported-address-data>[\n]"
    D/Wire    (29355): http-outgoing-1 << "      </prop>[\n]"
    D/Wire    (29355): http-outgoing-1 << "      <status>HTTP/1.1 200 OK</status>[\n]"
    D/Wire    (29355): http-outgoing-1 << "    </propstat>[\n]"
    D/Wire    (29355): http-outgoing-1 << "    <propstat>[\n]"
    D/Wire    (29355): http-outgoing-1 << "      <prop>[\n]"
    D/Wire    (29355): http-outgoing-1 << "        <A:calendar-color/>[\n]"
    D/Wire    (29355): http-outgoing-1 << "      </prop>[\n]"
    D/Wire    (29355): http-outgoing-1 << "      <status>HTTP/1.1 404 Not Found</status>[\n]"
    D/Wire    (29355): http-outgoing-1 << "    </propstat>[\n]"
    D/Wire    (29355): http-outgoing-1 << "  </response>[\n]"
    D/Wire    (29355): http-outgoing-1 << "</multistatus>[\n]"
    D/HttpClient(29355): Connection can be kept alive indefinitely
    D/HttpClient(29355): Authentication succeeded
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    V/davdroid.URIUtils(29355): Normalized URI /dav/addressbooks/user/user@fastmail.fm/Default/ -> /dav/addressbooks/user/user@fastmail.fm/Default/ assuming that it was an URI or path name
    D/davdroid.WebDavResource(29355): Processing multi-status element: https://carddav-d49.messagingengine.com/dav/addressbooks/user/user@fastmail.fm/Default/
    D/HttpClient(29355): Connection [id: 1][route: HttpRoute[{s}->https://carddav-d49.messagingengine.com:443]] can be kept alive indefinitely
    D/HttpClient(29355): Connection released: [id: 1][route: HttpRoute[{s}->https://carddav-d49.messagingengine.com:443]][total kept alive: 1; route allocated: 1 of 2; total allocated: 1 of 3]
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    I/davdroid.SyncManager(29355): Remotely removing 0 deleted resource(s) (if not changed)
    E/NetworkReportService(14598): ERROR: No reports from previous days.
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 17
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 5
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 17
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 5
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    E/MP-Decision( 1658): Update arg 2
    E/MP-Decision( 1658): Update arg 1
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 17
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 5
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    E/MP-Decision( 1658): Update arg 2
    E/MP-Decision( 1658): Update arg 1
    E/MP-Decision( 1658): Update arg 2
    E/MP-Decision( 1658): Update arg 1
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 17
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 5
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 33
    I/davdroid.SyncManager(29355): Uploading 301 new resource(s) (if not existing)
    W/davdroid.Contact(29355): No FN (formatted name) available to generate VCard
    W/davdroid.Contact(29355): Created potentially invalid VCard:
    W/davdroid.Contact(29355): W00: A StructuredName property is required for vCard versions 2.1 and 3.0.
    W/davdroid.Contact(29355): W01: A FormattedName property is required for vCard versions 3.0 and 4.0.
    D/HttpClient(29355): CookieSpec selected: best-match
    D/HttpClient(29355): Connection request: [route: HttpRoute[{s}->https://carddav-d49.messagingengine.com:443]][total kept alive: 1; route allocated: 1 of 2; total allocated: 1 of 3]
    D/HttpClient(29355): Connection leased: [id: 1][route: HttpRoute[{s}->https://carddav-d49.messagingengine.com:443]][total kept alive: 0; route allocated: 1 of 2; total allocated: 1 of 3]
    D/HttpClient(29355): Executing request PUT /dav/addressbooks/user/myself@fastmail.fm/Default/censored.vcf HTTP/1.1
    D/HttpClient(29355): Target auth state: SUCCESS
    D/HttpClient(29355): Proxy auth state: UNCHALLENGED
    D/Wire    (29355): http-outgoing-1 >> "PUT /dav/addressbooks/user/myself@fastmail.fm/Default/censored.vcf HTTP/1.1[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "If-None-Match: *[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Content-Type: text/vcard; charset=UTF-8[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Content-Length: 179[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Host: carddav-d49.messagingengine.com[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Connection: Keep-Alive[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "User-Agent: DAVdroid/0.8.4[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "Authorization: Basic bleepbloop==[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "BEGIN:VCARD[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "VERSION:3.0[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "UID:d9d6720e-df95-474f-960e-dfed96ae9e52[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "EMAIL;TYPE=pref:somemail@stud.ntnu.no[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "PRODID:DAVdroid/0.8.4 (ez-vcard/0.9.6)[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "REV:20150828T163455Z[\r][\n]"
    D/Wire    (29355): http-outgoing-1 >> "END:VCARD[\r][\n]"
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 17
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 5
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 32
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 32
    E/wpa_supplicant(13388): send_and_recv error 0 - cmd 50
    D/WirelessDisplayService( 1001): getDiscoveryDongleList
    D/Wire    (29355): http-outgoing-1 << "HTTP/1.1 403 Forbidden[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Server: nginx[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Date: Fri, 28 Aug 2015 16:34:56 GMT[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Content-Type: application/xml; charset=utf-8[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Content-Length: 142[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Connection: keep-alive[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Cache-Control: no-cache[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "Vary: Accept-Encoding[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "[\r][\n]"
    D/Wire    (29355): http-outgoing-1 << "<?xml version="1.0" encoding="utf-8"?>[\n]"
    D/Wire    (29355): http-outgoing-1 << "<D:error xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">[\n]"
    D/Wire    (29355): http-outgoing-1 << "  <C:valid-address-data/>[\n]"
    D/Wire    (29355): http-outgoing-1 << "</D:error>[\n]"
    D/HttpClient(29355): Connection can be kept alive indefinitely
    D/HttpClient(29355): http-outgoing-1: Shutdown connection
    D/HttpClient(29355): Connection discarded
    D/HttpClient(29355): http-outgoing-1: Close connection
    D/HttpClient(29355): Connection released: [id: 1][route: HttpRoute[{s}->https://carddav-d49.messagingengine.com:443]][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 3]
    E/davdroid.DavSyncAdapter(29355): Hard HTTP error 403
    E/davdroid.DavSyncAdapter(29355): at.bitfire.davdroid.webdav.ForbiddenException: 403 Forbidden
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.webdav.WebDavResource.checkResponse(WebDavResource.java:349)
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.webdav.WebDavResource.checkResponse(WebDavResource.java:327)
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.webdav.WebDavResource.put(WebDavResource.java:304)
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.resource.WebDavCollection.add(WebDavCollection.java:169)
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.syncadapter.SyncManager.pushNew(SyncManager.java:147)
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.syncadapter.SyncManager.synchronize(SyncManager.java:55)
    E/davdroid.DavSyncAdapter(29355):       at at.bitfire.davdroid.syncadapter.DavSyncAdapter.onPerformSync(DavSyncAdapter.java:138)
    E/davdroid.DavSyncAdapter(29355):       at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:259)
    I/davdroid.DavSyncAdapter(29355): Sync complete for com.android.contacts
    D/davdroid.DavSyncAdapter(29355): Closing httpClient
    

    I've included the part of the log that seemed relevant, let me know if you need more information.

    For all I know this could be a Fastmail problem? I also tried removing the contact that made it hang, but it still seems to try to sync the same contact.

    Phone: HTC One Mini 2
    Android 4.4.2 build 2.18.401.3 CL405590



  • Fastmail expects an address field on your contact for some reason.

    /cc @robn



  • I'm not sure if our behaviour is correct off the top of my head. I will try to find time to look into it this weekend and will report back soon.

    /cc @brong



  • The problem is right there in the log:

    W/davdroid.Contact(29355): No FN (formatted name) available to generate VCard
    W/davdroid.Contact(29355): Created potentially invalid VCard:
    W/davdroid.Contact(29355): W00: A StructuredName property is required for vCard versions 2.1 and 3.0.
    W/davdroid.Contact(29355): W01: A FormattedName property is required for vCard versions 3.0 and 4.0.
    

    The card is missing the FN field. Along with VERSION and UID, FN is a required field in vCard 3.0. See https://tools.ietf.org/html/rfc6350#section-6.2.1.



  • The FastMail client and iOS both handle this case by setting an empty FN field. DAVDroid should probably do the same.



  • I see, though I'm not sure whether it is DavDroid that generates those broken vcards. In any case the error message of the server is a bit misleading.

    On 29 August 2015 05:19:16 CEST, Rob N notifications@github.com wrote:

    The FastMail client and iOS both handle this case by setting an empty
    FN field. DAVDroid should probably do the same.


    Reply to this email directly or view it on GitHub:
    https://github.com/bitfireAT/davdroid/issues/629#issuecomment-135934090

    --
    Sent from my phone. Please excuse my brevity.



  • Thanks; I didn't look closely at that.

    The HTTP response code looks like a bug; I'm fairly sure it should be 412 (Precondition Failed). I'll check this with our backend engineers.

    Considering the response body:

    <D:error xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
      <C:valid-address-data/>
    </D:error>
    

    This is unambiguous per RFC 6352 section 6.3.2.1.

    (CARDDAV:valid-address-data): The resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST be valid data for the media type being specified (i.e., MUST contain valid vCard data).

    A vCard that does not have an FN field is not a valid vCard.



  • I see, I thought valid-address-data referred exclusively to ADR fields.

    On Sat, Aug 29, 2015 at 06:56:21AM -0700, Rob N wrote:

    Thanks; I didn't look closely at that.

    The HTTP response code looks like a bug; I'm fairly sure it should be 412 (Precondition Failed). I'll check this with our backend engineers.

    Considering the response body:

    <D:error xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
      <C:valid-address-data/>
    </D:error>
    

    This is unambiguous per RFC 6352 section 6.3.2.1.

    (CARDDAV:valid-address-data): The resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST be valid data for the media type being specified (i.e., MUST contain valid vCard data).

    A vCard that does not have an FN field is not a valid vCard.


    Reply to this email directly or view it on GitHub:
    https://github.com/bitfireAT/davdroid/issues/629#issuecomment-135988620


Log in to reply
 

Looks like your connection to Bitfire App Forums was lost, please wait while we try to reconnect.