From 9d7895c567e8f38abfff35da1b6d6d6a0a06f9aa Mon Sep 17 00:00:00 2001 From: Ryan Date: 2009年2月16日 01:02:00 +0100 Subject: [PATCH 1/2] add dependencies --- .gitmodules | 6 ++++++ deps/ebb | 1 + deps/oi | 1 + 3 files changed, 8 insertions(+) create mode 100644 .gitmodules create mode 160000 deps/ebb create mode 160000 deps/oi diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1350dd7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "deps/oi"] + path = deps/oi + url = git://github.com/ry/liboi.git +[submodule "deps/ebb"] + path = deps/ebb + url = git://github.com/ry/libebb.git diff --git a/deps/ebb b/deps/ebb new file mode 160000 index 0000000..6460653 --- /dev/null +++ b/deps/ebb @@ -0,0 +1 @@ +Subproject commit 646065359957956c9a0a611aa91ee79fb4928e6d diff --git a/deps/oi b/deps/oi new file mode 160000 index 0000000..988d979 --- /dev/null +++ b/deps/oi @@ -0,0 +1 @@ +Subproject commit 988d97948634359cf2a6740dd5228c69a27015ae From 61890720c8a22a7f1577327b32a180a2d267d765 Mon Sep 17 00:00:00 2001 From: Ryan Date: 2009年2月16日 01:34:45 +0100 Subject: [PATCH 2/2] add readme and initial code --- Makefile | 32 ++ README | 4 + js_http_request_processor.cc | 606 +++++++++++++++++++++++++++++++++++ js_http_request_processor.h | 104 ++++++ server.cc | 247 ++++++++++++++ 5 files changed, 993 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 js_http_request_processor.cc create mode 100644 js_http_request_processor.h create mode 100644 server.cc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..80dae8e --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +EVDIR=$(HOME)/local/libev +V8INC = $(HOME)/src/v8/include +V8LIB = $(HOME)/src/v8/libv8.a + +CFLAGS = -g -I$(V8INC) -Ideps/oi -DHAVE_GNUTLS=0 -Ideps/ebb +LDFLAGS = -lev #-lefence + +ifdef EVDIR + CFLAGS += -I$(EVDIR)/include + LDFLAGS += -L$(EVDIR)/lib +endif + +server: server.o deps/oi/oi_socket.o deps/ebb/ebb_request_parser.o + g++ $(CFLAGS) $(LDFLAGS) $(V8LIB) -o server $^ + +server.o: server.cc + g++ $(CFLAGS) -c $@ $< + +ebb_request_parser.o: ebb_request_parser.c deps/ebb/ebb_request_parser.h + gcc $(CFLAGS) -c $@ $< + +ebb_request_parser.c: deps/ebb/ebb_request_parser.rl + ragel -s -G2 $< -o $@ + +oi_socket.o: deps/oi/oi_socket.c deps/oi/oi_socket.h + gcc $(CFLAGS) -c $@ $< + +clean: + rm -f *.o + rm -f server + +.PHONY: clean test diff --git a/README b/README new file mode 100644 index 0000000..b177f94 --- /dev/null +++ b/README @@ -0,0 +1,4 @@ + +git submodule init +git submodule update +make diff --git a/js_http_request_processor.cc b/js_http_request_processor.cc new file mode 100644 index 0000000..5c76f4b --- /dev/null +++ b/js_http_request_processor.cc @@ -0,0 +1,606 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +// To avoid warnings from
    on windows we disable exceptions. +#define _HAS_EXCEPTIONS 0 +#include +#include
      + +#include + +using namespace std; +using namespace v8; + +static Handle LogCallback + ( const Arguments& args + ) +{ + if (args.Length() < 1) return v8::Undefined(); + HandleScope scope; + Handle arg = args[0]; + String::Utf8Value value(arg); + HttpRequestProcessor::Log(*value); + return v8::Undefined(); +} + + +// Execute the script and fetch the Process method. +bool JsHttpRequestProcessor::Initialize + ( map* opts + , map* output + ) +{ + // Create a handle scope to hold the temporary references. + HandleScope handle_scope; + + // Create a template for the global object where we set the + // built-in global functions. + Handle global = ObjectTemplate::New(); + global->Set(String::New("log"), FunctionTemplate::New(LogCallback)); + + // Each processor gets its own context so different processors + // don't affect each other (ignore the first three lines). + Handle context = Context::New(NULL, global); + + // Store the context in the processor object in a persistent handle, + // since we want the reference to remain after we return from this + // method. + context_ = Persistent::New(context); + + // Enter the new context so all the following operations take place + // within it. + Context::Scope context_scope(context); + + // Make the options mapping available within the context + if (!InstallMaps(opts, output)) + return false; + + // Compile and run the script + if (!ExecuteScript(script_)) + return false; + + // The script compiled and ran correctly. Now we fetch out the + // Process function from the global object. + Handle process_name = String::New("Process"); + Handle process_val = context->Global()->Get(process_name); + + // If there is no Process function, or if it is not a function, + // bail out + if (!process_val->IsFunction()) return false; + + // It is a function; cast it to a Function + Handle process_fun = Handle::Cast(process_val); + + // Store the function in a Persistent handle, since we also want + // that to remain after this call returns + process_ = Persistent::New(process_fun); + + // All done; all went well + return true; +} + + +bool JsHttpRequestProcessor::ExecuteScript + ( Handle script + ) +{ + HandleScope handle_scope; + + // We're just about to compile the script; set up an error handler to + // catch any exceptions the script might throw. + TryCatch try_catch; + + // Compile the script and check for errors. + Handle> compiled_script = Script::Compile(script); + if (compiled_script.IsEmpty()) { + String::Utf8Value error(try_catch.Exception()); + Log(*error); + // The script failed to compile; bail out. + return false; + } + + // Run the script! + Handle result = compiled_script->Run(); + if (result.IsEmpty()) { + // The TryCatch above is still in effect and will have caught the error. + String::Utf8Value error(try_catch.Exception()); + Log(*error); + // Running the script failed; bail out. + return false; + } + return true; +} + +bool JsHttpRequestProcessor::InstallMaps + ( map* opts + , map* output + ) +{ + HandleScope handle_scope; + + // Wrap the map object in a JavaScript wrapper + Handle opts_obj = WrapMap(opts); + + // Set the options object as a property on the global object. + context_->Global()->Set(String::New("options"), opts_obj); + + Handle output_obj = WrapMap(output); + context_->Global()->Set(String::New("output"), output_obj); + + return true; +} + + +bool JsHttpRequestProcessor::Process + ( HttpRequest* request + ) +{ + // Create a handle scope to keep the temporary object references. + HandleScope handle_scope; + + // Enter this processor's context so all the remaining operations + // take place there + Context::Scope context_scope(context_); + + // Wrap the C++ request object in a JavaScript wrapper + Handle request_obj = WrapRequest(request); + + // Set up an exception handler before calling the Process function + TryCatch try_catch; + + // Invoke the process function, giving the global object as 'this' + // and one argument, the request. + const int argc = 1; + Handle argv[argc] = { request_obj }; + Handle result = process_->Call(context_->Global(), argc, argv); + if (result.IsEmpty()) { + String::Utf8Value error(try_catch.Exception()); + Log(*error); + return false; + } else { + return true; + } +} + + +JsHttpRequestProcessor::~JsHttpRequestProcessor + ( + ) +{ + // Dispose the persistent handles. When noone else has any + // references to the objects stored in the handles they will be + // automatically reclaimed. + context_.Dispose(); + process_.Dispose(); +} + + +Persistent JsHttpRequestProcessor::request_template_; +Persistent JsHttpRequestProcessor::map_template_; + + +// ----------------------------------- +// --- A c c e s s i n g M a p s --- +// ----------------------------------- + +// Utility function that wraps a C++ http request object in a +// JavaScript object. +Handle JsHttpRequestProcessor::WrapMap + ( map* obj + ) +{ + // Handle scope for temporary handles. + HandleScope handle_scope; + + // Fetch the template for creating JavaScript map wrappers. + // It only has to be created once, which we do on demand. + if (request_template_.IsEmpty()) { + Handle raw_template = MakeMapTemplate(); + map_template_ = Persistent::New(raw_template); + } + Handle templ = map_template_; + + // Create an empty map wrapper. + Handle result = templ->NewInstance(); + + // Wrap the raw C++ pointer in an External so it can be referenced + // from within JavaScript. + Handle map_ptr = External::New(obj); + + // Store the map pointer in the JavaScript wrapper. + result->SetInternalField(0, map_ptr); + + // Return the result through the current handle scope. Since each + // of these handles will go away when the handle scope is deleted + // we need to call Close to let one, the result, escape into the + // outer handle scope. + return handle_scope.Close(result); +} + + +// Utility function that extracts the C++ map pointer from a wrapper +// object. +map* JsHttpRequestProcessor::UnwrapMap + ( Handle obj + ) +{ + Handle field = Handle::Cast(obj->GetInternalField(0)); + void* ptr = field->Value(); + return static_cast
        *>(ptr); +} + + +// Convert a JavaScript string to a std::string. To not bother too +// much with string encodings we just use ascii. +string ObjectToString + ( Local value + ) +{ + String::Utf8Value utf8_value(value); + return string(*utf8_value); +} + + +Handle JsHttpRequestProcessor::MapGet + ( Local name + , const AccessorInfo& info + ) +{ + // Fetch the map wrapped by this object. + map* obj = UnwrapMap(info.Holder()); + + // Convert the JavaScript string to a std::string. + string key = ObjectToString(name); + + // Look up the value if it exists using the standard STL ideom. + map::iterator iter = obj->find(key); + + // If the key is not present return an empty handle as signal + if (iter == obj->end()) return Handle(); + + // Otherwise fetch the value and wrap it in a JavaScript string + const string& value = (*iter).second; + return String::New(value.c_str(), value.length()); +} + + +Handle JsHttpRequestProcessor::MapSet + ( Local name + , Local value_obj + , const AccessorInfo& info + ) +{ + // Fetch the map wrapped by this object. + map* obj = UnwrapMap(info.Holder()); + + // Convert the key and value to std::strings. + string key = ObjectToString(name); + string value = ObjectToString(value_obj); + + // Update the map. + (*obj)[key] = value; + + // Return the value; any non-empty handle will work. + return value_obj; +} + + +Handle JsHttpRequestProcessor::MakeMapTemplate + ( + ) +{ + HandleScope handle_scope; + + Handle result = ObjectTemplate::New(); + result->SetInternalFieldCount(1); + result->SetNamedPropertyHandler(MapGet, MapSet); + + // Again, return the result through the current handle scope. + return handle_scope.Close(result); +} + + +// ------------------------------------------- +// --- A c c e s s i n g R e q u e s t s --- +// ------------------------------------------- + +/** + * Utility function that wraps a C++ http request object in a + * JavaScript object. + */ +Handle JsHttpRequestProcessor::WrapRequest + ( HttpRequest* request + ) +{ + // Handle scope for temporary handles. + HandleScope handle_scope; + + // Fetch the template for creating JavaScript http request wrappers. + // It only has to be created once, which we do on demand. + if (request_template_.IsEmpty()) { + Handle raw_template = MakeRequestTemplate(); + request_template_ = Persistent::New(raw_template); + } + Handle templ = request_template_; + + // Create an empty http request wrapper. + Handle result = templ->NewInstance(); + + // Wrap the raw C++ pointer in an External so it can be referenced + // from within JavaScript. + Handle request_ptr = External::New(request); + + // Store the request pointer in the JavaScript wrapper. + result->SetInternalField(0, request_ptr); + + // Return the result through the current handle scope. Since each + // of these handles will go away when the handle scope is deleted + // we need to call Close to let one, the result, escape into the + // outer handle scope. + return handle_scope.Close(result); +} + + +/** + * Utility function that extracts the C++ http request object from a + * wrapper object. + */ +HttpRequest* JsHttpRequestProcessor::UnwrapRequest + ( Handle obj + ) +{ + Handle field = Handle::Cast(obj->GetInternalField(0)); + void* ptr = field->Value(); + return static_cast(ptr); +} + +Handle JsHttpRequestProcessor::GetPath + ( Local name + , const AccessorInfo& info + ) +{ + // Extract the C++ request object from the JavaScript wrapper. + HttpRequest* request = UnwrapRequest(info.Holder()); + + // Fetch the path. + const string& path = request->Path(); + + // Wrap the result in a JavaScript string and return it. + return String::New(path.c_str(), path.length()); +} + + +Handle JsHttpRequestProcessor::GetReferrer + ( Local name + , const AccessorInfo& info + ) +{ + HttpRequest* request = UnwrapRequest(info.Holder()); + const string& path = request->Referrer(); + return String::New(path.c_str(), path.length()); +} + + +Handle JsHttpRequestProcessor::GetHost + ( Local name + , const AccessorInfo& info + ) +{ + HttpRequest* request = UnwrapRequest(info.Holder()); + const string& path = request->Host(); + return String::New(path.c_str(), path.length()); +} + + +Handle JsHttpRequestProcessor::GetUserAgent + ( Local name + , const AccessorInfo& info + ) +{ + HttpRequest* request = UnwrapRequest(info.Holder()); + const string& path = request->UserAgent(); + return String::New(path.c_str(), path.length()); +} + + +Handle JsHttpRequestProcessor::MakeRequestTemplate + ( + ) +{ + HandleScope handle_scope; + + Handle result = ObjectTemplate::New(); + result->SetInternalFieldCount(1); + + // Add accessors for each of the fields of the request. + result->SetAccessor(String::NewSymbol("path"), GetPath); + result->SetAccessor(String::NewSymbol("referrer"), GetReferrer); + result->SetAccessor(String::NewSymbol("host"), GetHost); + result->SetAccessor(String::NewSymbol("userAgent"), GetUserAgent); + + // Again, return the result through the current handle scope. + return handle_scope.Close(result); +} + + +// --- Test --- + + +void HttpRequestProcessor::Log + ( const char* event + ) +{ + printf("Logged: %s\n", event); +} + + +/** + * A simplified http request. + */ +class StringHttpRequest : public HttpRequest +{ +public: + StringHttpRequest + ( const string& path + , const string& referrer + , const string& host + , const string& user_agent + ); + virtual const string& Path () { return path_; } + virtual const string& Referrer () { return referrer_; } + virtual const string& Host () { return host_; } + virtual const string& UserAgent () { return user_agent_; } +private: + string path_; + string referrer_; + string host_; + string user_agent_; +}; + + +StringHttpRequest::StringHttpRequest + ( const string& path + , const string& referrer + , const string& host + , const string& user_agent + ) + : path_ (path) + , referrer_ (referrer) + , host_ (host) + , user_agent_ (user_agent) +{ +} + +void ParseOptions + ( int argc + , char* argv[] + , map& options + , string* file + ) +{ + for (int i = 1; i < argc; i++) { + string arg = argv[i]; + int index = arg.find('=', 0); + if (index == string::npos) { + *file = arg; + } else { + string key = arg.substr(0, index); + string value = arg.substr(index+1); + options[key] = value; + } + } +} + + +// Reads a file into a v8 string. +Handle ReadFile + ( const string& name + ) +{ + FILE* file = fopen(name.c_str(), "rb"); + if (file == NULL) return Handle(); + + fseek(file, 0, SEEK_END); + int size = ftell(file); + rewind(file); + + char* chars = new char[size + 1]; + chars[size] = '0円'; + for (int i = 0; i < size;) { + int read = fread(&chars[i], 1, size - i, file); + i += read; + } + fclose(file); + Handle result = String::New(chars, size); + delete[] chars; + return result; +} + + +const int kSampleSize = 6; +StringHttpRequest kSampleRequests[kSampleSize] = + { StringHttpRequest("/process.cc", "localhost", "google.com", "firefox") + , StringHttpRequest("/", "localhost", "google.net", "firefox") + , StringHttpRequest("/", "localhost", "google.org", "safari") + , StringHttpRequest("/", "localhost", "yahoo.com", "ie") + , StringHttpRequest("/", "localhost", "yahoo.com", "safari") + , StringHttpRequest("/", "localhost", "yahoo.com", "firefox") + }; + + +bool ProcessEntries + ( HttpRequestProcessor* processor + , int count + , StringHttpRequest* reqs + ) +{ + for (int i = 0; i < count; i++) { + if (!processor->Process(&reqs[i])) + return false; + } + return true; +} + + +void PrintMap + ( map* m + ) +{ + for (map::iterator i = m->begin(); i != m->end(); i++) { + pair entry = *i; + printf("%s: %s\n", entry.first.c_str(), entry.second.c_str()); + } +} + +#if 0 +int main(int argc, char* argv[]) { + map options; + string file; + ParseOptions(argc, argv, options, &file); + if (file.empty()) { + fprintf(stderr, "No script was specified.\n"); + return 1; + } + HandleScope scope; + Handle source = ReadFile(file); + if (source.IsEmpty()) { + fprintf(stderr, "Error reading '%s'.\n", file.c_str()); + return 1; + } + JsHttpRequestProcessor processor(source); + map output; + if (!processor.Initialize(&options, &output)) { + fprintf(stderr, "Error initializing processor.\n"); + return 1; + } + if (!ProcessEntries(&processor, kSampleSize, kSampleRequests)) + return 1; + PrintMap(&output); +} +#endif diff --git a/js_http_request_processor.h b/js_http_request_processor.h new file mode 100644 index 0000000..32d89e2 --- /dev/null +++ b/js_http_request_processor.h @@ -0,0 +1,104 @@ +#ifndef js_http_request_processor_h +#define js_http_request_processor_h + +#include +#include +#include
          + +using namespace std; +using namespace v8; + +// These interfaces represent an existing request processing interface. +// The idea is to imagine a real application that uses these interfaces +// and then add scripting capabilities that allow you to interact with +// the objects through JavaScript. + +/** + * A simplified http request. + */ +class HttpRequest { + public: + virtual ~HttpRequest() { } + virtual const string& Path() = 0; + virtual const string& Referrer() = 0; + virtual const string& Host() = 0; + virtual const string& UserAgent() = 0; +}; + +/** + * The abstract superclass of http request processors. + */ +class HttpRequestProcessor { + public: + virtual ~HttpRequestProcessor() { } + + // Initialize this processor. The map contains options that control + // how requests should be processed. + virtual bool Initialize(map* options, + map* output) = 0; + + // Process a single request. + virtual bool Process(HttpRequest* req) = 0; + + static void Log(const char* event); +}; + +/** + * An http request processor that is scriptable using JavaScript. + */ +class JsHttpRequestProcessor : public HttpRequestProcessor { + public: + + // Creates a new processor that processes requests by invoking the + // Process function of the JavaScript script given as an argument. + explicit JsHttpRequestProcessor(Handle script) : script_(script) { } + virtual ~JsHttpRequestProcessor(); + + virtual bool Initialize(map* opts, + map* output); + virtual bool Process(HttpRequest* req); + + private: + + // Execute the script associated with this processor and extract the + // Process function. Returns true if this succeeded, otherwise false. + bool ExecuteScript(Handle script); + + // Wrap the options and output map in a JavaScript objects and + // install it in the global namespace as 'options' and 'output'. + bool InstallMaps(map* opts, map* output); + + // Constructs the template that describes the JavaScript wrapper + // type for requests. + static Handle MakeRequestTemplate(); + static Handle MakeMapTemplate(); + + // Callbacks that access the individual fields of request objects. + static Handle GetPath(Local name, const AccessorInfo& info); + static Handle GetReferrer(Local name, + const AccessorInfo& info); + static Handle GetHost(Local name, const AccessorInfo& info); + static Handle GetUserAgent(Local name, + const AccessorInfo& info); + + // Callbacks that access maps + static Handle MapGet(Local name, const AccessorInfo& info); + static Handle MapSet(Local name, + Local value, + const AccessorInfo& info); + + // Utility methods for wrapping C++ objects as JavaScript objects, + // and going back again. + static Handle WrapMap(map* obj); + static map* UnwrapMap(Handle obj); + static Handle WrapRequest(HttpRequest* obj); + static HttpRequest* UnwrapRequest(Handle obj); + + Handle script_; + Persistent context_; + Persistent process_; + static Persistent request_template_; + static Persistent map_template_; +}; + +#endif // js_http_request_processor_h diff --git a/server.cc b/server.cc new file mode 100644 index 0000000..2fc6575 --- /dev/null +++ b/server.cc @@ -0,0 +1,247 @@ +#include + +extern "C" { +#include +#include +} + +#include +#include +#include
            + +using namespace v8; +using namespace std; + +#define PORT "1981" +#define MAX_URL 500 + +static oi_server server; +static struct ev_loop *loop; + +class Connection { +public: + Connection(void); + ebb_request_parser parser; + oi_socket socket; +}; + +class Request { +public: + Request(Connection &); + string path; + Connection &connection_; + ebb_request parser_info; +}; + +Request::Request + ( Connection &connection + ) + : connection_(connection) +{ + ebb_request_init(&parser_info); +} + +Connection::Connection + ( void + ) +{ + oi_socket_init (&socket, 30.0); + ebb_request_parser_init (&parser); +} + +void on_path + ( ebb_request *req + , const char *buf + , size_t len + ) +{ + Request *request = static_cast (req->data); + request->path.append(buf, len); +} + +void on_request_complete + ( ebb_request *req + ) +{ + Request *request = static_cast (req->data); + + // dispatch to javascript +} + +ebb_request * on_request + ( void *data + ) +{ + Connection *connection = static_cast (data); + + Request *request = new Request(*connection); + + request->parser_info.on_path = on_path; + request->parser_info.on_query_string = NULL; + request->parser_info.on_uri = NULL; + request->parser_info.on_fragment = NULL; + request->parser_info.on_header_field = NULL; + request->parser_info.on_header_value = NULL; + request->parser_info.on_headers_complete = NULL; + request->parser_info.on_body = NULL; + request->parser_info.on_complete = on_request_complete; + request->parser_info.data = request; + + return &request->parser_info; +} + +static void on_read + ( oi_socket *socket + , const void *buf + , size_t count + ) +{ + Connection *connection = static_cast (socket->data); + ebb_request_parser_execute ( &connection->parser + , static_cast (buf) // FIXME change ebb to use void* + , count + ); + /* TODO check for errors */ +} + +static void on_close + ( oi_socket *socket + ) +{ + Connection *connection = static_cast (socket->data); + /* TODO free requests */ + free(connection); +} + +static void on_drain + ( oi_socket *socket + ) +{ + Connection *connection = static_cast (socket->data); + //oi_socket_close(&connection->socket); +} + +static oi_socket* new_connection + ( oi_server *server + , struct sockaddr *addr + , socklen_t len + ) +{ + Connection *connection = new Connection(); + + /* initialize the components of Connection */ + oi_socket_init(&connection->socket, 30.0); + connection->socket.on_read = on_read; + connection->socket.on_error = NULL; + connection->socket.on_close = on_close; + connection->socket.on_timeout = NULL; + connection->socket.on_drain = on_drain; + connection->socket.data = connection; + + ebb_request_parser_init(&connection->parser); + connection->parser.new_request = on_request; + connection->parser.data = connection; + + return &connection->socket; +} + + +// Reads a file into a v8 string. +Handle ReadFile + ( const string& name + ) +{ + FILE* file = fopen(name.c_str(), "rb"); + if (file == NULL) return Handle(); + + fseek(file, 0, SEEK_END); + int size = ftell(file); + rewind(file); + + char* chars = new char[size + 1]; + chars[size] = '0円'; + for (int i = 0; i < size;) { + int read = fread(&chars[i], 1, size - i, file); + i += read; + } + fclose(file); + Handle result = String::New(chars, size); + delete[] chars; + return result; +} + +void ParseOptions + ( int argc + , char* argv[] + , map& options + , string* file + ) +{ + for (int i = 1; i < argc; i++) { + string arg = argv[i]; + int index = arg.find('=', 0); + if (index == string::npos) { + *file = arg; + } else { + string key = arg.substr(0, index); + string value = arg.substr(index+1); + options[key] = value; + } + } +} + +int main + ( int argc + , char *argv[] + ) +{ + map options; + string file; + ParseOptions(argc, argv, options, &file); + if (file.empty()) { + fprintf(stderr, "No script was specified.\n"); + return 1; + } + HandleScope scope; + Handle source = ReadFile(file); + if (source.IsEmpty()) { + fprintf(stderr, "Error reading '%s'.\n", file.c_str()); + return 1; + } + /* + HttpRequestProcessor processor(source); + map output; + if (!processor.Initialize(&options, &output)) { + fprintf(stderr, "Error initializing processor.\n"); + return 1; + } + */ + + ///////////////////////////////////// + + + loop = ev_default_loop(0); + + oi_server_init(&server, 1024); + server.on_connection = new_connection; + + // get addrinfo for localhost, PORT + struct addrinfo *servinfo; + struct addrinfo hints; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + int r = getaddrinfo(NULL, PORT, &hints, &servinfo); + assert(r == 0); + + r = oi_server_listen(&server, servinfo); + assert(r == 0); + + oi_server_attach(&server, loop); + + printf("Running at http://localhost:%s/\n", PORT); + + ev_loop(loop, 0); + return 0; +}

            AltStyle によって変換されたページ (->オリジナル) /