1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #include "node_buffer.h"
24 #include "node_http_parser.h"
26 #include "base-object.h"
27 #include "base-object-inl.h"
34 #include <stdlib.h> // free()
35 #include <string.h> // strdup()
38 #define strcasecmp _stricmp
40 #include <strings.h> // strcasecmp()
43 // This is a binding to http_parser (https://github.com/joyent/http-parser)
44 // The goal is to decouple sockets from parsing for more javascript-level
45 // agility. A Buffer is read from a socket and passed to parser.execute().
46 // The parser then issues callbacks with slices of the data
47 // parser.onMessageBegin
51 // No copying is performed when slicing the buffer, only small reference
61 using v8::FunctionCallbackInfo;
62 using v8::FunctionTemplate;
64 using v8::HandleScope;
72 const uint32_t kOnHeaders = 0;
73 const uint32_t kOnHeadersComplete = 1;
74 const uint32_t kOnBody = 2;
75 const uint32_t kOnMessageComplete = 3;
78 #define HTTP_CB(name) \
79 static int name(http_parser* p_) { \
80 Parser* self = CONTAINER_OF(p_, Parser, parser_); \
81 return self->name##_(); \
86 #define HTTP_DATA_CB(name) \
87 static int name(http_parser* p_, const char* at, size_t length) { \
88 Parser* self = CONTAINER_OF(p_, Parser, parser_); \
89 return self->name##_(at, length); \
91 int name##_(const char* at, size_t length)
94 // helper class for the Parser
107 // If str_ does not point to a heap string yet, this function makes it do
108 // so. This is called at the end of each http_parser_execute() so as not
109 // to leak references. See issue #2438 and test-http-parser-bad-ref.js.
111 if (!on_heap_ && size_ > 0) {
112 char* s = new char[size_];
113 memcpy(s, str_, size_);
131 void Update(const char* str, size_t size) {
134 else if (on_heap_ || str_ + size_ != str) {
135 // Non-consecutive input, make a copy on the heap.
136 // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
137 char* s = new char[size_ + size];
138 memcpy(s, str_, size_);
139 memcpy(s + size_, str, size);
152 Local<String> ToString(Environment* env) const {
154 return OneByteString(env->isolate(), str_, size_);
156 return String::Empty(env->isolate());
166 class Parser : public BaseObject {
168 Parser(Environment* env, Local<Object> wrap, enum http_parser_type type)
169 : BaseObject(env, wrap),
170 current_buffer_len_(0),
171 current_buffer_data_(NULL) {
172 MakeWeak<Parser>(this);
181 HTTP_CB(on_message_begin) {
182 num_fields_ = num_values_ = 0;
184 status_message_.Reset();
189 HTTP_DATA_CB(on_url) {
190 url_.Update(at, length);
195 HTTP_DATA_CB(on_status) {
196 status_message_.Update(at, length);
201 HTTP_DATA_CB(on_header_field) {
202 if (num_fields_ == num_values_) {
203 // start of new field name
205 if (num_fields_ == ARRAY_SIZE(fields_)) {
206 // ran out of space - flush to javascript land
211 fields_[num_fields_ - 1].Reset();
214 assert(num_fields_ < static_cast<int>(ARRAY_SIZE(fields_)));
215 assert(num_fields_ == num_values_ + 1);
217 fields_[num_fields_ - 1].Update(at, length);
223 HTTP_DATA_CB(on_header_value) {
224 if (num_values_ != num_fields_) {
225 // start of new header value
227 values_[num_values_ - 1].Reset();
230 assert(num_values_ < static_cast<int>(ARRAY_SIZE(values_)));
231 assert(num_values_ == num_fields_);
233 values_[num_values_ - 1].Update(at, length);
239 HTTP_CB(on_headers_complete) {
240 Local<Object> obj = object();
241 Local<Value> cb = obj->Get(kOnHeadersComplete);
243 if (!cb->IsFunction())
246 Local<Object> message_info = Object::New(env()->isolate());
249 // Slow case, flush remaining headers.
252 // Fast case, pass headers and URL to JS land.
253 message_info->Set(env()->headers_string(), CreateHeaders());
254 if (parser_.type == HTTP_REQUEST)
255 message_info->Set(env()->url_string(), url_.ToString(env()));
257 num_fields_ = num_values_ = 0;
260 if (parser_.type == HTTP_REQUEST) {
261 message_info->Set(env()->method_string(),
262 Uint32::NewFromUnsigned(env()->isolate(),
267 if (parser_.type == HTTP_RESPONSE) {
268 message_info->Set(env()->status_code_string(),
269 Integer::New(env()->isolate(), parser_.status_code));
270 message_info->Set(env()->status_message_string(),
271 status_message_.ToString(env()));
275 message_info->Set(env()->version_major_string(),
276 Integer::New(env()->isolate(), parser_.http_major));
277 message_info->Set(env()->version_minor_string(),
278 Integer::New(env()->isolate(), parser_.http_minor));
280 message_info->Set(env()->should_keep_alive_string(),
281 http_should_keep_alive(&parser_) ?
282 True(env()->isolate()) : False(env()->isolate()));
284 message_info->Set(env()->upgrade_string(),
285 parser_.upgrade ? True(env()->isolate())
286 : False(env()->isolate()));
288 Local<Value> argv[1] = { message_info };
289 Local<Value> head_response =
290 cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
292 if (head_response.IsEmpty()) {
293 got_exception_ = true;
297 return head_response->IsTrue() ? 1 : 0;
301 HTTP_DATA_CB(on_body) {
302 HandleScope scope(env()->isolate());
304 Local<Object> obj = object();
305 Local<Value> cb = obj->Get(kOnBody);
307 if (!cb->IsFunction())
310 Local<Value> argv[3] = {
312 Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
313 Integer::NewFromUnsigned(env()->isolate(), length)
316 Local<Value> r = cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
319 got_exception_ = true;
327 HTTP_CB(on_message_complete) {
328 HandleScope scope(env()->isolate());
331 Flush(); // Flush trailing HTTP headers.
333 Local<Object> obj = object();
334 Local<Value> cb = obj->Get(kOnMessageComplete);
336 if (!cb->IsFunction())
339 Local<Value> r = cb.As<Function>()->Call(obj, 0, NULL);
342 got_exception_ = true;
350 static void New(const FunctionCallbackInfo<Value>& args) {
351 HandleScope handle_scope(args.GetIsolate());
352 Environment* env = Environment::GetCurrent(args.GetIsolate());
353 http_parser_type type =
354 static_cast<http_parser_type>(args[0]->Int32Value());
355 assert(type == HTTP_REQUEST || type == HTTP_RESPONSE);
356 new Parser(env, args.This(), type);
362 status_message_.Save();
364 for (int i = 0; i < num_fields_; i++) {
368 for (int i = 0; i < num_values_; i++) {
374 // var bytesParsed = parser->execute(buffer);
375 static void Execute(const FunctionCallbackInfo<Value>& args) {
376 Environment* env = Environment::GetCurrent(args.GetIsolate());
377 HandleScope scope(env->isolate());
379 Parser* parser = Unwrap<Parser>(args.This());
380 assert(parser->current_buffer_.IsEmpty());
381 assert(parser->current_buffer_len_ == 0);
382 assert(parser->current_buffer_data_ == NULL);
383 assert(Buffer::HasInstance(args[0]) == true);
385 Local<Object> buffer_obj = args[0].As<Object>();
386 char* buffer_data = Buffer::Data(buffer_obj);
387 size_t buffer_len = Buffer::Length(buffer_obj);
389 // This is a hack to get the current_buffer to the callbacks with the least
390 // amount of overhead. Nothing else will run while http_parser_execute()
391 // runs, therefore this pointer can be set and used for the execution.
392 parser->current_buffer_ = buffer_obj;
393 parser->current_buffer_len_ = buffer_len;
394 parser->current_buffer_data_ = buffer_data;
395 parser->got_exception_ = false;
398 http_parser_execute(&parser->parser_, &settings, buffer_data, buffer_len);
402 // Unassign the 'buffer_' variable
403 parser->current_buffer_.Clear();
404 parser->current_buffer_len_ = 0;
405 parser->current_buffer_data_ = NULL;
407 // If there was an exception in one of the callbacks
408 if (parser->got_exception_)
411 Local<Integer> nparsed_obj = Integer::New(env->isolate(), nparsed);
412 // If there was a parse error in one of the callbacks
413 // TODO(bnoordhuis) What if there is an error on EOF?
414 if (!parser->parser_.upgrade && nparsed != buffer_len) {
415 enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
417 Local<Value> e = Exception::Error(env->parse_error_string());
418 Local<Object> obj = e->ToObject();
419 obj->Set(env->bytes_parsed_string(), nparsed_obj);
420 obj->Set(env->code_string(),
421 OneByteString(env->isolate(), http_errno_name(err)));
423 args.GetReturnValue().Set(e);
425 args.GetReturnValue().Set(nparsed_obj);
430 static void Finish(const FunctionCallbackInfo<Value>& args) {
431 Environment* env = Environment::GetCurrent(args.GetIsolate());
432 HandleScope scope(env->isolate());
434 Parser* parser = Unwrap<Parser>(args.This());
436 assert(parser->current_buffer_.IsEmpty());
437 parser->got_exception_ = false;
439 int rv = http_parser_execute(&(parser->parser_), &settings, NULL, 0);
441 if (parser->got_exception_)
445 enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
447 Local<Value> e = env->parse_error_string();
448 Local<Object> obj = e->ToObject();
449 obj->Set(env->bytes_parsed_string(), Integer::New(env->isolate(), 0));
450 obj->Set(env->code_string(),
451 OneByteString(env->isolate(), http_errno_name(err)));
453 args.GetReturnValue().Set(e);
458 static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
459 HandleScope handle_scope(args.GetIsolate());
460 Environment* env = Environment::GetCurrent(args.GetIsolate());
462 http_parser_type type =
463 static_cast<http_parser_type>(args[0]->Int32Value());
465 assert(type == HTTP_REQUEST || type == HTTP_RESPONSE);
466 Parser* parser = Unwrap<Parser>(args.This());
467 // Should always be called from the same context.
468 assert(env == parser->env());
473 template <bool should_pause>
474 static void Pause(const FunctionCallbackInfo<Value>& args) {
475 HandleScope handle_scope(args.GetIsolate());
476 Environment* env = Environment::GetCurrent(args.GetIsolate());
477 Parser* parser = Unwrap<Parser>(args.This());
478 // Should always be called from the same context.
479 assert(env == parser->env());
480 http_parser_pause(&parser->parser_, should_pause);
486 Local<Array> CreateHeaders() {
487 // num_values_ is either -1 or the entry # of the last header
488 // so num_values_ == 0 means there's a single header
489 Local<Array> headers = Array::New(env()->isolate(), 2 * num_values_);
491 for (int i = 0; i < num_values_; ++i) {
492 headers->Set(2 * i, fields_[i].ToString(env()));
493 headers->Set(2 * i + 1, values_[i].ToString(env()));
500 // spill headers and request path to JS land
502 HandleScope scope(env()->isolate());
504 Local<Object> obj = object();
505 Local<Value> cb = obj->Get(kOnHeaders);
507 if (!cb->IsFunction())
510 Local<Value> argv[2] = {
515 Local<Value> r = cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
518 got_exception_ = true;
521 have_flushed_ = true;
525 void Init(enum http_parser_type type) {
526 http_parser_init(&parser_, type);
528 status_message_.Reset();
531 have_flushed_ = false;
532 got_exception_ = false;
537 StringPtr fields_[32]; // header fields
538 StringPtr values_[32]; // header values
540 StringPtr status_message_;
545 Local<Object> current_buffer_;
546 size_t current_buffer_len_;
547 char* current_buffer_data_;
548 static const struct http_parser_settings settings;
552 const struct http_parser_settings Parser::settings = {
553 Parser::on_message_begin,
556 Parser::on_header_field,
557 Parser::on_header_value,
558 Parser::on_headers_complete,
560 Parser::on_message_complete
564 void InitHttpParser(Handle<Object> target,
565 Handle<Value> unused,
566 Handle<Context> context,
568 Environment* env = Environment::GetCurrent(context);
569 Local<FunctionTemplate> t = FunctionTemplate::New(env->isolate(),
571 t->InstanceTemplate()->SetInternalFieldCount(1);
572 t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
574 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
575 Integer::New(env->isolate(), HTTP_REQUEST));
576 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
577 Integer::New(env->isolate(), HTTP_RESPONSE));
578 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
579 Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
580 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
581 Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
582 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
583 Integer::NewFromUnsigned(env->isolate(), kOnBody));
584 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
585 Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
587 Local<Array> methods = Array::New(env->isolate());
588 #define V(num, name, string) \
589 methods->Set(num, FIXED_ONE_BYTE_STRING(env->isolate(), #string));
592 t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods);
594 NODE_SET_PROTOTYPE_METHOD(t, "execute", Parser::Execute);
595 NODE_SET_PROTOTYPE_METHOD(t, "finish", Parser::Finish);
596 NODE_SET_PROTOTYPE_METHOD(t, "reinitialize", Parser::Reinitialize);
597 NODE_SET_PROTOTYPE_METHOD(t, "pause", Parser::Pause<true>);
598 NODE_SET_PROTOTYPE_METHOD(t, "resume", Parser::Pause<false>);
600 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
606 NODE_MODULE_CONTEXT_AWARE_BUILTIN(http_parser, node::InitHttpParser)