-
Notifications
You must be signed in to change notification settings - Fork 265
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
ISSUE: 501. CORS Support. #3032
Conversation
Tests added ISSUE: 501. CORS Support. cnr fix
About @jmcanterafonseca 's comment
about the line below:
I did what was suggested but then, storing these values in an array then looping over it to form this string again felt a bit of an overkill. Should we instead have a string constant for each HTTP header and them create a constant string concatenating them in What is the standard way of handling this kind of issues in the context of Orion? I will do another commit for this after your feedback. |
@@ -40,6 +40,42 @@ orionCurl --url /v2/entities -X OPTIONS | |||
echo | |||
echo | |||
|
|||
echo "03. Allowed headers: GET DELETE OPTIONS" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I undertand, https://github.com/telefonicaid/fiware-orion/pull/3032/files#diff-c7a50c3b97af231671cfad8674374d21R844 is adding 10 new routes (i.e. 10 new URLs supporting OPTIONS).
However, only 6 new URL/steps have been included...
Maybe I'm missing something? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had discussed about this more than a few times, it is normal to get confused :)
Right now we have 12 different routes for /v2 which have 8 different verb sets.
As an example, by having optionsGetPostOnly
handler, we cover both /v2/entities
and /v2/subscriptions
. So that's why we have less handlers than the number of routes, similar to bad verb handlers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think I see now your point...
Note functional tests should be designed from usage/API perspective, not implementation perspective. I mean, I agree with you that in this particular case and with the current implementation, with just the 8 operations you include in the test you can cover the 8 methods options handlers.
However, imagine that at some point and for some unknown reason at the present moment the implementation changes (but not the API). You would need to re-think the test in order to align with the new implementation. Thus, if the test is designed with API perspective from the very beginning, you would change the implementation without changing test... which at the end is the actual purpose of functional testing ;)
Moreover, in this case the modification in the .test is pretty simple. Just adding the 4 missing cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a similar situation occurs with cors_bad_verbs.test. It would be great (and easy :) to pass from 8 to 12 URLs also in that .test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And now... I see your point :)
You are absolutely right, thanks for pointing this out. I'll fix this in the next commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh.. I just realized the name of this test file should have been allowed_methods. I will fixed that as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b9a8b2f
@@ -40,6 +40,12 @@ orionCurl --url /v2 -X OPTIONS | |||
echo | |||
echo | |||
|
|||
echo "03. Bad Verb Entry Points" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already being tested https://github.com/telefonicaid/fiware-orion/pull/3032/files#diff-a375d95dcfcfe65f4a0395db510119dbR33, isn't it?
In that case, maybe this step is redundand in this .test and could be removed...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 88eeebb
I don't remember if we have an standard way for that... however, the approach of have a string constant for each HTTP header and them create a constant string concatenating them in restReply.cpp as cors_allowed_headers sound good. However, instead of using string constants for each HTTP header maybe a I'd suggest you try something in that line a let's see how it looks like. |
@fgalan I would prefer having a separate PR for this since a new response header ( I am not sure if the new PR should belong to #3030 or #501 though, what do you think? |
@fgalan, one more question about the HTTP header definitions. I thought one of these might be suitable to hold the definitions but I am not sure which: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job!
Just a few minor things
src/lib/rest/restReply.cpp
Outdated
@@ -162,8 +162,8 @@ void restReply(ConnectionInfo* ciP, const std::string& _answer) | |||
} | |||
} | |||
|
|||
//Check if CORS is enabled | |||
if (strlen(restAllowedOrigin) > 0) | |||
//Check if CORS is enabled and the response is not bad verb response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style guide: space after //
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b9a8b2f
src/lib/rest/restReply.cpp
Outdated
//Check if CORS is enabled | ||
if (strlen(restAllowedOrigin) > 0) | ||
//Check if CORS is enabled and the response is not bad verb response | ||
if (strlen(restAllowedOrigin) > 0 && ciP->httpStatusCode != SccBadVerb) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
restAllowedOrigin ... I have a feeling this variable will never change (set at startup and then never touched again).
I don't like very much to to a strlen() over and over on a string that doesn't change ...
Perhaps invent a boolean variable?
bool originAllowed = restAllowedOrigin[0] != 0;
Or something similar (and then use originAllowed
of couirse :-)).
Easier to read and faster to execute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested names:
allowedOrigin
for the stringhasAllowedOrigin
for the bool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, this would be much better, thanks for the suggestion.
One comment about the name of the boolean variable. In the code we basically do the check (the length check as of now) to see if CORS is enabled or not. I think it would make more sense to have the variable name something like corsEnabled
. This would also make the code easier to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corsEnabled
sounds great
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corsEnabled
is fine for the bool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b9a8b2f
ciP->httpHeaderValue.push_back("GET, DELETE"); | ||
std::string headerValue = "GET, DELETE"; | ||
//OPTIONS verb is only available for V2 API | ||
if (strlen(restAllowedOrigin) > 0 && ciP->apiVersion == V2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same same, both comment and strlen(restAllowedOrigin) > 0
.
Also, the style guide proposes to use parenthesis for 'complex' conditions, so:
if ((originAllowed == true) && (ciP->apiVersion == V2)) ...
Like this, there is no way it can go wrong and it is a little bit easier to read, right?
[ The same corrections for 7 more occurrences ]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in b9a8b2f
@@ -55,11 +56,16 @@ std::string badVerbAllNotDelete | |||
OrionError oe(SccBadVerb, ERROR_DESC_BAD_VERB); | |||
|
|||
ciP->httpHeader.push_back("Allow"); | |||
ciP->httpHeaderValue.push_back("GET, PATCH, POST, PUT"); | |||
std::string headerValue = "GET, PATCH, POST, PUT"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for curiosity, is there any 'established' order for the verbs/methods ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting question... what does the CORS specification say about that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CORS specification does not provide any rules for the order of the methods and the example scenarios provided do not seem to be following any pattern.
Please see the example scneario at the end of the subsection: 7.1.5 Cross-Origin Request with Preflight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, NTC (alphabetic order seems ok to me)
I think I used an (by myself invented) "estimated use-frequency order", as: GOT. POST, PUT. PATCH ...
We should change the badVerb service routines to do alphabetic order instead . Can't go wrong ... (except perhaps for 100% backward compatibility :-( )
To be discussed, and nothing to be done in this PR. of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should change the badVerb service routines to do alphabetic order instead . Can't go wrong ... (except perhaps for 100% backward compatibility :-( )
To be discussed, and nothing to be done in this PR. of course.
Taking into account order doesn't matter from specification point of view, I don't see any value on changing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking into account order doesn't matter from specification point of view, I don't see any value on changing that.
Uniformity seems like reason enough to me (surprised to hear that you don't care :-))
If it wasn't for the possible backward compatibility I would change it, it's easy enough.
But, let's not
Yeah, that sounds good |
In @kzangeli , @fgalan I know it is not related to this PR but this might be a good opportunity to discuss if it is worth to create an issue for adding more header definitions to the list. There are many occurrences of hard-coded string values of HTTP headers in our source files and all these can be replaced by macros which can be added to HttpHeaders.h, extending the list of HTTP header definitions we have. |
src/lib/rest/rest.cpp
Outdated
@@ -1781,6 +1782,7 @@ void restInit | |||
mhdConnectionTimeout = _mhdTimeoutInSeconds; | |||
|
|||
strncpy(restAllowedOrigin, _allowedOrigin, sizeof(restAllowedOrigin)); | |||
corsEnabled = (restAllowedOrigin[0] != 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A cryptic way of checking if the char string is empty but it's ok... :)
Just to be sure... how restAllowedOrigin
array is initialized? Can we asure that first element is zero? Or it is random and could be initilizalied with random stuff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it was suggested by @kzangeli :) I think it is better than checking the length.
restAllowedOrigin
gets the value of -corsOrigin switch or if the switch is not used, initialized with empty string, ""
. For empty string, the first char will always be zero.
By the way, since we are talking about the variable, we have re-used some of the code Jose Manuel wrote for the first CORS implementation and some of the variable names that made sense back then, now got a bit confusing. Especially restAllowedOrigin. So this is the flow we have now:
- We take the
-corsOrigin
switch value and assign it toallowedOrigin
incontextBroker.cpp
- We call the restInit function, passing the value of
allowedOrigin
variable incontextBroker.cpp
- We define a global variable in
rest.cpp
calledrestAllowedOrigin
- In
restInit
function, the passed value is mapped to_allowedOrigin
in the signature and the value is re-assigned torestAllowedOrigin
.
As you see, there are a lot of name changes which makes the code hard to read and harder to maintain. I propose using the same name corsOrigin except the method signature of restInit
where we can have it as _corsOrigin
. Same goes for restCORSMaxAge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the switch is not used, initialized with empty string, ""
That's the piece of the puzzle I missed. I didn't know if the argument parsing library puts ""
in the case of missing swich or just left the holding variable with undefined content. I understand is the former.
I propose using the same name corsOrigin except the method signature of restInit where we can have it as _corsOrigin. Same goes for restCORSMaxAge.
Sounds good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is related with
{ "-corsOrigin", allowedOrigin, "ALLOWED_ORIGIN", PaString, PaOpt, _i "", PaNL, PaNL, ALLOWED_ORIGIN_DESC },
That _i ""
ensures that in the case of not using -corsOrigin
at the CLI, the value for allowedOrigin is univocally set to empty string, isn't it @kzangeli ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. So this comment (and with it the whole PR, as far as I remember) is only pending of a new commit with the refactor in the variable names, as @McMutton suggested above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in e3a6471
Makes fully sense. Issue has been created: #3035 |
No, there are no pending tasks, I plan to do the final commit today. |
I don't like LGTM. Thasnk for the work! Passing the ball to @kzangeli for final LGTM. |
LGTM |
Implements #501
Rest of the /v2 resources now support CORS. New unit and functional tests are added.