Egnyte wrote:
What do you mean by "you are going to have to go deeper than that" ?
Would it be possible for you to pm me a test account on your server ? I can then test my Mavericks against your server to see if this issue shows up.
I just mean that something like this requires additional supporting evidence. I was looking for the HTTP headers, which you provided.
My server is inside an application. Hopefully it will get approved and be in the Mac App Store any day now. Unfortunately, I have heavily dependent on the Finder working correctly on the reviewer's machine. As you know, such things are not guaranteed. Send me an e-mail and I will give you either a promo code or a test iTunes account, depending on my luck in the next 48 hours. You can crank your LogLevel to 9 and fill your console.app log - no Wireshark required.
However, you may need to go quite deep with this one. I looked at the webdav client code for Mavericks, and I just don't see any way for it to not include the Lock-Token. This is the only place UNLOCK is ever sent from. The C++ style comments are from me.
int network_unlock_with_nodecache_locked(
struct node_entry *node) /* -> node to unlock on server */
{
int error;
CFURLRef urlRef;
CFStringRef lockTokenRef;
char* locktokentofree = NULL;
uid_t file_locktoken_uid = 0;
/* the 2 headers */
CFIndex headerCount = 2;
struct HeaderFieldValue headers[] = {
{ CFSTR("Accept"), CFSTR("*/*") },
// Apple seems to think this is required.
{ CFSTR("Lock-Token"), NULL },
{ CFSTR("translate"), CFSTR("f") }
};
if (gServerIdent & WEBDAV_MICROSOFT_IIS_SERVER) {
/* translate flag only for Microsoft IIS Server */
headerCount += 1;
}
locktokentofree = node->file_locktoken;
node->file_locktoken = NULL;
file_locktoken_uid = node->file_locktoken_uid;
node->file_locktoken_uid = 0;
/*unlocking the node cache before calling send_transaction()*/
unlock_node_cache();
/* create a CFURL to the node */
urlRef = create_cfurl_from_node(node, NULL, 0);
require_action_quiet(urlRef != NULL, create_cfurl_from_node, error = EIO);
// Code obviously copy and pasted from network_delete() function.
/* in the unlikely event that this fails, the DELETE will fail */
// Event if locktokentofree is null or empty, lockTokenRef should still have a
// non-null value.
lockTokenRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<%s>"), locktokentofree);
// Don't even send the message if lockTokenRef is null.
require_action_quiet(lockTokenRef != NULL, CFStringCreateWithFormat, error = EIO);
// Lock-Token gets a value here. Is there some value that will make
// CFHTTPMessageSetHeaderFieldValue drop the header entirely in send_transaction()?
headers[1].value = lockTokenRef;
/* send request to the server and get the response */
/* Note: we use the credentials of the user than obtained the LOCK */
error = send_transaction(file_locktoken_uid, urlRef, NULL, CFSTR("UNLOCK"), NULL,
headerCount, headers, REDIRECT_DISABLE, NULL, NULL, NULL);
CFRelease(lockTokenRef);
CFStringCreateWithFormat:
CFRelease(urlRef);
create_cfurl_from_node:
free(locktokentofree);
locktokentofree = NULL;
/*Locking the node cache as the function returns a locked node*/
lock_node_cache();
return ( error );
}
The only real difference between the Mavericks code and the Mountain Lion version is that Mavericks has better thread safety. Mavericks pulls values from the node and sets the final node values right away, sending the old values over the wire. If send_transaction() fails or hangs, then the node is still unlocked and other routines can access the node.
I think you should look at all of your messages and find where the Lock-Token no longer gets included. Still, I don't see how it is even possible. If there is some header value you can provide such that CFHTTPMessageSetHeaderFieldValue does not create the header, then that would be your bug. It seems to handle null just fine and would emit "<>" on an empty string, which would still be a valid header.