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