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

GET w/ bad Accept header now returns proper error #966

Closed
wants to merge 7 commits into from

Conversation

bseeger
Copy link
Contributor

@bseeger bseeger commented Dec 22, 2015

  • When an invalid or unsupported format type was requested the wrong
    HTTP error code was returned. Now it returns the correct one.

Resolves: https://jira.duraspace.org/browse/FCREPO-1840

final HttpGet get = new HttpGet(serverAddress + id);
get.addHeader("Accept", "application/turtle");

try (final CloseableHttpResponse response = execute(get)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a getStatus method in the superclass that does the closing for you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an example of what @ajs6f is suggesting: http://git.io/vEcjc

bseeger added 3 commits January 28, 2016 16:30
- When an invalid or unsupported format type was requested the wrong
HTTP error code was returned.  Now it returns the correct one.

Resolves: https://jira.duraspace.org/browse/FCREPO-1840
public Response describe(@HeaderParam("Range") final String rangeValue) throws IOException {
checkCacheControlHeaders(request, servletResponse, resource(), session);

LOGGER.info("GET resource '{}'", externalPath);

final ImmutableList<MediaType> acceptableMediaTypes =
new ImmutableList.Builder<MediaType>().addAll(headers.getAcceptableMediaTypes()).build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the static factory method ImmutableList.builder(), and acceptableMediaTypes can just be typed List<MediaType>. Actually, do you really need to copy the value of getAcceptableMediaTypes() over at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't think so, but I was trying to prevent a few function calls to access that list. I could just call headers.getAcceptableMediaTypes() whenever I need the list, or just use a

final List<MediaType> acceptableMediaTypes = headers.getAcceptableMediaTypes();

Which way is preferred in Java?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the result of getAcceptableMediaTypes() isn't likely to change in the course of this method, I think final List<MediaType> acceptableMediaTypes = headers.getAcceptableMediaTypes(); is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the record, function calls in Java are incredibly cheap (JIT). Creating short-lived objects is what you really want to avoid.

@@ -67,10 +67,11 @@

public static final List<Variant> POSSIBLE_RDF_VARIANTS = mediaTypes(
RDF_XML_TYPE, TURTLE_TYPE, N3_TYPE, N3_ALT2_TYPE, NTRIPLES_TYPE, APPLICATION_XML_TYPE,
TEXT_PLAIN_TYPE, TURTLE_X_TYPE, JSON_LD_TYPE).add().build();
TEXT_PLAIN_TYPE, TURTLE_X_TYPE, JSON_LD_TYPE, TEXT_HTML_TYPE, APPLICATION_XHTML_XML_TYPE).add().build();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have serious concerns about introducing arguably incorrect RDF variants: html and xhtml.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By what means could Fedora possibly be producing HTML RDF output? Are you thinking about the HTML "admin" presentation?

@bseeger
Copy link
Contributor Author

bseeger commented Feb 12, 2016

Reverted back to simpler mime-type checking. Changed the method name from describe(...) to getResource(...). Let me know what you think.

@awoods
Copy link

awoods commented Feb 12, 2016

Thanks, @bseeger.
First question, does the PR resolve the issue described in the ticket?
Second question, does the PR introduce unexpected side effects?

@bseeger
Copy link
Contributor Author

bseeger commented Feb 12, 2016

First question: Yes! it now returns a 406 if someone requests an invalid mime-type on a RdfResource
Legitimate request: $>curl -XGET -i -H"Accept: text/turtle" http://localhost:8080/fcrepo/rest/pizza/ HTTP/1.1 200 OK
Bad Request: $>curl -XGET -i -H"Accept: application/turtle" http://localhost:8080/fcrepo/rest/pizza/ HTTP/1.1 406 Not Acceptable

Second question: Yes! You can't specify the mime-type for a binary, you'll get a 406 every time you do - even if you pick the correct mime-type. And... and... I'm not sure what to do with this. I can put the */* back in the @produces line and do mime-type checking only on binary resources, but then the original bug exists again, unless I do mime-type checking on everything (skipping JAX-RS) and then we go in circles. ;)

@awoods
Copy link

awoods commented Feb 12, 2016

Thanks again, @bseeger. Your summary is helpful for expectation-setting.
We don't do conneg on binaries... so it is not completely insane to respond with a 406 when it is attempted.
I have put your ticket back into "Review".

@ajs6f
Copy link
Contributor

ajs6f commented Feb 12, 2016

No, it's not insane and it may be as good as we can do. But it is weird. Are we saying that if I stick in a binary, then request it with the correct mimetype, I will still get an error?

@bseeger
Copy link
Contributor Author

bseeger commented Feb 12, 2016

Yes, you will get a 406. It is weird, though unless we list all the relevant mime-types for binaries in the @produces line, we would need to do our own mime-type checking further down (or fix the larger issue of both Rdf and Non-Rdf resources being fetched via the same method).

@ajs6f
Copy link
Contributor

ajs6f commented Feb 12, 2016

Well, we definitely can't list all the relevant mimetypes, because we don't know them! :)

@awoods
Copy link

awoods commented Feb 14, 2016

After testing this updated PR, I will add one point of clarification to the comments above:

  • If you GET a binary resource with an Accept header from this list, the binary is downloaded correctly, with the real content-type, not the Accept content-type.
    I think this is better than the current behavior of returning a 500, but not ideal.

I would suggest adding to the current PR a simple check in "ContentExposingResource.getContent()" before line:194 for a match of the Accept header (if it exists) and either the real contentTypeString or mediaType, which ever works better. If the Accept header exists and matches, great; if not, then 406.
Reasonable?

@bseeger
Copy link
Contributor Author

bseeger commented Feb 15, 2016

With the PR the way it currently is, a GET request for a Binary with an Accept header would never get that far - because the */* has been taken out of the @Produces line. If I put that back in, then the original bug is unresolved unless I go back to mime-type checking everything outside of JaxRS.

I realize this is outside the scope of the bug, but how crazy would it be to reverse the semantics for getting a binary and it's associated metadata. Ie, take out the /fcr:metadata/ and always return metadata unless they tack on a /fcr:binary/ on the end.

Meaning, if /blahbinary/ is a binary, then:
curl -XGET -v -i -H"Accept: text/plain" http://localhost:8080/fcrepo/rest/blahbinary/
Returns the metadata for that binary.
And:
curl -XGET -v -i -H"Accept: text/plain" http://localhost:8080/fcrepo/rest/blahbinary/fcr:binary
Actually gets the binary. Then we could split the GET into two functions (one for metadata, one for binaries) and clean up the api.

... I have no clue how what I'm suggesting would impact current users. Might be an absolutely terrible idea.

@ajs6f
Copy link
Contributor

ajs6f commented Feb 15, 2016

That's what we used to do, except it was fcr:content, not fcr:binary. I can't remember why we changed. @barmintor, wasn't that your idea?

@awoods
Copy link

awoods commented Feb 15, 2016

@bseeger, When a GET request for a binary resource is made with an Accept header of something like text/turtle, it goes through successfully. With that in mind, please re-read: #966 (comment)

p.s. I do not think revisiting the /fcr:metadata question is on the table in the context of this PR.

@bseeger
Copy link
Contributor Author

bseeger commented Feb 15, 2016

Thanks for the clarification, @awoods. I see the distinction now. Yes, I'm all for adding that mime-type checking before line:194 as described above. I can add that today.

@barmintor
Copy link
Contributor

@ajs6f @bseeger it wasn't my idea, but I can point you to a couple of relevant posts:

a2b9358#commitcomment-7650435

https://groups.google.com/forum/#!searchin/fedora-tech/beta$20release$20notes/fedora-tech/mADFnf_1G30/i4XzmLIiq4kJ

IIRC: Our experience back in the early beta was that this issue set you chasing your own tail about various bad implementation experiences as a consequence of JAXRS & JCR, but that this approach minimized the weirdness required of the client to know about where & what to POST or DELETE to manage LDP-NRs.

@cbeer
Copy link
Contributor

cbeer commented Feb 15, 2016

POST, DELETE, and PUT are all pretty weird for the client with fcr:content:

  • PUT for an LDP-NR ought to create the resource at the location given in the request. Requiring fcr:content either requires client knowledge about interacting fcrepo4, or some awkward hand-waving about when you're updating content or metadata.
  • DELETE for an LDP-NR cascades to the LDP-RS describing it, and having a delete request for a resource also delete its "parent" is not intuitive

@ajs6f
Copy link
Contributor

ajs6f commented Feb 15, 2016

Now I wish we had taken the high road and refused to use any magic URLs. When people create bitstreams, we could have returned the URI of the description in a header. We could have done the work of decoupling hierarchy and lifecycle. We would have been much better off in the long run.

@barmintor
Copy link
Contributor

But we do this! When you create a bitstream, the URI of the description is
in a Link@rel="describedBy" header! This is a LDP-ism.

On Mon, Feb 15, 2016 at 10:47 AM, A. Soroka notifications@github.com
wrote:

Now I wish we had taken the high road and refused to use any magic URLs.
When people create bitstreams, we could have returned the URI of the
description in a header. We could have done the work of decoupling
hierarchy and lifecycle. We would have been much better off in the long run.


Reply to this email directly or view it on GitHub
#966 (comment).

@awoods
Copy link

awoods commented Feb 15, 2016

May I suggest creating a GitHub issue for the fcr:metadata discussion. It is out of scope for the work that @bseeger is doing here.

@ajs6f
Copy link
Contributor

ajs6f commented Feb 15, 2016

Then why do we need fcr:metadata at all?

@bseeger
Copy link
Contributor Author

bseeger commented Feb 18, 2016

The latest commit fixes the loophole where asking for a binary with Accept header containing a mime-type listed in the @produces line, but not the binary's actual mime-type, returned the resource. Now, if the mime-type of the binary does not match a mime-type requested in the Accept field, a 406 will be returned instead.

I had to introduce this change in the FedoraLdp.java file before the getContent() call because it seems you have to have the header info complete before the response builder (in getContent()) calls build(). I'm open to moving things around, this just seemed the cleanest of all the options I thought about and tried.

@awoods
Copy link

awoods commented Feb 18, 2016

@bseeger, please put the JIRA ticket back into "Review" if you are ready.

@awoods
Copy link

awoods commented Feb 22, 2016

Resolved with: 825d26f

@awoods awoods closed this Feb 22, 2016
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

Successfully merging this pull request may close these issues.

None yet

6 participants