示例#1
0
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);
}
示例#2
0
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);
}
示例#3
0
static void accesslog_append_escaped(buffer *dest, buffer *str) {
	char *ptr, *start, *end;

	/* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
	/* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
	if (buffer_string_is_empty(str)) return;
	buffer_string_prepare_append(dest, buffer_string_length(str));

	for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) {
		unsigned char const c = (unsigned char) *ptr;
		if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
			/* nothing to change, add later as one block */
		} else {
			/* copy previous part */
			if (start < ptr) {
				buffer_append_string_len(dest, start, ptr - start);
			}
			start = ptr + 1;

			switch (c) {
			case '"':
				BUFFER_APPEND_STRING_CONST(dest, "\\\"");
				break;
			case '\\':
				BUFFER_APPEND_STRING_CONST(dest, "\\\\");
				break;
			case '\b':
				BUFFER_APPEND_STRING_CONST(dest, "\\b");
				break;
			case '\n':
				BUFFER_APPEND_STRING_CONST(dest, "\\n");
				break;
			case '\r':
				BUFFER_APPEND_STRING_CONST(dest, "\\r");
				break;
			case '\t':
				BUFFER_APPEND_STRING_CONST(dest, "\\t");
				break;
			case '\v':
				BUFFER_APPEND_STRING_CONST(dest, "\\v");
				break;
			default: {
					/* non printable char => \xHH */
					char hh[5] = {'\\','x',0,0,0};
					char h = c / 16;
					hh[2] = (h > 9) ? (h - 10 + 'A') : (h + '0');
					h = c % 16;
					hh[3] = (h > 9) ? (h - 10 + 'A') : (h + '0');
					buffer_append_string_len(dest, &hh[0], 4);
				}
				break;
			}
		}
	}

	if (start < end) {
		buffer_append_string_len(dest, start, end - start);
	}
}
示例#4
0
char* buffer_append_base64_encode(buffer *out, const unsigned char* in, size_t in_length, base64_charset charset) {
	size_t reserve = 4*(in_length/3) + 4;
	char* result = buffer_string_prepare_append(out, reserve);
	size_t out_pos = li_to_base64(result, reserve, in, in_length, charset);

	buffer_commit(out, out_pos);

	return result;
}
示例#5
0
void buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
	char *target_buf;

	force_assert(NULL != b);
	force_assert(NULL != s || s_len == 0);

	target_buf = buffer_string_prepare_append(b, s_len);

	if (0 == s_len) return; /* nothing to append */

	memcpy(target_buf, s, s_len);

	buffer_commit(b, s_len);
}
示例#6
0
void buffer_append_uint_hex(buffer *b, uintmax_t value) {
	char *buf;
	int shift = 0;

	{
		uintmax_t copy = value;
		do {
			copy >>= 8;
			shift += 2; /* counting nibbles (4 bits) */
		} while (0 != copy);
	}

	buf = buffer_string_prepare_append(b, shift);
	buffer_commit(b, shift); /* will fill below */

	shift <<= 2; /* count bits now */
	while (shift > 0) {
		shift -= 4;
		*(buf++) = hex_chars[(value >> shift) & 0x0F];
	}
}
示例#7
0
void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
	unsigned char *ds, *d;
	size_t d_len, ndx;
	const char *map = NULL;

	force_assert(NULL != b);
	force_assert(NULL != s || 0 == s_len);

	if (0 == s_len) return;

	switch(encoding) {
	case ENCODING_REL_URI:
		map = encoded_chars_rel_uri;
		break;
	case ENCODING_REL_URI_PART:
		map = encoded_chars_rel_uri_part;
		break;
	case ENCODING_HTML:
		map = encoded_chars_html;
		break;
	case ENCODING_MINIMAL_XML:
		map = encoded_chars_minimal_xml;
		break;
	case ENCODING_HEX:
		map = encoded_chars_hex;
		break;
	case ENCODING_HTTP_HEADER:
		map = encoded_chars_http_header;
		break;
	}

	force_assert(NULL != map);

	/* count to-be-encoded-characters */
	for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
		if (map[*ds]) {
			switch(encoding) {
			case ENCODING_REL_URI:
			case ENCODING_REL_URI_PART:
				d_len += 3;
				break;
			case ENCODING_HTML:
			case ENCODING_MINIMAL_XML:
				d_len += 6;
				break;
			case ENCODING_HTTP_HEADER:
			case ENCODING_HEX:
				d_len += 2;
				break;
			}
		} else {
			d_len++;
		}
	}

	d = (unsigned char*) buffer_string_prepare_append(b, d_len);
	buffer_commit(b, d_len); /* fill below */
	force_assert('\0' == *d);

	for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
		if (map[*ds]) {
			switch(encoding) {
			case ENCODING_REL_URI:
			case ENCODING_REL_URI_PART:
				d[d_len++] = '%';
				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
				d[d_len++] = hex_chars[(*ds) & 0x0F];
				break;
			case ENCODING_HTML:
			case ENCODING_MINIMAL_XML:
				d[d_len++] = '&';
				d[d_len++] = '#';
				d[d_len++] = 'x';
				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
				d[d_len++] = hex_chars[(*ds) & 0x0F];
				d[d_len++] = ';';
				break;
			case ENCODING_HEX:
				d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
				d[d_len++] = hex_chars[(*ds) & 0x0F];
				break;
			case ENCODING_HTTP_HEADER:
				d[d_len++] = *ds;
				d[d_len++] = '\t';
				break;
			}
		} else {
			d[d_len++] = *ds;
		}
	}
示例#8
0
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;
}
示例#9
0
unsigned char* buffer_append_base64_decode(buffer *out, const char* in, size_t in_length, base64_charset charset) {
	unsigned char *result;
	size_t out_pos = 0; /* current output character (position) that is decoded. can contain partial result */
	unsigned int group = 0; /* how many base64 digits in the current group were decoded already. each group has up to 4 digits */
	size_t i;
	const short* base64_reverse_table;

	switch (charset) {
	case BASE64_STANDARD:
		base64_reverse_table = base64_standard_reverse_table;
		break;
	case BASE64_URL:
		base64_reverse_table = base64_url_reverse_table;
		break;
	default:
		return NULL;
	}

	result = (unsigned char *) buffer_string_prepare_append(out, 3*(in_length / 4) + 3);

	/* run through the whole string, converting as we go */
	for (i = 0; i < in_length; i++) {
		unsigned char c = (unsigned char) in[i];
		short ch;

		if (c == '\0') break;
		if (c >= 128) return NULL; /* only 7-bit characters allowed */

		ch = base64_reverse_table[c];
		if (-3 == ch) {
			/* pad character; can only come after 2 base64 digits in a group */
			if (group < 2) return NULL;
			break;
		} else if (-2 == ch) {
			continue; /* skip character */
		} else if (ch < 0) {
			return NULL; /* invalid character, abort */
		}

		switch(group) {
		case 0:
			result[out_pos] = ch << 2;
			group = 1;
			break;
		case 1:
			result[out_pos++] |= ch >> 4;
			result[out_pos] = (ch & 0x0f) << 4;
			group = 2;
			break;
		case 2:
			result[out_pos++] |= ch >>2;
			result[out_pos] = (ch & 0x03) << 6;
			group = 3;
			break;
		case 3:
			result[out_pos++] |= ch;
			group = 0;
			break;
		}
	}

	switch(group) {
	case 0:
		/* ended on boundary */
		break;
	case 1:
		/* need at least 2 base64 digits per group */
		return NULL;
	case 2:
		/* have 2 base64 digits in last group => one real octect, two zeroes padded */
	case 3:
		/* have 3 base64 digits in last group => two real octects, one zero padded */

		/* for both cases the current index already is on the first zero padded octet
		 * - check it really is zero (overlapping bits) */
		if (0 != result[out_pos]) return NULL;
		break;
	}

	buffer_commit(out, out_pos);

	return result;
}