fixed bug in HTTPServer. wasn't properly destroying requests.
This commit is contained in:
Родитель
b4985d1a6e
Коммит
64ac9efb3d
26
example.js
26
example.js
|
@ -1,26 +0,0 @@
|
|||
function encode(data) {
|
||||
var chunk = data.toString();
|
||||
return chunk.length.toString(16) + "\r\n" + chunk + "\r\n";
|
||||
}
|
||||
|
||||
function Process(request) {
|
||||
|
||||
log( "path: " + request.path );
|
||||
log( "query string: " + request.query_string );
|
||||
|
||||
// onBody sends null on the last chunk.
|
||||
request.onBody = function (chunk) {
|
||||
if(chunk) {
|
||||
this.respond(encode(chunk));
|
||||
} else {
|
||||
this.respond(encode("\n"));
|
||||
this.respond("0\r\n\r\n");
|
||||
this.respond(null); // signals end-of-request
|
||||
}
|
||||
}
|
||||
request.respond("HTTP/1.0 200 OK\r\n");
|
||||
request.respond("Content-Type: text/plain\r\n");
|
||||
request.respond("Transfer-Encoding: chunked\r\n");
|
||||
request.respond("\r\n");
|
||||
}
|
||||
|
5
node.cc
5
node.cc
|
@ -57,8 +57,6 @@ ReadFile (const string& name)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
ParseOptions (int argc, char* argv[], map<string, string>& options, string* file)
|
||||
{
|
||||
|
@ -132,7 +130,8 @@ BlockingFileReadCallback (const Arguments& args)
|
|||
|
||||
String::Utf8Value filename(args[0]);
|
||||
|
||||
return ReadFile (*filename);
|
||||
Handle<String> output = ReadFile (*filename);
|
||||
return scope.Close(output);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
165
node_http.cc
165
node_http.cc
|
@ -12,67 +12,6 @@ using namespace std;
|
|||
|
||||
static Persistent<ObjectTemplate> request_template;
|
||||
|
||||
static string status_lines[] =
|
||||
{ "100 Continue"
|
||||
, "101 Switching Protocols"
|
||||
#define LEVEL_100 1
|
||||
, "200 OK"
|
||||
, "201 Created"
|
||||
, "202 Accepted"
|
||||
, "203 Non-Authoritative Information"
|
||||
, "204 No Content"
|
||||
, "205 Reset Content"
|
||||
, "206 Partial Content"
|
||||
, "207 Multi-Status"
|
||||
#define LEVEL_200 7
|
||||
, "300 Multiple Choices"
|
||||
, "301 Moved Permanently"
|
||||
, "302 Moved Temporarily"
|
||||
, "303 See Other"
|
||||
, "304 Not Modified"
|
||||
, "305 Use Proxy"
|
||||
, "306 unused"
|
||||
, "307 Temporary Redirect"
|
||||
#define LEVEL_300 7
|
||||
, "400 Bad Request"
|
||||
, "401 Unauthorized"
|
||||
, "402 Payment Required"
|
||||
, "403 Forbidden"
|
||||
, "404 Not Found"
|
||||
, "405 Not Allowed"
|
||||
, "406 Not Acceptable"
|
||||
, "407 Proxy Authentication Required"
|
||||
, "408 Request Time-out"
|
||||
, "409 Conflict"
|
||||
, "410 Gone"
|
||||
, "411 Length Required"
|
||||
, "412 Precondition Failed"
|
||||
, "413 Request Entity Too Large"
|
||||
, "414 Request-URI Too Large"
|
||||
, "415 Unsupported Media Type"
|
||||
, "416 Requested Range Not Satisfiable"
|
||||
, "417 Expectation Failed"
|
||||
, "418 unused"
|
||||
, "419 unused"
|
||||
, "420 unused"
|
||||
, "421 unused"
|
||||
, "422 Unprocessable Entity"
|
||||
, "423 Locked"
|
||||
, "424 Failed Dependency"
|
||||
#define LEVEL_400 24
|
||||
, "500 Internal Server Error"
|
||||
, "501 Method Not Implemented"
|
||||
, "502 Bad Gateway"
|
||||
, "503 Service Temporarily Unavailable"
|
||||
, "504 Gateway Time-out"
|
||||
, "505 HTTP Version Not Supported"
|
||||
, "506 Variant Also Negotiates"
|
||||
, "507 Insufficient Storage"
|
||||
, "508 unused"
|
||||
, "509 unused"
|
||||
, "510 Not Extended"
|
||||
};
|
||||
|
||||
// globals
|
||||
static Persistent<String> path_str;
|
||||
static Persistent<String> uri_str;
|
||||
|
@ -130,8 +69,8 @@ public:
|
|||
|
||||
void Parse(const void *buf, size_t count);
|
||||
void Write();
|
||||
HttpRequest* RequestBegin ();
|
||||
void RequestEnd (HttpRequest*);
|
||||
void Close();
|
||||
void AddRequest (HttpRequest *request);
|
||||
|
||||
oi_socket socket;
|
||||
Persistent<Function> js_onrequest;
|
||||
|
@ -139,6 +78,7 @@ public:
|
|||
private:
|
||||
ebb_request_parser parser;
|
||||
list<HttpRequest*> requests;
|
||||
list<HttpRequest*> finished_requests;
|
||||
friend class Server;
|
||||
};
|
||||
|
||||
|
@ -197,6 +137,8 @@ RespondCallback (const Arguments& args)
|
|||
{
|
||||
HandleScope scope;
|
||||
|
||||
printf("respondcallback!\n");
|
||||
|
||||
// TODO check that args.Holder()->GetInternalField(0)
|
||||
// is not NULL if so raise INVALID_STATE_ERR
|
||||
|
||||
|
@ -218,7 +160,6 @@ HttpRequest::Respond (Handle<Value> data)
|
|||
s->WriteAscii(buf->base, 0, s->Length());
|
||||
output.push_back(buf);
|
||||
}
|
||||
|
||||
connection.Write();
|
||||
}
|
||||
|
||||
|
@ -342,7 +283,8 @@ static ebb_request * on_request
|
|||
{
|
||||
Connection *connection = static_cast<Connection*> (data);
|
||||
|
||||
HttpRequest *request = connection->RequestBegin();
|
||||
HttpRequest *request = new HttpRequest(*connection);
|
||||
connection->AddRequest(request);
|
||||
|
||||
return &request->parser_info;
|
||||
}
|
||||
|
@ -354,25 +296,29 @@ static void on_read
|
|||
)
|
||||
{
|
||||
Connection *connection = static_cast<Connection*> (socket->data);
|
||||
write(1, buf, count);
|
||||
connection->Parse(buf, count);
|
||||
if(count == 0) {
|
||||
connection->Close();
|
||||
} else {
|
||||
//write(1, buf, count);
|
||||
connection->Parse(buf, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_close
|
||||
( oi_socket *socket
|
||||
)
|
||||
{
|
||||
printf("on_close\n");
|
||||
Connection *connection = static_cast<Connection*> (socket->data);
|
||||
delete connection;
|
||||
}
|
||||
|
||||
HttpRequest::~HttpRequest ()
|
||||
{
|
||||
connection.RequestEnd(this);
|
||||
|
||||
HandleScope scope;
|
||||
printf("request destruct %s\n", path.c_str());
|
||||
// HandleScope scope; needed?
|
||||
// delete a reference c++ HttpRequest
|
||||
js_object->SetInternalField(0, Null());
|
||||
js_object->SetInternalField(0, Undefined());
|
||||
// dispose of Persistent handle so that
|
||||
// it can be GC'd normally.
|
||||
js_object.Dispose();
|
||||
|
@ -398,10 +344,10 @@ HttpRequest::HttpRequest (Connection &c) : connection(c)
|
|||
void
|
||||
HttpRequest::MakeBodyCallback (const char *base, size_t length)
|
||||
{
|
||||
printf("makebodycallback\n");
|
||||
|
||||
HandleScope handle_scope;
|
||||
//
|
||||
// XXX don't always allocate onbody strings
|
||||
//
|
||||
|
||||
Handle<Value> onbody_val = js_object->Get(on_body_str);
|
||||
if (!onbody_val->IsFunction()) return;
|
||||
Handle<Function> onbody = Handle<Function>::Cast(onbody_val);
|
||||
|
@ -411,7 +357,7 @@ HttpRequest::MakeBodyCallback (const char *base, size_t length)
|
|||
Handle<Value> argv[argc];
|
||||
|
||||
if(length) {
|
||||
// TODO use array for binary data
|
||||
// TODO ByteArray?
|
||||
Handle<String> chunk = String::New(base, length);
|
||||
argv[0] = chunk;
|
||||
} else {
|
||||
|
@ -496,8 +442,10 @@ HttpRequest::CreateJSObject ()
|
|||
result->Set(headers_str, headers);
|
||||
|
||||
js_object = Persistent<Object>::New(result);
|
||||
// weak ref?
|
||||
|
||||
// XXX does the request's js_object need a MakeWeak callback?
|
||||
// i dont think so because at some point the connection closes
|
||||
// and we're going to delete the request.
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
|
||||
|
@ -505,6 +453,7 @@ HttpRequest::CreateJSObject ()
|
|||
static oi_socket*
|
||||
on_connection (oi_server *_server, struct sockaddr *addr, socklen_t len)
|
||||
{
|
||||
printf("on connection\n");
|
||||
HandleScope scope;
|
||||
|
||||
Server *server = static_cast<Server*> (_server->data);
|
||||
|
@ -524,31 +473,36 @@ on_connection (oi_server *_server, struct sockaddr *addr, socklen_t len)
|
|||
|
||||
Connection::Connection ()
|
||||
{
|
||||
oi_socket_init (&socket, 30.0);
|
||||
socket.on_read = on_read;
|
||||
socket.on_error = NULL;
|
||||
socket.on_close = on_close;
|
||||
socket.on_timeout = on_close;
|
||||
socket.on_drain = NULL;
|
||||
socket.data = this;
|
||||
oi_socket_init (&socket, 30.0); // TODO make timeout adjustable
|
||||
socket.on_read = on_read;
|
||||
socket.on_error = NULL;
|
||||
socket.on_close = on_close;
|
||||
socket.on_timeout = NULL;
|
||||
socket.on_drain = NULL;
|
||||
socket.data = this;
|
||||
|
||||
ebb_request_parser_init (&parser);
|
||||
parser.new_request = on_request;
|
||||
parser.data = this;
|
||||
parser.new_request = on_request;
|
||||
parser.data = this;
|
||||
}
|
||||
|
||||
Connection::~Connection ()
|
||||
{
|
||||
list<HttpRequest*>::iterator i = requests.begin();
|
||||
while(i != requests.end()) {
|
||||
delete *i; // this will call RequestEnd()
|
||||
}
|
||||
list<HttpRequest*>::iterator it = requests.begin();
|
||||
|
||||
// delete all the requests
|
||||
|
||||
for(it = requests.begin(); it != requests.end(); it++)
|
||||
delete *it;
|
||||
|
||||
for(it = finished_requests.begin(); it != finished_requests.end(); it++)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
void
|
||||
Connection::Parse(const void *buf, size_t count)
|
||||
{
|
||||
// FIXME change ebb_request_parser to use void* arg
|
||||
// FIXME change ebb_request_parser to have void* arg
|
||||
ebb_request_parser_execute ( &parser
|
||||
, static_cast<const char*> (buf)
|
||||
, count
|
||||
|
@ -560,18 +514,10 @@ Connection::Parse(const void *buf, size_t count)
|
|||
}
|
||||
}
|
||||
|
||||
HttpRequest *
|
||||
Connection::RequestBegin( )
|
||||
void
|
||||
Connection::AddRequest(HttpRequest *request)
|
||||
{
|
||||
HttpRequest *request = new HttpRequest(*this);
|
||||
requests.push_back(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
void
|
||||
Connection::RequestEnd(HttpRequest *request)
|
||||
{
|
||||
requests.remove(request);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -589,18 +535,25 @@ Connection::Write ( )
|
|||
}
|
||||
|
||||
if(request->done) {
|
||||
printf("pop request\n");
|
||||
|
||||
if(!ebb_request_should_keep_alive(&request->parser_info)) {
|
||||
printf("not keep-alive closing\n");
|
||||
socket.on_drain = oi_socket_close;
|
||||
} else {
|
||||
printf("keep-alive\n");
|
||||
}
|
||||
}
|
||||
|
||||
requests.pop_front();
|
||||
delete request;
|
||||
finished_requests.push_back(request);
|
||||
|
||||
Write();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Connection::Close ( )
|
||||
{
|
||||
oi_socket_close(&socket);
|
||||
}
|
||||
|
||||
static void
|
||||
server_destroy (Persistent<Value> _, void *data)
|
||||
{
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
<html lang=en-US-x-hixie>
|
||||
<head>
|
||||
<title>Node API</title>
|
||||
<link href="specification.css" rel=stylesheet>
|
||||
<!-- <link href="http://www.whatwg.org/style/specification"
|
||||
rel=stylesheet> -->
|
||||
<!-- <link href="specification.css" rel=stylesheet>-->
|
||||
<link href="http://www.whatwg.org/style/specification" rel=stylesheet>
|
||||
|
||||
<body class=draft>
|
||||
<div class=head>
|
||||
|
|
Загрузка…
Ссылка в новой задаче