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