Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call to undefined method getETag() #659

Closed
jurgenhaas opened this issue May 20, 2015 · 25 comments
Closed

Call to undefined method getETag() #659

jurgenhaas opened this issue May 20, 2015 · 25 comments
Assignees
Labels
Milestone

Comments

@jurgenhaas
Copy link

I know this has been reported and "fixed" in #428 but I found another occurance in the 2.x branch. In Sabre\DAV\Server.php line 1347 there is $etag = $node->getETag(); and in my case the $node is an instance of SimpleCollection which doesn't implement that method.

Should the Method getETag be implemented in Node and by default return NULL?

@Hywan Hywan added the bug label May 20, 2015
@Hywan
Copy link
Member

Hywan commented May 20, 2015

getETag is required by the IFile interface, so for files, not directories. https://github.com/fruux/sabre-dav/blob/2.1/lib/DAV/Server.php#L1347 must be protected by an instanceof IFile at least. /cc @evert

@evert
Copy link
Member

evert commented May 21, 2015

I agree with @Hywan that checking the correct instance is the correct solution.

@evert
Copy link
Member

evert commented May 21, 2015

Can you tell us how you triggered this @jurgenhaas , as far as I can tell this only happens in buggy clients. If that's the case it's not really a critical issue (but still worth fixing).

@evert evert self-assigned this May 21, 2015
@evert evert added this to the 3.0 milestone May 21, 2015
@jurgenhaas
Copy link
Author

I'm currently implementing SabreDAV into Drupal (http://drupal.org) and I have an endpoint /sabredav in Drupal's menu router and each enabled submodule (one for cards and one for calendars) implements additional endpoints like /sabredav/addressbooks and /sabredav/calendars. Now, when calling http://www.example.com/sabredav I should be getting the directory that shows addressbooks and calendars as available childs. This is working fine when that line is commented out but it fails if enabled. This is because the $node in that context is a SimpleCollection (implementing Directory and not File) and that class doesn't come with a getETag method.

@evert
Copy link
Member

evert commented May 21, 2015

Yes but as far as I can tell this would only be triggered in a case where a client sends an If-Match header (or If-None-Match, which has the same problem) along with a request that never defined an ETag header in the first place.

Without the (broken) If-Match / If-None-Match header, the bug would not occur.

@jurgenhaas
Copy link
Author

I don't get it. My client is a web browser and I'm calling a page where I get the BrowserPlugin class to deliver the root directory. And that directory never has an ETag, so it shouldn't be called.

@evert
Copy link
Member

evert commented May 21, 2015

So why is your browser sending If-Match, is there something in drupal that automatically generates etags?

@evert
Copy link
Member

evert commented May 21, 2015

Actually it's probably If-None-Match in that case.

@jurgenhaas
Copy link
Author

That's what I'm not getting: what do you mean by "sending If-Match", I'm not doing anything like that.

@evert
Copy link
Member

evert commented May 21, 2015

The error can only be thrown if the browser sends an If-None-Match header. The browser will only send this header if it knows about an etag that the server sent. sabredav does not send etags for collections, thus there is something else that generated an etag.

@jurgenhaas
Copy link
Author

OK, as far as I can tell, Drupal is never setting those headers. However, I can confirm that incoming HTTP requests are having that header set if one of the directories is called the second or subsequent times. When I unset that header before initializing the SabreDAV library then I no longer get the error.

Is that Apache that sets that header maybe?

@evert
Copy link
Member

evert commented May 21, 2015

It's possible but it would be a very weird and undesirable setting. What is the content of the header? Can you find out when the browser first receives it?

@jurgenhaas
Copy link
Author

When receiving a request that contains that header then these are the header values:

AUTHORIZATION: Basic .....
HOST: localhost
USER_AGENT: "Mozilla..."
ACCEPT: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
ACCEPT_LANGAUGE: de,en-US;q=0.7,en;q=0.3
ACCEPT_ENCODING: gzip, deflate
CONNECTION: keep-alive
IF_MODIFED_SINCE: Thu, 21 May 2015 13:31:46 GMT
IF_NONE_MATCH: "1432215106-gzip"
CACHE_CONTROL: max-age=0

@evert
Copy link
Member

evert commented May 21, 2015

Interesting =) Do you have some kind of gzip module in your webserver? Try turning it off and wipe your browser cache.

@jurgenhaas
Copy link
Author

Should be good for now. I'm not sure where the headers are coming from but the current approach to unset that header in the specific context is working and I need to get something delivered to my client, so I need to get back to that before I can offer more help in debugging this.

@Hywan
Copy link
Member

Hywan commented May 21, 2015

@jurgenhaas I suggest you to not delete the header while it fixes your issue. This is an important one :-p.

@jurgenhaas
Copy link
Author

@Hywan you mean not to delete the "whole" header? I'm currently only deleting the IF_NONE_MATCH and leave all the other untouched. And this only happens for the sabredav endpoint, not for all the other paths on that same server.

Or am I misunderstanding your suggestion?

@Hywan
Copy link
Member

Hywan commented May 22, 2015

@jurgenhaas I meant: If-None-Match is also very useful for sabre/dav, so we better might understand how this error happen instead of using such a fix that can be “dangerous” in a short time.

@jurgenhaas
Copy link
Author

@Hywan thanks for your clarification. I've looked into the communication a bit deeper and here is what I found:

Drupal, by default responds to HTTP request with an etag in the header which is set to the current timestamp. The client (i.e. the browser) receives the etag with an appended "-gzip" and I'm uncertain where that is coming from but ignore that for now.

The client is then using the etag-value from the previous request as the "If-None-Match" header value for the subsequent request which is what I'm seeing in Drupal as described above.

So, it sounds like I need to avoid that Drupal is adding that etag header for its responses. Is that correct? And if so, under which circumstances should that be removed and when is it important to be imcluded?

@evert
Copy link
Member

evert commented May 25, 2015

I would simply suggest to ensure that drupal never does this.

The problem is that both drupal and sabredav may generate and validate etags. If drupal acts as the 'proxy' in front of sabredav, it should fully handle its own etags and not pass them on, while also internally managing the etags coming in and out of sabredav. This is much more sophisticated than drupal's currently functionality, so it's best to disable this altogether.

The problem with just removing the header, is that you effectively turn off conflict detection, so multiple clients may overwrite resources.

evert added a commit that referenced this issue May 25, 2015
evert added a commit that referenced this issue May 25, 2015
@evert evert closed this as completed in c806966 May 25, 2015
@evert
Copy link
Member

evert commented May 25, 2015

This is now fixed in master. If you ran master you would no longer see this error, but please keep in mind that there's more subtle, hidden errors that are not immediately prevalent, but will cause loss of data. The commits only fix the error, not your root cause. The only way to fix that, is to fix drupal.

@jurgenhaas
Copy link
Author

Thanks @evert for fixing this and also for clarifying the background to me. I don't think there really is an issue with the Drupal implementation as Drupal won't be involved with the client communication when it comes down to updating and syncing cards. Drupal is only delivering html pages to browsers that are reading the tree and that's where Drupal includes the etag in the header. But that's not the case when talking to a WebDAV client.

@evert
Copy link
Member

evert commented May 27, 2015

I think that's incorrect. WebDAV clients still use etags, and still use plain HTTP. There's no reason to believe Drupal doesn't do the exact same there, but I did all I could! Good luck.

@jurgenhaas
Copy link
Author

Yes they do, but my Drupal implementation routes them to different parts in the code where Drupal's delivery mechanism is bypassed and therefore it won't ever set the header as in the issue handled here.

@evert
Copy link
Member

evert commented May 27, 2015

Ah ok, good to hear

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants