mirror of https://github.com/nodejs/node.git
Merge branch 'v0.4'
commit
b6a742d76f
|
@ -2,3 +2,4 @@ tags
|
|||
*.o
|
||||
test
|
||||
test_g
|
||||
test_fast
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 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))
|
||||
|
||||
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
#define LOWER(c) (unsigned char)(c | 0x20)
|
||||
#define TOKEN(c) tokens[(unsigned char)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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
})();
|
|
@ -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
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…
Reference in New Issue