Merge pull request #1292 from jboeuf/load_file_with_null_term

Adding option to add a null terminator when loading a file.
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index ebea70d..d2f46dd 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -127,7 +127,7 @@
   gpr_slice creds_data;
   int file_ok = 0;
   if (creds_path == NULL) return NULL;
-  creds_data = gpr_load_file(creds_path, &file_ok);
+  creds_data = gpr_load_file(creds_path, 1, &file_ok);
   gpr_free(creds_path);
   if (file_ok) {
     result = grpc_jwt_credentials_create(
@@ -145,7 +145,7 @@
   gpr_slice creds_data;
   int file_ok = 0;
   if (creds_path == NULL) return NULL;
-  creds_data = gpr_load_file(creds_path, &file_ok);
+  creds_data = gpr_load_file(creds_path, 1, &file_ok);
   gpr_free(creds_path);
   if (file_ok) {
     result = grpc_refresh_token_credentials_create(
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index 0813780..dbfcf55 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -359,7 +359,6 @@
     peer_name = allocated_name;
     if (!peer_name) return 0;
   }
-  
   r = tsi_ssl_peer_matches_name(peer, peer_name);
   gpr_free(allocated_name);
   return r;
@@ -453,13 +452,13 @@
   if (default_root_certs_path == NULL) {
     default_pem_root_certs = gpr_empty_slice();
   } else {
-    default_pem_root_certs = gpr_load_file(default_root_certs_path, NULL);
+    default_pem_root_certs = gpr_load_file(default_root_certs_path, 0, NULL);
     gpr_free(default_root_certs_path);
   }
 
   /* Fall back to installed certs if needed. */
   if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) {
-    default_pem_root_certs = gpr_load_file(installed_roots_path, NULL);
+    default_pem_root_certs = gpr_load_file(installed_roots_path, 0, NULL);
   }
 }
 
diff --git a/src/core/support/file.c b/src/core/support/file.c
index 70100b7..3a4ac6f 100644
--- a/src/core/support/file.c
+++ b/src/core/support/file.c
@@ -41,13 +41,14 @@
 
 #include "src/core/support/string.h"
 
-gpr_slice gpr_load_file(const char *filename, int *success) {
+gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
+                        int *success) {
   unsigned char *contents = NULL;
   size_t contents_size = 0;
-  unsigned char buf[4096];
   char *error_msg = NULL;
   gpr_slice result = gpr_empty_slice();
   FILE *file = fopen(filename, "rb");
+  size_t bytes_read = 0;
 
   if (file == NULL) {
     gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
@@ -55,27 +56,22 @@
     GPR_ASSERT(error_msg != NULL);
     goto end;
   }
-
-  while (1) {
-    size_t bytes_read = fread(buf, 1, sizeof(buf), file);
-    if (bytes_read > 0) {
-      contents = gpr_realloc(contents, contents_size + bytes_read);
-      memcpy(contents + contents_size, buf, bytes_read);
-      contents_size += bytes_read;
-    }
-    if (bytes_read < sizeof(buf)) {
-      if (ferror(file)) {
-        gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
-                     strerror(errno), filename);
-        GPR_ASSERT(error_msg != NULL);
-        goto end;
-      } else {
-        GPR_ASSERT(feof(file));
-        break;
-      }
-    }
+  fseek(file, 0, SEEK_END);
+  contents_size = ftell(file);
+  fseek(file, 0, SEEK_SET);
+  contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0));
+  bytes_read = fread(contents, 1, contents_size, file);
+  if (bytes_read < contents_size) {
+    GPR_ASSERT(ferror(file));
+    gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
+                 strerror(errno), filename);
+    GPR_ASSERT(error_msg != NULL);
+    goto end;
   }
   if (success != NULL) *success = 1;
+  if (add_null_terminator) {
+    contents[contents_size++] = 0;
+  }
   result = gpr_slice_new(contents, contents_size, gpr_free);
 
 end:
diff --git a/src/core/support/file.h b/src/core/support/file.h
index ee6ca7b..1dafe39 100644
--- a/src/core/support/file.h
+++ b/src/core/support/file.h
@@ -44,9 +44,11 @@
 
 /* File utility functions */
 
-/* Loads the content of a file into a slice. The success parameter, if not NULL,
+/* Loads the content of a file into a slice. add_null_terminator will add
+   a NULL terminator if non-zero. The success parameter, if not NULL,
    will be set to 1 in case of success and 0 in case of failure. */
-gpr_slice gpr_load_file(const char *filename, int *success);
+gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
+                        int *success);
 
 /* Creates a temporary file from a prefix.
    If tmp_filename is not NULL, *tmp_filename is assigned the name of the
diff --git a/test/core/security/create_jwt.c b/test/core/security/create_jwt.c
index 614dd1e..b02469f 100644
--- a/test/core/security/create_jwt.c
+++ b/test/core/security/create_jwt.c
@@ -48,7 +48,7 @@
   grpc_auth_json_key key;
   int ok = 0;
   char *jwt;
-  gpr_slice json_key_data = gpr_load_file(json_key_file_path, &ok);
+  gpr_slice json_key_data = gpr_load_file(json_key_file_path, 1, &ok);
   if (!ok) {
     fprintf(stderr, "Could not read %s.\n", json_key_file_path);
     exit(1);
diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c
index cc847c8..7a40fe0 100644
--- a/test/core/security/fetch_oauth2.c
+++ b/test/core/security/fetch_oauth2.c
@@ -77,7 +77,7 @@
 static grpc_credentials *create_service_account_creds(
     const char *json_key_file_path, const char *scope) {
   int success;
-  gpr_slice json_key = gpr_load_file(json_key_file_path, &success);
+  gpr_slice json_key = gpr_load_file(json_key_file_path, 1, &success);
   if (!success) {
     gpr_log(GPR_ERROR, "Could not read file %s.", json_key_file_path);
     exit(1);
@@ -91,7 +91,7 @@
     const char *json_refresh_token_file_path) {
   int success;
   gpr_slice refresh_token =
-      gpr_load_file(json_refresh_token_file_path, &success);
+      gpr_load_file(json_refresh_token_file_path, 1, &success);
   if (!success) {
     gpr_log(GPR_ERROR, "Could not read file %s.", json_refresh_token_file_path);
     exit(1);
diff --git a/test/core/support/file_test.c b/test/core/support/file_test.c
index dd8caf7..56e7a49 100644
--- a/test/core/support/file_test.c
+++ b/test/core/support/file_test.c
@@ -49,6 +49,7 @@
 static void test_load_empty_file(void) {
   FILE *tmp = NULL;
   gpr_slice slice;
+  gpr_slice slice_with_null_term;
   int success;
   char *tmp_name;
 
@@ -59,13 +60,19 @@
   GPR_ASSERT(tmp != NULL);
   fclose(tmp);
 
-  slice = gpr_load_file(tmp_name, &success);
+  slice = gpr_load_file(tmp_name, 0, &success);
   GPR_ASSERT(success == 1);
   GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 0);
 
+  slice_with_null_term = gpr_load_file(tmp_name, 1, &success);
+  GPR_ASSERT(success == 1);
+  GPR_ASSERT(GPR_SLICE_LENGTH(slice_with_null_term) == 1);
+  GPR_ASSERT(GPR_SLICE_START_PTR(slice_with_null_term)[0] == 0);
+
   remove(tmp_name);
   gpr_free(tmp_name);
   gpr_slice_unref(slice);
+  gpr_slice_unref(slice_with_null_term);
 }
 
 static void test_load_failure(void) {
@@ -82,7 +89,7 @@
   fclose(tmp);
   remove(tmp_name);
 
-  slice = gpr_load_file(tmp_name, &success);
+  slice = gpr_load_file(tmp_name, 0, &success);
   GPR_ASSERT(success == 0);
   GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 0);
   gpr_free(tmp_name);
@@ -92,6 +99,7 @@
 static void test_load_small_file(void) {
   FILE *tmp = NULL;
   gpr_slice slice;
+  gpr_slice slice_with_null_term;
   int success;
   char *tmp_name;
   const char *blah = "blah";
@@ -104,14 +112,21 @@
   GPR_ASSERT(fwrite(blah, 1, strlen(blah), tmp) == strlen(blah));
   fclose(tmp);
 
-  slice = gpr_load_file(tmp_name, &success);
+  slice = gpr_load_file(tmp_name, 0, &success);
   GPR_ASSERT(success == 1);
   GPR_ASSERT(GPR_SLICE_LENGTH(slice) == strlen(blah));
   GPR_ASSERT(!memcmp(GPR_SLICE_START_PTR(slice), blah, strlen(blah)));
 
+  slice_with_null_term = gpr_load_file(tmp_name, 1, &success);
+  GPR_ASSERT(success == 1);
+  GPR_ASSERT(GPR_SLICE_LENGTH(slice_with_null_term) == (strlen(blah) + 1));
+  GPR_ASSERT(strcmp((const char *)GPR_SLICE_START_PTR(slice_with_null_term),
+                    blah) == 0);
+
   remove(tmp_name);
   gpr_free(tmp_name);
   gpr_slice_unref(slice);
+  gpr_slice_unref(slice_with_null_term);
 }
 
 static void test_load_big_file(void) {
@@ -135,7 +150,7 @@
   GPR_ASSERT(fwrite(buffer, 1, sizeof(buffer), tmp) == sizeof(buffer));
   fclose(tmp);
 
-  slice = gpr_load_file(tmp_name, &success);
+  slice = gpr_load_file(tmp_name, 0, &success);
   GPR_ASSERT(success == 1);
   GPR_ASSERT(GPR_SLICE_LENGTH(slice) == sizeof(buffer));
   current = GPR_SLICE_START_PTR(slice);