Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 356 lines (288 sloc) 12.141 kb
e02b71e @ry exit program on top level exceptions
ry authored
1 #include "node.h"
67af958 @ry rename a few files to remove node_ prefix
ry authored
2 #include "http.h"
5a071ad @ry Begin refactor of http.cc. Remove libebb add http_parser.
ry authored
3 #include <http_parser.h>
6189072 @ry add readme and initial code
ry authored
4
1a126ed @ry use the WAF build system
ry authored
5 #include <assert.h>
5a071ad @ry Begin refactor of http.cc. Remove libebb add http_parser.
ry authored
6 #include <stdio.h>
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
7 #include <strings.h>
1a126ed @ry use the WAF build system
ry authored
8
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
9 #define ENCODING_SYMBOL String::NewSymbol("encoding")
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
10
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
11 #define MESSAGE_HANDLER_SYMBOL String::NewSymbol("messageHandler")
12
13 #define ON_MESSAGE_SYMBOL String::NewSymbol("onMessage")
14 #define ON_PATH_SYMBOL String::NewSymbol("onPath")
15 #define ON_QUERY_STRING_SYMBOL String::NewSymbol("onQueryString")
16 #define ON_URI_SYMBOL String::NewSymbol("onURI")
17 #define ON_FRAGMENT_SYMBOL String::NewSymbol("onFragment")
18 #define ON_HEADER_FIELD_SYMBOL String::NewSymbol("onHeaderField")
19 #define ON_HEADER_VALUE_SYMBOL String::NewSymbol("onHeaderValue")
20 #define ON_HEADERS_COMPLETE_SYMBOL String::NewSymbol("onHeadersComplete")
21 #define ON_BODY_SYMBOL String::NewSymbol("onBody")
22 #define ON_MESSAGE_COMPLETE_SYMBOL String::NewSymbol("onMessageComplete")
09c2ae5 @ry Slight change in tcp connection constructor
ry authored
23
4d39a35 @ry Path, URI, Fragment, etc were not getting passed to RequestHandler.
ry authored
24 #define STATUS_CODE_SYMBOL String::NewSymbol("status_code")
25 #define HTTP_VERSION_SYMBOL String::NewSymbol("http_version")
26 #define SHOULD_KEEP_ALIVE_SYMBOL String::NewSymbol("should_keep_alive")
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
27
6189072 @ry add readme and initial code
ry authored
28 using namespace v8;
5a071ad @ry Begin refactor of http.cc. Remove libebb add http_parser.
ry authored
29 using namespace node;
6189072 @ry add readme and initial code
ry authored
30 using namespace std;
31
9c3770d @ry Implement HTTPServer (untested!)
ry authored
32 Persistent<FunctionTemplate> HTTPConnection::client_constructor_template;
33 Persistent<FunctionTemplate> HTTPConnection::server_constructor_template;
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
34
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
35 static Persistent<Object> http_module;
36
b4985d1 @ry working towards working keep-alive. need tests
ry authored
37 void
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
38 HTTPConnection::Initialize (Handle<Object> target)
2ee65b8 @ry add headers to request object
ry authored
39 {
f16e50d @ry refactor js_request creation into method
ry authored
40 HandleScope scope;
d945ba6 @ry compactify the code into a single file. will abstract later.
ry authored
41
2e5b85a @ry Some fixes to allow HTTPServer to begin listening.
ry authored
42 Local<FunctionTemplate> t = FunctionTemplate::New(v8NewClient);
9c3770d @ry Implement HTTPServer (untested!)
ry authored
43 client_constructor_template = Persistent<FunctionTemplate>::New(t);
44 client_constructor_template->Inherit(Connection::constructor_template);
45 client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
46 target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction());
9c3770d @ry Implement HTTPServer (untested!)
ry authored
47
2e5b85a @ry Some fixes to allow HTTPServer to begin listening.
ry authored
48 t = FunctionTemplate::New(v8NewServer);
9c3770d @ry Implement HTTPServer (untested!)
ry authored
49 server_constructor_template = Persistent<FunctionTemplate>::New(t);
50 server_constructor_template->Inherit(Connection::constructor_template);
51 server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
52 target->Set(String::NewSymbol("ServerSideSocket"),
9c3770d @ry Implement HTTPServer (untested!)
ry authored
53 server_constructor_template->GetFunction());
6189072 @ry add readme and initial code
ry authored
54 }
55
5a071ad @ry Begin refactor of http.cc. Remove libebb add http_parser.
ry authored
56 Handle<Value>
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
57 HTTPConnection::v8NewClient (const Arguments& args)
a890b67 @ry Add beginnings of the setTimeout interface
ry authored
58 {
59 HandleScope scope;
73fb24f @ry Relatively large update to TCP API. No more "protocol".
ry authored
60 new HTTPConnection(args.This(), HTTP_RESPONSE);
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
61 return args.This();
62 }
19478ed @ry Major refactoring: program name now "node"
ry authored
63
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
64 Handle<Value>
65 HTTPConnection::v8NewServer (const Arguments& args)
66 {
67 HandleScope scope;
73fb24f @ry Relatively large update to TCP API. No more "protocol".
ry authored
68 new HTTPConnection(args.This(), HTTP_REQUEST);
5a071ad @ry Begin refactor of http.cc. Remove libebb add http_parser.
ry authored
69 return args.This();
d945ba6 @ry compactify the code into a single file. will abstract later.
ry authored
70 }
71
19478ed @ry Major refactoring: program name now "node"
ry authored
72 void
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
73 HTTPConnection::OnReceive (const void *buf, size_t len)
74 {
75 http_parser_execute(&parser_, static_cast<const char*>(buf), len);
76
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
77 if (http_parser_has_error(&parser_))
78 ForceClose();
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
79 }
80
81 int
82 HTTPConnection::on_message_begin (http_parser *parser)
83 {
84 HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
85 HandleScope scope;
86
73fb24f @ry Relatively large update to TCP API. No more "protocol".
ry authored
87 Local<Value> on_message_v = connection->handle_->Get(ON_MESSAGE_SYMBOL);
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
88 if (!on_message_v->IsFunction()) return -1;
89 Handle<Function> on_message = Handle<Function>::Cast(on_message_v);
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
90
91 TryCatch try_catch;
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
92 Local<Object> message_handler = on_message->NewInstance();
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
93 if (try_catch.HasCaught()) {
94 fatal_exception(try_catch);
95 return -1;
96 }
97
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
98 connection->handle_->SetHiddenValue(MESSAGE_HANDLER_SYMBOL, message_handler);
99 return 0;
100 }
101
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
102 #define DEFINE_PARSER_CALLBACK(name, symbol) \
103 int \
104 HTTPConnection::name (http_parser *parser, const char *buf, size_t len) \
105 { \
106 HandleScope scope; \
107 HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data); \
108 Local<Value> message_handler_v = \
109 connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL); \
110 if (message_handler_v->IsObject() == false) \
111 return -1; \
112 Local<Object> message_handler = message_handler_v->ToObject(); \
113 Local<Value> callback_v = message_handler->Get(symbol); \
114 if (callback_v->IsFunction() == false) \
115 return 0; \
116 Local<Function> callback = Local<Function>::Cast(callback_v); \
117 TryCatch try_catch; \
118 Local<Value> argv[1] = { String::New(buf, len) }; \
119 Local<Value> ret = callback->Call(message_handler, 1, argv); \
120 if (ret.IsEmpty()) { \
121 fatal_exception(try_catch); \
122 return -2; \
123 } \
124 if (ret->IsFalse()) return -3; \
125 return 0; \
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
126 }
127
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
128 DEFINE_PARSER_CALLBACK(on_path, ON_PATH_SYMBOL)
129 DEFINE_PARSER_CALLBACK(on_query_string, ON_QUERY_STRING_SYMBOL)
130 DEFINE_PARSER_CALLBACK(on_uri, ON_URI_SYMBOL)
131 DEFINE_PARSER_CALLBACK(on_fragment, ON_FRAGMENT_SYMBOL)
132 DEFINE_PARSER_CALLBACK(on_header_field, ON_HEADER_FIELD_SYMBOL)
133 DEFINE_PARSER_CALLBACK(on_header_value, ON_HEADER_VALUE_SYMBOL)
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
134
135 int
136 HTTPConnection::on_headers_complete (http_parser *parser)
19478ed @ry Major refactoring: program name now "node"
ry authored
137 {
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
138 HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
139 HandleScope scope;
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
140
141 Local<Value> message_handler_v =
142 connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
143 Local<Object> message_handler = message_handler_v->ToObject();
144
145 // STATUS
146 message_handler->Set(STATUS_CODE_SYMBOL,
147 Integer::New(connection->parser_.status_code));
148
149 // VERSION
150 char version[10];
09c2ae5 @ry Slight change in tcp connection constructor
ry authored
151 snprintf( version
152 , 10
153 , "%d.%d"
154 , connection->parser_.version_major
155 , connection->parser_.version_minor
156 );
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
157 message_handler->Set(HTTP_VERSION_SYMBOL, String::New(version));
158
7869ed6 @ry Add keep-alive handling.
ry authored
159 // SHOULD KEEP ALIVE
160 message_handler->Set( SHOULD_KEEP_ALIVE_SYMBOL
161 , http_parser_should_keep_alive(&connection->parser_) ? True() : False()
162 );
163
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
164
165 Local<Value> on_headers_complete_v = message_handler->Get(ON_HEADERS_COMPLETE_SYMBOL);
166 if (on_headers_complete_v->IsFunction() == false) return 0;
167
168 Handle<Function> on_headers_complete = Handle<Function>::Cast(on_headers_complete_v);
169
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
170 TryCatch try_catch;
171 Local<Value> ret = on_headers_complete->Call(message_handler, 0, NULL);
172 if (ret.IsEmpty()) {
173 fatal_exception(try_catch);
174 return -2;
175 }
176 if (ret->IsFalse()) return -3;
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
177
178 return 0;
19478ed @ry Major refactoring: program name now "node"
ry authored
179 }
6189072 @ry add readme and initial code
ry authored
180
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
181 int
182 HTTPConnection::on_body (http_parser *parser, const char *buf, size_t len)
183 {
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
184 assert(len != 0);
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
185
186 HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
187 HandleScope scope;
188
189 Local<Value> message_handler_v =
190 connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
191 Local<Object> message_handler = message_handler_v->ToObject();
192
193 Local<Value> on_body_v = message_handler->Get(ON_BODY_SYMBOL);
194 if (on_body_v->IsFunction() == false) return 0;
195 Handle<Function> on_body = Handle<Function>::Cast(on_body_v);
196
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
197 /* Look at the value of message_handler.encoding to decide how to
198 * send the body chunk. This is rather sloppy and unnecesary. FIXME
199 */
200 enum encoding encoding = RAW;
201 Local<Value> encoding_v = message_handler->Get(ENCODING_SYMBOL);
202 if (encoding_v->IsString()) {
203 Local<String> encoding_string = encoding_v->ToString();
204 char buf[5]; // need enough room for "utf8" or "raw"
205 encoding_string->WriteAscii(buf, 0, 4);
206 buf[4] = '\0';
207 if(strcasecmp(buf, "utf8") == 0)
208 encoding = UTF8;
209 }
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
210
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
211 Handle<Value> argv[1];
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
212 // TODO each message should have their encoding.
213 // don't look at the conneciton for encoding
103a880 @ry Binary HTTP bodies for both requests and responses.
ry authored
214 if(encoding == UTF8) {
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
215 // utf8 encoding
216 Handle<String> chunk = String::New((const char*)buf, len);
217 argv[0] = chunk;
218
219 } else {
220 // raw encoding
221 Local<Array> array = Array::New(len);
222 for (size_t i = 0; i < len; i++) {
223 char val = static_cast<const char*>(buf)[i];
224 array->Set(Integer::New(i), Integer::New(val));
225 }
226 argv[0] = array;
227 }
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
228
229 TryCatch try_catch;
febbf75 @ry Wrap calls in TryCatch; Check return values after UNWRAP.
ry authored
230 Local<Value> ret = on_body->Call(message_handler, 1, argv);
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
231 if (ret.IsEmpty()) {
232 fatal_exception(try_catch);
233 return -2;
234 }
235 if (ret->IsFalse()) return -3;
236
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
237 return 0;
238 }
239
240 int
241 HTTPConnection::on_message_complete (http_parser *parser)
242 {
243 HTTPConnection *connection = static_cast<HTTPConnection*> (parser->data);
244 HandleScope scope;
245
246 Local<Value> message_handler_v =
247 connection->handle_->GetHiddenValue(MESSAGE_HANDLER_SYMBOL);
248 Local<Object> message_handler = message_handler_v->ToObject();
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
249 connection->handle_->DeleteHiddenValue(MESSAGE_HANDLER_SYMBOL);
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
250
251 Local<Value> on_msg_complete_v = message_handler->Get(ON_MESSAGE_COMPLETE_SYMBOL);
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
252 if (on_msg_complete_v->IsFunction() == false)
253 return 0;
254 Handle<Function> on_msg_complete = Handle<Function>::Cast(on_msg_complete_v);
255
256 TryCatch try_catch;
257 Local<Value> ret = on_msg_complete->Call(message_handler, 0, NULL);
258 if (ret.IsEmpty()) {
259 fatal_exception(try_catch);
260 return -2;
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
261 }
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
262 if (ret->IsFalse()) return -3;
263
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
264 return 0;
265 }
266
73fb24f @ry Relatively large update to TCP API. No more "protocol".
ry authored
267 HTTPConnection::HTTPConnection (Handle<Object> handle, enum http_parser_type type)
268 : Connection(handle)
19478ed @ry Major refactoring: program name now "node"
ry authored
269 {
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
270 http_parser_init (&parser_, type);
271 parser_.on_message_begin = on_message_begin;
272 parser_.on_path = on_path;
09c2ae5 @ry Slight change in tcp connection constructor
ry authored
273 parser_.on_query_string = on_query_string;
274 parser_.on_uri = on_uri;
275 parser_.on_fragment = on_fragment;
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
276 parser_.on_header_field = on_header_field;
277 parser_.on_header_value = on_header_value;
278 parser_.on_headers_complete = on_headers_complete;
4860f1c @ry add onMessageComplete and onBody handlers.
ry authored
279 parser_.on_body = on_body;
280 parser_.on_message_complete = on_message_complete;
be6b3ac @ry extract headers, status_code, path, http version from http messages.
ry authored
281 parser_.data = this;
282 }
283
9c3770d @ry Implement HTTPServer (untested!)
ry authored
284 Persistent<FunctionTemplate> HTTPServer::constructor_template;
285
286 void
287 HTTPServer::Initialize (Handle<Object> target)
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
288 {
9c3770d @ry Implement HTTPServer (untested!)
ry authored
289 HandleScope scope;
290
2e5b85a @ry Some fixes to allow HTTPServer to begin listening.
ry authored
291 Local<FunctionTemplate> t = FunctionTemplate::New(v8New);
9c3770d @ry Implement HTTPServer (untested!)
ry authored
292 constructor_template = Persistent<FunctionTemplate>::New(t);
293 constructor_template->Inherit(Acceptor::constructor_template);
294 constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
a80591a @ry Create node.http.Server and node.http.LowLevelServer
ry authored
295 target->Set(String::NewSymbol("LowLevelServer"), constructor_template->GetFunction());
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
296 }
297
298 Handle<Value>
299 HTTPServer::v8New (const Arguments& args)
300 {
9c3770d @ry Implement HTTPServer (untested!)
ry authored
301 HandleScope scope;
302
303 if (args.Length() < 1 || args[0]->IsFunction() == false)
304 return ThrowException(String::New("Must at give connection handler as the first argument"));
305
306 Local<Function> protocol_class = Local<Function>::Cast(args[0]);
307 Local<Object> options;
308
309 if (args.Length() > 1 && args[1]->IsObject()) {
310 options = args[1]->ToObject();
311 } else {
312 options = Object::New();
313 }
314
2e5b85a @ry Some fixes to allow HTTPServer to begin listening.
ry authored
315 new HTTPServer(args.This(), protocol_class, options);
9c3770d @ry Implement HTTPServer (untested!)
ry authored
316
317 return args.This();
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
318 }
319
320 Connection*
321 HTTPServer::OnConnection (struct sockaddr *addr, socklen_t len)
322 {
9c3770d @ry Implement HTTPServer (untested!)
ry authored
323 HandleScope scope;
324
73fb24f @ry Relatively large update to TCP API. No more "protocol".
ry authored
325 Local<Function> connection_handler = GetConnectionHandler ();
326 if (connection_handler.IsEmpty()) {
9c3770d @ry Implement HTTPServer (untested!)
ry authored
327 Close();
328 return NULL;
329 }
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
330
589d8af @ry Wrap NewInstance with TryCatch. (Was still missing the error.)
ry authored
331 TryCatch try_catch;
332
9c3770d @ry Implement HTTPServer (untested!)
ry authored
333 Local<Object> connection_handle =
73fb24f @ry Relatively large update to TCP API. No more "protocol".
ry authored
334 HTTPConnection::server_constructor_template->GetFunction()->NewInstance(0, NULL);
9c3770d @ry Implement HTTPServer (untested!)
ry authored
335
589d8af @ry Wrap NewInstance with TryCatch. (Was still missing the error.)
ry authored
336 if (connection_handle.IsEmpty()) {
337 fatal_exception(try_catch);
338 return NULL;
339 }
340
9c3770d @ry Implement HTTPServer (untested!)
ry authored
341 HTTPConnection *connection = NODE_UNWRAP(HTTPConnection, connection_handle);
febbf75 @ry Wrap calls in TryCatch; Check return values after UNWRAP.
ry authored
342 if (!connection) return NULL;
343
9c3770d @ry Implement HTTPServer (untested!)
ry authored
344 connection->SetAcceptor(handle_);
345
81691c7 @ry Fixes to get HTTP working with new TCP API.
ry authored
346 Handle<Value> argv[1] = { connection_handle };
347
348 Local<Value> ret = connection_handler->Call(handle_, 1, argv);
349
350 if (ret.IsEmpty())
351 fatal_exception(try_catch);
352
9c3770d @ry Implement HTTPServer (untested!)
ry authored
353 return connection;
354 }
38726e7 @ry various clean ups; HTTPConnection (js side) inherits from TCPConnection
ry authored
355
Something went wrong with that request. Please try again.