Browse Source

Merge branch 'v0.4'

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
b6a742d76f
  1. 1
      deps/http_parser/.gitignore
  2. 6
      deps/http_parser/LICENSE-MIT
  3. 13
      deps/http_parser/Makefile
  4. 114
      deps/http_parser/http_parser.c
  5. 21
      deps/http_parser/http_parser.h
  6. 141
      deps/http_parser/test.c
  7. 2
      doc/api/assert.markdown
  8. 6
      doc/api/crypto.markdown
  9. 7
      doc/api/fs.markdown
  10. 6
      doc/api/globals.markdown
  11. 2
      doc/api/util.markdown
  12. 18
      lib/_debugger.js
  13. 2
      lib/stream.js
  14. 4
      lib/url.js
  15. 58
      src/node_crypto.cc
  16. 58
      test/simple/test-stream-pipe-error-handling.js
  17. 30
      test/simple/test-url.js
  18. 12
      wscript

1
deps/http_parser/.gitignore

@ -2,3 +2,4 @@ tags
*.o
test
test_g
test_fast

6
deps/http_parser/LICENSE-MIT

@ -1,4 +1,8 @@
Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
Igor Sysoev.
Additional changes are licensed under the same terms as NGINX and
copyright Joyent, Inc. and other Node contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to

13
deps/http_parser/Makefile

@ -1,11 +1,14 @@
OPT_DEBUG=-O0 -g -Wall -Wextra -Werror -I.
OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 -I.
CPPFLAGS?=-Wall -Wextra -Werror -I.
OPT_DEBUG=$(CPPFLAGS) -O0 -g -DHTTP_PARSER_STRICT=1
OPT_FAST=$(CPPFLAGS) -O3 -DHTTP_PARSER_STRICT=0
CC?=gcc
AR?=ar
test: test_g
test: test_g test_fast
./test_g
./test_fast
test_g: http_parser_g.o test_g.o
$(CC) $(OPT_DEBUG) http_parser_g.o test_g.o -o $@
@ -31,11 +34,13 @@ test_fast: http_parser.o test.c http_parser.h
test-run-timed: test_fast
while(true) do time ./test_fast > /dev/null; done
package: http_parser.o
$(AR) rcs libhttp_parser.a http_parser.o
tags: http_parser.c http_parser.h test.c
ctags $^
clean:
rm -f *.o test test_fast test_g http_parser.tar tags
rm -f *.o *.a test test_fast test_g http_parser.tar tags
.PHONY: clean package test-run test-run-timed test-valgrind

114
deps/http_parser/http_parser.c

@ -1,4 +1,7 @@
/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
*
* Additional changes are licensed under the same terms as NGINX and
* copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -97,6 +100,7 @@ static const char *method_strings[] =
, "NOTIFY"
, "SUBSCRIBE"
, "UNSUBSCRIBE"
, "PATCH"
};
@ -186,7 +190,7 @@ static const uint8_t normal_url_char[256] = {
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
1, 1, 1, 1, 1, 1, 1, 1,
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
1, 1, 1, 1, 1, 1, 1, 0 };
1, 1, 1, 1, 1, 1, 1, 0, };
enum state
@ -240,15 +244,17 @@ enum state
, s_header_almost_done
, s_chunk_size_start
, s_chunk_size
, s_chunk_parameters
, s_chunk_size_almost_done
, s_headers_almost_done
/* Important: 's_headers_almost_done' must be the last 'header' state. All
* states beyond this must be 'body' states. It is used for overflow
* checking. See the PARSING_HEADER() macro.
*/
, s_chunk_size_start
, s_chunk_size
, s_chunk_size_almost_done
, s_chunk_parameters
, s_chunk_data
, s_chunk_data_almost_done
, s_chunk_data_done
@ -258,7 +264,7 @@ enum state
};
#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
#define PARSING_HEADER(state) (state <= s_headers_almost_done)
enum header_states
@ -288,20 +294,24 @@ enum header_states
};
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_TRAILING = 1 << 3
, F_UPGRADE = 1 << 4
, F_SKIPBODY = 1 << 5
};
/* Macros for character classes; depends on strict-mode */
#define CR '\r'
#define LF '\n'
#define LOWER(c) (unsigned char)(c | 0x20)
#define TOKEN(c) tokens[(unsigned char)c]
#define TOKEN(c) (tokens[(unsigned char)c])
#define IS_ALPHA(c) ((c) >= 'a' && (c) <= 'z')
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
#if HTTP_PARSER_STRICT
#define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
#else
#define IS_URL_CHAR(c) \
(normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
#define IS_HOST_CHAR(c) \
(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
#endif
#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
@ -478,7 +488,7 @@ size_t http_parser_execute (http_parser *parser,
break;
}
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->http_major *= 10;
parser->http_major += ch - '0';
@ -489,7 +499,7 @@ size_t http_parser_execute (http_parser *parser,
/* first digit of minor HTTP version */
case s_res_first_http_minor:
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->http_minor = ch - '0';
state = s_res_http_minor;
break;
@ -502,7 +512,7 @@ size_t http_parser_execute (http_parser *parser,
break;
}
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->http_minor *= 10;
parser->http_minor += ch - '0';
@ -513,7 +523,7 @@ size_t http_parser_execute (http_parser *parser,
case s_res_first_status_code:
{
if (ch < '0' || ch > '9') {
if (!IS_NUM(ch)) {
if (ch == ' ') {
break;
}
@ -526,7 +536,7 @@ size_t http_parser_execute (http_parser *parser,
case s_res_status_code:
{
if (ch < '0' || ch > '9') {
if (!IS_NUM(ch)) {
switch (ch) {
case ' ':
state = s_res_status;
@ -578,7 +588,7 @@ size_t http_parser_execute (http_parser *parser,
CALLBACK2(message_begin);
if (ch < 'A' || 'Z' < ch) goto error;
if (!IS_ALPHA(LOWER(ch))) goto error;
start_req_method_assign:
parser->method = (enum http_method) 0;
@ -592,7 +602,9 @@ size_t http_parser_execute (http_parser *parser,
case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
case 'N': parser->method = HTTP_NOTIFY; break;
case 'O': parser->method = HTTP_OPTIONS; break;
case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
case 'P': parser->method = HTTP_POST;
/* or PROPFIND or PROPPATCH or PUT or PATCH */
break;
case 'R': parser->method = HTTP_REPORT; break;
case 'S': parser->method = HTTP_SUBSCRIBE; break;
case 'T': parser->method = HTTP_TRACE; break;
@ -633,6 +645,8 @@ size_t http_parser_execute (http_parser *parser,
parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
} else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
parser->method = HTTP_PUT;
} else if (index == 1 && parser->method == HTTP_POST && ch == 'A') {
parser->method = HTTP_PATCH;
} else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
parser->method = HTTP_UNSUBSCRIBE;
} else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
@ -657,9 +671,13 @@ size_t http_parser_execute (http_parser *parser,
c = LOWER(ch);
if (c >= 'a' && c <= 'z') {
/* Proxied requests are followed by scheme of an absolute URI (alpha).
* CONNECT is followed by a hostname, which begins with alphanum.
* All other methods are followed by '/' or '*' (handled above).
*/
if (IS_ALPHA(ch) || (parser->method == HTTP_CONNECT && IS_NUM(ch))) {
MARK(url);
state = s_req_schema;
state = (parser->method == HTTP_CONNECT) ? s_req_host : s_req_schema;
break;
}
@ -670,17 +688,11 @@ size_t http_parser_execute (http_parser *parser,
{
c = LOWER(ch);
if (c >= 'a' && c <= 'z') break;
if (IS_ALPHA(c)) break;
if (ch == ':') {
state = s_req_schema_slash;
break;
} else if (ch == '.') {
state = s_req_host;
break;
} else if ('0' <= ch && ch <= '9') {
state = s_req_host;
break;
}
goto error;
@ -699,8 +711,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_host:
{
c = LOWER(ch);
if (c >= 'a' && c <= 'z') break;
if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
if (IS_HOST_CHAR(ch)) break;
switch (ch) {
case ':':
state = s_req_port;
@ -717,6 +728,9 @@ size_t http_parser_execute (http_parser *parser,
CALLBACK(url);
state = s_req_http_start;
break;
case '?':
state = s_req_query_string_start;
break;
default:
goto error;
}
@ -725,7 +739,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_port:
{
if (ch >= '0' && ch <= '9') break;
if (IS_NUM(ch)) break;
switch (ch) {
case '/':
MARK(path);
@ -739,6 +753,9 @@ size_t http_parser_execute (http_parser *parser,
CALLBACK(url);
state = s_req_http_start;
break;
case '?':
state = s_req_query_string_start;
break;
default:
goto error;
}
@ -747,7 +764,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_path:
{
if (normal_url_char[(unsigned char)ch]) break;
if (IS_URL_CHAR(ch)) break;
switch (ch) {
case ' ':
@ -785,7 +802,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_query_string_start:
{
if (normal_url_char[(unsigned char)ch]) {
if (IS_URL_CHAR(ch)) {
MARK(query_string);
state = s_req_query_string;
break;
@ -821,7 +838,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_query_string:
{
if (normal_url_char[(unsigned char)ch]) break;
if (IS_URL_CHAR(ch)) break;
switch (ch) {
case '?':
@ -858,7 +875,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_fragment_start:
{
if (normal_url_char[(unsigned char)ch]) {
if (IS_URL_CHAR(ch)) {
MARK(fragment);
state = s_req_fragment;
break;
@ -895,7 +912,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_fragment:
{
if (normal_url_char[(unsigned char)ch]) break;
if (IS_URL_CHAR(ch)) break;
switch (ch) {
case ' ':
@ -973,7 +990,7 @@ size_t http_parser_execute (http_parser *parser,
break;
}
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->http_major *= 10;
parser->http_major += ch - '0';
@ -984,7 +1001,7 @@ size_t http_parser_execute (http_parser *parser,
/* first digit of minor HTTP version */
case s_req_first_http_minor:
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->http_minor = ch - '0';
state = s_req_http_minor;
break;
@ -1004,7 +1021,7 @@ size_t http_parser_execute (http_parser *parser,
/* XXX allow spaces after digit? */
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->http_minor *= 10;
parser->http_minor += ch - '0';
@ -1237,7 +1254,7 @@ size_t http_parser_execute (http_parser *parser,
break;
case h_content_length:
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->content_length = ch - '0';
break;
@ -1286,7 +1303,7 @@ size_t http_parser_execute (http_parser *parser,
case h_content_length:
if (ch == ' ') break;
if (ch < '0' || ch > '9') goto error;
if (!IS_NUM(ch)) goto error;
parser->content_length *= 10;
parser->content_length += ch - '0';
break;
@ -1458,6 +1475,7 @@ size_t http_parser_execute (http_parser *parser,
case s_chunk_size_start:
{
assert(nread == 1);
assert(parser->flags & F_CHUNKED);
c = unhex[(unsigned char)ch];
@ -1507,6 +1525,8 @@ size_t http_parser_execute (http_parser *parser,
assert(parser->flags & F_CHUNKED);
STRICT_CHECK(ch != LF);
nread = 0;
if (parser->content_length == 0) {
parser->flags |= F_TRAILING;
state = s_header_field_start;

21
deps/http_parser/http_parser.h

@ -1,4 +1,4 @@
/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -24,6 +24,8 @@
extern "C" {
#endif
#define HTTP_PARSER_VERSION_MAJOR 1
#define HTTP_PARSER_VERSION_MINOR 0
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__)
@ -47,8 +49,6 @@ typedef int ssize_t;
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#else
# define HTTP_PARSER_STRICT 0
#endif
@ -106,16 +106,29 @@ enum http_method
, HTTP_NOTIFY
, HTTP_SUBSCRIBE
, HTTP_UNSUBSCRIBE
/* RFC-5789 */
, HTTP_PATCH
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_TRAILING = 1 << 3
, F_UPGRADE = 1 << 4
, F_SKIPBODY = 1 << 5
};
struct http_parser {
/** PRIVATE **/
unsigned char type : 2;
unsigned char flags : 6;
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned char state;
unsigned char header_state;
unsigned char index;

141
deps/http_parser/test.c

@ -1,4 +1,4 @@
/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@ -498,7 +498,7 @@ const struct message requests[] =
#define CONNECT_REQUEST 17
, {.name = "connect request"
,.type= HTTP_REQUEST
,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n"
,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
"User-agent: Mozilla/1.1N\r\n"
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
"\r\n"
@ -510,7 +510,7 @@ const struct message requests[] =
,.query_string= ""
,.fragment= ""
,.request_path= ""
,.request_url= "home0.netscape.com:443"
,.request_url= "0-home0.netscape.com:443"
,.num_headers= 2
,.upgrade=1
,.headers= { { "User-agent", "Mozilla/1.1N" }
@ -557,7 +557,7 @@ const struct message requests[] =
,.body= ""
}
#define MSEARCH_REQ 19
#define MSEARCH_REQ 20
, {.name= "m-search request"
,.type= HTTP_REQUEST
,.raw= "M-SEARCH * HTTP/1.1\r\n"
@ -582,6 +582,139 @@ const struct message requests[] =
,.body= ""
}
#define QUERY_TERMINATED_HOST 21
, {.name= "host terminated by a query string"
,.type= HTTP_REQUEST
,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= "hail=all"
,.fragment= ""
,.request_path= ""
,.request_url= "http://hypnotoad.org?hail=all"
,.num_headers= 0
,.headers= { }
,.body= ""
}
#define QUERY_TERMINATED_HOSTPORT 22
, {.name= "host:port terminated by a query string"
,.type= HTTP_REQUEST
,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= "hail=all"
,.fragment= ""
,.request_path= ""
,.request_url= "http://hypnotoad.org:1234?hail=all"
,.num_headers= 0
,.headers= { }
,.body= ""
}
#define SPACE_TERMINATED_HOSTPORT 23
, {.name= "host:port terminated by a space"
,.type= HTTP_REQUEST
,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= ""
,.request_url= "http://hypnotoad.org:1234"
,.num_headers= 0
,.headers= { }
,.body= ""
}
#if !HTTP_PARSER_STRICT
#define UTF8_PATH_REQ 24
, {.name= "utf-8 path request"
,.type= HTTP_REQUEST
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
"Host: github.com\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= "q=1"
,.fragment= "narf"
,.request_path= "/δ¶/δt/pope"
,.request_url= "/δ¶/δt/pope?q=1#narf"
,.num_headers= 1
,.headers= { {"Host", "github.com" }
}
,.body= ""
}
#define HOSTNAME_UNDERSCORE 25
, {.name = "hostname underscore"
,.type= HTTP_REQUEST
,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
"User-agent: Mozilla/1.1N\r\n"
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
"\r\n"
,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 0
,.method= HTTP_CONNECT
,.query_string= ""
,.fragment= ""
,.request_path= ""
,.request_url= "home_0.netscape.com:443"
,.num_headers= 2
,.upgrade=1
,.headers= { { "User-agent", "Mozilla/1.1N" }
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
}
,.body= ""
}
#endif /* !HTTP_PARSER_STRICT */
#define PATCH_REQ 26
, {.name = "PATCH request"
,.type= HTTP_REQUEST
,.raw= "PATCH /file.txt HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Content-Type: application/example\r\n"
"If-Match: \"e0023aa4e\"\r\n"
"Content-Length: 10\r\n"
"\r\n"
"cccccccccc"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_PATCH
,.query_string= ""
,.fragment= ""
,.request_path= "/file.txt"
,.request_url= "/file.txt"
,.num_headers= 4
,.upgrade=0
,.headers= { { "Host", "www.example.com" }
, { "Content-Type", "application/example" }
, { "If-Match", "\"e0023aa4e\"" }
, { "Content-Length", "10" }
}
,.body= "cccccccccc"
}
, {.name= NULL } /* sentinel */
};

2
doc/api/assert.markdown

@ -5,7 +5,7 @@ access it with `require('assert')`.
### assert.fail(actual, expected, message, operator)
Tests if `actual` is equal to `expected` using the operator provided.
Throws an exception that displays the values for `actual` and `expected` separated by the provided operator.
### assert.ok(value, [message])

6
doc/api/crypto.markdown

@ -93,7 +93,7 @@ Returns the enciphered contents, and can be called many times with new data as i
### cipher.final(output_encoding='binary')
Returns any remaining enciphered contents, with `output_encoding` being one of: `'binary'`, `'ascii'` or `'utf8'`.
Returns any remaining enciphered contents, with `output_encoding` being one of: `'binary'`, `'base64'` or `'hex'`.
### crypto.createDecipher(algorithm, key)
@ -108,7 +108,7 @@ The `output_decoding` specifies in what format to return the deciphered plaintex
### decipher.final(output_encoding='binary')
Returns any remaining plaintext which is deciphered,
with `output_encoding' being one of: `'binary'`, `'ascii'` or `'utf8'`.
with `output_encoding` being one of: `'binary'`, `'ascii'` or `'utf8'`.
### crypto.createSign(algorithm)
@ -142,7 +142,7 @@ This can be called many times with new data as it is streamed.
### verifier.verify(cert, signature, signature_format='binary')
Verifies the signed data by using the `cert` which is a string containing
the PEM encoded certificate, and `signature`, which is the previously calculates
the PEM encoded certificate, and `signature`, which is the previously calculated
signature for the data, in the `signature_format` which can be `'binary'`, `'hex'` or `'base64'`.
Returns true or false depending on the validity of the signature for the data and public key.

7
doc/api/fs.markdown

@ -148,14 +148,15 @@ See the [fs.Stats](#fs.Stats) section below for more information.
### fs.lstat(path, [callback])
Asynchronous lstat(2). The callback gets two arguments `(err, stats)` where
`stats` is a `fs.Stats` object. lstat() is identical to stat(), except that if
path is a symbolic link, then the link itself is stat-ed, not the file that it
`stats` is a `fs.Stats` object. `lstat()` is identical to `stat()`, except that if
`path` is a symbolic link, then the link itself is stat-ed, not the file that it
refers to.
### fs.fstat(fd, [callback])
Asynchronous fstat(2). The callback gets two arguments `(err, stats)` where
`stats` is a `fs.Stats` object.
`stats` is a `fs.Stats` object. `fstat()` is identical to `stat()`, except that
the file to be stat-ed is specified by the file descriptor `fd`.
### fs.statSync(path)

6
doc/api/globals.markdown

@ -32,6 +32,12 @@ To require modules. See the [Modules](modules.html#modules) section.
Use the internal `require()` machinery to look up the location of a module,
but rather than loading the module, just return the resolved filename.
### require.cache
Modules are cached in this object when they are required. By deleting a key
value from this object, the next `require` will reload the module.
### require.paths
An array of search paths for `require()`. This array can be modified to add

2
doc/api/util.markdown

@ -16,7 +16,7 @@ output `string` immediately to `stderr`.
Output with timestamp on `stdout`.
require('util').log('Timestmaped message.');
require('util').log('Timestamped message.');
### util.inspect(object, showHidden=false, depth=2)

18
lib/_debugger.js

@ -785,7 +785,7 @@ Interface.prototype.handleCommand = function(cmd) {
self._lastCommand = null;
self.tryQuit();
} else if (/^r(un)?/.test(cmd)) {
} else if (/^r(un)?$/.test(cmd)) {
self._lastCommand = null;
if (self.child) {
self.restartQuestion(function(yes) {
@ -805,7 +805,7 @@ Interface.prototype.handleCommand = function(cmd) {
self.trySpawn();
}
} else if (/^help/.test(cmd)) {
} else if (/^help$/.test(cmd)) {
console.log(helpMessage);
term.prompt();
@ -819,7 +819,7 @@ Interface.prototype.handleCommand = function(cmd) {
term.prompt();
});
} else if (/info +breakpoints/.test(cmd)) {
} else if (/^info(\s+breakpoint)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;
@ -867,7 +867,7 @@ Interface.prototype.handleCommand = function(cmd) {
term.prompt();
});
} else if (/^backtrace/.test(cmd) || /^bt/.test(cmd)) {
} else if (/^b(ack)?t(race)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;
@ -905,7 +905,7 @@ Interface.prototype.handleCommand = function(cmd) {
self.printScripts(cmd.indexOf('full') > 0);
term.prompt();
} else if (/^c(ontinue)?/.test(cmd)) {
} else if (/^c(ontinue)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;
@ -916,7 +916,7 @@ Interface.prototype.handleCommand = function(cmd) {
self.resume();
});
} else if (/^k(ill)?/.test(cmd)) {
} else if (/^k(ill)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;
@ -934,7 +934,7 @@ Interface.prototype.handleCommand = function(cmd) {
self.term.prompt();
}
} else if (/^next/.test(cmd) || /^n/.test(cmd)) {
} else if (/^n(ext)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;
@ -943,7 +943,7 @@ Interface.prototype.handleCommand = function(cmd) {
// Wait for break point. (disable raw mode?)
});
} else if (/^step/.test(cmd) || /^s/.test(cmd)) {
} else if (/^s(tep)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;
@ -952,7 +952,7 @@ Interface.prototype.handleCommand = function(cmd) {
// Wait for break point. (disable raw mode?)
});
} else if (/^print/.test(cmd) || /^p/.test(cmd)) {
} else if (/^p(rint)?$/.test(cmd)) {
if (!client) {
self.printNotConnected();
return;

2
lib/stream.js

@ -95,7 +95,7 @@ Stream.prototype.pipe = function(dest, options) {
// don't leave dangling pipes when there are errors.
function onerror(er) {
cleanup();
if (this.listeners('error').length === 1) {
if (this.listeners('error').length === 0) {
throw er; // Unhandled stream error in pipe.
}
}

4
lib/url.js

@ -54,9 +54,7 @@ var protocolPattern = /^([a-z0-9]+:)/i,
// protocols that never have a hostname.
hostlessProtocol = {
'javascript': true,
'javascript:': true,
'file': true,
'file:': true
'javascript:': true
},
// protocols that always have a path component.
pathedProtocol = {

58
src/node_crypto.cc

@ -99,11 +99,23 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
String::Utf8Value sslmethod(args[0]->ToString());
if (strcmp(*sslmethod, "SSLv2_method") == 0) {
#ifndef OPENSSL_NO_SSL2
method = SSLv2_method();
#else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif
} else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) {
#ifndef OPENSSL_NO_SSL2
method = SSLv2_server_method();
#else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif
} else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) {
#ifndef OPENSSL_NO_SSL2
method = SSLv2_client_method();
#else
return ThrowException(Exception::Error(String::New("SSLv2 methods disabled")));
#endif
} else if (strcmp(*sslmethod, "SSLv3_method") == 0) {
method = SSLv3_method();
} else if (strcmp(*sslmethod, "SSLv3_server_method") == 0) {
@ -1827,8 +1839,10 @@ class Cipher : public ObjectWrap {
initialised_ = false;
}
~Cipher ()
{
~Cipher () {
if (initialised_) {
EVP_CIPHER_CTX_cleanup(&ctx);
}
}
private:
@ -2276,7 +2290,11 @@ class Decipher : public ObjectWrap {
initialised_ = false;
}
~Decipher () { }
~Decipher () {
if (initialised_) {
EVP_CIPHER_CTX_cleanup(&ctx);
}
}
private:
@ -2466,7 +2484,11 @@ class Hmac : public ObjectWrap {
initialised_ = false;
}
~Hmac () { }
~Hmac () {
if (initialised_) {
HMAC_CTX_cleanup(&ctx);
}
}
private:
@ -2622,7 +2644,11 @@ class Hash : public ObjectWrap {
initialised_ = false;
}
~Hash () { }
~Hash () {
if (initialised_) {
EVP_MD_CTX_cleanup(&mdctx);
}
}
private:
@ -2827,7 +2853,11 @@ class Sign : public ObjectWrap {
initialised_ = false;
}
~Sign () { }
~Sign () {
if (initialised_) {
EVP_MD_CTX_cleanup(&mdctx);
}
}
private:
@ -3043,7 +3073,11 @@ class Verify : public ObjectWrap {
initialised_ = false;
}
~Verify () { }
~Verify () {
if (initialised_) {
EVP_MD_CTX_cleanup(&mdctx);
}
}
private:
@ -3576,16 +3610,12 @@ void InitCrypto(Handle<Object> target) {
ERR_load_crypto_strings();
// Turn off compression. Saves memory - do it in userland.
#ifdef SSL_COMP_get_compression_methods
// Before OpenSSL 0.9.8 this was not possible.
STACK_OF(SSL_COMP)* comp_methods = SSL_COMP_get_compression_methods();
#if 0
if (comp_methods && sk_SSL_COMP_num(comp_methods) > 0) {
default_compression_method = sk_SSL_COMP_pop(comp_methods);
fprintf(stderr, "SSL_COMP_get_name %s\n",
SSL_COMP_get_name(default_compression_method->method));
}
#endif
sk_SSL_COMP_zero(comp_methods);
assert(sk_SSL_COMP_num(comp_methods) == 0);
#endif
SecureContext::Initialize(target);
Connection::Initialize(target);

58
test/simple/test-stream-pipe-error-handling.js

@ -0,0 +1,58 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var Stream = require('stream').Stream;
(function testErrorListenerCatches() {
var source = new Stream();
var dest = new Stream();
source.pipe(dest);
var gotErr = null;
source.on('error', function(err) {
gotErr = err;
});
var err = new Error('This stream turned into bacon.');
source.emit('error', err);
assert.strictEqual(gotErr, err);
})();
(function testErrorWithoutListenerThrows() {
var source = new Stream();
var dest = new Stream();
source.pipe(dest);
var err = new Error('This stream turned into bacon.');
var gotErr = null;
try {
source.emit('error', err);
} catch (e) {
gotErr = e;
}
assert.strictEqual(gotErr, err);
})();

30
test/simple/test-url.js

@ -166,12 +166,38 @@ var parseTests = {
'file:///etc/passwd' : {
'href': 'file:///etc/passwd',
'protocol': 'file:',
'pathname': '///etc/passwd'
'pathname': '/etc/passwd',
'hostname': ''
},
'file://localhost/etc/passwd' : {
'href': 'file://localhost/etc/passwd',
'protocol': 'file:',
'pathname': '/etc/passwd',
'hostname': 'localhost'
},
'file://foo/etc/passwd' : {
'href': 'file://foo/etc/passwd',
'protocol': 'file:',
'pathname': '/etc/passwd',
'hostname': 'foo'
},
'file:///etc/node/' : {
'href': 'file:///etc/node/',
'protocol': 'file:',
'pathname': '///etc/node/'
'pathname': '/etc/node/',
'hostname': ''
},
'file://localhost/etc/node/' : {
'href': 'file://localhost/etc/node/',
'protocol': 'file:',
'pathname': '/etc/node/',
'hostname': 'localhost'
},
'file://foo/etc/node/' : {
'href': 'file://foo/etc/node/',
'protocol': 'file:',
'pathname': '/etc/node/',
'hostname': 'foo'
},
'http:/baz/../foo/bar' : {
'href': 'http:/baz/../foo/bar',

12
wscript

@ -143,6 +143,13 @@ def set_options(opt):
, dest='openssl_libpath'
)
opt.add_option( '--no-ssl2'
, action='store_true'
, default=False
, help="Disable OpenSSL v2"
, dest='openssl_nov2'
)
opt.add_option( '--gdb'
, action='store_true'
, default=False
@ -257,6 +264,11 @@ def configure(conf):
if not Options.options.without_ssl:
# Don't override explicitly supplied openssl paths with pkg-config results.
explicit_openssl = o.openssl_includes or o.openssl_libpath
# Disable ssl v2 methods
if o.openssl_nov2:
conf.env.append_value("CPPFLAGS", "-DOPENSSL_NO_SSL2=1")
if not explicit_openssl and conf.check_cfg(package='openssl',
args='--cflags --libs',
uselib_store='OPENSSL'):

Loading…
Cancel
Save