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

transfer response handling #12480

Closed
wants to merge 11 commits into from
Closed

transfer response handling #12480

wants to merge 11 commits into from

Conversation

icing
Copy link
Contributor

@icing icing commented Dec 7, 2023

The last PR in the "client writer" series. This clarifies the handling of server responses by folding the code for the complicated protocols into their protocol handlers. This concerns mainly HTTP and its bastard sibling RTSP.

Nomenclature

The terms "read" and "write" are often used without clear context if they refer to the connect or the client/application side of a transfer. This PR uses "read/write" for operations on the client side and "send/receive" for the connection, e.g. server side. If this is considered useful, we can revisit renaming of further methods in another PR.

Protocol Handler Interface

Curl's protocol handler readwrite() method been changed:

-  CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn,
-                        const char *buf, size_t blen,
-                        size_t *pconsumed, bool *readmore);
+  CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
+                         bool is_eos, bool *done);

The name was changed to clarify that this writes reponse data to the client side. The parameter changes are:

  • conn removed as it always operates on data->conn
  • pconsumed removed as the method needs to handle all data on success
  • readmore removed as no longer necessary
  • is_eos as indicator that this is the last call for the transfer response (end-of-stream).
  • done TRUE on return iff the transfer response is to be treated as finished

This change affects many files only because of updated comments in handlers that provide no implementation. The real change is that the HTTP protocol handlers now provide an implementation.

HTTP/RTSP write_resp()

The HTTP protocol handlers write_resp() implementation will get passed all raw data of a server response for the transfer. The HTTP/1.x formatted status and headers, as well as the undecoded response body. Curl_http_write_resp_hds() is used internally to parse the response headers and pass them on. This method is public as the RTSP protocol handler also uses it.

HTTP/1.1 "chunked" transport encoding is now part of the general content encoding writer stack, just like other encodings. A new flag CLIENTWRITE_EOS was added for the last client write. This allows writers to verify that they are in a valid end state. The chunked decoder will check if it indeed has seen the last chunk.

General transfer.c handling

The general response handling in transfer.c:466 happens in function readwrite_data(). This mainly operates now like:

static CURLcode readwrite_data(data, ...)
{
  do {
    Curl_xfer_recv_resp(data, buf)
    ...
    Curl_xfer_write_resp(data, buf)
    ...
  } while(interested);
  ...
}

All the response data handling is implemented in Curl_xfer_write_resp(). It calls the protocol handler's
write_resp() implementation if available, or does the default behaviour.

All raw response data needs to pass through this function. Which also means that anyone in possession of such data may call Curl_xfer_write_resp(). This was implemented for HTTP/2 in #12468 to demonstrate the effect this has on transfer handling.

@icing
Copy link
Contributor Author

icing commented Jan 4, 2024

@monnerat, could I interest you in taking a glance at this PR? It is basically an extensions of the content encoder stack that, I believe, was done by you. Would be nice to get some feedback.

@bagder
Copy link
Member

bagder commented Jan 7, 2024

@icing this merge conflicts now

/* supported content encodings table. */
static const struct Curl_cwtype * const encodings[] = {
/* supported general content decoders. */
static const struct Curl_cwtype * const general_decoders[] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

When i wrote this, I preferred using "unencode" rather than "decode" to emphasize the context of encoding handling. So I'm not a big fan of the renaming.

Copy link
Contributor Author

@icing icing Jan 8, 2024

Choose a reason for hiding this comment

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

I can change that back. I thought "decode" was the opposite of "encode", but English is not my first language.

Copy link
Member

Choose a reason for hiding this comment

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

It is. "unencode" was always very weird to read in my eyes. What does it mean? In English you encode one way and you decode the other way.

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought "decode" was the opposite of "encode"

Yes it is indeed. And the word "unencode" is not very elegant I admit.
This was just because we are dealing with encodings.
Thus I may be ok with decoding if you change it everywhare for consistency!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed as proposed.

@@ -851,6 +851,13 @@ static const struct Curl_cwtype * const encodings[] = {
NULL
};

/* supported content decoders only for transfer encodings */
static const struct Curl_cwtype * const transfer_decoders[] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be easier to keep a single table and add bit flags in the Curl_cwtype structure to specify the allowed phase(s) and if it may be skipped or not? Just a suggestion.

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 prefer to keep them separate and void testing a flag while iterating. Matter of taste, probably.

lib/content_encoding.c Outdated Show resolved Hide resolved
@bagder bagder closed this in d7b6ce6 Jan 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

3 participants