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

net/gcoap: add Uri-Query strings for requests #7402

Merged
merged 2 commits into from
Aug 8, 2017

Conversation

haukepetersen
Copy link
Contributor

@haukepetersen haukepetersen commented Jul 24, 2017

Needs kaspar030/sock#16 merged to work...

This PR adds means to gcoap for adding query strings (Uri-Query options) to any given CoAP request. The functionality is split and partly placed in nanocoap.

The usage is very simple, e.g.:

gcoap_req_init(&pkt, buf, sizeof(buf), COAP_METHOD_POST, "/some/url");
gcoap_add_qstring(&pkt, "key1", "some_value");
gcoap_add_qstring(&pkt, "bier", NULL);
gcoap_add_qstring(&pkt, "foo", "bar");
gcoap_finish(&pkt, 0, COAP_FORMAT_TEXT);

will result in:

POST: HOST.../some/url?key1=some_value&bier&foo=bar

@haukepetersen haukepetersen added Area: network Area: Networking Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Jul 24, 2017
@haukepetersen haukepetersen added this to the Release 2017.10 milestone Jul 24, 2017
@haukepetersen
Copy link
Contributor Author

added missing qs buffer initialization

@kb2ma
Copy link
Member

kb2ma commented Jul 30, 2017

Here is an idea for a somewhat lower level approach to this implementation. We assume there is no intrinsic value to gcoap in storage of the URL-encoded query string in coap_pkt_t.qs. Instead, we can save some memcpys and write the coded CoAP options to coap_pkt_t.qs.

With this approach, gcoap_add_qstring() uses coap_put_option() to append each encoded option to qs. This approach means we need to add a qs_len attribute to coap_pkt_t to know where to append the next option.

Then in _write_options(), one more adaptation required -- fixing the option number delta for the first option in qs. To solve this, we need to expose a low level API in nanocoap to read and write an option header:

  1. Convert the existing _put_odelta() to coap_put_opt_hdr()
  2. Convert the existing _decode_value() to coap_get_opt_hdr()

So, in _write_options() first call coap_get_opt_hdr() on qs to get the length of the first option. Then call coap_put_opt_hdr() on the PDU buf, using this length. Finally memcpy qs to the PDU buf, skipping the first byte in qs.

On the receiving side, use the new coap_find_opt() in nanocoap #18 to read out the query values directly from the packet buf.

So then, with this approach the rework to coap_put_option_url() in nanocoap #16 becomes unnecessary.

We could even take this implementation another step and eliminate coap_pkt_t.qs. The insight here is that the order of Uri-Query options is not significant. So, we can take the technique described above and write to coap_pkt_t.url, but write from the back of the buffer toward the front. It doesn't matter because the option delta always is zero. In this case we would need to add a url_qopt_head pointer parameter to coap_pkt_t to know where the Uri-Query options begin in the url buffer.

With this extension we can eliminate nanocoap #16 altogether. The real beauty here is that the use of the url buffer for its original purpose it not affected because the url and the Uri-Query options are separated by \0 bytes. We just need to be sure they don't overlap.

@haukepetersen
Copy link
Contributor Author

I agree that we can quite significantly optimize this PR (and some other parts with it). I would actually go so far as to remove the 'special' handling of the Uri-Query and the Uri-Path option all together and unify everything down to one set of generic option handling functions (probably as port of nanocaop), and maybe only extend this with some optional, user friendly access function(s) in gcaop. And idea we should think about here is to simply add pointers to options into a list of points, which is then compiled into the actual coap header. With this approach, there is no need for separate buffers for any type of option anymore.

My problem is only, that this type of refactoring will take a (little) while, stalling the merger of all the RD related code. So I would like to request if we could merge my current proposal like this (with all its drawbacks), and optimize the whole option handling as the next step.

@kb2ma
Copy link
Member

kb2ma commented Aug 2, 2017

I look forward to the proposal for generic improvements to option handling. At the same time, I am disappointed to see the addition of a 64-byte array to coap_pkt_t, and hope its life is short. I will review this PR ASAP from that perspective.

@kb2ma
Copy link
Member

kb2ma commented Aug 3, 2017

I suggest limiting GCOAP_REQ_OPTIONS_BUF to 40 bytes. My concern is with a PUT or a POST over 802.15.4. gcoap_req_init() allows a payload length reduced by the size of the header, the path, and this options buf value. Let's assume 128 - 6 (header+token) - 10 (path option) = 112. Then 112 - 48 (options) = 64 bytes for the payload.

For the payload, I think 64 bytes is the minimum acceptable, to support a power-of-2 block transfer. Ideally I would want to support 80 bytes for the payload without a block option, assuming we have header compression.

So, I think 48 bytes is too generous on the options side, and would cut that back a bit. The other option is to extend GCOAP_PDU_BUF_SIZE larger than 128. I don't feel really strongly about this change though -- just putting it out there for feedback.

Copy link
Member

@kb2ma kb2ma left a comment

Choose a reason for hiding this comment

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

Tested on native. Code is clear, and nice comment for the function. Also, consider referencing the new function in the 'Creating a request' section of the module documentation.

@@ -633,6 +633,20 @@ size_t gcoap_obs_send(const uint8_t *buf, size_t len,
*/
uint8_t gcoap_op_state(void);

/**
* @brief Add Uri-Query options to a CoAP request
Copy link
Member

Choose a reason for hiding this comment

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

I suggest "Adds a Uri-Query option..." I have used the 3rd person verb rather than the 2nd person imperative form for other gcoap commands.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, fixed.

/**
* @brief Add Uri-Query options to a CoAP request
*
* @param[out] pkt The package that is being build
Copy link
Member

Choose a reason for hiding this comment

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

I suggest naming the variable 'pdu', to be consistent with other gcoap functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed.

@@ -473,7 +474,14 @@ static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len)
if (pdu->content_type != COAP_FORMAT_NONE) {
bufpos += coap_put_option_ct(bufpos, last_optnum, pdu->content_type);
/* uncomment when add an option after Content-Format */
/* last_optnum = COAP_OPT_CONTENT_FORMAT; */
last_optnum = COAP_OPT_CONTENT_FORMAT;
Copy link
Member

Choose a reason for hiding this comment

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

Please remove the comment above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed.

@haukepetersen
Copy link
Contributor Author

rebased, fixed comments, and switched nanocoap pkg to newest commit.

@kb2ma
Copy link
Member

kb2ma commented Aug 8, 2017

Thanks for those updates. The only open question for me then is your reaction to my comment above on the size of GCOAP_REQ_OPTIONS_BUF relative to the remaining payload size.

@haukepetersen
Copy link
Contributor Author

Oh sorry, slipped through yesterday. Changed GCOAP_REQ_OPTIONS_BUF to 40 byte.

@kb2ma
Copy link
Member

kb2ma commented Aug 8, 2017

I'll ACK to that!

@haukepetersen haukepetersen added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Aug 8, 2017
Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

Proxy-ACK, but please rebase.

@haukepetersen
Copy link
Contributor Author

done

@haukepetersen
Copy link
Contributor Author

all green -> go

@haukepetersen haukepetersen merged commit fb07d98 into RIOT-OS:master Aug 8, 2017
@haukepetersen haukepetersen deleted the add_gcoap_qshandling branch August 8, 2017 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants