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

lein deps fails when Maven repo server responds with 204 #2093

Closed
camdez opened this issue Feb 17, 2016 · 22 comments
Closed

lein deps fails when Maven repo server responds with 204 #2093

camdez opened this issue Feb 17, 2016 · 22 comments

Comments

@camdez
Copy link

camdez commented Feb 17, 2016

Apologies because I haven't yet found a trivial way to reproduce this, but I ran into this issue when installing dependencies on CircleCI when using Datomic—which, notably, is installed from its own repo requiring authentication, not from a public package repository.

Dependency installation on a fresh server works fine, but when the .m2 directory is preserved from a previous test run, this issue occurs:

$ lein with-profile test deps
Retrieving com/google/guava/guava/13.0.1/guava-13.0.1.jar from central
Could not transfer artifact com.datomic:datomic-pro:pom:0.9.5344 from/to my.datomic.com (https://my.datomic.com/repo): Failed to transfer file: https://my.datomic.com/repo/com/datomic/datomic-pro/0.9.5344/datomic-pro-0.9.5344.pom. Return code is: 204, ReasonPhrase: No Content.
This could be due to a typo in :dependencies or network issues.
If you are behind a proxy, try setting the 'http_proxy' environment variable.
Error encountered performing task 'deps' with profile(s): 'test'

lein with-profile test deps returned exit code 1

(peterromfeld also appears to be discussing the same error in this Slack conversation under slightly different circumstances.)

It appears that Leiningen is issuing a HEAD request and the repo is responding with a 204 No Content, which Leiningen should likely be treating as a success response, but instead it is handled as an error (I imagine it's just looking for 200s). I confirmed that HEAD requests are in fact handled this way by issuing a request with curl:

$ curl -I --user REDACTED:REDACTED https://my.datomic.com/repo/com/datomic/datomic-pro/0.9.5344/datomic-pro-0.9.5344.zip
HTTP/1.1 204 No Content
Accept-Ranges: bytes
Content-Type: application/zip
Date: Wed, 17 Feb 2016 13:14:33 GMT
Server: Apache-Coyote/1.1
Set-Cookie: my-datomic=REDACTED
Connection: keep-alive

The issue appears to be the same as this one in Apache Ivy.

The easiest workaround is to delete the Datomic JAR (rm -rf ~/.m2/repository/com/datomic/datomic-pro/0.9.5344/), causing it to be refetched without issue.

I'm happy to work on this issue but it's not clear to me where this request logic lives. Perhaps someone could point me in the right direction? Thanks.

@hypirion
Copy link
Collaborator

Hi, thanks for the report!

I did some digging around, and found out that this is an issue with the maven-wagon repository. I've added WAGON-451 to track it.

Since this requires a bit of internal knowledge on aether/maven-wagon, I decided to create the patch apache/maven-wagon#23, which should resolve this issue. I hope that's not a big problem?

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@hypirion Wow, impressive turnaround time. 😄 I'm a bit unsure how to test this since it's in a dependency, but it looks sensible.

@michael-o
Copy link

I am about to close the Wagon issue and the PR because the server in question violates the RFC for HEAD. Fix your servers.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@michael-o Unfortunately it's not my server, or else I would. I understand your position, but a more useful response might be to cite the RFC in question.

@michael-o
Copy link

Pardon me, here is the quote from RFC 7231:

4.3.2. HEAD

The HEAD method is identical to GET except that the server MUST NOT
send a message body in the response (i.e., the response terminates at
the end of the header section). The server SHOULD send the same
header fields in response to a HEAD request as it would have sent if
the request had been a GET, except that the payload header fields
(Section 3.3) MAY be omitted. This method can be used for obtaining
metadata about the selected representation without transferring the
representation data and is often used for testing hypertext links for
validity, accessibility, and recent modification.

I thnk this is pretty obvious. Have you contacted the server admin?

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@michael-o Not yet. What about this response is out of compliance with the RFC?

@michael-o
Copy link

@camdez Can you rephrase the question? I am not certain I understand the way you intend it to be understood.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@michael-o I just saw your comments on the wagon issue so you can disregard my previous question.

By the way, I think we had a miscommunication earlier because it looks like you left out a word: "violates the RFC for. Fix...". I wouldn't have asked you to cite an RFC if I had known you were just taking about HTTP.

@michael-o
Copy link

@camdez Sorry for that. You are right. I have updated my comment. Hopefully it is clear now. For the record: I refuse to fix WAGON-451 and pull the PR because the behaviour of the repo server is question violates RFC 7231, section 4.3.2.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@michael-o Thank you for the clarification. I'm still unclear on your reading of the spec. What do you feel is in violation? I assume you feel a HEAD request should never return a 204, but what leads you to that conclusion? The first sentence?

@hypirion
Copy link
Collaborator

@camdez: From what I can read from the specification, I assume this is the part:

The server SHOULD send the same header fields in response to a HEAD request as it would have sent if the request had been a GET, except that the payload header fields (Section 3.3) MAY be omitted.

Sending the status code 204 implies the GET request would return 204 as well.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@hypirion "The server SHOULD send the same header fields" (not necessarily status code).

Considering that Response Status Codes (6) and Response Header Fields (7) are separate top-level sections of the RFC, it seems odd to me to assume the status code is considered a header field without some other reason to do so. Wouldn't you agree? Is there some other reason?

@hypirion
Copy link
Collaborator

@camdez Oh, you're right, I thought the status code was considered a header field.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@hypirion Thanks for reconsidering.

To be clear, I completely support @michael-o's approach of strictly following the spec. I'm certainly NOT asking that the library be relaxed to handle non-compliant servers. But I think we need to read the spec carefully.

@michael-o
Copy link

@camdez I expect HEAD to return the very same status code as GET would. Altering it is a bug. Headers are a different story not discussed here. Any status code is fine as long it is served for both request methods equally.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@michael-o I actually think that is sensible, but is it a requirement of the spec? (If so, where do you find that?)

Alternately, we can approach it this way: you say "[a]ny status code is fine as long it is served for both request methods equally"—as a thought experiment, let's pretend GET https://my.datomic.com/repo/com/datomic/datomic-pro/0.9.5344/datomic-pro-0.9.5344.pom returns 204. Then that means that returning a 204 on a HEAD request is also possible.

It's possible that you may also feel a 204 is never a valid response to a GET request, but in that case I'd point you towards this passage on page 14 of RFC 7231:

If the request method is GET or HEAD and the response status code is 200 (OK), 204 (No Content), 206 (Partial Content), or 304 (Not Modified), the payload is a representation of the resource identified by the effective request URI (Section 5.5 of [RFC7230]).

Clearly at least one of GET or HEAD is allowed to return a 204. If it's GET, then HEAD can also return 204 by your logic. If it's HEAD then there's no dispute.

@michael-o
Copy link

@camdez I never said that 204 is not valid. The last statement properly rephrases my understanding of the issue. If GET returns 204 then HEAD must also return 204. Same applies for 200 => 200 and so on. Every status code from 100 to 599 is valid as long as both return the same. Personally use 204 in a REST service where 204 indicates that the resource exists but the way the request has been issued, the response is empty.

@camdez
Copy link
Author

camdez commented Feb 18, 2016

@michael-o Ok. The client is issuing a HEAD request; the server is responding with 204, which you state is a valid response. Surely this contradicts your original statement that "the server in question violates the RFC for HEAD". (The server may well return a 204 for GET, right?)

(I do understand that actually issuing / receiving that GET response would be problematic from an application level, but I suspect we can agree at this point that the HTTP spec has not been violated by our presumption of what a future request would return.)

So then the question becomes: "should the application choose to fail after the server returns a(n RFC-compliant) 204 response to a HEAD request in anticipation of a similar GET request returning a(n unusable) 204, in conformance with a particular reading of said RFC?" I'm not sure I see the case. Let it fail if / when the server does return a GET / 204.

GitHub used to return 204s to resources that would 200. The Java EE 6 Pocket Guide suggests the practice is reasonable. These are by no means infallible sources, but I wonder if they suggest it's not an altogether unreasonable reading of the spec to think that a HEAD / 204 might be a representation of a resource that would 200 on a GET. I don't see why the library should be hyper-vigilant in enforcing what we feel is the most reasonable interpretation of the spec when other readings are compliant + match the behavior of real servers (in this case another Apache project, BTW—Coyote).

@michael-o
Copy link

@camdez Please stop overinterpreting my statements. Again, 204 is a valid response as long as a GET would issue a 204 too. You are citing Coyote code from Tomcat 4.x, seriously? If I would issue a HEAD to a resource and would receive a 204, I would never reissue a GET because I know the content is empty. That is a false conclusion. A 200 is a must in this case. Plain simple.

@camdez
Copy link
Author

camdez commented Feb 19, 2016

@michael-o I'm sorry you feel I'm over-interpreting you statements, it's not my intention. But it looks like you're repeating exactly what I said above so I'm not sure how it's a mischaracterization:

So then the question becomes: "should the application choose to fail after the server returns a(n RFC-compliant) 204 response to a HEAD request in anticipation of a similar GET request returning a(n unusable) 204, in conformance with a particular reading of said RFC?"

RE:

You are citing Coyote code from Tomcat 4.x, seriously?

I'm not citing Coyote as a miracle of modern computing, I'm citing it because it's literally what the server is.

I'm growing tired of this and I'm not going to belabor it because this is not my hill to die on; I just wanted to save others developers some trouble.

Just bear in mind that you're choosing to throw away a perfectly usable response which yielded the exact dependency information you requested because you're anticipating (what you interpret to be) a non-compliant HTTP response to a request you're never going to make. Despite the fact that there are clearly other interpretations, and that this dogmatism breaks interactions with existing software.

If that's the stance of the project then there's nothing to discuss.

@michael-o
Copy link

@camdez

So then the question becomes: "should the application choose to fail after the server returns a(n RFC-compliant) 204 response to a HEAD request in anticipation of a similar GET request returning a(n unusable) 204, in conformance with a particular reading of said RFC?"

This exactly describes what I would expect from the application.

@technomancy
Copy link
Owner

Closing this since fixing it from within Leiningen isn't feasible and it seems to be a problem with the remote server.

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

No branches or pull requests

4 participants