src: deduplicate CHECK_EQ/CHECK_NE macros
[platform/upstream/nodejs.git] / src / node_http_parser.cc
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
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:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
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.
21
22 #include "node.h"
23 #include "node_buffer.h"
24 #include "node_http_parser.h"
25
26 #include "base-object.h"
27 #include "base-object-inl.h"
28 #include "env.h"
29 #include "env-inl.h"
30 #include "util.h"
31 #include "util-inl.h"
32 #include "v8.h"
33
34 #include <stdlib.h>  // free()
35 #include <string.h>  // strdup()
36
37 #if defined(_MSC_VER)
38 #define strcasecmp _stricmp
39 #else
40 #include <strings.h>  // strcasecmp()
41 #endif
42
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
48 //     parser.onPath
49 //     parser.onBody
50 //     ...
51 // No copying is performed when slicing the buffer, only small reference
52 // allocations.
53
54
55 namespace node {
56
57 using v8::Array;
58 using v8::Context;
59 using v8::Exception;
60 using v8::Function;
61 using v8::FunctionCallbackInfo;
62 using v8::FunctionTemplate;
63 using v8::Handle;
64 using v8::HandleScope;
65 using v8::Integer;
66 using v8::Local;
67 using v8::Object;
68 using v8::String;
69 using v8::Uint32;
70 using v8::Value;
71
72 const uint32_t kOnHeaders = 0;
73 const uint32_t kOnHeadersComplete = 1;
74 const uint32_t kOnBody = 2;
75 const uint32_t kOnMessageComplete = 3;
76
77
78 #define HTTP_CB(name)                                                         \
79   static int name(http_parser* p_) {                                          \
80     Parser* self = CONTAINER_OF(p_, Parser, parser_);                         \
81     return self->name##_();                                                   \
82   }                                                                           \
83   int name##_()
84
85
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);                                         \
90   }                                                                           \
91   int name##_(const char* at, size_t length)
92
93
94 // helper class for the Parser
95 struct StringPtr {
96   StringPtr() {
97     on_heap_ = false;
98     Reset();
99   }
100
101
102   ~StringPtr() {
103     Reset();
104   }
105
106
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.
110   void Save() {
111     if (!on_heap_ && size_ > 0) {
112       char* s = new char[size_];
113       memcpy(s, str_, size_);
114       str_ = s;
115       on_heap_ = true;
116     }
117   }
118
119
120   void Reset() {
121     if (on_heap_) {
122       delete[] str_;
123       on_heap_ = false;
124     }
125
126     str_ = NULL;
127     size_ = 0;
128   }
129
130
131   void Update(const char* str, size_t size) {
132     if (str_ == NULL)
133       str_ = str;
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);
140
141       if (on_heap_)
142         delete[] str_;
143       else
144         on_heap_ = true;
145
146       str_ = s;
147     }
148     size_ += size;
149   }
150
151
152   Local<String> ToString(Environment* env) const {
153     if (str_)
154       return OneByteString(env->isolate(), str_, size_);
155     else
156       return String::Empty(env->isolate());
157   }
158
159
160   const char* str_;
161   bool on_heap_;
162   size_t size_;
163 };
164
165
166 class Parser : public BaseObject {
167  public:
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);
173     Init(type);
174   }
175
176
177   ~Parser() {
178   }
179
180
181   HTTP_CB(on_message_begin) {
182     num_fields_ = num_values_ = 0;
183     url_.Reset();
184     status_message_.Reset();
185     return 0;
186   }
187
188
189   HTTP_DATA_CB(on_url) {
190     url_.Update(at, length);
191     return 0;
192   }
193
194
195   HTTP_DATA_CB(on_status) {
196     status_message_.Update(at, length);
197     return 0;
198   }
199
200
201   HTTP_DATA_CB(on_header_field) {
202     if (num_fields_ == num_values_) {
203       // start of new field name
204       num_fields_++;
205       if (num_fields_ == ARRAY_SIZE(fields_)) {
206         // ran out of space - flush to javascript land
207         Flush();
208         num_fields_ = 1;
209         num_values_ = 0;
210       }
211       fields_[num_fields_ - 1].Reset();
212     }
213
214     assert(num_fields_ < static_cast<int>(ARRAY_SIZE(fields_)));
215     assert(num_fields_ == num_values_ + 1);
216
217     fields_[num_fields_ - 1].Update(at, length);
218
219     return 0;
220   }
221
222
223   HTTP_DATA_CB(on_header_value) {
224     if (num_values_ != num_fields_) {
225       // start of new header value
226       num_values_++;
227       values_[num_values_ - 1].Reset();
228     }
229
230     assert(num_values_ < static_cast<int>(ARRAY_SIZE(values_)));
231     assert(num_values_ == num_fields_);
232
233     values_[num_values_ - 1].Update(at, length);
234
235     return 0;
236   }
237
238
239   HTTP_CB(on_headers_complete) {
240     Local<Object> obj = object();
241     Local<Value> cb = obj->Get(kOnHeadersComplete);
242
243     if (!cb->IsFunction())
244       return 0;
245
246     Local<Object> message_info = Object::New(env()->isolate());
247
248     if (have_flushed_) {
249       // Slow case, flush remaining headers.
250       Flush();
251     } else {
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()));
256     }
257     num_fields_ = num_values_ = 0;
258
259     // METHOD
260     if (parser_.type == HTTP_REQUEST) {
261       message_info->Set(env()->method_string(),
262                         Uint32::NewFromUnsigned(env()->isolate(),
263                                                 parser_.method));
264     }
265
266     // STATUS
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()));
272     }
273
274     // VERSION
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));
279
280     message_info->Set(env()->should_keep_alive_string(),
281                       http_should_keep_alive(&parser_) ?
282                           True(env()->isolate()) : False(env()->isolate()));
283
284     message_info->Set(env()->upgrade_string(),
285                       parser_.upgrade ? True(env()->isolate())
286                                       : False(env()->isolate()));
287
288     Local<Value> argv[1] = { message_info };
289     Local<Value> head_response =
290         cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
291
292     if (head_response.IsEmpty()) {
293       got_exception_ = true;
294       return -1;
295     }
296
297     return head_response->IsTrue() ? 1 : 0;
298   }
299
300
301   HTTP_DATA_CB(on_body) {
302     HandleScope scope(env()->isolate());
303
304     Local<Object> obj = object();
305     Local<Value> cb = obj->Get(kOnBody);
306
307     if (!cb->IsFunction())
308       return 0;
309
310     Local<Value> argv[3] = {
311       current_buffer_,
312       Integer::NewFromUnsigned(env()->isolate(), at - current_buffer_data_),
313       Integer::NewFromUnsigned(env()->isolate(), length)
314     };
315
316     Local<Value> r = cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
317
318     if (r.IsEmpty()) {
319       got_exception_ = true;
320       return -1;
321     }
322
323     return 0;
324   }
325
326
327   HTTP_CB(on_message_complete) {
328     HandleScope scope(env()->isolate());
329
330     if (num_fields_)
331       Flush();  // Flush trailing HTTP headers.
332
333     Local<Object> obj = object();
334     Local<Value> cb = obj->Get(kOnMessageComplete);
335
336     if (!cb->IsFunction())
337       return 0;
338
339     Local<Value> r = cb.As<Function>()->Call(obj, 0, NULL);
340
341     if (r.IsEmpty()) {
342       got_exception_ = true;
343       return -1;
344     }
345
346     return 0;
347   }
348
349
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);
357   }
358
359
360   void Save() {
361     url_.Save();
362     status_message_.Save();
363
364     for (int i = 0; i < num_fields_; i++) {
365       fields_[i].Save();
366     }
367
368     for (int i = 0; i < num_values_; i++) {
369       values_[i].Save();
370     }
371   }
372
373
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());
378
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);
384
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);
388
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;
396
397     size_t nparsed =
398       http_parser_execute(&parser->parser_, &settings, buffer_data, buffer_len);
399
400     parser->Save();
401
402     // Unassign the 'buffer_' variable
403     parser->current_buffer_.Clear();
404     parser->current_buffer_len_ = 0;
405     parser->current_buffer_data_ = NULL;
406
407     // If there was an exception in one of the callbacks
408     if (parser->got_exception_)
409       return;
410
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_);
416
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)));
422
423       args.GetReturnValue().Set(e);
424     } else {
425       args.GetReturnValue().Set(nparsed_obj);
426     }
427   }
428
429
430   static void Finish(const FunctionCallbackInfo<Value>& args) {
431     Environment* env = Environment::GetCurrent(args.GetIsolate());
432     HandleScope scope(env->isolate());
433
434     Parser* parser = Unwrap<Parser>(args.This());
435
436     assert(parser->current_buffer_.IsEmpty());
437     parser->got_exception_ = false;
438
439     int rv = http_parser_execute(&(parser->parser_), &settings, NULL, 0);
440
441     if (parser->got_exception_)
442       return;
443
444     if (rv != 0) {
445       enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
446
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)));
452
453       args.GetReturnValue().Set(e);
454     }
455   }
456
457
458   static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
459     HandleScope handle_scope(args.GetIsolate());
460     Environment* env = Environment::GetCurrent(args.GetIsolate());
461
462     http_parser_type type =
463         static_cast<http_parser_type>(args[0]->Int32Value());
464
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());
469     parser->Init(type);
470   }
471
472
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);
481   }
482
483
484  private:
485
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_);
490
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()));
494     }
495
496     return headers;
497   }
498
499
500   // spill headers and request path to JS land
501   void Flush() {
502     HandleScope scope(env()->isolate());
503
504     Local<Object> obj = object();
505     Local<Value> cb = obj->Get(kOnHeaders);
506
507     if (!cb->IsFunction())
508       return;
509
510     Local<Value> argv[2] = {
511       CreateHeaders(),
512       url_.ToString(env())
513     };
514
515     Local<Value> r = cb.As<Function>()->Call(obj, ARRAY_SIZE(argv), argv);
516
517     if (r.IsEmpty())
518       got_exception_ = true;
519
520     url_.Reset();
521     have_flushed_ = true;
522   }
523
524
525   void Init(enum http_parser_type type) {
526     http_parser_init(&parser_, type);
527     url_.Reset();
528     status_message_.Reset();
529     num_fields_ = 0;
530     num_values_ = 0;
531     have_flushed_ = false;
532     got_exception_ = false;
533   }
534
535
536   http_parser parser_;
537   StringPtr fields_[32];  // header fields
538   StringPtr values_[32];  // header values
539   StringPtr url_;
540   StringPtr status_message_;
541   int num_fields_;
542   int num_values_;
543   bool have_flushed_;
544   bool got_exception_;
545   Local<Object> current_buffer_;
546   size_t current_buffer_len_;
547   char* current_buffer_data_;
548   static const struct http_parser_settings settings;
549 };
550
551
552 const struct http_parser_settings Parser::settings = {
553   Parser::on_message_begin,
554   Parser::on_url,
555   Parser::on_status,
556   Parser::on_header_field,
557   Parser::on_header_value,
558   Parser::on_headers_complete,
559   Parser::on_body,
560   Parser::on_message_complete
561 };
562
563
564 void InitHttpParser(Handle<Object> target,
565                     Handle<Value> unused,
566                     Handle<Context> context,
567                     void* priv) {
568   Environment* env = Environment::GetCurrent(context);
569   Local<FunctionTemplate> t = FunctionTemplate::New(env->isolate(),
570                                                     Parser::New);
571   t->InstanceTemplate()->SetInternalFieldCount(1);
572   t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));
573
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));
586
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));
590   HTTP_METHOD_MAP(V)
591 #undef V
592   t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods);
593
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>);
599
600   target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
601               t->GetFunction());
602 }
603
604 }  // namespace node
605
606 NODE_MODULE_CONTEXT_AWARE_BUILTIN(http_parser, node::InitHttpParser)