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