void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm) { size_t r; char* buf; force_assert(NULL != b); force_assert(NULL != tm); if (NULL == format || '\0' == format[0]) { /* empty format */ buffer_string_prepare_append(b, 0); return; } buf = buffer_string_prepare_append(b, 255); r = strftime(buf, buffer_string_space(b), format, tm); /* 0 (in some apis buffer_string_space(b)) signals the string may have * been too small; but the format could also just have lead to an empty * string */ if (0 == r || r >= buffer_string_space(b)) { /* give it a second try with a larger string */ buf = buffer_string_prepare_append(b, 4095); r = strftime(buf, buffer_string_space(b), format, tm); } if (r >= buffer_string_space(b)) r = 0; buffer_commit(b, r); }
void chunkqueue_get_memory(chunkqueue *cq, char **mem, size_t *len, size_t min_size, size_t alloc_size) { static const size_t REALLOC_MAX_SIZE = 256; chunk *c; buffer *b; char *dummy_mem; size_t dummy_len; force_assert(NULL != cq); if (NULL == mem) mem = &dummy_mem; if (NULL == len) len = &dummy_len; /* default values: */ if (0 == min_size) min_size = 1024; if (0 == alloc_size) alloc_size = 4096; if (alloc_size < min_size) alloc_size = min_size; if (NULL != cq->last && MEM_CHUNK == cq->last->type) { size_t have; b = cq->last->mem; have = buffer_string_space(b); /* unused buffer: allocate space */ if (buffer_string_is_empty(b)) { buffer_string_prepare_copy(b, alloc_size); have = buffer_string_space(b); } /* if buffer is really small just make it bigger */ else if (have < min_size && b->size <= REALLOC_MAX_SIZE) { size_t cur_len = buffer_string_length(b); size_t new_size = cur_len + min_size, append; if (new_size < alloc_size) new_size = alloc_size; append = new_size - cur_len; if (append >= min_size) { buffer_string_prepare_append(b, append); have = buffer_string_space(b); } } /* return pointer into existing buffer if large enough */ if (have >= min_size) { *mem = b->ptr + buffer_string_length(b); *len = have; return; } } /* allocate new chunk */ c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; chunkqueue_append_chunk(cq, c); b = c->mem; buffer_string_prepare_append(b, alloc_size); *mem = b->ptr + buffer_string_length(b); *len = buffer_string_space(b); }
static void test_buffer_string_space(void) { buffer *b = buffer_init(); size_t space; space = buffer_string_space(b); assert(0 == space); buffer_copy_string_len(b, CONST_STR_LEN("")); space = buffer_string_space(b); assert(space > 0); assert(space + buffer_string_length(b) == b->size - 1); buffer_commit(b, b->size - 1); assert(b->used == b->size); space = buffer_string_space(b); assert(0 == space); buffer_free(b); }
static int proxy_demux_response(server *srv, handler_ctx *hctx) { int fin = 0; int b; ssize_t r; plugin_data *p = hctx->plugin_data; connection *con = hctx->remote_conn; int proxy_fd = hctx->fd; /* check how much we have to read */ if (ioctl(hctx->fd, FIONREAD, &b)) { log_error_write(srv, __FILE__, __LINE__, "sd", "ioctl failed: ", proxy_fd); return -1; } if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sd", "proxy - have to read:", b); } if (b > 0) { buffer_string_prepare_append(hctx->response, b); if (-1 == (r = read(hctx->fd, hctx->response->ptr + buffer_string_length(hctx->response), buffer_string_space(hctx->response)))) { if (errno == EAGAIN) return 0; log_error_write(srv, __FILE__, __LINE__, "sds", "unexpected end-of-file (perhaps the proxy process died):", proxy_fd, strerror(errno)); return -1; } /* this should be catched by the b > 0 above */ force_assert(r); buffer_commit(hctx->response, r); #if 0 log_error_write(srv, __FILE__, __LINE__, "sdsbs", "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":"); #endif if (0 == con->got_response) { con->got_response = 1; buffer_string_prepare_copy(hctx->response_header, 1023); } if (0 == con->file_started) { char *c; /* search for the \r\n\r\n in the string */ if (NULL != (c = buffer_search_string_len(hctx->response, CONST_STR_LEN("\r\n\r\n")))) { size_t hlen = c - hctx->response->ptr + 4; size_t blen = buffer_string_length(hctx->response) - hlen; /* found */ buffer_append_string_len(hctx->response_header, hctx->response->ptr, hlen); #if 0 log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header); #endif /* parse the response header */ proxy_response_parse(srv, con, p, hctx->response_header); /* enable chunked-transfer-encoding */ if (con->request.http_version == HTTP_VERSION_1_1 && !(con->parsed_response & HTTP_CONTENT_LENGTH)) { con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; } con->file_started = 1; if (blen > 0) http_chunk_append_mem(srv, con, c + 4, blen); buffer_reset(hctx->response); joblist_append(srv, con); } } else { http_chunk_append_buffer(srv, con, hctx->response); joblist_append(srv, con); buffer_reset(hctx->response); } } else { /* reading from upstream done */ con->file_finished = 1; http_chunk_close(srv, con); joblist_append(srv, con); fin = 1; } return fin; }