diff options
-rw-r--r-- | lib/ws.c | 456 |
1 files changed, 286 insertions, 170 deletions
@@ -108,6 +108,15 @@ struct ws_encoder { BIT(contfragment); /* set TRUE if the previous fragment sent was not final */ }; +/* Control frames are allowed up to 125 characters, rfc6455, ch. 5.5 */ +#define WS_MAX_CNTRL_LEN 125 + +struct ws_cntrl_frame { + unsigned int type; + size_t payload_len; + unsigned char payload[WS_MAX_CNTRL_LEN]; +}; + /* A websocket connection with en- and decoder that treat frames * and keep track of boundaries. */ struct websocket { @@ -117,6 +126,7 @@ struct websocket { struct bufq recvbuf; /* raw data from the server */ struct bufq sendbuf; /* raw data to be sent to the server */ struct curl_ws_frame recvframe; /* the current WS FRAME received */ + struct ws_cntrl_frame pending; /* a control frame pending to be sent */ size_t sendbuf_payload; /* number of payload bytes in sendbuf */ }; @@ -229,7 +239,7 @@ static CURLcode ws_frame_flags2firstbyte(struct Curl_easy *data, switch(flags & ~CURLWS_OFFSET) { case 0: if(contfragment) { - infof(data, "[WS] no flags given; interpreting as continuation " + CURL_TRC_WS(data, "no flags given; interpreting as continuation " "fragment for compatibility"); *pfirstbyte = (WSBIT_OPCODE_CONT | WSBIT_FIN); return CURLE_OK; @@ -316,12 +326,12 @@ static CURLcode ws_send_raw_blocking(struct Curl_easy *data, struct websocket *ws, const char *buffer, size_t buflen); -typedef ssize_t ws_write_payload(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *userp, - CURLcode *err); +typedef CURLcode ws_write_payload(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *userp, + size_t *pnwritten); static void ws_dec_next_frame(struct ws_decoder *dec) { @@ -390,21 +400,20 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_PING && dec->head[1] > 125) { + if(dec->frame_flags & CURLWS_PING && dec->head[1] > WS_MAX_CNTRL_LEN) { /* The maximum valid size of PING frames is 125 bytes. Accepting overlong pings would mean sending equivalent pongs! */ failf(data, "[WS] received PING frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_PONG && dec->head[1] > 125) { + if(dec->frame_flags & CURLWS_PONG && dec->head[1] > WS_MAX_CNTRL_LEN) { /* The maximum valid size of PONG frames is 125 bytes. */ failf(data, "[WS] received PONG frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_CLOSE && dec->head[1] > 125) { - /* The maximum valid size of CLOSE frames is 125 bytes. */ + if(dec->frame_flags & CURLWS_CLOSE && dec->head[1] > WS_MAX_CNTRL_LEN) { failf(data, "[WS] received CLOSE frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; @@ -479,7 +488,7 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, { const unsigned char *inbuf; size_t inlen; - ssize_t nwritten; + size_t nwritten; CURLcode result; curl_off_t remain = dec->payload_len - dec->payload_offset; @@ -487,15 +496,15 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) { if((curl_off_t)inlen > remain) inlen = (size_t)remain; - nwritten = write_cb(inbuf, inlen, dec->frame_age, dec->frame_flags, - dec->payload_offset, dec->payload_len, - write_ctx, &result); - if(nwritten < 0) + result = write_cb(inbuf, inlen, dec->frame_age, dec->frame_flags, + dec->payload_offset, dec->payload_len, + write_ctx, &nwritten); + if(result) return result; - Curl_bufq_skip(inraw, (size_t)nwritten); - dec->payload_offset += (curl_off_t)nwritten; + Curl_bufq_skip(inraw, nwritten); + dec->payload_offset += nwritten; remain = dec->payload_len - dec->payload_offset; - CURL_TRC_WS(data, "passed %zd bytes payload, %" + CURL_TRC_WS(data, "passed %zu bytes payload, %" FMT_OFF_T " remain", nwritten, remain); } @@ -532,12 +541,12 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, /* head parsing done */ dec->state = WS_DEC_PAYLOAD; if(dec->payload_len == 0) { - ssize_t nwritten; + size_t nwritten; const unsigned char tmp = '\0'; /* special case of a 0 length frame, need to write once */ - nwritten = write_cb(&tmp, 0, dec->frame_age, dec->frame_flags, - 0, 0, write_ctx, &result); - if(nwritten < 0) + result = write_cb(&tmp, 0, dec->frame_age, dec->frame_flags, + 0, 0, write_ctx, &nwritten); + if(result) return result; dec->state = WS_DEC_INIT; break; @@ -602,43 +611,82 @@ struct ws_cw_dec_ctx { int cw_type; }; -static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *user_data, - CURLcode *err) +static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, + bool blocking); +static CURLcode ws_enc_send(struct Curl_easy *data, + struct websocket *ws, + const unsigned char *buffer, + size_t buflen, + curl_off_t fragsize, + unsigned int flags, + size_t *sent); +static CURLcode ws_enc_add_pending(struct Curl_easy *data, + struct websocket *ws); + +static CURLcode ws_enc_add_cntrl(struct Curl_easy *data, + struct websocket *ws, + const unsigned char *payload, + size_t plen, + unsigned int frame_type) +{ + DEBUGASSERT(plen <= WS_MAX_CNTRL_LEN); + if(plen > WS_MAX_CNTRL_LEN) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Overwrite any pending frame with the new one, we keep + * only one. */ + ws->pending.type = frame_type; + ws->pending.payload_len = plen; + memcpy(ws->pending.payload, payload, plen); + + if(!ws->enc.payload_remain) { /* not in the middle of another frame */ + CURLcode result = ws_enc_add_pending(data, ws); + if(!result) + (void)ws_flush(data, ws, Curl_is_in_callback(data)); + return result; + } + return CURLE_OK; +} + +static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *user_data, + size_t *pnwritten) { struct ws_cw_dec_ctx *ctx = user_data; struct Curl_easy *data = ctx->data; struct websocket *ws = ctx->ws; bool auto_pong = !data->set.ws_no_auto_pong; curl_off_t remain = (payload_len - (payload_offset + buflen)); + CURLcode result; (void)frame_age; + *pnwritten = 0; if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ - size_t bytes; - infof(data, "[WS] auto-respond to PING with a PONG"); + CURL_TRC_WS(data, "auto PONG to [PING payload=%" FMT_OFF_T + "/%" FMT_OFF_T "]", payload_offset, payload_len); /* send back the exact same content as a PONG */ - *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG); - if(*err) - return -1; + result = ws_enc_add_cntrl(data, ws, buf, buflen, CURLWS_PONG); + if(result) + return result; } else if(buflen || !remain) { /* forward the decoded frame to the next client writer. */ update_meta(ws, frame_age, frame_flags, payload_offset, payload_len, buflen); - *err = Curl_cwriter_write(data, ctx->next_writer, + result = Curl_cwriter_write(data, ctx->next_writer, (ctx->cw_type | CLIENTWRITE_0LEN), (const char *)buf, buflen); - if(*err) - return -1; + if(result) + return result; } - *err = CURLE_OK; - return (ssize_t)buflen; + *pnwritten = buflen; + return CURLE_OK; } static CURLcode ws_cw_write(struct Curl_easy *data, @@ -664,7 +712,7 @@ static CURLcode ws_cw_write(struct Curl_easy *data, result = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf, nbytes, &nwritten); if(result) { - infof(data, "WS: error adding data to buffer %d", result); + infof(data, "[WS] error adding data to buffer %d", result); return result; } } @@ -753,7 +801,7 @@ static void ws_enc_init(struct ws_encoder *enc) +---------------------------------------------------------------+ */ -static CURLcode ws_enc_write_head(struct Curl_easy *data, +static CURLcode ws_enc_add_frame(struct Curl_easy *data, struct ws_encoder *enc, unsigned int flags, curl_off_t payload_len, @@ -787,18 +835,15 @@ static CURLcode ws_enc_write_head(struct Curl_easy *data, enc->contfragment = (flags & CURLWS_CONT) ? (bit)TRUE : (bit)FALSE; } - if(flags & CURLWS_PING && payload_len > 125) { - /* The maximum valid size of PING frames is 125 bytes. */ + if(flags & CURLWS_PING && payload_len > WS_MAX_CNTRL_LEN) { failf(data, "[WS] given PING frame is too big"); return CURLE_TOO_LARGE; } - if(flags & CURLWS_PONG && payload_len > 125) { - /* The maximum valid size of PONG frames is 125 bytes. */ + if(flags & CURLWS_PONG && payload_len > WS_MAX_CNTRL_LEN) { failf(data, "[WS] given PONG frame is too big"); return CURLE_TOO_LARGE; } - if(flags & CURLWS_CLOSE && payload_len > 125) { - /* The maximum valid size of CLOSE frames is 125 bytes. */ + if(flags & CURLWS_CLOSE && payload_len > WS_MAX_CNTRL_LEN) { failf(data, "[WS] given CLOSE frame is too big"); return CURLE_TOO_LARGE; } @@ -847,6 +892,23 @@ static CURLcode ws_enc_write_head(struct Curl_easy *data, return CURLE_OK; } +static CURLcode ws_enc_write_head(struct Curl_easy *data, + struct websocket *ws, + struct ws_encoder *enc, + unsigned int flags, + curl_off_t payload_len, + struct bufq *out) +{ + /* starting a new frame, we want a clean sendbuf. + * Any pending control frame we can add now as part of the flush. */ + if(ws->pending.type) { + CURLcode result = ws_enc_add_pending(data, ws); + if(result) + return result; + } + return ws_enc_add_frame(data, enc, flags, payload_len, out); +} + static CURLcode ws_enc_write_payload(struct ws_encoder *enc, struct Curl_easy *data, const unsigned char *buf, size_t buflen, @@ -881,6 +943,139 @@ static CURLcode ws_enc_write_payload(struct ws_encoder *enc, return CURLE_OK; } +static CURLcode ws_enc_add_pending(struct Curl_easy *data, + struct websocket *ws) +{ + CURLcode result; + size_t n; + + if(!ws->pending.type) /* no pending frame here */ + return CURLE_OK; + if(ws->enc.payload_remain) /* in the middle of another frame */ + return CURLE_AGAIN; + + result = ws_enc_add_frame(data, &ws->enc, ws->pending.type, + (curl_off_t)ws->pending.payload_len, + &ws->sendbuf); + if(result) { + CURL_TRC_WS(data, "ws_enc_cntrl(), error addiong head: %d", + result); + goto out; + } + result = ws_enc_write_payload(&ws->enc, data, ws->pending.payload, + ws->pending.payload_len, + &ws->sendbuf, &n); + if(result) { + CURL_TRC_WS(data, "ws_enc_cntrl(), error adding payload: %d", + result); + goto out; + } + /* our buffer should always be able to take in a control frame */ + DEBUGASSERT(n == ws->pending.payload_len); + DEBUGASSERT(!ws->enc.payload_remain); + +out: + memset(&ws->pending, 0, sizeof(ws->pending)); + return result; +} + +static CURLcode ws_enc_send(struct Curl_easy *data, + struct websocket *ws, + const unsigned char *buffer, + size_t buflen, + curl_off_t fragsize, + unsigned int flags, + size_t *pnsent) +{ + size_t n; + CURLcode result = CURLE_OK; + + DEBUGASSERT(!data->set.ws_raw_mode); + *pnsent = 0; + + if(ws->enc.payload_remain || !Curl_bufq_is_empty(&ws->sendbuf)) { + /* a frame is ongoing with payload buffered or more payload + * that needs to be encoded into the buffer */ + if(buflen < ws->sendbuf_payload) { + /* We have been called with LESS buffer data than before. This + * is not how it's supposed too work. */ + failf(data, "[WS] curl_ws_send() called with smaller 'buflen' than " + "bytes already buffered in previous call, %zu vs %zu", + buflen, ws->sendbuf_payload); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if((curl_off_t)buflen > + (ws->enc.payload_remain + (curl_off_t)ws->sendbuf_payload)) { + /* too large buflen beyond payload length of frame */ + failf(data, "[WS] unaligned frame size (sending %zu instead of %" + FMT_OFF_T ")", + buflen, ws->enc.payload_remain + ws->sendbuf_payload); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + else { + result = ws_flush(data, ws, Curl_is_in_callback(data)); + if(result) + return result; + + result = ws_enc_write_head(data, ws, &ws->enc, flags, + (flags & CURLWS_OFFSET) ? + fragsize : (curl_off_t)buflen, + &ws->sendbuf); + if(result) { + CURL_TRC_WS(data, "curl_ws_send(), error writing frame head %d", result); + return result; + } + } + + /* While there is either sendbuf to flush OR more payload to encode... */ + while(!Curl_bufq_is_empty(&ws->sendbuf) || (buflen > ws->sendbuf_payload)) { + /* Try to add more payload to sendbuf */ + if(buflen > ws->sendbuf_payload) { + size_t prev_len = Curl_bufq_len(&ws->sendbuf); + result = ws_enc_write_payload(&ws->enc, data, + buffer + ws->sendbuf_payload, + buflen - ws->sendbuf_payload, + &ws->sendbuf, &n); + if(result && (result != CURLE_AGAIN)) + return result; + ws->sendbuf_payload += Curl_bufq_len(&ws->sendbuf) - prev_len; + if(!ws->sendbuf_payload) { + return CURLE_AGAIN; + } + } + + /* flush, blocking when in callback */ + result = ws_flush(data, ws, Curl_is_in_callback(data)); + if(!result && ws->sendbuf_payload > 0) { + *pnsent += ws->sendbuf_payload; + buffer += ws->sendbuf_payload; + buflen -= ws->sendbuf_payload; + ws->sendbuf_payload = 0; + } + else if(result == CURLE_AGAIN) { + if(ws->sendbuf_payload > Curl_bufq_len(&ws->sendbuf)) { + /* blocked, part of payload bytes remain, report length + * that we managed to send. */ + size_t flushed = (ws->sendbuf_payload - Curl_bufq_len(&ws->sendbuf)); + *pnsent += flushed; + ws->sendbuf_payload -= flushed; + return CURLE_OK; + } + else { + /* blocked before sending headers or 1st payload byte. We cannot report + * OK on 0-length send (caller counts only payload) and EAGAIN */ + CURL_TRC_WS(data, "EAGAIN flushing sendbuf, payload_encoded: %zu/%zu", + ws->sendbuf_payload, buflen); + DEBUGASSERT(*pnsent == 0); + return CURLE_AGAIN; + } + } + else + return result; /* real error sending the data */ + } + return CURLE_OK; +} struct cr_ws_ctx { struct Curl_creader super; @@ -959,7 +1154,7 @@ static CURLcode cr_ws_read(struct Curl_easy *data, if(!ws->enc.payload_remain && Curl_bufq_is_empty(&ws->sendbuf)) { /* encode the data as a new BINARY frame */ - result = ws_enc_write_head(data, &ws->enc, CURLWS_BINARY, nread, + result = ws_enc_write_head(data, ws, &ws->enc, CURLWS_BINARY, nread, &ws->sendbuf); if(result) goto out; @@ -1229,6 +1424,7 @@ out: struct ws_collect { struct Curl_easy *data; + struct websocket *ws; unsigned char *buffer; size_t buflen; size_t bufidx; @@ -1239,19 +1435,20 @@ struct ws_collect { bool written; }; -static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *userp, - CURLcode *err) +static CURLcode ws_client_collect(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *userp, + size_t *pnwritten) { struct ws_collect *ctx = userp; struct Curl_easy *data = ctx->data; bool auto_pong = !data->set.ws_no_auto_pong; - size_t nwritten; curl_off_t remain = (payload_len - (payload_offset + buflen)); + CURLcode result = CURLE_OK; + *pnwritten = 0; if(!ctx->bufidx) { /* first write */ ctx->frame_age = frame_age; @@ -1262,31 +1459,30 @@ static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ - size_t bytes; - infof(ctx->data, "[WS] auto-respond to PING with a PONG"); + CURL_TRC_WS(data, "auto PONG to [PING payload=%" FMT_OFF_T + "/%" FMT_OFF_T "]", payload_offset, payload_len); /* send back the exact same content as a PONG */ - *err = curl_ws_send(ctx->data, buf, buflen, &bytes, 0, CURLWS_PONG); - if(*err) - return -1; - nwritten = bytes; + result = ws_enc_add_cntrl(ctx->data, ctx->ws, buf, buflen, CURLWS_PONG); + if(result) + return result; + *pnwritten = buflen; } else { + size_t write_len; + ctx->written = TRUE; DEBUGASSERT(ctx->buflen >= ctx->bufidx); - nwritten = CURLMIN(buflen, ctx->buflen - ctx->bufidx); - if(!nwritten) { - if(!buflen) { /* 0 length write, we accept that */ - *err = CURLE_OK; - return 0; - } - *err = CURLE_AGAIN; /* no more space */ - return -1; + write_len = CURLMIN(buflen, ctx->buflen - ctx->bufidx); + if(!write_len) { + if(!buflen) /* 0 length write, we accept that */ + return CURLE_OK; + return CURLE_AGAIN; /* no more space */ } - *err = CURLE_OK; - memcpy(ctx->buffer + ctx->bufidx, buf, nwritten); - ctx->bufidx += nwritten; + memcpy(ctx->buffer + ctx->bufidx, buf, write_len); + ctx->bufidx += write_len; + *pnwritten = write_len; } - return nwritten; + return result; } static CURLcode nw_in_recv(void *reader_ctx, @@ -1334,6 +1530,7 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, memset(&ctx, 0, sizeof(ctx)); ctx.data = data; + ctx.ws = ws; ctx.buffer = buffer; ctx.buflen = buflen; @@ -1384,6 +1581,13 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, FMT_OFF_T ", %" FMT_OFF_T " left)", buflen, *nread, ws->recvframe.offset, ws->recvframe.bytesleft); + /* all's well, try to send any pending control. we do not know + * when the application will call `curl_ws_send()` again. */ + if(!data->set.ws_raw_mode && ws->pending.type) { + CURLcode r2 = ws_enc_add_pending(data, ws); + if(!r2) + (void)ws_flush(data, ws, Curl_is_in_callback(data)); + } return CURLE_OK; } @@ -1531,9 +1735,10 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, { struct websocket *ws; const unsigned char *buffer = buffer_arg; - size_t n; CURLcode result = CURLE_OK; struct Curl_easy *data = d; + size_t ndummy; + size_t *pnsent = sent ? sent : &ndummy; if(!GOOD_EASY_HANDLE(data)) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -1541,8 +1746,7 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, ", flags=%x), raw=%d", buflen, fragsize, flags, data->set.ws_raw_mode); - if(sent) - *sent = 0; + *pnsent = 0; if(!buffer && buflen) { failf(data, "[WS] buffer is NULL when buflen is not"); @@ -1586,107 +1790,18 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, failf(data, "[WS] fragsize and flags must be zero in raw mode"); return CURLE_BAD_FUNCTION_ARGUMENT; } - result = ws_send_raw(data, buffer, buflen, sent); + result = ws_send_raw(data, buffer, buflen, pnsent); goto out; } - /* Not RAW mode, buf we do the frame encoding */ - - if(ws->enc.payload_remain || !Curl_bufq_is_empty(&ws->sendbuf)) { - /* a frame is ongoing with payload buffered or more payload - * that needs to be encoded into the buffer */ - if(buflen < ws->sendbuf_payload) { - /* We have been called with LESS buffer data than before. This - * is not how it's supposed too work. */ - failf(data, "[WS] curl_ws_send() called with smaller 'buflen' than " - "bytes already buffered in previous call, %zu vs %zu", - buflen, ws->sendbuf_payload); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; - } - if((curl_off_t)buflen > - (ws->enc.payload_remain + (curl_off_t)ws->sendbuf_payload)) { - /* too large buflen beyond payload length of frame */ - failf(data, "[WS] unaligned frame size (sending %zu instead of %" - FMT_OFF_T ")", - buflen, ws->enc.payload_remain + ws->sendbuf_payload); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; - } - } - else { - /* starting a new frame, we want a clean sendbuf */ - result = ws_flush(data, ws, Curl_is_in_callback(data)); - if(result) - goto out; - - result = ws_enc_write_head(data, &ws->enc, flags, - (flags & CURLWS_OFFSET) ? - fragsize : (curl_off_t)buflen, - &ws->sendbuf); - if(result) { - CURL_TRC_WS(data, "curl_ws_send(), error writing frame head %d", result); - goto out; - } - } - - /* While there is either sendbuf to flush OR more payload to encode... */ - while(!Curl_bufq_is_empty(&ws->sendbuf) || (buflen > ws->sendbuf_payload)) { - /* Try to add more payload to sendbuf */ - if(buflen > ws->sendbuf_payload) { - size_t prev_len = Curl_bufq_len(&ws->sendbuf); - result = ws_enc_write_payload(&ws->enc, data, - buffer + ws->sendbuf_payload, - buflen - ws->sendbuf_payload, - &ws->sendbuf, &n); - if(result && (result != CURLE_AGAIN)) - goto out; - ws->sendbuf_payload += Curl_bufq_len(&ws->sendbuf) - prev_len; - if(!ws->sendbuf_payload) { - result = CURLE_AGAIN; - goto out; - } - } - - /* flush, blocking when in callback */ - result = ws_flush(data, ws, Curl_is_in_callback(data)); - if(!result && ws->sendbuf_payload > 0) { - if(sent) - *sent += ws->sendbuf_payload; - buffer += ws->sendbuf_payload; - buflen -= ws->sendbuf_payload; - ws->sendbuf_payload = 0; - } - else if(result == CURLE_AGAIN) { - if(ws->sendbuf_payload > Curl_bufq_len(&ws->sendbuf)) { - /* blocked, part of payload bytes remain, report length - * that we managed to send. */ - size_t flushed = (ws->sendbuf_payload - Curl_bufq_len(&ws->sendbuf)); - if(sent) - *sent += flushed; - ws->sendbuf_payload -= flushed; - result = CURLE_OK; - goto out; - } - else { - /* blocked before sending headers or 1st payload byte. We cannot report - * OK on 0-length send (caller counts only payload) and EAGAIN */ - CURL_TRC_WS(data, "EAGAIN flushing sendbuf, payload_encoded: %zu/%zu", - ws->sendbuf_payload, buflen); - DEBUGASSERT(!sent || *sent == 0); - result = CURLE_AGAIN; - goto out; - } - } - else - goto out; /* real error sending the data */ - } + /* Not RAW mode, we do the frame encoding */ + result = ws_enc_send(data, ws, buffer, buflen, fragsize, flags, pnsent); out: CURL_TRC_WS(data, "curl_ws_send(len=%zu, fragsize=%" FMT_OFF_T ", flags=%x, raw=%d) -> %d, %zu", buflen, fragsize, flags, data->set.ws_raw_mode, result, - sent ? *sent : 0); + *pnsent); return result; } @@ -1760,7 +1875,8 @@ CURL_EXTERN CURLcode curl_ws_start_frame(CURL *d, goto out; } - result = ws_enc_write_head(data, &ws->enc, flags, frame_len, &ws->sendbuf); + result = ws_enc_write_head(data, ws, &ws->enc, flags, frame_len, + &ws->sendbuf); if(result) CURL_TRC_WS(data, "curl_start_frame(), error adding frame head %d", result); |