Ruby  2.0.0p247(2013-06-27revision41674)
nacl/pepper_main.c
Go to the documentation of this file.
00001 /******************************************************************************
00002  Copyright 2012 Google Inc. All Rights Reserved.
00003  Author: yugui@google.com (Yugui Sonoda)
00004  ******************************************************************************/
00005 
00006 #include <stdlib.h>
00007 #include <stdio.h>
00008 #include <string.h>
00009 #include <pthread.h>
00010 #include <sys/stat.h>
00011 #include <fcntl.h>
00012 #include <pthread.h>
00013 #include "ppapi/c/pp_errors.h"
00014 #include "ppapi/c/pp_module.h"
00015 #include "ppapi/c/pp_var.h"
00016 #include "ppapi/c/ppb.h"
00017 #include "ppapi/c/ppb_core.h"
00018 #include "ppapi/c/ppb_file_ref.h"
00019 #include "ppapi/c/ppb_instance.h"
00020 #include "ppapi/c/ppb_messaging.h"
00021 #include "ppapi/c/ppb_url_loader.h"
00022 #include "ppapi/c/ppb_url_request_info.h"
00023 #include "ppapi/c/ppb_url_response_info.h"
00024 #include "ppapi/c/ppb_var.h"
00025 #include "ppapi/c/ppp.h"
00026 #include "ppapi/c/ppp_instance.h"
00027 #include "ppapi/c/ppp_messaging.h"
00028 
00029 #include "verconf.h"
00030 #include "ruby/ruby.h"
00031 #include "version.h"
00032 #include "gc.h"
00033 
00034 #ifdef HAVE_STRUCT_PPB_CORE
00035 typedef struct PPB_Core PPB_Core;
00036 #endif
00037 #ifdef HAVE_STRUCT_PPB_MESSAGING
00038 typedef struct PPB_Messaging PPB_Messaging;
00039 #endif
00040 #ifdef HAVE_STRUCT_PPB_VAR
00041 typedef struct PPB_Var PPB_Var;
00042 #endif
00043 #ifdef HAVE_STRUCT_PPB_URLLOADER
00044 typedef struct PPB_URLLoader PPB_URLLoader;
00045 #endif
00046 #ifdef HAVE_STRUCT_PPB_URLREQUESTINFO
00047 typedef struct PPB_URLRequestInfo PPB_URLRequestInfo;
00048 #endif
00049 #ifdef HAVE_STRUCT_PPB_URLRESPONSEINFO
00050 typedef struct PPB_URLResponseInfo PPB_URLResponseInfo;
00051 #endif
00052 #ifdef HAVE_STRUCT_PPP_INSTANCE
00053 typedef struct PPP_Instance PPP_Instance;
00054 #endif
00055 
00056 static PP_Module module_id = 0;
00057 static PPB_Core* core_interface = NULL;
00058 static PPB_Messaging* messaging_interface = NULL;
00059 static PPB_Var* var_interface = NULL;
00060 static PPB_URLLoader* loader_interface = NULL;
00061 static PPB_URLRequestInfo* request_interface = NULL;
00062 static PPB_URLResponseInfo* response_interface = NULL;
00063 static PPB_FileRef* fileref_interface = NULL;
00064 static struct st_table* instance_data = NULL;
00065 
00066 static VALUE instance_table = Qundef;
00067 
00068 static PP_Instance current_instance = 0;
00069 
00070 /******************************************************************************
00071  * State of instance
00072  ******************************************************************************/
00073 
00074 static void inst_mark(void *const ptr);
00075 static void inst_free(void *const ptr);
00076 static size_t inst_memsize(void *const ptr);
00077 static const rb_data_type_t pepper_instance_data_type = {
00078   "PepperInstance",
00079   { inst_mark, inst_free, inst_memsize }
00080 };
00081 
00082 struct PepperInstance {
00083   PP_Instance instance;
00084   PP_Resource url_loader;
00085   VALUE self;
00086   void* async_call_args;
00087   union {
00088     int32_t as_int;
00089     const char* as_str;
00090     VALUE as_value;
00091   } async_call_result;
00092   char buf[1000];
00093 
00094   pthread_t th;
00095   pthread_mutex_t mutex;
00096   pthread_cond_t cond;
00097 };
00098 
00099 struct PepperInstance*
00100 pruby_get_instance(PP_Instance instance)
00101 {
00102   VALUE self = rb_hash_aref(instance_table, INT2FIX(instance));
00103   if (RTEST(self)) {
00104     struct PepperInstance *inst;
00105     TypedData_Get_Struct(self, struct PepperInstance, &pepper_instance_data_type, inst);
00106     return inst;
00107   }
00108   else {
00109     return NULL;
00110   }
00111 }
00112 
00113 #define GET_PEPPER_INSTANCE() (pruby_get_instance(current_instance))
00114 
00115 struct PepperInstance*
00116 pruby_register_instance(PP_Instance instance)
00117 {
00118   VALUE obj;
00119   struct PepperInstance *data;
00120   obj = TypedData_Make_Struct(rb_cData, struct PepperInstance, &pepper_instance_data_type, data);
00121   data->self = obj;
00122   data->instance = instance;
00123   data->url_loader = 0;
00124 
00125   pthread_mutex_init(&data->mutex, NULL);
00126   pthread_cond_init(&data->cond, NULL);
00127 
00128   rb_hash_aset(instance_table, INT2FIX(instance), obj);
00129   return data;
00130 }
00131 
00132 int
00133 pruby_unregister_instance(PP_Instance instance)
00134 {
00135   VALUE inst = rb_hash_delete(instance_table, INT2FIX(instance));
00136   return RTEST(inst);
00137 }
00138 
00139 static void
00140 inst_mark(void *const ptr)
00141 {
00142   RUBY_MARK_ENTER("PepperInstance"0);
00143   if (ptr) {
00144     const struct PepperInstance* inst = (struct PepperInstance*)ptr;
00145     RUBY_MARK_UNLESS_NULL(inst->async_call_result.as_value);
00146   }
00147   RUBY_MARK_LEAVE("PepperInstance"0);
00148 }
00149 
00150 static void
00151 inst_free(void *const ptr)
00152 {
00153   ruby_xfree(ptr);
00154 }
00155 
00156 static size_t
00157 inst_memsize(void *const ptr)
00158 {
00159   if (ptr) {
00160     const struct PepperInstance* inst = (struct PepperInstance*)ptr;
00161     return sizeof(*inst);
00162   } else {
00163     return 0;
00164   }
00165 }
00166 
00167 void
00168 pruby_async_return_int(void* data, int32_t result)
00169 {
00170   /* PPAPI main thread */
00171   struct PepperInstance* const instance = (struct PepperInstance*)data;
00172   instance->async_call_result.as_int = result;
00173   if (pthread_cond_signal(&instance->cond)) {
00174     perror("pepper-ruby:pthread_cond_signal");
00175   }
00176 }
00177 
00178 void
00179 pruby_async_return_str(void* data, const char *result)
00180 {
00181   /* PPAPI main thread */
00182   struct PepperInstance* const instance = (struct PepperInstance*)data;
00183   instance->async_call_result.as_str = result;
00184   if (pthread_cond_signal(&instance->cond)) {
00185     perror("pepper-ruby:pthread_cond_signal");
00186   }
00187 }
00188 
00189 void
00190 pruby_async_return_value(void* data, VALUE value)
00191 {
00192   /* PPAPI main thread */
00193   struct PepperInstance* const instance = (struct PepperInstance*)data;
00194   instance->async_call_result.as_value = value;
00195   if (pthread_cond_signal(&instance->cond)) {
00196     perror("pepper-ruby:pthread_cond_signal");
00197   }
00198 }
00199 /******************************************************************************
00200  * Conversion between Ruby's VALUE, Pepper's Var and C string
00201  ******************************************************************************/
00202 
00210 static struct PP_Var
00211 pruby_cstr_to_var(const char* str)
00212 {
00213 #ifdef PPB_VAR_INTERFACE_1_0
00214   if (var_interface != NULL)
00215     return var_interface->VarFromUtf8(module_id, str, strlen(str));
00216   return PP_MakeUndefined();
00217 #else
00218   return var_interface->VarFromUtf8(str, strlen(str));
00219 #endif
00220 }
00221 
00232 static char*
00233 pruby_var_to_cstr(struct PP_Var var)
00234 {
00235   uint32_t len = 0;
00236   if (var_interface != NULL) {
00237     const char* var_c_str = var_interface->VarToUtf8(var, &len);
00238     if (len > 0) {
00239       char* c_str = (char*)malloc(len + 1);
00240       memcpy(c_str, var_c_str, len);
00241       c_str[len] = '\0';
00242       return c_str;
00243     }
00244   }
00245   return NULL;
00246 }
00247 
00248 static struct PP_Var
00249 pruby_str_to_var(volatile VALUE str)
00250 {
00251   if (!RB_TYPE_P(str, T_STRING)) {
00252     fprintf(stderr, "[BUG] Unexpected object type: %x\n", TYPE(str));
00253     exit(EXIT_FAILURE);
00254   }
00255 #ifdef PPB_VAR_INTERFACE_1_0
00256   if (var_interface != NULL) {
00257     return var_interface->VarFromUtf8(module_id, RSTRING_PTR(str), RSTRING_LEN(str));
00258   }
00259 #else
00260   return var_interface->VarFromUtf8(RSTRING_PTR(str), RSTRING_LEN(str));
00261 #endif
00262   return PP_MakeUndefined();
00263 }
00264 
00265 static struct PP_Var
00266 pruby_obj_to_var(volatile VALUE obj)
00267 {
00268   static const char* const error =
00269       "throw 'Failed to convert the result to a JavaScript object';";
00270   int state;
00271   obj = rb_protect(&rb_obj_as_string, obj, &state);
00272   if (!state) {
00273       return pruby_str_to_var(obj);
00274   }
00275   else {
00276       return pruby_cstr_to_var(error);
00277   }
00278 }
00279 
00280 int
00281 pruby_var_equal_to_cstr_p(struct PP_Var lhs, const char* rhs)
00282 {
00283   uint32_t len = 0;
00284   if (var_interface == NULL) {
00285     return 0;
00286   }
00287   else {
00288     const char* const cstr = var_interface->VarToUtf8(lhs, &len);
00289     return strncmp(cstr, rhs, len) == 0;
00290   }
00291 }
00292 
00293 int
00294 pruby_var_prefixed_p(struct PP_Var var, const char* prefix)
00295 {
00296   uint32_t len = 0;
00297   if (var_interface == NULL) {
00298     return 0;
00299   }
00300   else {
00301     const char* const cstr = var_interface->VarToUtf8(var, &len);
00302     const size_t prefix_len = strlen(prefix);
00303     return len >= prefix_len && memcmp(cstr, prefix, len) == 0;
00304   }
00305 }
00306 
00307 
00308 /******************************************************************************
00309  * Messaging
00310  ******************************************************************************/
00311 
00312 /* Posts the given C string as a message.
00313  * @param data pointer to a NULL-terminated string */
00314 void
00315 pruby_post_cstr(void* data)
00316 {
00317   /* PPAPI main thread */
00318   struct PepperInstance* const instance = (struct PepperInstance*)data;
00319   const char* const msg = (const char*)instance->async_call_args;
00320   messaging_interface->PostMessage(instance->instance,
00321                                    pruby_cstr_to_var(msg));
00322 }
00323 
00324 /* Posts the given Ruby VALUE as a message.
00325  * @param data a VALUE casted to void* */
00326 void
00327 pruby_post_value(void* data)
00328 {
00329   /* PPAPI main thread */
00330   struct PepperInstance* const instance = (struct PepperInstance*)data;
00331   volatile VALUE value = (VALUE)instance->async_call_args;
00332   messaging_interface->PostMessage(instance->instance, pruby_obj_to_var(value));
00333 }
00334 
00335 
00336 
00337 /******************************************************************************
00338  * Ruby initialization
00339  ******************************************************************************/
00340 
00341 static void
00342 init_loadpath(void)
00343 {
00344   ruby_incpush("lib/ruby/"RUBY_LIB_VERSION);
00345   ruby_incpush("lib/ruby/"RUBY_LIB_VERSION"/"RUBY_PLATFORM);
00346   ruby_incpush(".");
00347 }
00348 
00349 static VALUE
00350 init_libraries_internal(VALUE unused)
00351 {
00352   extern void Init_enc();
00353   extern void Init_ext();
00354 
00355   init_loadpath();
00356   Init_enc();
00357   Init_ext();
00358   return Qnil;
00359 }
00360 
00361 static void*
00362 init_libraries(void* data)
00363 {
00364   int state;
00365   struct PepperInstance* const instance = (struct PepperInstance*)data;
00366   current_instance = instance->instance;
00367 
00368   if (pthread_mutex_lock(&instance->mutex)) {
00369     perror("pepper-ruby:pthread_mutex_lock");
00370     return 0;
00371   }
00372   rb_protect(&init_libraries_internal, Qnil, &state);
00373   pthread_mutex_unlock(&instance->mutex);
00374 
00375   if (state) {
00376     volatile VALUE err = rb_errinfo();
00377     err = rb_obj_as_string(err);
00378   } else {
00379     instance->async_call_args = (void*)"rubyReady";
00380     core_interface->CallOnMainThread(
00381         0, PP_MakeCompletionCallback(pruby_post_cstr, instance), 0);
00382   }
00383   return NULL;
00384 }
00385 
00386 static int
00387 init_libraries_if_necessary(void)
00388 {
00389   static int initialized = 0;
00390   if (!initialized) {
00391     struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
00392     int err;
00393     initialized = 1;
00394     err = pthread_create(&instance->th, NULL, &init_libraries, instance);
00395     if (err) {
00396       fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
00397       exit(EXIT_FAILURE);
00398     }
00399     pthread_detach(instance->th);
00400   }
00401   return 0;
00402 }
00403 
00404 static int
00405 pruby_init(void)
00406 {
00407   RUBY_INIT_STACK;
00408   ruby_init();
00409 
00410   instance_table = rb_hash_new();
00411   rb_gc_register_mark_object(instance_table);
00412 
00413   return 0;
00414 }
00415 
00416 
00417 /******************************************************************************
00418  * Ruby evaluation
00419  ******************************************************************************/
00420 
00421 static void*
00422 pruby_eval(void* data)
00423 {
00424   extern VALUE ruby_eval_string_from_file_protect(const char* src, const char* path, int* state);
00425   struct PepperInstance* const instance = (struct PepperInstance*)data;
00426   volatile VALUE src = (VALUE)instance->async_call_args;
00427   volatile VALUE result = Qnil;
00428   volatile int state;
00429 
00430   RUBY_INIT_STACK;
00431 
00432   if (pthread_mutex_lock(&instance->mutex)) {
00433     perror("pepper-ruby:pthread_mutex_lock");
00434     return 0;
00435   }
00436   result = ruby_eval_string_from_file_protect(
00437       RSTRING_PTR(src), "(pepper-ruby)", &state);
00438   pthread_mutex_unlock(&instance->mutex);
00439 
00440   if (!state) {
00441       instance->async_call_args =
00442           rb_str_concat(rb_usascii_str_new_cstr("return:"),
00443                         rb_obj_as_string(result));
00444       core_interface->CallOnMainThread(
00445           0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
00446       return NULL;
00447   }
00448   else {
00449       rb_set_errinfo(Qnil);
00450       instance->async_call_args =
00451           rb_str_concat(rb_usascii_str_new_cstr("error:"),
00452                         rb_obj_as_string(result));
00453       core_interface->CallOnMainThread(
00454           0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
00455       return NULL;
00456   }
00457 }
00458 
00459 
00460 /******************************************************************************
00461  * Pepper Module callbacks
00462  ******************************************************************************/
00463 
00486 static PP_Bool
00487 Instance_DidCreate(PP_Instance instance,
00488                    uint32_t argc, const char* argn[], const char* argv[])
00489 {
00490   struct PepperInstance* data = pruby_register_instance(instance);
00491   current_instance = instance;
00492   return init_libraries_if_necessary() ? PP_FALSE : PP_TRUE;
00493 }
00494 
00502 static void Instance_DidDestroy(PP_Instance instance) {
00503   struct PepperInstance* data = pruby_get_instance(instance);
00504   core_interface->ReleaseResource(data->url_loader);
00505   pruby_unregister_instance(instance);
00506 }
00507 
00520 #ifdef PPP_INSTANCE_INTERFACE_1_0
00521 static void
00522 Instance_DidChangeView(PP_Instance instance,
00523                        const struct PP_Rect* position,
00524                        const struct PP_Rect* clip)
00525 {
00526 }
00527 #else
00528 static void
00529 Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource)
00530 {
00531 }
00532 #endif
00533 
00551 static void
00552 Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus)
00553 {
00554 }
00555 
00566 static PP_Bool
00567 Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader)
00568 {
00569   /* NaCl modules do not need to handle the document load function. */
00570   return PP_FALSE;
00571 }
00572 
00573 
00589 void
00590 Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message)
00591 {
00592   char* const message = pruby_var_to_cstr(var_message);
00593   size_t message_len = strlen(message);
00594   current_instance = instance;
00595 
00596   if (strstr(message, "eval:") != NULL) {
00597     volatile VALUE src;
00598     struct PepperInstance* const instance_data = GET_PEPPER_INSTANCE();
00599     int err;
00600 #define EVAL_PREFIX_LEN 5
00601     src = rb_str_new(message + EVAL_PREFIX_LEN, message_len - EVAL_PREFIX_LEN);
00602     instance_data->async_call_args = (void*)src;
00603     err = pthread_create(&instance_data->th, NULL, &pruby_eval, instance_data);
00604     if (err) {
00605       fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
00606       exit(EXIT_FAILURE);
00607     }
00608     pthread_detach(instance_data->th);
00609   }
00610   free(message);
00611 }
00612 
00620 PP_EXPORT int32_t
00621 PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser_interface)
00622 {
00623   module_id = a_module_id;
00624   core_interface = (PPB_Core*)(get_browser_interface(PPB_CORE_INTERFACE));
00625   if (core_interface == NULL) return PP_ERROR_NOINTERFACE;
00626 
00627   var_interface = (PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE));
00628   if (var_interface == NULL) return PP_ERROR_NOINTERFACE;
00629 
00630   messaging_interface = (PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE));
00631   if (messaging_interface == NULL) return PP_ERROR_NOINTERFACE;
00632 
00633   loader_interface = (PPB_URLLoader*)(get_browser_interface(PPB_URLLOADER_INTERFACE));
00634   if (loader_interface == NULL) return PP_ERROR_NOINTERFACE;
00635 
00636   request_interface = (PPB_URLRequestInfo*)(get_browser_interface(PPB_URLREQUESTINFO_INTERFACE));
00637   if (request_interface == NULL) return PP_ERROR_NOINTERFACE;
00638 
00639   response_interface = (PPB_URLResponseInfo*)(get_browser_interface(PPB_URLRESPONSEINFO_INTERFACE));
00640   if (response_interface == NULL) return PP_ERROR_NOINTERFACE;
00641 
00642   fileref_interface = (PPB_FileRef*)(get_browser_interface(PPB_FILEREF_INTERFACE));
00643   if (fileref_interface == NULL) return PP_ERROR_NOINTERFACE;
00644 
00645   return pruby_init() ? PP_ERROR_FAILED : PP_OK;
00646 }
00647 
00654 PP_EXPORT const void*
00655 PPP_GetInterface(const char* interface_name)
00656 {
00657   if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
00658     static PPP_Instance instance_interface = {
00659       &Instance_DidCreate,
00660       &Instance_DidDestroy,
00661       &Instance_DidChangeView,
00662       &Instance_DidChangeFocus,
00663       &Instance_HandleDocumentLoad
00664     };
00665     return &instance_interface;
00666   } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
00667     static PPP_Messaging messaging_interface = {
00668       &Messaging_HandleMessage
00669     };
00670     return &messaging_interface;
00671   }
00672   return NULL;
00673 }
00674 
00678 PP_EXPORT void
00679 PPP_ShutdownModule()
00680 {
00681   ruby_cleanup(0);
00682 }
00683 
00684 /******************************************************************************
00685  * Overwrites rb_file_load_ok
00686  ******************************************************************************/
00687 
00688 static void
00689 load_ok_internal(void* data, int32_t unused)
00690 {
00691   /* PPAPI main thread */
00692   struct PepperInstance* const instance = (struct PepperInstance*)data;
00693   const char *const path = (const char*)instance->async_call_args;
00694   PP_Resource req;
00695   int result;
00696 
00697   instance->url_loader = loader_interface->Create(instance->instance);
00698   req = request_interface->Create(instance->instance);
00699   request_interface->SetProperty(
00700       req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("HEAD"));
00701   request_interface->SetProperty(
00702       req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path));
00703 
00704   result = loader_interface->Open(
00705       instance->url_loader, req,
00706       PP_MakeCompletionCallback(pruby_async_return_int, instance));
00707   if (result != PP_OK_COMPLETIONPENDING) {
00708     pruby_async_return_int(instance, result);
00709   }
00710 }
00711 
00712 static void
00713 pruby_file_fetch_check_response(void* data, int32_t unused)
00714 {
00715   /* PPAPI main thread */
00716   PP_Resource res;
00717   struct PepperInstance* const instance = (struct PepperInstance*)data;
00718 
00719   res = loader_interface->GetResponseInfo(instance->url_loader);
00720   if (res) {
00721     struct PP_Var status =
00722         response_interface->GetProperty(res, PP_URLRESPONSEPROPERTY_STATUSCODE);
00723     if (status.type == PP_VARTYPE_INT32) {
00724       pruby_async_return_int(instance, status.value.as_int / 100 == 2 ? PP_OK : PP_ERROR_FAILED);
00725       return;
00726     }
00727     else {
00728       messaging_interface->PostMessage(
00729           instance->instance, pruby_cstr_to_var("Unexpected type: ResponseInfoInterface::GetProperty"));
00730     }
00731   }
00732   else {
00733     messaging_interface->PostMessage(
00734         instance->instance, pruby_cstr_to_var("Failed to open URL: URLLoaderInterface::GetResponseInfo"));
00735   }
00736   pruby_async_return_int(instance, PP_ERROR_FAILED);
00737 }
00738 
00739 
00740 int
00741 rb_file_load_ok(const char *path)
00742 {
00743   struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
00744   if (path[0] == '.' && path[1] == '/') path += 2;
00745 
00746   instance->async_call_args = (void*)path;
00747   core_interface->CallOnMainThread(
00748       0, PP_MakeCompletionCallback(load_ok_internal, instance), 0);
00749   if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
00750     perror("pepper-ruby:pthread_cond_wait");
00751     return 0;
00752   }
00753   if (instance->async_call_result.as_int != PP_OK) {
00754     fprintf(stderr, "Failed to open URL: %d: %s\n",
00755             instance->async_call_result.as_int, path);
00756     return 0;
00757   }
00758 
00759   core_interface->CallOnMainThread(
00760       0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0);
00761   if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
00762     perror("pepper-ruby:pthread_cond_wait");
00763     return 0;
00764   }
00765   return instance->async_call_result.as_int == PP_OK;
00766 }
00767 
00768 /******************************************************************************
00769  * Overwrites rb_load_file
00770  ******************************************************************************/
00771 
00772 static void
00773 load_file_internal(void* data, int32_t unused)
00774 {
00775   /* PPAPI main thread */
00776   struct PepperInstance* const instance = (struct PepperInstance*)data;
00777   const char *const path = (const char*)instance->async_call_args;
00778   PP_Resource req;
00779   int result;
00780 
00781   instance->url_loader = loader_interface->Create(instance->instance);
00782   req = request_interface->Create(instance->instance);
00783   request_interface->SetProperty(
00784       req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("GET"));
00785   request_interface->SetProperty(
00786       req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path));
00787 
00788   result = loader_interface->Open(
00789       instance->url_loader, req,
00790       PP_MakeCompletionCallback(pruby_async_return_int, instance));
00791   if (result != PP_OK_COMPLETIONPENDING) {
00792     pruby_async_return_int(instance, result);
00793   }
00794 }
00795 
00796 static void
00797 load_file_read_contents_callback(void *data, int result)
00798 {
00799   struct PepperInstance* const instance = (struct PepperInstance*)data;
00800   if (result > 0) {
00801     rb_str_buf_cat(instance->async_call_result.as_value,
00802                    instance->buf, result);
00803     loader_interface->ReadResponseBody(
00804         instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance));
00805   }
00806   else if (result == 0) {
00807     pruby_async_return_value(data, instance->async_call_result.as_value);
00808   }
00809   else {
00810     pruby_async_return_value(data, INT2FIX(result));
00811   }
00812 }
00813 
00814 static void
00815 load_file_read_contents(void *data, int result)
00816 {
00817   struct PepperInstance* const instance = (struct PepperInstance*)data;
00818   instance->async_call_result.as_value = rb_str_new(0, 0);
00819   loader_interface->ReadResponseBody(
00820       instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance));
00821 }
00822 
00823 void*
00824 rb_load_file(const char *path)
00825 {
00826   const char *real_path;
00827   struct PepperInstance* instance;
00828   if (path[0] != '.' || path[1] != '/') path += 2;
00829 
00830   instance = GET_PEPPER_INSTANCE();
00831 
00832   instance->async_call_args = (void*)path;
00833   core_interface->CallOnMainThread(
00834       0, PP_MakeCompletionCallback(load_file_internal, instance), 0);
00835   if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
00836     perror("pepper-ruby:pthread_cond_wait");
00837     return 0;
00838   }
00839   if (instance->async_call_result.as_int != PP_OK) {
00840     fprintf(stderr, "Failed to open URL: %d: %s\n",
00841             instance->async_call_result.as_int, path);
00842     return 0;
00843   }
00844 
00845   core_interface->CallOnMainThread(
00846       0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0);
00847   if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
00848     perror("pepper-ruby:pthread_cond_wait");
00849     return 0;
00850   }
00851   if (instance->async_call_result.as_int != PP_OK) return 0;
00852 
00853   core_interface->CallOnMainThread(
00854       0, PP_MakeCompletionCallback(load_file_read_contents, instance), 0);
00855   if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
00856     perror("pepper-ruby:pthread_cond_wait");
00857     return 0;
00858   }
00859   if (FIXNUM_P(instance->async_call_result.as_value)) {
00860     return 0;
00861   }
00862   else if (RB_TYPE_P(instance->async_call_result.as_value, T_STRING)) {
00863     VALUE str = instance->async_call_result.as_value;
00864     extern void* rb_compile_cstr(const char *f, const char *s, int len, int line);
00865     return rb_compile_cstr(path, RSTRING_PTR(str), RSTRING_LEN(str), 0);
00866   }
00867   else {
00868     return 0;
00869   }
00870 }
00871