Adds the reply to the reply linked list. * Note: some edits to this function need to be relayed to AddReplyFromClient. */
| 310 | /* Adds the reply to the reply linked list. |
| 311 | * Note: some edits to this function need to be relayed to AddReplyFromClient. */ |
| 312 | void _addReplyProtoToList(client *c, const char *s, size_t len) { |
| 313 | if (c->flags & CLIENT_CLOSE_AFTER_REPLY) return; |
| 314 | |
| 315 | listNode *ln = listLast(c->reply); |
| 316 | clientReplyBlock *tail = ln? listNodeValue(ln): NULL; |
| 317 | |
| 318 | /* Note that 'tail' may be NULL even if we have a tail node, because when |
| 319 | * addReplyDeferredLen() is used, it sets a dummy node to NULL just |
| 320 | * fo fill it later, when the size of the bulk length is set. */ |
| 321 | |
| 322 | /* Append to tail string when possible. */ |
| 323 | if (tail) { |
| 324 | /* Copy the part we can fit into the tail, and leave the rest for a |
| 325 | * new node */ |
| 326 | size_t avail = tail->size - tail->used; |
| 327 | size_t copy = avail >= len? len: avail; |
| 328 | memcpy(tail->buf + tail->used, s, copy); |
| 329 | tail->used += copy; |
| 330 | s += copy; |
| 331 | len -= copy; |
| 332 | } |
| 333 | if (len) { |
| 334 | /* Create a new node, make sure it is allocated to at |
| 335 | * least PROTO_REPLY_CHUNK_BYTES */ |
| 336 | size_t size = len < PROTO_REPLY_CHUNK_BYTES? PROTO_REPLY_CHUNK_BYTES: len; |
| 337 | tail = zmalloc(size + sizeof(clientReplyBlock)); |
| 338 | /* take over the allocation's internal fragmentation */ |
| 339 | tail->size = zmalloc_usable_size(tail) - sizeof(clientReplyBlock); |
| 340 | tail->used = len; |
| 341 | memcpy(tail->buf, s, len); |
| 342 | listAddNodeTail(c->reply, tail); |
| 343 | c->reply_bytes += tail->size; |
| 344 | |
| 345 | closeClientOnOutputBufferLimitReached(c, 1); |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | /* ----------------------------------------------------------------------------- |
| 350 | * Higher level functions to queue data on the client output buffer. |
no test coverage detected