Skip to content
Snippets Groups Projects
Commit b239da9a authored by Makarand Dharmapurikar's avatar Makarand Dharmapurikar
Browse files

removed multiple allocs, refactored b64 encoder

Added new api to b64.h for directly encoding to memory.
Using slice_sub instead of string operations for separating
path from query.
parent 366c9c5a
Branches
Tags
No related merge requests found
...@@ -296,28 +296,44 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx, ...@@ -296,28 +296,44 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
* MDELEM by appending base64 encoded query to the path */ * MDELEM by appending base64 encoded query to the path */
static const int k_url_safe = 1; static const int k_url_safe = 1;
static const int k_multi_line = 0; static const int k_multi_line = 0;
static char *k_query_separator = "?"; static const char *k_query_separator = "?";
char *strs_to_concatenate[3];
strs_to_concatenate[0] = grpc_dump_slice( grpc_slice path_slice =
GRPC_MDVALUE(op->send_initial_metadata->idx.named.path->md), GRPC_MDVALUE(op->send_initial_metadata->idx.named.path->md);
GPR_DUMP_ASCII); /* sum up individual component's lengths and allocate enough memory to
strs_to_concatenate[1] = k_query_separator; * hold combined path+query */
strs_to_concatenate[2] = grpc_base64_encode( size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
(const void *)calld->payload_bytes, op->send_message->length, estimated_len += strlen(k_query_separator);
k_url_safe, k_multi_line); estimated_len += grpc_base64_estimate_encoded_size(
size_t concatenated_len; op->send_message->length, k_url_safe, k_multi_line);
char *path_with_query = gpr_strjoin((const char **)strs_to_concatenate, estimated_len += 1; /* for the trailing 0 */
3, &concatenated_len); grpc_slice path_with_query_slice = grpc_slice_malloc(estimated_len);
gpr_log(GPR_DEBUG, "Path with query: %s\n", path_with_query);
gpr_free(strs_to_concatenate[0]); /* memcopy individual pieces into this slice */
gpr_free(strs_to_concatenate[2]); char *write_ptr = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
/* substitute previous path with the new path */ char *original_path = (char *)GRPC_SLICE_START_PTR(path_slice);
memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice));
write_ptr += (int)GRPC_SLICE_LENGTH(path_slice);
memcpy(write_ptr, k_query_separator, strlen(k_query_separator));
write_ptr += strlen(k_query_separator);
grpc_base64_encode_core(write_ptr, calld->payload_bytes,
op->send_message->length, k_url_safe,
k_multi_line);
/* remove trailing unused memory and add trailing 0 to terminate string
*/
char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
size_t path_length = strlen(t) + 1;
*(t + path_length) = 0;
path_with_query_slice =
grpc_slice_sub(path_with_query_slice, 0, path_length);
/* substitute previous path with the new path+query */
grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices( grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_PATH, exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice);
grpc_slice_from_copied_buffer((const char *)path_with_query,
concatenated_len));
gpr_free(path_with_query);
grpc_metadata_batch *b = op->send_initial_metadata; grpc_metadata_batch *b = op->send_initial_metadata;
error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path, error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
mdelem_path_and_query); mdelem_path_and_query);
......
...@@ -200,31 +200,34 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx, ...@@ -200,31 +200,34 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
} else if (*calld->recv_cacheable_request == true) { } else if (*calld->recv_cacheable_request == true) {
/* We have a cacheable request made with GET verb. The path contains the /* We have a cacheable request made with GET verb. The path contains the
* query parameter which is base64 encoded request payload. */ * query parameter which is base64 encoded request payload. */
char *path = static const char *k_query_separator = "?";
grpc_dump_slice(GRPC_MDVALUE(b->idx.named.path->md), GPR_DUMP_ASCII); grpc_slice path_slice = GRPC_MDVALUE(b->idx.named.path->md);
static const char *QUERY_SEPARATOR = "?"; char *path_ptr = (char *)GRPC_SLICE_START_PTR(path_slice);
char **query_parts; size_t path_length = GRPC_SLICE_LENGTH(path_slice);
size_t num_query_parts; /* offset of the character '?' */
gpr_string_split(path, QUERY_SEPARATOR, &query_parts, &num_query_parts); size_t offset = 0;
GPR_ASSERT(num_query_parts == 2); for (offset = 0; *path_ptr != k_query_separator[0] && offset < path_length;
path_ptr++, offset++)
;
grpc_slice query_slice =
grpc_slice_sub(path_slice, offset + 1, path_length);
/* substitute path metadata with just the path (not query) */ /* substitute path metadata with just the path (not query) */
grpc_mdelem mdelem_path_without_query = grpc_mdelem_from_slices( grpc_mdelem mdelem_path_without_query = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_PATH, exec_ctx, GRPC_MDSTR_PATH, grpc_slice_sub(path_slice, 0, offset));
grpc_slice_from_copied_buffer((const char *)query_parts[0],
strlen(query_parts[0])));
grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path, grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
mdelem_path_without_query); mdelem_path_without_query);
gpr_free(query_parts[0]);
/* decode query into payload and add it to the slice buffer to be returned /* decode payload from query and add to the slice buffer to be returned */
* */
static const int k_url_safe = 1; static const int k_url_safe = 1;
grpc_slice_buffer_add( grpc_slice_buffer_add(
&calld->read_slice_buffer, &calld->read_slice_buffer,
grpc_base64_decode(exec_ctx, (const char *)query_parts[1], k_url_safe)); grpc_base64_decode(exec_ctx,
(const char *)GRPC_SLICE_START_PTR(query_slice),
k_url_safe));
grpc_slice_buffer_stream_init(&calld->read_stream, grpc_slice_buffer_stream_init(&calld->read_stream,
&calld->read_slice_buffer, 0); &calld->read_slice_buffer, 0);
gpr_free(query_parts[1]);
calld->seen_path_with_query = true; calld->seen_path_with_query = true;
} }
......
...@@ -71,15 +71,31 @@ static const char base64_url_safe_chars[] = ...@@ -71,15 +71,31 @@ static const char base64_url_safe_chars[] =
char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
int multiline) { int multiline) {
const unsigned char *data = vdata; size_t result_projected_size =
const char *base64_chars = grpc_base64_estimate_encoded_size(data_size, url_safe, multiline);
url_safe ? base64_url_safe_chars : base64_url_unsafe_chars; char *result = gpr_malloc(result_projected_size);
grpc_base64_encode_core(result, vdata, data_size, url_safe, multiline);
return result;
}
size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe,
int multiline) {
size_t result_projected_size = size_t result_projected_size =
4 * ((data_size + 3) / 3) + 4 * ((data_size + 3) / 3) +
2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS)) 2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS))
: 0) + : 0) +
1; 1;
char *result = gpr_malloc(result_projected_size); return result_projected_size;
}
void grpc_base64_encode_core(char *result, const void *vdata, size_t data_size,
int url_safe, int multiline) {
const unsigned char *data = vdata;
const char *base64_chars =
url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
size_t result_projected_size =
grpc_base64_estimate_encoded_size(data_size, url_safe, multiline);
char *current = result; char *current = result;
size_t num_blocks = 0; size_t num_blocks = 0;
size_t i = 0; size_t i = 0;
...@@ -119,7 +135,6 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, ...@@ -119,7 +135,6 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
GPR_ASSERT(current >= result); GPR_ASSERT(current >= result);
GPR_ASSERT((uintptr_t)(current - result) < result_projected_size); GPR_ASSERT((uintptr_t)(current - result) < result_projected_size);
result[current - result] = '\0'; result[current - result] = '\0';
return result;
} }
grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64, grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
......
...@@ -41,6 +41,17 @@ ...@@ -41,6 +41,17 @@
char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
int multiline); int multiline);
/* estimate the upper bound on size of base64 encoded data. The actual size
* is guaranteed to be less than or equal to the size returned here. */
size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe,
int multiline);
/* Encodes data using base64 and write it to memory pointed to by result. It is
* the caller's responsiblity to allocate enough memory in |result| to fit the
* encoded data. */
void grpc_base64_encode_core(char *result, const void *vdata, size_t data_size,
int url_safe, int multiline);
/* Decodes data according to the base64 specification. Returns an empty /* Decodes data according to the base64 specification. Returns an empty
slice in case of failure. */ slice in case of failure. */
grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64, grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment