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:
~HttpRequest()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:
~HttpRequestProcessor()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.
JsHttpRequestProcessor(Isolate * isolate,Handle<String> script)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
GetIsolate()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
LogCallback(const v8::FunctionCallbackInfo<v8::Value> & args)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.
Initialize(map<string,string> * opts,map<string,string> * output)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
ExecuteScript(Handle<String> script)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
InstallMaps(map<string,string> * opts,map<string,string> * output)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
Process(HttpRequest * request)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
~JsHttpRequestProcessor()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.
WrapMap(map<string,string> * obj)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.
UnwrapMap(Handle<Object> obj)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.
ObjectToString(Local<Value> value)356 string ObjectToString(Local<Value> value) {
357 String::Utf8Value utf8_value(value);
358 return string(*utf8_value);
359 }
360
361
MapGet(Local<String> name,const PropertyCallbackInfo<Value> & info)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
MapSet(Local<String> name,Local<Value> value_obj,const PropertyCallbackInfo<Value> & info)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
MakeMapTemplate(Isolate * isolate)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 */
WrapRequest(HttpRequest * request)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 */
UnwrapRequest(Handle<Object> obj)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
GetPath(Local<String> name,const PropertyCallbackInfo<Value> & info)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
GetReferrer(Local<String> name,const PropertyCallbackInfo<Value> & info)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
GetHost(Local<String> name,const PropertyCallbackInfo<Value> & info)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
GetUserAgent(Local<String> name,const PropertyCallbackInfo<Value> & info)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
MakeRequestTemplate(Isolate * isolate)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
Log(const char * event)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);
Path()555 virtual const string& Path() { return path_; }
Referrer()556 virtual const string& Referrer() { return referrer_; }
Host()557 virtual const string& Host() { return host_; }
UserAgent()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
StringHttpRequest(const string & path,const string & referrer,const string & host,const string & user_agent)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
ParseOptions(int argc,char * argv[],map<string,string> * options,string * file)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.
ReadFile(Isolate * isolate,const string & name)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
ProcessEntries(HttpRequestProcessor * processor,int count,StringHttpRequest * reqs)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
PrintMap(map<string,string> * m)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
main(int argc,char * argv[])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