The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / src / http.cc @ 90fc8d36

History | View | Annotate | Download (17.4 KB)

1
#include "node.h"
2
#include "http.h"
3

    
4
#include <oi_socket.h>
5
#include <ebb_request_parser.h>
6

    
7
#include <string>
8
#include <list>
9

    
10
#include <assert.h>
11

    
12
using namespace v8;
13
using namespace std;
14

    
15
static Persistent<ObjectTemplate> request_template;
16

    
17
// globals
18
static Persistent<String> path_str; 
19
static Persistent<String> uri_str; 
20
static Persistent<String> query_string_str; 
21
static Persistent<String> fragment_str; 
22
static Persistent<String> method_str; 
23
static Persistent<String> http_version_str; 
24
static Persistent<String> headers_str; 
25

    
26
static Persistent<String> on_request_str; 
27
static Persistent<String> on_body_str; 
28
static Persistent<String> respond_str; 
29

    
30
static Persistent<String> copy_str;
31
static Persistent<String> delete_str;
32
static Persistent<String> get_str;
33
static Persistent<String> head_str;
34
static Persistent<String> lock_str;
35
static Persistent<String> mkcol_str;
36
static Persistent<String> move_str;
37
static Persistent<String> options_str;
38
static Persistent<String> post_str;
39
static Persistent<String> propfind_str;
40
static Persistent<String> proppatch_str;
41
static Persistent<String> put_str;
42
static Persistent<String> trace_str;
43
static Persistent<String> unlock_str;
44

    
45
#define INVALID_STATE_ERR 1
46

    
47
class HttpServer {
48
public:
49
  HttpServer (Handle<Object> _js_server);
50
  ~HttpServer ();
51

    
52
  int Start(struct addrinfo *servinfo);
53
  void Stop();
54

    
55
  Handle<Value> Callback()
56
  {
57
    HandleScope scope;
58
    Handle<Value> value = js_server->Get(on_request_str);
59
    return scope.Close(value);
60
  }
61

    
62
private:
63
  oi_server server;
64
  Persistent<Object> js_server;
65
};
66

    
67
class HttpRequest;
68

    
69
class Connection {
70
public:
71
  Connection();
72
  ~Connection();
73

    
74
  void Parse(const void *buf, size_t count);
75
  void Write();
76
  void Close();
77
  void AddRequest (HttpRequest *request);
78

    
79
  oi_socket socket;
80
  Persistent<Function> js_onrequest;
81

    
82
private:
83
  ebb_request_parser parser;
84
  list<HttpRequest*> requests;
85
  list<HttpRequest*> finished_requests;
86
  friend class HttpServer;
87
};
88

    
89
class HttpRequest {
90
 public:
91
  HttpRequest (Connection &c);
92
  /* Deleted from C++ as soon as possible.
93
   * Javascript object might linger. This is okay
94
   */
95
  ~HttpRequest();
96

    
97
  void MakeBodyCallback (const char *base, size_t length);
98
  Local<Object> CreateJSObject ();
99
  void Respond (Handle<Value> data);
100

    
101
  string path;
102
  string query_string;
103
  string fragment;
104
  string uri;
105

    
106
  list<string> header_fields;
107
  list<string> header_values;
108

    
109
  Connection &connection;
110
  ebb_request parser_info;
111

    
112
  list<oi_buf*> output;
113
  bool done;
114
  Persistent<Object> js_object;
115
};
116

    
117
static Handle<Value>
118
GetMethodString (int method)
119
{
120
  switch(method) {
121
    case EBB_COPY:      return copy_str;
122
    case EBB_DELETE:    return delete_str;
123
    case EBB_GET:       return get_str;
124
    case EBB_HEAD:      return head_str;
125
    case EBB_LOCK:      return lock_str;
126
    case EBB_MKCOL:     return mkcol_str;
127
    case EBB_MOVE:      return move_str;
128
    case EBB_OPTIONS:   return options_str;
129
    case EBB_POST:      return post_str;
130
    case EBB_PROPFIND:  return propfind_str;
131
    case EBB_PROPPATCH: return proppatch_str;
132
    case EBB_PUT:       return put_str;
133
    case EBB_TRACE:     return trace_str;
134
    case EBB_UNLOCK:    return unlock_str;
135
  }
136
  return Null();
137
}
138

    
139
static Handle<Value>
140
RespondCallback (const Arguments& args) 
141
{
142
  HandleScope scope;
143

    
144
  Handle<Value> v = args.Holder()->GetInternalField(0);
145
  if(v->IsUndefined()) {
146
    // check that args.Holder()->GetInternalField(0)
147
    // is not NULL if so raise INVALID_STATE_ERR
148
    printf("null request external\n");
149
    ThrowException(Integer::New(INVALID_STATE_ERR)); 
150
    return Undefined();
151
  }
152
  Handle<External> field = Handle<External>::Cast(v);
153
  HttpRequest* request = static_cast<HttpRequest*>(field->Value());
154
  request->Respond(args[0]);
155
  return Undefined();
156
}
157

    
158
void
159
HttpRequest::Respond (Handle<Value> data)
160
{
161
  if(data == Null()) {
162
    done = true;
163
  } else {
164
    Handle<String> s = data->ToString();
165

    
166
    size_t l1 = s->Utf8Length(), l2;
167
    oi_buf *buf = oi_buf_new2(l1);
168
    l2 = s->WriteUtf8(buf->base, l1);
169
    assert(l1 == l2);
170

    
171
    output.push_back(buf);
172
  }
173
  connection.Write();
174
}
175

    
176

    
177
static void
178
on_path (ebb_request *req, const char *buf, size_t len)
179
{
180
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
181
  request->path.append(buf, len);
182
}
183

    
184
static void
185
on_uri (ebb_request *req, const char *buf, size_t len)
186
{
187
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
188
  request->uri.append(buf, len);
189
}
190

    
191
static void
192
on_query_string (ebb_request *req, const char *buf, size_t len)
193
{
194
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
195
  request->query_string.append(buf, len);
196
}
197

    
198
static void
199
on_fragment (ebb_request *req, const char *buf, size_t len)
200
{
201
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
202
  request->fragment.append(buf, len);
203
}
204

    
205
static const char upcase[] =
206
  "\0______________________________"
207
  "_________________0123456789_____"
208
  "__ABCDEFGHIJKLMNOPQRSTUVWXYZ____"
209
  "__ABCDEFGHIJKLMNOPQRSTUVWXYZ____"
210
  "________________________________"
211
  "________________________________"
212
  "________________________________"
213
  "________________________________";
214

    
215
static void
216
on_header_field (ebb_request *req, const char *buf, size_t len, int header_index)
217
{
218
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
219

    
220
  char upbuf[len];
221

    
222
  for(int i = 0; i < len; i++) 
223
    upbuf[i] = upcase[buf[i]];
224

    
225
  if( request->header_fields.size() == header_index - 1) {
226
    request->header_fields.back().append(upbuf, len);
227
  } else { 
228
    request->header_fields.push_back( string(upbuf, len) );
229
  }
230
}
231

    
232
static void
233
on_header_value (ebb_request *req, const char *buf, size_t len, int header_index)
234
{
235
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
236

    
237
  if( request->header_values.size() == header_index - 1) {
238
    request->header_values.back().append(buf, len);
239
  } else { 
240
    request->header_values.push_back( string(buf, len) );
241
  }
242
}
243

    
244
static void
245
on_headers_complete (ebb_request *req)
246
{
247
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
248

    
249
  HandleScope scope;
250

    
251
  Handle<Object> js_request = request->CreateJSObject();
252

    
253
  // Set up an exception handler before calling the Process function
254
  TryCatch try_catch;
255

    
256
  // Invoke the process function, giving the global object as 'this'
257
  // and one argument, the request.
258
  const int argc = 1;
259
  Handle<Value> argv[argc] = { js_request };
260
  Handle<Value> r = request->connection.js_onrequest->Call(Context::GetCurrent()->Global(), argc, argv);
261

    
262
  if(try_catch.HasCaught())
263
    node_fatal_exception(try_catch);
264
}
265

    
266
static void
267
on_request_complete (ebb_request *req)
268
{
269
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
270
  request->MakeBodyCallback(NULL, 0); // EOF
271
}
272

    
273
static void
274
on_body (ebb_request *req, const char *base, size_t length)
275
{
276
  HttpRequest *request = static_cast<HttpRequest*> (req->data);
277

    
278
  if(length)
279
    request->MakeBodyCallback(base, length);
280
}
281

    
282
static ebb_request * on_request
283
  ( void *data
284
  ) 
285
{
286
  Connection *connection = static_cast<Connection*> (data);
287

    
288
  HttpRequest *request = new HttpRequest(*connection);
289
  connection->AddRequest(request);
290
  
291
  return &request->parser_info;
292
}
293

    
294
static void on_read 
295
  ( oi_socket *socket
296
  , const void *buf
297
  , size_t count
298
  )
299
{
300
  Connection *connection = static_cast<Connection*> (socket->data);
301
  if(count == 0) {
302
    connection->Close();
303
  } else {
304
    //write(1, buf, count);
305
    connection->Parse(buf, count);  
306
  }
307
}
308

    
309
static void on_close 
310
  ( oi_socket *socket
311
  )
312
{
313
  Connection *connection = static_cast<Connection*> (socket->data);
314
  delete connection;
315
}
316

    
317
HttpRequest::~HttpRequest ()
318
{
319
  HandleScope scope; // needed?
320
  // delete a reference c++ HttpRequest
321
  js_object->SetInternalField(0, Undefined());
322
  js_object->Delete(respond_str);
323
  // dispose of Persistent handle so that 
324
  // it can be GC'd normally.
325
  js_object.Dispose();
326
}
327

    
328
HttpRequest::HttpRequest (Connection &c) : connection(c)
329
{
330
  ebb_request_init(&parser_info); 
331
  parser_info.on_path             = on_path;
332
  parser_info.on_query_string     = on_query_string;
333
  parser_info.on_uri              = on_uri;
334
  parser_info.on_fragment         = on_fragment;
335
  parser_info.on_header_field     = on_header_field;
336
  parser_info.on_header_value     = on_header_value;
337
  parser_info.on_headers_complete = on_headers_complete;
338
  parser_info.on_body             = on_body;
339
  parser_info.on_complete         = on_request_complete;
340
  parser_info.data                = this;
341

    
342
  done = false;
343
}
344

    
345
void
346
HttpRequest::MakeBodyCallback (const char *base, size_t length)
347
{
348
  HandleScope handle_scope;
349

    
350
  Handle<Value> onbody_val = js_object->Get(on_body_str);  
351
  if (!onbody_val->IsFunction()) return;
352
  Handle<Function> onbody = Handle<Function>::Cast(onbody_val);
353

    
354
  TryCatch try_catch;
355
  const int argc = 1;
356
  Handle<Value> argv[argc];
357
  
358
  if(length) {
359
    // TODO ByteArray?
360
    //
361
    
362
    uint16_t expanded_base[length];
363
    for(int i = 0; i < length; i++) {
364
      expanded_base[i] = base[i];
365
    }
366

    
367
    Handle<String> chunk = String::New(expanded_base, length);
368
    argv[0] = chunk;
369
  } else {
370
    argv[0] = Null();
371
  }
372

    
373
  Handle<Value> result = onbody->Call(js_object, argc, argv);
374

    
375
  if(try_catch.HasCaught())
376
    node_fatal_exception(try_catch);
377
}
378

    
379
Local<Object>
380
HttpRequest::CreateJSObject ()
381
{
382
  HandleScope scope;
383

    
384
  if (request_template.IsEmpty()) {
385
    Handle<ObjectTemplate> raw_template = ObjectTemplate::New();
386
    raw_template->SetInternalFieldCount(1);
387
    raw_template->Set(respond_str, FunctionTemplate::New(RespondCallback));
388

    
389
    request_template = Persistent<ObjectTemplate>::New(raw_template);
390
  }
391

    
392
  // Create an empty http request wrapper.
393
  Handle<Object> result = request_template->NewInstance();
394

    
395
  // Wrap the raw C++ pointer in an External so it can be referenced
396
  // from within JavaScript.
397
  Handle<External> request_ptr = External::New(this);
398

    
399
  // Store the request pointer in the JavaScript wrapper.
400
  result->SetInternalField(0, request_ptr);
401

    
402
  result->Set ( path_str
403
              , String::New(path.c_str(), path.length())
404
              );
405

    
406
  result->Set ( uri_str
407
              , String::New(uri.c_str(), uri.length())
408
              );
409

    
410
  result->Set ( query_string_str
411
              , String::New(query_string.c_str(), query_string.length())
412
              );
413

    
414
  result->Set ( fragment_str
415
              , String::New(fragment.c_str(), fragment.length())
416
              );
417

    
418
  result->Set ( method_str
419
              , GetMethodString(parser_info.method)
420
              );
421

    
422
  char version[10];
423
  snprintf ( version
424
           , 10 // big enough? :)
425
           , "%d.%d"
426
           , parser_info.version_major
427
           , parser_info.version_minor
428
           ); 
429
  result->Set ( http_version_str
430
              , String::New(version)
431
              );
432

    
433
  
434
  Handle<Object> headers = Object::New();
435
  list<string>::iterator field_iterator = header_fields.begin();
436
  list<string>::iterator value_iterator = header_values.begin();
437
  while( value_iterator != header_values.end() ) {
438
    string &f = *field_iterator;
439
    string &v = *value_iterator;
440
    
441
    headers->Set( String::NewSymbol(f.c_str(), f.length())
442
                , String::New(v.c_str(), v.length() ) 
443
                );
444

    
445
    field_iterator++;
446
    value_iterator++;
447
  }
448
  result->Set(headers_str, headers);
449

    
450
  js_object = Persistent<Object>::New(result);
451
  // XXX does the request's js_object need a MakeWeak callback?
452
  // i dont think so because at some point the connection closes
453
  // and we're going to delete the request. 
454
  
455
  return scope.Close(result);
456
}
457

    
458

    
459
static oi_socket*
460
on_connection (oi_server *_server, struct sockaddr *addr, socklen_t len)
461
{
462
  HandleScope scope;
463

    
464
  HttpServer *server = static_cast<HttpServer*> (_server->data);
465

    
466
  Handle<Value> callback_v = server->Callback();
467

    
468
  if(callback_v == Undefined())
469
    return NULL;
470

    
471
  Connection *connection = new Connection();
472

    
473
  Handle<Function> f = Handle<Function>::Cast(callback_v);
474
  connection->js_onrequest = Persistent<Function>::New(f);
475

    
476
  return &connection->socket;
477
}
478

    
479
Connection::Connection ()
480
{
481
  oi_socket_init (&socket, 30.0); // TODO make timeout adjustable
482
  socket.on_read    = on_read;
483
  socket.on_error   = NULL;
484
  socket.on_close   = on_close;
485
  socket.on_timeout = NULL;
486
  socket.on_drain   = NULL;
487
  socket.data       = this;
488

    
489
  ebb_request_parser_init (&parser);
490
  parser.new_request = on_request;
491
  parser.data        = this;
492
}
493

    
494
Connection::~Connection ()
495
{
496
  list<HttpRequest*>::iterator it = requests.begin();
497

    
498
  // delete all the requests
499

    
500
  for(it = requests.begin(); it != requests.end(); it++)
501
    delete *it;
502

    
503
  for(it = finished_requests.begin(); it != finished_requests.end(); it++)
504
    delete *it;
505
}
506

    
507
void
508
Connection::Parse(const void *buf, size_t count)
509
{
510
  // FIXME change ebb_request_parser to have void* arg
511
  ebb_request_parser_execute ( &parser
512
                             , static_cast<const char*> (buf) 
513
                             , count
514
                             );
515

    
516
  if(ebb_request_parser_has_error(&parser)) {
517
    fprintf(stderr, "parse error closing connection\n");
518
    oi_socket_close(&socket);
519
  }
520
}
521

    
522
void 
523
Connection::AddRequest(HttpRequest *request)
524
{
525
  requests.push_back(request);
526
}
527

    
528
void
529
Connection::Write ( ) 
530
{
531
  if(requests.size() == 0)
532
    return;
533

    
534
  HttpRequest *request = requests.front(); 
535

    
536
  while(request->output.size() > 0) {
537
    oi_buf *buf = request->output.front();
538
    oi_socket_write(&socket, buf);
539
    request->output.pop_front();
540
  }
541

    
542
  if(request->done) {
543
    if(!ebb_request_should_keep_alive(&request->parser_info)) {
544
      socket.on_drain = oi_socket_close;
545
    } 
546

    
547
    requests.pop_front();
548
    finished_requests.push_back(request);
549

    
550
    Write();
551
  }
552
}
553

    
554
void
555
Connection::Close ( ) 
556
{
557
  oi_socket_close(&socket);
558
}
559

    
560
static void
561
server_destroy (Persistent<Value> _, void *data)
562
{
563
  HttpServer *server = static_cast<HttpServer *> (data);
564
  delete server;
565
}
566

    
567
HttpServer::HttpServer (Handle<Object> _js_server)
568
{
569
  oi_server_init(&server, 1024);
570
  server.on_connection = on_connection;
571
  server.data = this;
572
  HandleScope scope;
573
  js_server = Persistent<Object>::New (_js_server);
574
  // are we ever going to need this external?
575
  js_server->SetInternalField (0, External::New(this));
576
  js_server.MakeWeak (this, server_destroy);
577
}
578

    
579
HttpServer::~HttpServer ()
580
{
581
  Stop();
582
  js_server.Dispose();
583
  js_server.Clear(); // necessary? 
584
}
585

    
586
int
587
HttpServer::Start(struct addrinfo *servinfo) 
588
{
589
  int r = oi_server_listen(&server, servinfo);
590
  if(r == 0)
591
    oi_server_attach(EV_DEFAULT_UC_ &server);
592
  return r;
593
}
594

    
595
void
596
HttpServer::Stop() 
597
{
598
  oi_server_close (&server);
599
  oi_server_detach (&server);
600
}
601

    
602
/* This constructor takes 2 arguments: host, port. */
603
static Handle<Value>
604
newHTTPHttpServer (const Arguments& args) 
605
{
606
  if (args.Length() < 3)
607
    return Undefined();
608

    
609
  HandleScope scope;
610

    
611
  char *host = NULL; 
612
  String::AsciiValue host_v(args[0]->ToString());
613
  if(args[0]->IsString()) {
614
    host = *host_v;
615
  }
616
  String::AsciiValue port(args[1]->ToString());
617

    
618
  Handle<Function> onrequest = Handle<Function>::Cast(args[2]);
619
  args.This()->Set(on_request_str, onrequest);
620

    
621
  // get addrinfo for localhost, PORT
622
  struct addrinfo *servinfo;
623
  struct addrinfo hints;
624
  memset(&hints, 0, sizeof hints);
625
  hints.ai_family = AF_UNSPEC;
626
  hints.ai_socktype = SOCK_STREAM;
627
  hints.ai_flags = AI_PASSIVE;
628
  // FIXME BLOCKING
629
  int r = getaddrinfo(host, *port, &hints, &servinfo);
630
  if (r != 0)
631
    return Undefined(); // XXX raise error?
632

    
633
  //
634
  //
635
  //
636
  // TODO host is ignored for now assumed localhost
637
  //
638
  //
639
  //
640
  //
641

    
642
  HttpServer *server = new HttpServer(args.This());
643
  if(server == NULL)
644
    return Undefined(); // XXX raise error?
645

    
646
  r = server->Start(servinfo);
647
  if (r != 0)
648
    return Undefined(); // XXX raise error?
649

    
650
  return args.This();
651
}
652

    
653
void
654
NodeInit_http (Handle<Object> target)
655
{
656
  HandleScope scope;
657

    
658
  Local<FunctionTemplate> server_t = FunctionTemplate::New(newHTTPHttpServer);
659
  server_t->InstanceTemplate()->SetInternalFieldCount(1);
660
  
661
  server_t->Set("INVALID_STATE_ERR", Integer::New(INVALID_STATE_ERR));
662

    
663
  target->Set(String::New("HTTPServer"), server_t->GetFunction());
664

    
665
  path_str         = Persistent<String>::New( String::NewSymbol("path") );
666
  uri_str          = Persistent<String>::New( String::NewSymbol("uri") );
667
  query_string_str = Persistent<String>::New( String::NewSymbol("query_string") );
668
  fragment_str     = Persistent<String>::New( String::NewSymbol("fragment") );
669
  method_str       = Persistent<String>::New( String::NewSymbol("method") );
670
  http_version_str = Persistent<String>::New( String::NewSymbol("http_version") );
671
  headers_str      = Persistent<String>::New( String::NewSymbol("headers") );
672

    
673
  on_request_str = Persistent<String>::New( String::NewSymbol("onrequest") );
674
  on_body_str    = Persistent<String>::New( String::NewSymbol("onbody") );
675
  respond_str    = Persistent<String>::New( String::NewSymbol("respond") );
676

    
677
  copy_str      = Persistent<String>::New( String::New("COPY") );
678
  delete_str    = Persistent<String>::New( String::New("DELETE") );
679
  get_str       = Persistent<String>::New( String::New("GET") );
680
  head_str      = Persistent<String>::New( String::New("HEAD") );
681
  lock_str      = Persistent<String>::New( String::New("LOCK") );
682
  mkcol_str     = Persistent<String>::New( String::New("MKCOL") );
683
  move_str      = Persistent<String>::New( String::New("MOVE") );
684
  options_str   = Persistent<String>::New( String::New("OPTIONS") );
685
  post_str      = Persistent<String>::New( String::New("POST") );
686
  propfind_str  = Persistent<String>::New( String::New("PROPFIND") );
687
  proppatch_str = Persistent<String>::New( String::New("PROPPATCH") );
688
  put_str       = Persistent<String>::New( String::New("PUT") );
689
  trace_str     = Persistent<String>::New( String::New("TRACE") );
690
  unlock_str    = Persistent<String>::New( String::New("UNLOCK") );
691
}