Home | History | Annotate | Download | only in samples
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <include/v8.h>
     29 
     30 #include <include/libplatform/libplatform.h>
     31 
     32 #include <map>
     33 #include <string>
     34 
     35 #ifdef COMPRESS_STARTUP_DATA_BZ2
     36 #error Using compressed startup data is not supported for this sample
     37 #endif
     38 
     39 using namespace std;
     40 using namespace v8;
     41 
     42 // These interfaces represent an existing request processing interface.
     43 // The idea is to imagine a real application that uses these interfaces
     44 // and then add scripting capabilities that allow you to interact with
     45 // the objects through JavaScript.
     46 
     47 /**
     48  * A simplified http request.
     49  */
     50 class HttpRequest {
     51  public:
     52   virtual ~HttpRequest() { }
     53   virtual const string& Path() = 0;
     54   virtual const string& Referrer() = 0;
     55   virtual const string& Host() = 0;
     56   virtual const string& UserAgent() = 0;
     57 };
     58 
     59 
     60 /**
     61  * The abstract superclass of http request processors.
     62  */
     63 class HttpRequestProcessor {
     64  public:
     65   virtual ~HttpRequestProcessor() { }
     66 
     67   // Initialize this processor.  The map contains options that control
     68   // how requests should be processed.
     69   virtual bool Initialize(map<string, string>* options,
     70                           map<string, string>* output) = 0;
     71 
     72   // Process a single request.
     73   virtual bool Process(HttpRequest* req) = 0;
     74 
     75   static void Log(const char* event);
     76 };
     77 
     78 
     79 /**
     80  * An http request processor that is scriptable using JavaScript.
     81  */
     82 class JsHttpRequestProcessor : public HttpRequestProcessor {
     83  public:
     84   // Creates a new processor that processes requests by invoking the
     85   // Process function of the JavaScript script given as an argument.
     86   JsHttpRequestProcessor(Isolate* isolate, Handle<String> script)
     87       : isolate_(isolate), script_(script) { }
     88   virtual ~JsHttpRequestProcessor();
     89 
     90   virtual bool Initialize(map<string, string>* opts,
     91                           map<string, string>* output);
     92   virtual bool Process(HttpRequest* req);
     93 
     94  private:
     95   // Execute the script associated with this processor and extract the
     96   // Process function.  Returns true if this succeeded, otherwise false.
     97   bool ExecuteScript(Handle<String> script);
     98 
     99   // Wrap the options and output map in a JavaScript objects and
    100   // install it in the global namespace as 'options' and 'output'.
    101   bool InstallMaps(map<string, string>* opts, map<string, string>* output);
    102 
    103   // Constructs the template that describes the JavaScript wrapper
    104   // type for requests.
    105   static Handle<ObjectTemplate> MakeRequestTemplate(Isolate* isolate);
    106   static Handle<ObjectTemplate> MakeMapTemplate(Isolate* isolate);
    107 
    108   // Callbacks that access the individual fields of request objects.
    109   static void GetPath(Local<String> name,
    110                       const PropertyCallbackInfo<Value>& info);
    111   static void GetReferrer(Local<String> name,
    112                           const PropertyCallbackInfo<Value>& info);
    113   static void GetHost(Local<String> name,
    114                       const PropertyCallbackInfo<Value>& info);
    115   static void GetUserAgent(Local<String> name,
    116                            const PropertyCallbackInfo<Value>& info);
    117 
    118   // Callbacks that access maps
    119   static void MapGet(Local<String> name,
    120                      const PropertyCallbackInfo<Value>& info);
    121   static void MapSet(Local<String> name,
    122                      Local<Value> value,
    123                      const PropertyCallbackInfo<Value>& info);
    124 
    125   // Utility methods for wrapping C++ objects as JavaScript objects,
    126   // and going back again.
    127   Handle<Object> WrapMap(map<string, string>* obj);
    128   static map<string, string>* UnwrapMap(Handle<Object> obj);
    129   Handle<Object> WrapRequest(HttpRequest* obj);
    130   static HttpRequest* UnwrapRequest(Handle<Object> obj);
    131 
    132   Isolate* GetIsolate() { return isolate_; }
    133 
    134   Isolate* isolate_;
    135   Handle<String> script_;
    136   Persistent<Context> context_;
    137   Persistent<Function> process_;
    138   static Persistent<ObjectTemplate> request_template_;
    139   static Persistent<ObjectTemplate> map_template_;
    140 };
    141 
    142 
    143 // -------------------------
    144 // --- P r o c e s s o r ---
    145 // -------------------------
    146 
    147 
    148 static void LogCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    149   if (args.Length() < 1) return;
    150   HandleScope scope(args.GetIsolate());
    151   Handle<Value> arg = args[0];
    152   String::Utf8Value value(arg);
    153   HttpRequestProcessor::Log(*value);
    154 }
    155 
    156 
    157 // Execute the script and fetch the Process method.
    158 bool JsHttpRequestProcessor::Initialize(map<string, string>* opts,
    159                                         map<string, string>* output) {
    160   // Create a handle scope to hold the temporary references.
    161   HandleScope handle_scope(GetIsolate());
    162 
    163   // Create a template for the global object where we set the
    164   // built-in global functions.
    165   Handle<ObjectTemplate> global = ObjectTemplate::New(GetIsolate());
    166   global->Set(String::NewFromUtf8(GetIsolate(), "log"),
    167               FunctionTemplate::New(GetIsolate(), LogCallback));
    168 
    169   // Each processor gets its own context so different processors don't
    170   // affect each other. Context::New returns a persistent handle which
    171   // is what we need for the reference to remain after we return from
    172   // this method. That persistent handle has to be disposed in the
    173   // destructor.
    174   v8::Handle<v8::Context> context = Context::New(GetIsolate(), NULL, global);
    175   context_.Reset(GetIsolate(), context);
    176 
    177   // Enter the new context so all the following operations take place
    178   // within it.
    179   Context::Scope context_scope(context);
    180 
    181   // Make the options mapping available within the context
    182   if (!InstallMaps(opts, output))
    183     return false;
    184 
    185   // Compile and run the script
    186   if (!ExecuteScript(script_))
    187     return false;
    188 
    189   // The script compiled and ran correctly.  Now we fetch out the
    190   // Process function from the global object.
    191   Handle<String> process_name = String::NewFromUtf8(GetIsolate(), "Process");
    192   Handle<Value> process_val = context->Global()->Get(process_name);
    193 
    194   // If there is no Process function, or if it is not a function,
    195   // bail out
    196   if (!process_val->IsFunction()) return false;
    197 
    198   // It is a function; cast it to a Function
    199   Handle<Function> process_fun = Handle<Function>::Cast(process_val);
    200 
    201   // Store the function in a Persistent handle, since we also want
    202   // that to remain after this call returns
    203   process_.Reset(GetIsolate(), process_fun);
    204 
    205   // All done; all went well
    206   return true;
    207 }
    208 
    209 
    210 bool JsHttpRequestProcessor::ExecuteScript(Handle<String> script) {
    211   HandleScope handle_scope(GetIsolate());
    212 
    213   // We're just about to compile the script; set up an error handler to
    214   // catch any exceptions the script might throw.
    215   TryCatch try_catch;
    216 
    217   // Compile the script and check for errors.
    218   Handle<Script> compiled_script = Script::Compile(script);
    219   if (compiled_script.IsEmpty()) {
    220     String::Utf8Value error(try_catch.Exception());
    221     Log(*error);
    222     // The script failed to compile; bail out.
    223     return false;
    224   }
    225 
    226   // Run the script!
    227   Handle<Value> result = compiled_script->Run();
    228   if (result.IsEmpty()) {
    229     // The TryCatch above is still in effect and will have caught the error.
    230     String::Utf8Value error(try_catch.Exception());
    231     Log(*error);
    232     // Running the script failed; bail out.
    233     return false;
    234   }
    235   return true;
    236 }
    237 
    238 
    239 bool JsHttpRequestProcessor::InstallMaps(map<string, string>* opts,
    240                                          map<string, string>* output) {
    241   HandleScope handle_scope(GetIsolate());
    242 
    243   // Wrap the map object in a JavaScript wrapper
    244   Handle<Object> opts_obj = WrapMap(opts);
    245 
    246   v8::Local<v8::Context> context =
    247       v8::Local<v8::Context>::New(GetIsolate(), context_);
    248 
    249   // Set the options object as a property on the global object.
    250   context->Global()->Set(String::NewFromUtf8(GetIsolate(), "options"),
    251                          opts_obj);
    252 
    253   Handle<Object> output_obj = WrapMap(output);
    254   context->Global()->Set(String::NewFromUtf8(GetIsolate(), "output"),
    255                          output_obj);
    256 
    257   return true;
    258 }
    259 
    260 
    261 bool JsHttpRequestProcessor::Process(HttpRequest* request) {
    262   // Create a handle scope to keep the temporary object references.
    263   HandleScope handle_scope(GetIsolate());
    264 
    265   v8::Local<v8::Context> context =
    266       v8::Local<v8::Context>::New(GetIsolate(), context_);
    267 
    268   // Enter this processor's context so all the remaining operations
    269   // take place there
    270   Context::Scope context_scope(context);
    271 
    272   // Wrap the C++ request object in a JavaScript wrapper
    273   Handle<Object> request_obj = WrapRequest(request);
    274 
    275   // Set up an exception handler before calling the Process function
    276   TryCatch try_catch;
    277 
    278   // Invoke the process function, giving the global object as 'this'
    279   // and one argument, the request.
    280   const int argc = 1;
    281   Handle<Value> argv[argc] = { request_obj };
    282   v8::Local<v8::Function> process =
    283       v8::Local<v8::Function>::New(GetIsolate(), process_);
    284   Handle<Value> result = process->Call(context->Global(), argc, argv);
    285   if (result.IsEmpty()) {
    286     String::Utf8Value error(try_catch.Exception());
    287     Log(*error);
    288     return false;
    289   } else {
    290     return true;
    291   }
    292 }
    293 
    294 
    295 JsHttpRequestProcessor::~JsHttpRequestProcessor() {
    296   // Dispose the persistent handles.  When noone else has any
    297   // references to the objects stored in the handles they will be
    298   // automatically reclaimed.
    299   context_.Reset();
    300   process_.Reset();
    301 }
    302 
    303 
    304 Persistent<ObjectTemplate> JsHttpRequestProcessor::request_template_;
    305 Persistent<ObjectTemplate> JsHttpRequestProcessor::map_template_;
    306 
    307 
    308 // -----------------------------------
    309 // --- A c c e s s i n g   M a p s ---
    310 // -----------------------------------
    311 
    312 // Utility function that wraps a C++ http request object in a
    313 // JavaScript object.
    314 Handle<Object> JsHttpRequestProcessor::WrapMap(map<string, string>* obj) {
    315   // Handle scope for temporary handles.
    316   EscapableHandleScope handle_scope(GetIsolate());
    317 
    318   // Fetch the template for creating JavaScript map wrappers.
    319   // It only has to be created once, which we do on demand.
    320   if (map_template_.IsEmpty()) {
    321     Handle<ObjectTemplate> raw_template = MakeMapTemplate(GetIsolate());
    322     map_template_.Reset(GetIsolate(), raw_template);
    323   }
    324   Handle<ObjectTemplate> templ =
    325       Local<ObjectTemplate>::New(GetIsolate(), map_template_);
    326 
    327   // Create an empty map wrapper.
    328   Local<Object> result = templ->NewInstance();
    329 
    330   // Wrap the raw C++ pointer in an External so it can be referenced
    331   // from within JavaScript.
    332   Handle<External> map_ptr = External::New(GetIsolate(), obj);
    333 
    334   // Store the map pointer in the JavaScript wrapper.
    335   result->SetInternalField(0, map_ptr);
    336 
    337   // Return the result through the current handle scope.  Since each
    338   // of these handles will go away when the handle scope is deleted
    339   // we need to call Close to let one, the result, escape into the
    340   // outer handle scope.
    341   return handle_scope.Escape(result);
    342 }
    343 
    344 
    345 // Utility function that extracts the C++ map pointer from a wrapper
    346 // object.
    347 map<string, string>* JsHttpRequestProcessor::UnwrapMap(Handle<Object> obj) {
    348   Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
    349   void* ptr = field->Value();
    350   return static_cast<map<string, string>*>(ptr);
    351 }
    352 
    353 
    354 // Convert a JavaScript string to a std::string.  To not bother too
    355 // much with string encodings we just use ascii.
    356 string ObjectToString(Local<Value> value) {
    357   String::Utf8Value utf8_value(value);
    358   return string(*utf8_value);
    359 }
    360 
    361 
    362 void JsHttpRequestProcessor::MapGet(Local<String> name,
    363                                     const PropertyCallbackInfo<Value>& info) {
    364   // Fetch the map wrapped by this object.
    365   map<string, string>* obj = UnwrapMap(info.Holder());
    366 
    367   // Convert the JavaScript string to a std::string.
    368   string key = ObjectToString(name);
    369 
    370   // Look up the value if it exists using the standard STL ideom.
    371   map<string, string>::iterator iter = obj->find(key);
    372 
    373   // If the key is not present return an empty handle as signal
    374   if (iter == obj->end()) return;
    375 
    376   // Otherwise fetch the value and wrap it in a JavaScript string
    377   const string& value = (*iter).second;
    378   info.GetReturnValue().Set(String::NewFromUtf8(
    379       info.GetIsolate(), value.c_str(), String::kNormalString,
    380       static_cast<int>(value.length())));
    381 }
    382 
    383 
    384 void JsHttpRequestProcessor::MapSet(Local<String> name,
    385                                     Local<Value> value_obj,
    386                                     const PropertyCallbackInfo<Value>& info) {
    387   // Fetch the map wrapped by this object.
    388   map<string, string>* obj = UnwrapMap(info.Holder());
    389 
    390   // Convert the key and value to std::strings.
    391   string key = ObjectToString(name);
    392   string value = ObjectToString(value_obj);
    393 
    394   // Update the map.
    395   (*obj)[key] = value;
    396 
    397   // Return the value; any non-empty handle will work.
    398   info.GetReturnValue().Set(value_obj);
    399 }
    400 
    401 
    402 Handle<ObjectTemplate> JsHttpRequestProcessor::MakeMapTemplate(
    403     Isolate* isolate) {
    404   EscapableHandleScope handle_scope(isolate);
    405 
    406   Local<ObjectTemplate> result = ObjectTemplate::New(isolate);
    407   result->SetInternalFieldCount(1);
    408   result->SetNamedPropertyHandler(MapGet, MapSet);
    409 
    410   // Again, return the result through the current handle scope.
    411   return handle_scope.Escape(result);
    412 }
    413 
    414 
    415 // -------------------------------------------
    416 // --- A c c e s s i n g   R e q u e s t s ---
    417 // -------------------------------------------
    418 
    419 /**
    420  * Utility function that wraps a C++ http request object in a
    421  * JavaScript object.
    422  */
    423 Handle<Object> JsHttpRequestProcessor::WrapRequest(HttpRequest* request) {
    424   // Handle scope for temporary handles.
    425   EscapableHandleScope handle_scope(GetIsolate());
    426 
    427   // Fetch the template for creating JavaScript http request wrappers.
    428   // It only has to be created once, which we do on demand.
    429   if (request_template_.IsEmpty()) {
    430     Handle<ObjectTemplate> raw_template = MakeRequestTemplate(GetIsolate());
    431     request_template_.Reset(GetIsolate(), raw_template);
    432   }
    433   Handle<ObjectTemplate> templ =
    434       Local<ObjectTemplate>::New(GetIsolate(), request_template_);
    435 
    436   // Create an empty http request wrapper.
    437   Local<Object> result = templ->NewInstance();
    438 
    439   // Wrap the raw C++ pointer in an External so it can be referenced
    440   // from within JavaScript.
    441   Handle<External> request_ptr = External::New(GetIsolate(), request);
    442 
    443   // Store the request pointer in the JavaScript wrapper.
    444   result->SetInternalField(0, request_ptr);
    445 
    446   // Return the result through the current handle scope.  Since each
    447   // of these handles will go away when the handle scope is deleted
    448   // we need to call Close to let one, the result, escape into the
    449   // outer handle scope.
    450   return handle_scope.Escape(result);
    451 }
    452 
    453 
    454 /**
    455  * Utility function that extracts the C++ http request object from a
    456  * wrapper object.
    457  */
    458 HttpRequest* JsHttpRequestProcessor::UnwrapRequest(Handle<Object> obj) {
    459   Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
    460   void* ptr = field->Value();
    461   return static_cast<HttpRequest*>(ptr);
    462 }
    463 
    464 
    465 void JsHttpRequestProcessor::GetPath(Local<String> name,
    466                                      const PropertyCallbackInfo<Value>& info) {
    467   // Extract the C++ request object from the JavaScript wrapper.
    468   HttpRequest* request = UnwrapRequest(info.Holder());
    469 
    470   // Fetch the path.
    471   const string& path = request->Path();
    472 
    473   // Wrap the result in a JavaScript string and return it.
    474   info.GetReturnValue().Set(String::NewFromUtf8(
    475       info.GetIsolate(), path.c_str(), String::kNormalString,
    476       static_cast<int>(path.length())));
    477 }
    478 
    479 
    480 void JsHttpRequestProcessor::GetReferrer(
    481     Local<String> name,
    482     const PropertyCallbackInfo<Value>& info) {
    483   HttpRequest* request = UnwrapRequest(info.Holder());
    484   const string& path = request->Referrer();
    485   info.GetReturnValue().Set(String::NewFromUtf8(
    486       info.GetIsolate(), path.c_str(), String::kNormalString,
    487       static_cast<int>(path.length())));
    488 }
    489 
    490 
    491 void JsHttpRequestProcessor::GetHost(Local<String> name,
    492                                      const PropertyCallbackInfo<Value>& info) {
    493   HttpRequest* request = UnwrapRequest(info.Holder());
    494   const string& path = request->Host();
    495   info.GetReturnValue().Set(String::NewFromUtf8(
    496       info.GetIsolate(), path.c_str(), String::kNormalString,
    497       static_cast<int>(path.length())));
    498 }
    499 
    500 
    501 void JsHttpRequestProcessor::GetUserAgent(
    502     Local<String> name,
    503     const PropertyCallbackInfo<Value>& info) {
    504   HttpRequest* request = UnwrapRequest(info.Holder());
    505   const string& path = request->UserAgent();
    506   info.GetReturnValue().Set(String::NewFromUtf8(
    507       info.GetIsolate(), path.c_str(), String::kNormalString,
    508       static_cast<int>(path.length())));
    509 }
    510 
    511 
    512 Handle<ObjectTemplate> JsHttpRequestProcessor::MakeRequestTemplate(
    513     Isolate* isolate) {
    514   EscapableHandleScope handle_scope(isolate);
    515 
    516   Local<ObjectTemplate> result = ObjectTemplate::New(isolate);
    517   result->SetInternalFieldCount(1);
    518 
    519   // Add accessors for each of the fields of the request.
    520   result->SetAccessor(
    521       String::NewFromUtf8(isolate, "path", String::kInternalizedString),
    522       GetPath);
    523   result->SetAccessor(
    524       String::NewFromUtf8(isolate, "referrer", String::kInternalizedString),
    525       GetReferrer);
    526   result->SetAccessor(
    527       String::NewFromUtf8(isolate, "host", String::kInternalizedString),
    528       GetHost);
    529   result->SetAccessor(
    530       String::NewFromUtf8(isolate, "userAgent", String::kInternalizedString),
    531       GetUserAgent);
    532 
    533   // Again, return the result through the current handle scope.
    534   return handle_scope.Escape(result);
    535 }
    536 
    537 
    538 // --- Test ---
    539 
    540 
    541 void HttpRequestProcessor::Log(const char* event) {
    542   printf("Logged: %s\n", event);
    543 }
    544 
    545 
    546 /**
    547  * A simplified http request.
    548  */
    549 class StringHttpRequest : public HttpRequest {
    550  public:
    551   StringHttpRequest(const string& path,
    552                     const string& referrer,
    553                     const string& host,
    554                     const string& user_agent);
    555   virtual const string& Path() { return path_; }
    556   virtual const string& Referrer() { return referrer_; }
    557   virtual const string& Host() { return host_; }
    558   virtual const string& UserAgent() { return user_agent_; }
    559  private:
    560   string path_;
    561   string referrer_;
    562   string host_;
    563   string user_agent_;
    564 };
    565 
    566 
    567 StringHttpRequest::StringHttpRequest(const string& path,
    568                                      const string& referrer,
    569                                      const string& host,
    570                                      const string& user_agent)
    571     : path_(path),
    572       referrer_(referrer),
    573       host_(host),
    574       user_agent_(user_agent) { }
    575 
    576 
    577 void ParseOptions(int argc,
    578                   char* argv[],
    579                   map<string, string>* options,
    580                   string* file) {
    581   for (int i = 1; i < argc; i++) {
    582     string arg = argv[i];
    583     size_t index = arg.find('=', 0);
    584     if (index == string::npos) {
    585       *file = arg;
    586     } else {
    587       string key = arg.substr(0, index);
    588       string value = arg.substr(index+1);
    589       (*options)[key] = value;
    590     }
    591   }
    592 }
    593 
    594 
    595 // Reads a file into a v8 string.
    596 Handle<String> ReadFile(Isolate* isolate, const string& name) {
    597   FILE* file = fopen(name.c_str(), "rb");
    598   if (file == NULL) return Handle<String>();
    599 
    600   fseek(file, 0, SEEK_END);
    601   int size = ftell(file);
    602   rewind(file);
    603 
    604   char* chars = new char[size + 1];
    605   chars[size] = '\0';
    606   for (int i = 0; i < size;) {
    607     int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
    608     i += read;
    609   }
    610   fclose(file);
    611   Handle<String> result =
    612       String::NewFromUtf8(isolate, chars, String::kNormalString, size);
    613   delete[] chars;
    614   return result;
    615 }
    616 
    617 
    618 const int kSampleSize = 6;
    619 StringHttpRequest kSampleRequests[kSampleSize] = {
    620   StringHttpRequest("/process.cc", "localhost", "google.com", "firefox"),
    621   StringHttpRequest("/", "localhost", "google.net", "firefox"),
    622   StringHttpRequest("/", "localhost", "google.org", "safari"),
    623   StringHttpRequest("/", "localhost", "yahoo.com", "ie"),
    624   StringHttpRequest("/", "localhost", "yahoo.com", "safari"),
    625   StringHttpRequest("/", "localhost", "yahoo.com", "firefox")
    626 };
    627 
    628 
    629 bool ProcessEntries(HttpRequestProcessor* processor, int count,
    630                     StringHttpRequest* reqs) {
    631   for (int i = 0; i < count; i++) {
    632     if (!processor->Process(&reqs[i]))
    633       return false;
    634   }
    635   return true;
    636 }
    637 
    638 
    639 void PrintMap(map<string, string>* m) {
    640   for (map<string, string>::iterator i = m->begin(); i != m->end(); i++) {
    641     pair<string, string> entry = *i;
    642     printf("%s: %s\n", entry.first.c_str(), entry.second.c_str());
    643   }
    644 }
    645 
    646 
    647 int main(int argc, char* argv[]) {
    648   v8::V8::InitializeICU();
    649   v8::Platform* platform = v8::platform::CreateDefaultPlatform();
    650   v8::V8::InitializePlatform(platform);
    651   v8::V8::Initialize();
    652   map<string, string> options;
    653   string file;
    654   ParseOptions(argc, argv, &options, &file);
    655   if (file.empty()) {
    656     fprintf(stderr, "No script was specified.\n");
    657     return 1;
    658   }
    659   Isolate* isolate = Isolate::New();
    660   Isolate::Scope isolate_scope(isolate);
    661   HandleScope scope(isolate);
    662   Handle<String> source = ReadFile(isolate, file);
    663   if (source.IsEmpty()) {
    664     fprintf(stderr, "Error reading '%s'.\n", file.c_str());
    665     return 1;
    666   }
    667   JsHttpRequestProcessor processor(isolate, source);
    668   map<string, string> output;
    669   if (!processor.Initialize(&options, &output)) {
    670     fprintf(stderr, "Error initializing processor.\n");
    671     return 1;
    672   }
    673   if (!ProcessEntries(&processor, kSampleSize, kSampleRequests))
    674     return 1;
    675   PrintMap(&output);
    676 }
    677