Compare commits

...

128 Commits

Author SHA1 Message Date
Ryan Dahl
428a670121 bump version to 0.2.4 2010-10-24 14:45:39 -07:00
Ryan Dahl
f7bc7fb031 Make sure Error object on exec() gets killed member
Also default to SIGTERM for destruction when exceeding timeout or buffer on
exec()

Back ported from v0.3; original commits:
bd8e4f656e
5a98fa4809
6570cd99e5
9bf2975f78
2010-10-24 12:57:57 -07:00
Ryan Dahl
d3e6834297 Add isatty for isaacs 2010-10-24 12:27:28 -07:00
Ryan Dahl
a958ebfca0 one more 'listening' race condition 2010-10-24 12:26:47 -07:00
Ryan Dahl
78afb12663 Fix a few 'listening' race conditions
in test-http-client-parse-error
2010-10-24 12:26:32 -07:00
Ryan Dahl
ad4fb5319b Do not spin on aceept() with EMFILE
When a server hit EMFILE it would continue to try to accept new connections
from the queue. This patch introduces a timeout of one second where it will
stop trying to accept new files. After the second is over it tries again.

This is a rather serious bug that has been effecting many highly concurrent
programs. It was introduced in 4593c0, version v0.2.0.

TODO: A test for this situation. Currently I test it like this

  termA% cd projects/node
  termA% ulimit -n 256
  termA% ./node benchmark/idle_server.js

  termB% cd projects/node
  termB% ./node benchmark/idle_clients.js

And watch how the server process behaves.
2010-10-24 12:25:04 -07:00
Tom Hughes
1e932ea930 Add signal handlers so we clean up before exiting.
Add SIGTERM and SIGINT signal handlers so that we run the exit handlers
before exiting when getting these signals. Fixes an issue where we
couldn't run vi after CTRL+C'ing node because the stdin fd was left
non-blocking.

Also the test from ceb5331a64
2010-10-23 19:14:08 -07:00
Vitali Lovich
ddb06cb552 Fix parsing of linux memory
If process name contains a space, this parsing fails for no good reason.
2010-10-23 19:08:22 -07:00
Ryan Dahl
60b5bcac0c Write write.txt into the tmpdir 2010-10-23 19:08:15 -07:00
Ryan Dahl
46eda290be Remove a confusing sentence in the docs 2010-10-23 19:08:05 -07:00
Tom Hughes
c19897b76a Add --max-stack-size flag.
v8 doesn't expose a command-line flag to set the stack size, so this
adds a new flag that node understands how to handle and uses v8's
ResourceConstraints API.
2010-10-23 18:32:20 -07:00
Ryan Dahl
8ec4870611 Fix race conditions in test-http-upgrade-client2 2010-10-23 18:30:17 -07:00
Ryan Dahl
8fb9cd2575 Fix test harness for Linux
Mostly just upgraded tools/test.py to the latest one that's in V8.  But also
fixing the before and after hooks to preserve the test/tmp directory so that
running tests manually usually works.
2010-10-23 18:30:04 -07:00
Ryan Dahl
006e283b78 Add idle connection test 2010-10-23 18:27:59 -07:00
Ryan Dahl
bdd82b7c5f Add 'make bench' script 2010-10-23 18:27:52 -07:00
Ryan Dahl
9f25dc1625 Improve benchmark/http_simple.js 2010-10-23 18:27:42 -07:00
Nathan Rajlich
511f80b3c8 http-parser: Allow whitespace in the 'Content-Length' header. 2010-10-23 18:26:46 -07:00
Joshua Peek
13dba0d1c1 Don't flush net writeQueue on end() if its still connecting 2010-10-23 18:26:07 -07:00
Ryan Dahl
97e3040202 Add future API for 'util' module 2010-10-23 18:18:24 -07:00
Rasmus Andersson
78fac9b863 environ symbol fix for Mac OS X 2010-10-23 18:16:40 -07:00
Ryan Dahl
969ee3dd83 Add flag to disable colors in REPL 2010-10-23 18:16:10 -07:00
Ryan Dahl
39a2a9d1b6 TCP clients should buffer writes before connection 2010-10-23 18:15:01 -07:00
TJ Holowaychuk
08f1bf42bb Added -e, --eval 2010-10-23 16:07:02 -07:00
Ryan Dahl
18ff6db648 ClearWeak on ObjectWraps. I /think/ this is the correct semantics 2010-10-23 16:06:51 -07:00
Ryan Dahl
dc103ae020 Bump version to v0.2.3 2010-10-02 06:05:56 -07:00
Ryan Dahl
fea3919d1b Fix zero length buffer bug for http res.end()
Reported by Kadir Pekel <kadirpekel@gmail.com>
2010-10-01 16:16:00 -07:00
Marco Rogers
b5dc54c6ed fix encoding option on ReadStream, updated test 2010-10-01 16:14:22 -07:00
Ryan Dahl
2fb393a768 Fix REPL crash on tabbing 'this.'
Thanks to Tim Becker for pointing this out.
2010-10-01 16:14:13 -07:00
Ryan Dahl
80974dc85b Drop reference to timer callback on clearTimeout
Reported here:
http://groups.google.com/group/nodejs-dev/browse_thread/thread/9e063d0938f99879

Would be good to test this somehow...
2010-10-01 16:13:59 -07:00
Evan Larkin
16f736200a fs.ReadStream: Passing null for file position on all reads except the first read of a range read. 2010-10-01 16:13:12 -07:00
Evan Larkin
d29e62d564 No longer using the global variable "stat" in unwatchFile 2010-10-01 16:11:42 -07:00
Ryan Dahl
41eca918e5 Add test for getting parse error from HTTP client
Made this test in response to this thread:
http://groups.google.com/group/nodejs/browse_thread/thread/f82835007a277de2/
But Node appears to be working correctly.
2010-10-01 16:11:17 -07:00
Ryan Dahl
45a01aff59 Move the http client's initParser() into prototype 2010-10-01 15:56:32 -07:00
Ryan Dahl
55aa7b17ab Put preprocessor defines into CPPFLAGS not compile flags... 2010-10-01 15:55:46 -07:00
Ryan Dahl
1165878e3c Fix timing on I/O benchmark 2010-10-01 15:54:49 -07:00
Ryan Dahl
b98958d7fe Add function_call benchmark 2010-10-01 15:54:44 -07:00
Fedor Indutny
448cbaf395 Fixed 'upgrade' event for httpclient
onend and ondata was cleaning on parser end
2010-10-01 15:54:27 -07:00
Tj Holowaychuk
b8eee9c6f0 Fixed fs.ReadStream() start: 0 bug 2010-10-01 15:53:53 -07:00
Mikeal Rogers
936a038bb7 HTTP: close connection on connection:close header.
rnewson found a good bug in keep-alive. we were only using the request
headers we send to enable/disable keep-alive but when the server sends
Connection: close we need to close down the connection regardless.

I wrote up a patch the Robert verified makes all his test client code work
now and I also added a new unittest for it.
2010-10-01 15:53:26 -07:00
Ryan Dahl
529cdad2dd Don't choose jobs based on processor
Leads to lots of builds with out-of-memory.
2010-10-01 15:53:02 -07:00
Ryan Dahl
7140933fcc More explicit openssl configure warning 2010-10-01 15:52:56 -07:00
Jorge Chamorro Bieling
27f6a20fdb sys.js: --needless Object.keys() --needless .map() in a single patch 2010-10-01 15:51:27 -07:00
Paul Querna
a30daa7b6c Fatal error out if OpenSSL was not explicitly disabled, we just couldn't autodetect it. 2010-10-01 15:50:32 -07:00
Jorge Chamorro Bieling
01035714a5 sys.js: sys.inspect: show function names 2010-10-01 15:50:18 -07:00
Ryan Dahl
f6f739b3a2 Pass correct message in HTTP client upgrade
Simplify and correct test.

Fix by Fedor Indutny.
2010-10-01 15:49:50 -07:00
Ryan Dahl
d7c1690c74 Revert requireNative changes: 4e6b9b0, d429033, 6abbfa0, bcad540 2010-10-01 15:45:21 -07:00
Ryan Dahl
7bf46bc980 bump version to v0.2.2 2010-09-17 11:34:16 -07:00
Ryan Dahl
bcbc52e257 ^c to get out of '...' in REPL 2010-09-17 11:23:08 -07:00
Ryan Dahl
c00a6a7169 Simplify REPL 2010-09-17 11:23:04 -07:00
Ryan Dahl
1d8b154e14 Safe constructors for fs.ReadStream and fs.WriteStream 2010-09-17 11:22:58 -07:00
Ryan Dahl
84f4ce742f Remove old versions of fs.read and fs.write from docs 2010-09-17 11:22:50 -07:00
Paul Querna
f9cc35fa57 Use the Apple recommended way of detecting OSX Versions
to enable KQueue, rather than deciding based on the compiler version.
2010-09-17 11:22:42 -07:00
Ryan Dahl
d506a42765 Handle writeStream errors in sys.pump 2010-09-17 11:21:59 -07:00
Russell Haering
09a41a7f9c Pass an error to the sys.pump callback if one occurs
- Add test case for pumping from unreadable stream.
- Document the sys.pump error handling behavior
2010-09-17 11:21:50 -07:00
Herbert Vojčík
8dcd6dccab Common subexpression in emit. 2010-09-17 11:20:52 -07:00
Herbert Vojčík
1375b8ed39 No need to do if (internalModuleCache...), it's in requireNative. 2010-09-17 11:20:32 -07:00
Herbert Vojčík
a3333e7393 Module system moved to the bottom, where only is it needed.
(this also splits the file into upper "setup" and lower "startup" sections)
2010-09-17 11:20:24 -07:00
Herbert Vojčík
d965640662 m.id unneccessary, id is enough. 2010-09-17 11:20:17 -07:00
Herbert Vojčík
ee253b374d Natives having their own self-contained minimalistic module system.
The main system is built upon this, and is optional, if only natives
are used in application (eg. node-core).

Natives not loaded into own context if NODE_MODULE_CONTEXTS=1.
This have its inner logic, if natives are seen just as lazy-loaded
parts of the core.
2010-09-17 11:19:33 -07:00
Ryan Dahl
b17b28531b shorten some lines in events.js 2010-09-17 11:18:59 -07:00
Ryan Dahl
10af67714b Optimize emit for two arguments 2010-09-17 11:18:54 -07:00
Ryan Dahl
180a04805b Make a list of known globals
And fix missing var!

It would be good to get this script running at the end of every test, so we
know that modules aren't leaking either - but it will require a lot
modification of the tests so that they themselves aren't leaking globals.
2010-09-17 11:18:42 -07:00
Ryan Dahl
ee21920571 Use child_process.exec rather than sys.exec 2010-09-17 11:17:33 -07:00
isaacs
66bce65d33 Bug in realpath with symlinks to absolute folder paths which have children.
Found by Cliffano Subagio
http://groups.google.com/group/nodejs/browse_thread/thread/f46f093938265ac0/387e14da08c7dd7b?
2010-09-17 11:17:26 -07:00
Tony Metzidis
2005ef9e37 Catch Exceptions thrown when openssl is disabled 2010-09-17 11:17:08 -07:00
Tony Metzidis
3816ebc85f - fix AttributeError on "use_openssl" when doing ./configure --without-ssl - error was: AttributeError: Values instance has no attribute 'use_openssl' 2010-09-17 11:17:00 -07:00
Ryan Dahl
4c5520a37e Fix style in node_object_wrap.h 2010-09-17 11:16:45 -07:00
Ryan Dahl
0ddad3fbc7 Fix style in readline 2010-09-17 11:12:01 -07:00
Ryan Dahl
db6a1788b2 Add SIGWINCH handler for readline 2010-09-17 11:11:52 -07:00
Ryan Dahl
1d17874a7d add to todo 2010-09-17 11:11:47 -07:00
Trent Mick
3191802605 add ANSI coloring option to sys.inspect and, by default, to the repl 2010-09-17 11:11:32 -07:00
Ryan Dahl
da235fa12c bump version to v0.2.1 2010-09-10 13:52:33 -07:00
Paul Querna
92fb664bfc Expose fingerproint from getPeerCertificate
Expose the SHA1 digest of the certificate as the fingerprint attribute in
the object returned by getPeerCertificate()
2010-09-10 13:31:46 -07:00
Ryan Dahl
7704fb9711 Fix fs.realpathSync('/') 2010-09-10 13:31:39 -07:00
isaacs
c099e274d2 Better temporary directory handling for tests.
Add a setUp and tearDown function to the test case class, and use it to
create and remove the test/tmp directory for each test.

TODO: amend other tests.
2010-09-10 13:31:34 -07:00
Ryan Dahl
c86f3c5d5c Don't use empty.js - breaks module test 2010-09-10 13:31:27 -07:00
Felix Geisendörfer
9b8577230f Simple benchmark for node's startup time 2010-09-10 13:31:21 -07:00
Ryan Dahl
9f6f26028f Use SetPointerInInternalField 2010-09-10 13:31:16 -07:00
Felix Geisendörfer
44f8756aab Fix: uncaughtException was broken for main module
See: 635986e433
2010-09-10 13:30:48 -07:00
Ryan Dahl
ae2f566fec Call Tick() after coming out of select()
Previously we would only call it before going into select(). This is needed
to fix test/simple/test-next-tick-ordering2.js.
2010-09-10 13:30:38 -07:00
isaacs
2f071ac7d1 Fix issue #262. Allow fs.realpath to traverse above the current working directory. 2010-09-08 17:56:34 -07:00
Tobie Langel
bd8ea2bb85 Test for ReadStream typo 2010-09-08 17:56:25 -07:00
Ryan Dahl
35682ac88e Fix style; undefined reference bug 2010-09-08 17:56:17 -07:00
Tobie Langel
5bbebf3593 Do not emit WriteStream's drain event before ws.write has been called. 2010-09-08 17:56:12 -07:00
Tobie Langel
0b9dab650e Avoid closing a WriteStream before it has been opened. 2010-09-08 17:55:58 -07:00
Tobie Langel
a6659e7612 Avoid missing ref error in WriteStream.prototype.destroy(). 2010-09-08 17:55:53 -07:00
Herbert Vojčík
727843eea1 Make test-global work with NODE_MODULE_CONTEXTS. 2010-09-08 17:55:44 -07:00
Herbert Vojčík
7e9a0173d7 Modifying test-global to accomodate v8 inter-context 'global' protection. 2010-09-08 17:55:38 -07:00
Herbert Vojčík
74b70c3cb1 Removing test-global-between-modules.
Using "global" to push data to require()d modules
not supported under NODE_MODULE_CONTEXTS=1.
2010-09-08 17:55:33 -07:00
Herbert Vojčík
d5deb4c4a3 Removed comment-out code. 2010-09-08 17:48:52 -07:00
Ryan Dahl
cc0164bc12 Increase ReadStream bufferSize to 64k 2010-09-08 17:48:45 -07:00
Trent Mick
ccd1304c5b Ctrl+W support for the REPL
FWIW, command-line style (delete back to whitespace) would be:
    leading = leading.replace(/\S+\s*$/, '');
2010-09-08 17:48:15 -07:00
Felix Geisendörfer
3d3d00d524 Test case showing a bug in nextTick ordering
nextTick should fire before setTimeout in this test, but it doesn't.
2010-09-08 17:48:02 -07:00
Ryan Dahl
dffa9e76a1 test-http-parser should not use private API 2010-09-08 17:47:36 -07:00
Ryan Dahl
90374797f0 Don't refer to private API in test-repl 2010-09-08 17:47:30 -07:00
Ryan Dahl
c1a4e10156 Special deepEquals for buffer 2010-09-08 17:47:23 -07:00
Ryan Dahl
b655ce5c08 typo: forceClose -> destroy for WriteStreams 2010-09-08 17:47:17 -07:00
Benjamin Thomas
b30b60717d Fix bug in process._tickCallback where callbacks can get abandoned.
Change process._tickCallback so that if a callback throws an error but
there are other callbacks after it, we indicate that
process._tickCallback needs to be ran again.

Currently, if a callback in process._tickCallback throws an error, and
that error is caught by an uncaughtException handler and
process.nextTick is never called again, then any other callbacks already
added to the nextTickQueue won't be called again.

Updated the next-tick-errors test to catch this scenario.
2010-09-08 17:46:58 -07:00
isaacs
b2dfea0361 Treat "//some_path" as pathname rather than hostname by default.
Note that "//" is still a special indicator for the hostname, and this does
not change the parsing of mailto: and other "slashless" url schemes.  It
does however remove some oddness in url.parse(req.url) which is the most
common use-case for the url.parse function.
2010-09-08 17:46:50 -07:00
Ryan Dahl
610743daee Make sure setInterval(cb, 0) loops infinitely 2010-09-08 17:46:43 -07:00
Ryan Dahl
df891c36a4 Fix style 2010-09-08 17:46:36 -07:00
Ryan Dahl
f35a8298b1 Fix style in test/simple/test-dgram-unix.js 2010-09-08 17:46:30 -07:00
Ryan Dahl
294c455678 Remove timer from test/simple/test-dgram-unix.js
Test running already has a timeout mechanism.
2010-09-08 17:46:24 -07:00
Marco Rogers
14f16ec592 fix for fs.readFile to return string when encoding specified on zero length read 2010-09-08 17:45:26 -07:00
Marco Rogers
cdee88051d Fixed async fs writes with length 0, it should fire the callback 2010-09-08 17:45:21 -07:00
Bradley Meck
b39b15d53f Allow Strings for ports on net.Server.listen 2010-09-08 17:45:07 -07:00
Fedor Indutny
b895568800 Constants should be readOnly and DontDelete 2010-09-08 17:44:40 -07:00
Ryan Dahl
ead58b9a93 Add failing uncaughtException test
FIXME
2010-09-08 17:44:30 -07:00
Johan Euphrosine
c306fa241c add readline support for meta-d 2010-09-08 17:44:13 -07:00
Benjamin Thomas
22f67f8585 Fix process.nextTick so thrown errors don't confuse it.
If the function for a process.nextTick throws an error, then the
splice() never removes that function from the nextTickQueue array.  This
makes sure the functions that have been run in _tickCallback get removed
regardless of errors.

Also add a test for this.
2010-09-08 17:43:47 -07:00
Ryan Dahl
416aa73946 Safe constructor: net.Server, net.Stream 2010-09-08 17:43:39 -07:00
Ryan Dahl
6a39a7ed83 Safe Constructor: Buffer 2010-09-08 17:43:32 -07:00
Ryan Dahl
ad960f4462 Safe constructors: http.Server and http.Client 2010-09-08 17:43:25 -07:00
Ryan Dahl
f78691e45c Only check for execinfo lib in freebsd
OpenEmbedded doesn't like it when you look in /usr/lib
2010-09-08 17:43:17 -07:00
Johan Euphrosine
3d8137c582 add test for readline putty support 2010-09-08 17:42:59 -07:00
Brian
c14c445cb6 Fix home/end keys in repl for putty/xterm. 2010-09-08 17:42:47 -07:00
Russell Haering
b9ca8435f5 Modify fs.open to use accept a callback without a mode 2010-09-08 17:42:36 -07:00
Johan Euphrosine
baa24bd40e add readline support for meta-f and meta-b 2010-09-08 17:42:23 -07:00
Johan Euphrosine
7a836ef813 add home/end support in rxvt and readline tests 2010-09-08 17:42:09 -07:00
Felix Geisendörfer
a2b9e02d83 Document WriteStream 'open' event 2010-09-08 17:41:59 -07:00
isaacs
3f7c791b13 Add testing items, and make npm lowercase 2010-09-08 17:40:59 -07:00
isaacs
53dac7c341 Missing 'var' in sys.inspect (Found by Oleg Slobodskoi) 2010-09-08 17:40:50 -07:00
Aria Stewart
c43ddf7acd Fix doc.js so that it doesn't misnest menu items in the TOC 2010-09-08 17:40:41 -07:00
Johan Euphrosine
699fdfaa43 fix home/end on GNU/Linux 2010-09-08 17:40:35 -07:00
Johan Euphrosine
8d2e79451e add tests for console.log arguments handling 2010-09-08 17:40:26 -07:00
Aria Stewart
760efc0758 s/HTTPS/SSL/ where appropriate 2010-09-08 17:39:55 -07:00
Ryan Dahl
1b1ad1d363 Improve appendix markdown 2010-09-08 17:39:38 -07:00
Ryan Dahl
c3eafdd3a4 Add appendix to docs 2010-09-08 17:39:28 -07:00
97 changed files with 2395 additions and 742 deletions

2
.gitignore vendored
View File

@@ -12,3 +12,5 @@ test/fixtures/hello.txt
tmp/
node
node_g
*.swp
.benchmark_reports

13
AUTHORS
View File

@@ -109,8 +109,21 @@ Chandra Sekar S <chandru.in@gmail.com>
Andrew Naylor <argon@mkbot.net>
Benjamin Kramer <benny.kra@gmail.com>
Danny Coates <dannycoates@gmail.com>
Samuel Shull <brickysam26@gmail.com>
Nick Stenning <nick@whiteink.com>
Bert Belder <bertbelder@gmail.com>
Trent Mick <trentm@gmail.com>
Fedor Indutny <fedor.indutny@gmail.com>
Illarionov Oleg <oleg@emby.ru>
Aria Stewart <aredridel@nbtsc.org>
Johan Euphrosine <proppy@aminche.com>
Russell Haering <russellhaering@gmail.com>
Bradley Meck <bradley.meck@gmail.com>
Tobie Langel <tobie.langel@gmail.com>
Tony Metzidis <tonym@tonym.us>
Jorge Chamorro Bieling <jorge@jorgechamorro.com>
Evan Larkin <evan.larkin.il.com>
Joshua Peek <josh@joshpeek.com>
Nathan Rajlich <nathan@tootallnate.net>
Tom Hughes <tom.hughes@palm.com>
Vitali Lovich <vitali.lovich@palm.com>

View File

@@ -1,4 +1,79 @@
2010.08.20, Version 0.2.0
2010.10.24, Version 0.2.4
* Add --eval to command line options (TJ Holowaychuk)
* net fixes
- TCP clients buffer writes before connection
- Don't flush net writeQueue on end() if its still connecting
(Joshua Peek)
- Do not spin on aceept() with EMFILE
* Add --max-stack-size flag. (Tom Hughes)
* Fixes to child_process.exec (timeouts and proper termination)
Default to SIGTERM instead of SIGKILL.
* Add signal handlers so we clean up before exiting. (Tom Hughes)
* Fix parsing of linux memory (Vitali Lovich)
* http-parser: Allow whitespace in the 'Content-Length' header.
(Nathan Rajlich)
* Add flag to disable colors in REPL
2010.10.02, Version 0.2.3, dc103ae020ecd6182aa2adb482ac72ea944130ee
* Fix require in REPL (bug introduced in v0.2.2)
* Pass correct message in client HTTP upgrade event.
(Fedor Indutny)
* Show function names in sys.inspect (Jorge Chamorro Bieling)
* In HTTP, close connection on the "connection:close" header.
(Mikeal Rogers)
* fs.ReadStream bug fixes (Tj Holowaychuk, Evan Larkin, Marco Rogers)
* Fix zero length buffer bug for http res.end()
2010.09.17, Version 0.2.2, 7bf46bc9808f4db98f1cf177d58a6ecf3a50b65d
* REPL improvements (Trent Mick)
* Fix bug in fs.realpath (Isaac Schlueter)
* sys.pump catches errors (Russell Haering)
2010.09.10, Version 0.2.1, da235fa12c208fc8243600e128db2c9b55624c5c
* REPL improvements (Johan Euphrosine, Brian White)
* nextTick bug fixes (Benjamin Thomas, Felix Geisendörfer,
Trent Mick)
* fs module bug fixes (Russell Haering, Marco Rogers, Tobie Langel,
Isaac Schlueter)
* Build script change for OpenEmbedded.
* Most constrctuors work without 'new' now.
* Allow Strings for ports on net.Server.listen (Bradley Meck)
* setInterval(cb, 0) loops infinitely
* Fixes for NODE_MODULE_CONTEXTS=1 (Herbert Vojčík)
* Expose fingerproint from getPeerCertificate (Paul Querna)
* API: forceClose -> destroy for WriteStreams
2010.08.20, Version 0.2.0, 9283e134e558900ba89d9a33c18a9bdedab07cb9
* process.title support for FreeBSD, Macintosh, Linux
@@ -116,7 +191,7 @@
* Upgrade http-parser, V8 to 2.2.21
2010.06.21, Version 0.1.99, a620b7298f68f68a855306437a3b60b650d61d78
2010.06.21, Version 0.1.99, a620b7298f68f68a855306437a3b60b650d61d78
* Datagram sockets (Paul Querna)
@@ -222,7 +297,7 @@
2010.05.06, Version 0.1.94, f711d5343b29d1e72e87107315708e40951a7826
* Look in /usr/local/lib/node for modules, so that there's a way
* Look in /usr/local/lib/node for modules, so that there's a way
to install modules globally (Issac Schlueter)
* SSL improvements (Rhys Jones, Paulo Matias)
@@ -242,7 +317,7 @@
* Bugfix: destroy() instead of end() http connection at end of
pipeline
* Bugfix: http.Client may be prematurely released back to the
* Bugfix: http.Client may be prematurely released back to the
free pool. (Thomas Lee)
* Upgrade V8 to 2.2.8

View File

@@ -36,9 +36,6 @@ test-pummel: all
test-internet: all
python tools/test.py internet
benchmark: all
build/default/node benchmark/run.js
# http://rtomayko.github.com/ronn
# gem install ronn
doc: doc/node.1 doc/api.html doc/index.html doc/changelog.html
@@ -85,4 +82,13 @@ dist: doc/node.1 doc/api.html
rm -rf $(TARNAME)
gzip -f -9 $(TARNAME).tar
.PHONY: benchmark clean docclean dist distclean check uninstall install all test test-all website-upload
bench:
benchmark/http_simple_bench.sh
bench-idle:
./node benchmark/idle_server.js &
sleep 1
./node benchmark/idle_clients.js &
.PHONY: bench clean docclean dist distclean check uninstall install all test test-all website-upload

4
TODO
View File

@@ -16,3 +16,7 @@
the maximum is reached it stops accepting new connections.
- compile under clang
- Use C++ style casts everywhere.
- fs.readFile[Sync] should not call stat() and use the length.
Test on Linux's /proc/sys/kernel/hostname
- Ruby-like Process#detach (is that possible?)
- stderr isn't flushing on exit

View File

@@ -1,6 +1,6 @@
for (var i = 0; i < 9000000; i++) {
for (var i = 0; i < 9e7; i++) {
b = new Buffer(10);
b[1] = 2
}

View File

@@ -0,0 +1,35 @@
var binding = require('./build/default/binding');
c = 0
function js() {
return c++; //(new Date()).getTime();
}
var cxx = binding.hello;
var i, N = 100000000;
console.log(js());
console.log(cxx());
var start = new Date();
for (i = 0; i < N; i++) {
js();
}
var jsDiff = new Date() - start;
console.log(N +" JS function calls: " + jsDiff);
var start = new Date();
for (i = 0; i < N; i++) {
cxx();
}
var cxxDiff = new Date() - start;
console.log(N +" C++ function calls: " + cxxDiff);
console.log("\nJS speedup " + (cxxDiff / jsDiff));

View File

@@ -0,0 +1,19 @@
#include <v8.h>
#include <node.h>
#include <time.h>
using namespace v8;
static int c = 0;
static Handle<Value> Hello(const Arguments& args) {
HandleScope scope;
//time_t tv = time(NULL);
return scope.Close(Integer::New(c++));
}
extern "C" void init (Handle<Object> target) {
HandleScope scope;
//target->Set(String::New("hello"), String::New("World"));
NODE_SET_METHOD(target, "hello", Hello);
}

View File

@@ -0,0 +1,15 @@
srcdir = '.'
blddir = 'build'
VERSION = '0.0.1'
def set_options(opt):
opt.tool_options('compiler_cxx')
def configure(conf):
conf.check_tool('compiler_cxx')
conf.check_tool('node_addon')
def build(bld):
obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
obj.target = 'binding'
obj.source = 'binding.cc'

View File

@@ -1,24 +1,40 @@
path = require("path");
Buffer = require("buffer").Buffer;
exec = require("child_process").exec;
http = require("http");
port = parseInt(process.env.PORT || 8000);
var old = (process.argv[2] == 'old');
console.log('pid ' + process.pid);
http = require(old ? "http_old" : 'http');
if (old) console.log('old version');
fixed = ""
for (var i = 0; i < 20*1024; i++) {
fixed += "C";
}
var uname, rev;
exec('git rev-list -1 HEAD', function (e, stdout) {
if (e) {
console.error("Problem executing: 'git rev-list -1 HEAD'");
throw new Error(e);
}
rev = stdout.replace(/\s/g, '');
});
exec('uname -a', function (e, stdout) {
if (e) {
console.error("Problem executing: 'uname -a'");
throw new Error(e);
}
uname = stdout.replace(/[\r\n]/g, '');
});
stored = {};
storedBuffer = {};
http.createServer(function (req, res) {
var server = http.createServer(function (req, res) {
var commands = req.url.split("/");
var command = commands[1];
var body = "";
@@ -57,6 +73,9 @@ http.createServer(function (req, res) {
} else if (command == "fixed") {
body = fixed;
} else if (command == "info") {
body = 'rev=' + rev + '\nuname="' + uname + '"\n';
} else {
status = 404;
body = "not found\n";
@@ -64,17 +83,13 @@ http.createServer(function (req, res) {
var content_length = body.length.toString();
res.writeHead( status
, { "Content-Type": "text/plain"
, "Content-Length": content_length
}
);
if (old) {
res.write(body, 'ascii');
res.close();
} else {
res.end(body, 'ascii');
}
}).listen(port);
res.writeHead(status, { "Content-Type": "text/plain",
"Content-Length": content_length });
res.end(body);
});
server.listen(port, function () {
console.log('Listening at http://127.0.0.1:'+port+'/');
});
console.log('Listening at http://127.0.0.1:'+port+'/');

77
benchmark/http_simple_bench.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/sh
SERVER=127.0.0.1
PORT=8000
# You may want to configure your TCP settings to make many ports available
# to node and ab. On macintosh use:
# sudo sysctl -w net.inet.ip.portrange.first=32768
# sudo sysctl -w net.inet.tcp.msl=1000
if [ ! -d benchmark/ ]; then
echo "Run this script from the node root directory"
exit 1
fi
if [ $SERVER == "127.0.0.1" ]; then
./node benchmark/http_simple.js &
node_pid=$!
sleep 1
fi
info=`curl -s http://$SERVER:$PORT/info`
eval $info
date=`date "+%Y%m%d%H%M%S"`
ab_hello_world() {
local type="$1"
local ressize="$2"
if [ $type == "string" ]; then
local uri="bytes/$ressize"
else
local uri="buffer/$ressize"
fi
name="ab-hello-world-$type-$ressize"
dir=".benchmark_reports/$name/$rev/"
if [ ! -d $dir ]; then
mkdir -p $dir
fi
summary_fn="$dir/$date.summary"
data_fn="$dir/$date.data"
echo "Bench $name starts in 3 seconds..."
# let shit calm down
sleep 3
# hammer that as hard as it can for 10 seconds.
ab -g $data_fn -c 100 -t 10 http://$SERVER:$PORT/$uri > $summary_fn
# add our data about the server
echo >> $summary_fn
echo >> $summary_fn
echo "webserver-rev: $rev" >> $summary_fn
echo "webserver-uname: $uname" >> $summary_fn
grep Req $summary_fn
echo "Summary: $summary_fn"
echo
}
# 1k
ab_hello_world 'string' '1024'
ab_hello_world 'buffer' '1024'
# 100k
ab_hello_world 'string' '102400'
ab_hello_world 'buffer' '102400'
if [ ! -z $node_pid ]; then
kill -9 $node_pid
fi

50
benchmark/idle_clients.js Normal file
View File

@@ -0,0 +1,50 @@
net = require('net');
var errors = 0, connections = 0;
function connect () {
process.nextTick(function () {
var s = net.Stream();
var gotConnected = false;
s.connect(9000);
s.on('connect', function () {
gotConnected = true;
connections++;
connect();
});
var haderror = false;
s.on('close', function () {
if (gotConnected) connections--;
if (!haderror) connect();
});
s.on('end', function () {
s.end();
});
s.on('error', function () {
haderror = true;
errors++;
});
});
}
connect();
var oldConnections, oldErrors;
setInterval(function () {
if (oldConnections != connections) {
oldConnections = connections;
console.log("CLIENT %d connections: %d", process.pid, connections);
}
if (oldErrors != errors) {
oldErrors = errors;
console.log("CLIENT %d errors: %d", process.pid, errors);
}
}, 1000);

33
benchmark/idle_server.js Normal file
View File

@@ -0,0 +1,33 @@
net = require('net');
connections = 0;
var errors = 0;
server = net.Server(function (socket) {
socket.on('end', function () {
socket.end();
});
socket.on('error', function () {
errors++;
});
});
server.listen(9000);
var oldConnections, oldErrors;
setInterval(function () {
if (oldConnections != server.connections) {
oldConnections = server.connections;
console.log("SERVER %d connections: %d", process.pid, server.connections);
}
if (oldErrors != errors) {
oldErrors = errors;
console.log("SERVER %d errors: %d", process.pid, errors);
}
}, 1000);

View File

@@ -5,13 +5,15 @@
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
int tsize = 1000 * 1048576;
const char *path = "/tmp/wt.dat";
int c = 0;
char* bufit(size_t l)
{
@@ -24,7 +26,7 @@ void writetest(int size, size_t bsize)
{
int i;
char *buf = bufit(bsize);
clock_t start, end;
struct timeval start, end;
double elapsed;
double mbps;
@@ -34,9 +36,10 @@ void writetest(int size, size_t bsize)
exit(254);
}
start = clock();
assert(0 == gettimeofday(&start, NULL));
for (i = 0; i < size; i += bsize) {
int rv = write(fd, buf, bsize);
if (c++ % 2000 == 0) fprintf(stderr, ".");
if (rv < 0) {
perror("write failed");
exit(254);
@@ -48,10 +51,10 @@ void writetest(int size, size_t bsize)
fsync(fd);
#endif
close(fd);
end = clock();
elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
assert(0 == gettimeofday(&end, NULL));
elapsed = (end.tv_sec - start.tv_sec) + ((double)(end.tv_usec - start.tv_usec))/100000.;
mbps = ((tsize/elapsed)) / 1048576;
fprintf(stderr, "Wrote %d bytes in %03fs using %d byte buffers: %03fmB/s\n", size, elapsed, bsize, mbps);
fprintf(stderr, "\nWrote %d bytes in %03fs using %ld byte buffers: %03fmB/s\n", size, elapsed, bsize, mbps);
free(buf);
}
@@ -60,7 +63,7 @@ void readtest(int size, size_t bsize)
{
int i;
char *buf = bufit(bsize);
clock_t start, end;
struct timeval start, end;
double elapsed;
double mbps;
@@ -70,7 +73,7 @@ void readtest(int size, size_t bsize)
exit(254);
}
start = clock();
assert(0 == gettimeofday(&start, NULL));
for (i = 0; i < size; i += bsize) {
int rv = read(fd, buf, bsize);
if (rv < 0) {
@@ -79,10 +82,10 @@ void readtest(int size, size_t bsize)
}
}
close(fd);
end = clock();
elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
assert(0 == gettimeofday(&end, NULL));
elapsed = (end.tv_sec - start.tv_sec) + ((double)(end.tv_usec - start.tv_usec))/100000.;
mbps = ((tsize/elapsed)) / 1048576;
fprintf(stderr, "Read %d bytes in %03fs using %d byte buffers: %03fmB/s\n", size, elapsed, bsize, mbps);
fprintf(stderr, "Read %d bytes in %03fs using %ld byte buffers: %03fmB/s\n", size, elapsed, bsize, mbps);
free(buf);
}

View File

@@ -1,4 +1,5 @@
var fs = require('fs');
var sys = require('sys');
var Buffer = require('buffer').Buffer;
var path = "/tmp/wt.dat";
@@ -21,6 +22,8 @@ function once(emitter, name, cb) {
emitter.addListener(name, incb);
}
c = 0
function writetest(size, bsize) {
var s = fs.createWriteStream(path, {'flags': 'w', 'mode': 0644});
var remaining = size;
@@ -40,6 +43,7 @@ function writetest(size, bsize) {
s.on('drain', function () {
dowrite();
if (c++ % 2000 == 0) sys.print(".");
});
dowrite();

26
benchmark/startup.js Normal file
View File

@@ -0,0 +1,26 @@
var spawn = require('child_process').spawn,
path = require('path'),
emptyJsFile = path.join(__dirname, '../test/fixtures/semicolon.js'),
starts = 100,
i = 0,
start;
function startNode() {
var node = spawn(process.execPath || process.argv[0], [emptyJsFile]);
node.on('exit', function(exitCode) {
if (exitCode !== 0) {
throw new Error('Error during node startup');
}
i++;
if (i < starts) {
startNode();
} else{
var duration = +new Date - start;
console.log('Started node %d times in %s ms. %d ms / start.', starts, duration, duration / starts);
}
});
}
start = +new Date;
startNode();

View File

@@ -1,6 +1,6 @@
for (var i = 0; i < 9000000; i++) {
for (var i = 0; i < 9e7; i++) {
s = '01234567890';
s[1] = "a";
}

View File

@@ -1264,6 +1264,7 @@ size_t http_parser_execute (http_parser *parser,
break;
case h_content_length:
if (ch == ' ') break;
if (ch < '0' || ch > '9') goto error;
parser->content_length *= 10;
parser->content_length += ch - '0';

View File

@@ -860,8 +860,9 @@ Experimental
Read the data from `readableStream` and send it to the `writableStream`.
When `writeableStream.write(data)` returns `false` `readableStream` will be
paused until the `drain` event occurs on the `writableStream`. `callback` is
called when `writableStream` is closed.
paused until the `drain` event occurs on the `writableStream`. `callback` gets
an error as its only argument and is called when `writableStream` is closed or
when an error occurs.
## Timers
@@ -911,9 +912,6 @@ normally, `code` is the final exit code of the process, otherwise `null`. If
the process terminated due to receipt of a signal, `signal` is the string name
of the signal, otherwise `null`.
After this event is emitted, the `'output'` and `'error'` callbacks will no
longer be made.
See `waitpid(2)`.
### child.stdin
@@ -1057,14 +1055,14 @@ There is a second optional argument to specify several options. The default opti
{ encoding: 'utf8'
, timeout: 0
, maxBuffer: 200*1024
, killSignal: 'SIGKILL'
, killSignal: 'SIGTERM'
, cwd: null
, env: null
}
If `timeout` is greater than 0, then it will kill the child process
if it runs longer than `timeout` milliseconds. The child process is killed with
`killSignal` (default: `'SIGKILL'`). `maxBuffer` specifies the largest
`killSignal` (default: `'SIGTERM'`). `maxBuffer` specifies the largest
amount of data allowed on stdout or stderr - if this value is exceeded then
the child process is killed.
@@ -1447,19 +1445,6 @@ See pwrite(2).
The callback will be given two arguments `(err, written)` where `written`
specifies how many _bytes_ were written.
### fs.write(fd, str, position, encoding='utf8', [callback])
Write the entire string `str` using the given `encoding` to the file specified
by `fd`.
`position` refers to the offset from the beginning of the file where this data
should be written. If `position` is `null`, the data will be written at the
current position.
See pwrite(2).
The callback will be given two arguments `(err, written)` where `written`
specifies how many _bytes_ were written.
### fs.writeSync(fd, buffer, offset, length, position)
Synchronous version of buffer-based `fs.write()`. Returns the number of bytes written.
@@ -1483,19 +1468,6 @@ If `position` is `null`, data will be read from the current file position.
The callback is given the two arguments, `(err, bytesRead)`.
### fs.read(fd, length, position, encoding, [callback])
Read data from the file specified by `fd`.
`length` is an integer specifying the number of bytes to read.
`position` is an integer specifying where to begin reading from in the file.
If `position` is `null`, data will be read from the current file position.
`encoding` is the desired encoding of the string of data read in from `fd`.
The callback is given the three arguments, `(err, str, bytesRead)`.
### fs.readSync(fd, buffer, offset, length, position)
Synchronous version of buffer-based `fs.read`. Returns the number of `bytesRead`.
@@ -1607,6 +1579,12 @@ An example to read the last 10 bytes of a file which is 100 bytes long:
`WriteStream` is a `Writable Stream`.
### Event: 'open'
`function (fd) { }`
`fd` is the file descriptor used by the WriteStream.
### fs.createWriteStream(path, [options])
Returns a new WriteStream object (See `Writable Stream`).
@@ -2225,7 +2203,7 @@ See `connect()`.
`function () { }`
Emitted when a stream connection successfully establishes a HTTPS handshake with its peer.
Emitted when a stream connection successfully establishes an SSL handshake with its peer.
### Event: 'data'
@@ -2314,9 +2292,9 @@ received.
### stream.setSecure([credentials])
Enables HTTPS support for the stream, with the crypto module credentials specifying the private key and certificate of the stream, and optionally the CA certificates for use in peer authentication.
Enables SSL support for the stream, with the crypto module credentials specifying the private key and certificate of the stream, and optionally the CA certificates for use in peer authentication.
If the credentials hold one ore more CA certificates, then the stream will request for the peer to submit a client certificate as part of the HTTPS connection handshake. The validity and content of this can be accessed via verifyPeer() and getPeerCertificate().
If the credentials hold one ore more CA certificates, then the stream will request for the peer to submit a client certificate as part of the SSL connection handshake. The validity and content of this can be accessed via verifyPeer() and getPeerCertificate().
### stream.verifyPeer()
@@ -3284,3 +3262,49 @@ All Node addons must export a function called `init` with this signature:
For the moment, that is all the documentation on addons. Please see
<http://github.com/ry/node_postgres> for a real example.
## Appendix - Third Party Modules
There are many third party modules for Node. At the time of writing, August
2010, the master repository of modules is
http://github.com/ry/node/wiki/modules[the wiki page].
This appendix is intended as a SMALL guide to new-comers to help them
quickly find what are considered to be quality modules. It is not intended
to be a complete list. There may be better more complete modules found
elsewhere.
- Module Installer: [npm](http://github.com/isaacs/npm)
- HTTP Middleware: [Connect](http://github.com/senchalabs/connect)
- Web Framework: [Express](http://github.com/visionmedia/express)
- Web Sockets: [Socket.IO](http://github.com/LearnBoost/Socket.IO-node)
- HTML Parsing: [HTML5](http://github.com/aredridel/html5)
- [mDNS/Zeroconf/Bonjour](http://github.com/agnat/node_mdns)
- [RabbitMQ, AMQP](http://github.com/ry/node-amqp)
- [mysql](http://github.com/felixge/node-mysql)
- Serialization: [msgpack](http://github.com/pgriess/node-msgpack)
- Scraping: [Apricot](http://github.com/silentrob/Apricot)
- Debugger: [ndb](http://github.com/smtlaissezfaire/ndb) is a CLI debugger
[inspector](http://github.com/dannycoates/node-inspector) is a web based
tool.
- [pcap binding](http://github.com/mranney/node_pcap)
- [ncurses](http://github.com/mscdex/node-ncurses)
- Testing/TDD/BDD: [vows](http://vowsjs.org/),
[expresso](http://github.com/visionmedia/expresso),
[mjsunit.runner](http://github.com/tmpvar/mjsunit.runner)
Patches to this list are welcome.

View File

@@ -295,7 +295,7 @@
<body>
<div id="toc">
<div id="toctitle">Node v0.2.0</div>
<div id="toctitle">Node v0.2.4</div>
<noscript>JavaScript must be enabled in your browser to display the table of contents.</noscript>
</div>
<div id='man'>

View File

@@ -23,6 +23,10 @@ NodeDoc.generateToc = function()
cur_level = this.tagName.substr(1, 1);
if (last_level != 0 && cur_level <= last_level) {
html.push("</li>")
}
if (cur_level > last_level)
{
html.push('<ul><li>');
@@ -38,15 +42,11 @@ NodeDoc.generateToc = function()
}
html.push('<a href="#' + $this.attr('id') + '">' + $this.text().replace(/\(.*\)$/gi, '') + '</a>');
if (cur_level == last_level || cur_level > last_level)
{
html.push('</li>');
}
last_level = cur_level;
});
html.push('</ul>');
html.push('</li></ul>');
var $toc = $('#toc').append(html.join('')).find('ul li ul').each(function()
{
@@ -175,4 +175,4 @@ NodeDoc.setupSmoothScrolling = function()
}
});
};
NodeDoc.init();
NodeDoc.init();

View File

@@ -89,8 +89,13 @@ net.createServer(function (socket) {
<a href="http://github.com/ry/node/tree/master">git repo</a>
</p>
<p>
2010.08.20
<a href="http://nodejs.org/dist/node-v0.2.0.tar.gz">node-v0.2.0.tar.gz</a>
Stable: 2010.10.24
<a href="http://nodejs.org/dist/node-v0.2.4.tar.gz">node-v0.2.4.tar.gz</a>
</p>
<p>
Unstable: 2010.10.23
<a href="http://nodejs.org/dist/node-v0.3.0.tar.gz">node-v0.3.0.tar.gz</a>
</p>
<p>Historical: <a href="http://nodejs.org/dist">versions</a>, <a href="http://nodejs.org/docs">docs</a></p>

View File

@@ -131,6 +131,15 @@ function _deepEqual(actual, expected) {
if (actual === expected) {
return true;
} else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
if (actual.length != expected.length) return false;
for (var i = 0; i < actual.length; i++) {
if (actual[i] !== expected[i]) return false;
}
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (actual instanceof Date && expected instanceof Date) {

View File

@@ -27,7 +27,7 @@ exports.execFile = function (file /* args, options, callback */) {
var options = { encoding: 'utf8'
, timeout: 0
, maxBuffer: 200*1024
, killSignal: 'SIGKILL'
, killSignal: 'SIGTERM'
, cwd: null
, env: null
};
@@ -60,15 +60,43 @@ exports.execFile = function (file /* args, options, callback */) {
var stdout = "";
var stderr = "";
var killed = false;
var exited = false;
var timeoutId;
function exithandler (code, signal) {
if (exited) return;
exited = true;
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
if (!callback) return;
if (code === 0 && signal === null) {
callback(null, stdout, stderr);
} else {
var e = new Error("Command failed: " + stderr);
e.killed = child.killed || killed;
e.code = code;
e.signal = signal;
callback(e, stdout, stderr);
}
}
function kill () {
killed = true;
child.kill(options.killSignal);
process.nextTick(function () {
exithandler(null, options.killSignal)
});
}
if (options.timeout > 0) {
timeoutId = setTimeout(function () {
if (!killed) {
child.kill(options.killSignal);
killed = true;
timeoutId = null;
}
kill();
timeoutId = null;
}, options.timeout);
}
@@ -77,32 +105,19 @@ exports.execFile = function (file /* args, options, callback */) {
child.stdout.addListener("data", function (chunk) {
stdout += chunk;
if (!killed && stdout.length > options.maxBuffer) {
child.kill(options.killSignal);
killed = true;
if (stdout.length > options.maxBuffer) {
kill();
}
});
child.stderr.addListener("data", function (chunk) {
stderr += chunk;
if (!killed && stderr.length > options.maxBuffer) {
child.kill(options.killSignal);
killed = true
if (stderr.length > options.maxBuffer) {
kill();
}
});
child.addListener("exit", function (code, signal) {
if (timeoutId) clearTimeout(timeoutId);
if (code === 0 && signal === null) {
if (callback) callback(null, stdout, stderr);
} else {
var e = new Error("Command failed: " + stderr);
e.killed = killed;
e.code = code;
e.signal = signal;
if (callback) callback(e, stdout, stderr);
}
});
child.addListener("exit", exithandler);
return child;
};
@@ -113,6 +128,8 @@ function ChildProcess () {
var self = this;
this.killed = false;
var gotCHLD = false;
var exitCode;
var termSignal;
@@ -158,7 +175,11 @@ inherits(ChildProcess, EventEmitter);
ChildProcess.prototype.kill = function (sig) {
return this._internal.kill(sig);
if (this._internal.pid) {
this.killed = true;
sig = sig || 'SIGTERM';
return this._internal.kill(sig);
}
};

View File

@@ -1,8 +1,8 @@
exports.EventEmitter = process.EventEmitter;
var EventEmitter = exports.EventEmitter = process.EventEmitter;
var isArray = Array.isArray;
process.EventEmitter.prototype.emit = function (type) {
EventEmitter.prototype.emit = function (type) {
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events || !this._events.error ||
@@ -18,27 +18,25 @@ process.EventEmitter.prototype.emit = function (type) {
}
if (!this._events) return false;
if (!this._events[type]) return false;
var handler = this._events[type];
if (!handler) return false;
if (typeof this._events[type] == 'function') {
if (arguments.length < 3) {
if (typeof handler == 'function') {
if (arguments.length <= 3) {
// fast case
this._events[type].call( this
, arguments[1]
, arguments[2]
);
handler.call(this, arguments[1], arguments[2]);
} else {
// slower
var args = Array.prototype.slice.call(arguments, 1);
this._events[type].apply(this, args);
handler.apply(this, args);
}
return true;
} else if (isArray(this._events[type])) {
} else if (isArray(handler)) {
var args = Array.prototype.slice.call(arguments, 1);
var listeners = this._events[type].slice(0);
var listeners = handler.slice();
for (var i = 0, l = listeners.length; i < l; i++) {
listeners[i].apply(this, args);
}
@@ -49,9 +47,9 @@ process.EventEmitter.prototype.emit = function (type) {
}
};
// process.EventEmitter is defined in src/node_events.cc
// process.EventEmitter.prototype.emit() is also defined there.
process.EventEmitter.prototype.addListener = function (type, listener) {
// EventEmitter is defined in src/node_events.cc
// EventEmitter.prototype.emit() is also defined there.
EventEmitter.prototype.addListener = function (type, listener) {
if ('function' !== typeof listener) {
throw new Error('addListener only takes instances of Function');
}
@@ -76,9 +74,9 @@ process.EventEmitter.prototype.addListener = function (type, listener) {
return this;
};
process.EventEmitter.prototype.on = process.EventEmitter.prototype.addListener;
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
process.EventEmitter.prototype.removeListener = function (type, listener) {
EventEmitter.prototype.removeListener = function (type, listener) {
if ('function' !== typeof listener) {
throw new Error('removeListener only takes instances of Function');
}
@@ -101,13 +99,13 @@ process.EventEmitter.prototype.removeListener = function (type, listener) {
return this;
};
process.EventEmitter.prototype.removeAllListeners = function (type) {
EventEmitter.prototype.removeAllListeners = function (type) {
// does not use listeners(), so no side effect of creating _events[type]
if (type && this._events && this._events[type]) this._events[type] = null;
return this;
};
process.EventEmitter.prototype.listeners = function (type) {
EventEmitter.prototype.listeners = function (type) {
if (!this._events) this._events = {};
if (!this._events[type]) this._events[type] = [];
if (!isArray(this._events[type])) {

317
lib/fs.js
View File

@@ -6,7 +6,7 @@ var binding = process.binding('fs');
var fs = exports;
var kMinPoolSpace = 128;
var kPoolSize = 40*1024;
var kPoolSize = 40 * 1024;
fs.Stats = binding.Stats;
@@ -56,7 +56,7 @@ fs.readFile = function (path, encoding_, callback) {
function doRead() {
if (size < 1) {
binding.close(fd);
callback(null, buffer);
callback(null, encoding ? '' : buffer);
return;
}
// position is offset or null so we can read files on unseekable mediums
@@ -140,8 +140,11 @@ fs.closeSync = function (fd) {
return binding.close(fd);
};
fs.open = function (path, flags, mode, callback) {
if (mode === undefined) { mode = 0666; }
fs.open = function (path, flags, mode_, callback) {
var mode = (typeof(mode_) == 'number' ? mode_ : 0666);
var callback_ = arguments[arguments.length - 1];
var callback = (typeof(callback_) == 'function' ? callback_ : null);
binding.open(path, stringToFlags(flags), mode, callback || noop);
};
@@ -208,7 +211,15 @@ fs.write = function (fd, buffer, offset, length, position, callback) {
offset = 0;
length = buffer.length;
}
if(!length) return;
if (!length) {
if (typeof callback == 'function') {
process.nextTick(function() {
callback(undefined, 0);
});
}
return;
}
binding.write(fd, buffer, offset, length, position, callback || noop);
};
@@ -445,6 +456,7 @@ fs.watchFile = function (filename) {
};
fs.unwatchFile = function (filename) {
var stat;
if (statWatchers[filename]) {
stat = statWatchers[filename];
stat.stop();
@@ -458,132 +470,121 @@ var path = require('path');
var normalize = path.normalize;
var normalizeArray = path.normalizeArray;
fs.realpathSync = function (path) {
var seen_links = {}, knownHards = {}, buf, i = 0, part, x, stats;
if (path.charAt(0) !== '/') {
var cwd = process.cwd().split('/');
path = cwd.concat(path.split('/'));
path = normalizeArray(path);
i = cwd.length;
buf = [].concat(cwd);
} else {
path = normalizeArray(path.split('/'));
// realpath
// Not using realpath(2) because it's bad.
// See: http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
fs.realpathSync = realpathSync;
fs.realpath = realpath;
function realpathSync (p) {
if (p.charAt(0) !== '/') {
p = path.join(process.cwd(), p);
}
p = p.split('/');
var buf = [ '' ];
var seenLinks = {};
var knownHard = {};
// walk down the path, swapping out linked pathparts for their real
// values, and pushing non-link path bits onto the buffer.
// then return the buffer.
// NB: path.length changes.
for (var i = 0; i < p.length; i ++) {
// skip over empty path parts.
if (p[i] === '') continue;
var part = buf.join('/')+'/'+p[i];
if (knownHard[part]) {
buf.push( p[i] );
continue;
}
var stat = fs.lstatSync(part);
if (!stat.isSymbolicLink()) {
// not a symlink. easy.
knownHard[ part ] = true;
buf.push(p[i]);
continue;
}
var id = stat.dev.toString(32)+':'+stat.ino.toString(32);
if (seenLinks[id]) throw new Error("cyclic link at "+part);
seenLinks[id] = true;
var target = fs.readlinkSync(part);
if (target.charAt(0) === '/') {
// absolute. Start over.
buf = [''];
p = path.normalizeArray(target.split('/').concat(p.slice(i + 1)));
i = 0;
continue;
}
// not absolute. join and splice.
target = target.split('/');
Array.prototype.splice.apply(p, [i, 1].concat(target));
p = path.normalizeArray(p);
i = 0;
buf = [''];
}
for (; i<path.length; i++) {
part = path.slice(0, i+1).join('/');
if (part.length !== 0) {
if (part in knownHards) {
buf.push(path[i]);
} else {
stats = fs.lstatSync(part);
if (stats.isSymbolicLink()) {
x = stats.dev.toString(32)+":"+stats.ino.toString(32);
if (x in seen_links)
throw new Error("cyclic link at "+part);
seen_links[x] = true;
part = fs.readlinkSync(part);
if (part.charAt(0) === '/') {
// absolute
path = normalizeArray(part.split('/'));
buf = [''];
i = 0;
} else {
// relative
Array.prototype.splice.apply(path, [i, 1].concat(part.split('/')));
part = normalizeArray(path);
var y = 0, L = Math.max(path.length, part.length), delta;
for (; y<L && path[y] === part[y]; y++);
if (y !== L) {
path = part;
delta = i-y;
i = y-1;
if (delta > 0) buf.splice(y, delta);
} else {
i--;
}
}
} else {
buf.push(path[i]);
knownHards[buf.join('/')] = true;
}
}
}
}
return buf.join('/');
return buf.join('/') || '/';
}
fs.realpath = function (path, callback) {
var seen_links = {}, knownHards = {}, buf = [''], i = 0, part, x;
if (path.charAt(0) !== '/') {
// assumes cwd is canonical
var cwd = process.cwd().split('/');
path = cwd.concat(path.split('/'));
path = normalizeArray(path);
i = cwd.length-1;
buf = [].concat(cwd);
} else {
path = normalizeArray(path.split('/'));
function realpath (p, cb) {
if (p.charAt(0) !== '/') {
p = path.join(process.cwd(), p);
}
function done(err) {
if (callback) {
if (!err) callback(err, buf.join('/'));
else callback(err);
p = p.split('/');
var buf = [ '' ];
var seenLinks = {};
var knownHard = {};
// walk down the path, swapping out linked pathparts for their real
// values, and pushing non-link path bits onto the buffer.
// then return the buffer.
// NB: path.length changes.
var i = 0;
var part;
LOOP();
function LOOP () {
i ++;
if (!(i < p.length)) return exit();
// skip over empty path parts.
if (p[i] === '') return process.nextTick(LOOP);
part = buf.join('/')+'/'+p[i];
if (knownHard[part]) {
buf.push( p[i] );
return process.nextTick(LOOP);
}
return fs.lstat(part, gotStat);
}
function next() {
if (++i === path.length) return done();
part = path.slice(0, i+1).join('/');
if (part.length === 0) return next();
if (part in knownHards) {
buf.push(path[i]);
next();
} else {
fs.lstat(part, function(err, stats){
if (err) return done(err);
if (stats.isSymbolicLink()) {
x = stats.dev.toString(32)+":"+stats.ino.toString(32);
if (x in seen_links)
return done(new Error("cyclic link at "+part));
seen_links[x] = true;
fs.readlink(part, function(err, npart){
if (err) return done(err);
part = npart;
if (part.charAt(0) === '/') {
// absolute
path = normalizeArray(part.split('/'));
buf = [''];
i = 0;
} else {
// relative
Array.prototype.splice.apply(path, [i, 1].concat(part.split('/')));
part = normalizeArray(path);
var y = 0, L = Math.max(path.length, part.length), delta;
for (; y<L && path[y] === part[y]; y++);
if (y !== L) {
path = part;
delta = i-y;
i = y-1; // resolve new node if needed
if (delta > 0) buf.splice(y, delta);
}
else {
i--; // resolve new node if needed
}
}
next();
}); // binding.readlink
}
else {
buf.push(path[i]);
knownHards[buf.join('/')] = true;
next();
}
}); // binding.lstat
function gotStat (er, stat) {
if (er) return cb(er);
if (!stat.isSymbolicLink()) {
// not a symlink. easy.
knownHard[ part ] = true;
buf.push(p[i]);
return process.nextTick(LOOP);
}
var id = stat.dev.toString(32)+':'+stat.ino.toString(32);
if (seenLinks[id]) return cb(new Error("cyclic link at "+part));
seenLinks[id] = true;
fs.readlink(part, gotTarget);
}
next();
};
function gotTarget (er, target) {
if (er) return cb(er);
if (target.charAt(0) === '/') {
// absolute. Start over.
buf = [''];
p = path.normalizeArray(target.split('/').concat(p.slice(i + 1)));
i = 0;
return process.nextTick(LOOP);
}
// not absolute. join and splice.
target = target.split('/');
Array.prototype.splice.apply(p, [i, 1].concat(target));
p = path.normalizeArray(p);
i = 0;
buf = [''];
return process.nextTick(LOOP);
}
function exit () {
cb(null, buf.join('/') || '/');
}
}
var pool;
function allocNewPool () {
@@ -598,8 +599,12 @@ fs.createReadStream = function(path, options) {
};
var ReadStream = fs.ReadStream = function(path, options) {
if (!(this instanceof ReadStream)) return new ReadStream(path, options);
events.EventEmitter.call(this);
var self = this;
this.path = path;
this.fd = null;
this.readable = true;
@@ -607,7 +612,7 @@ var ReadStream = fs.ReadStream = function(path, options) {
this.flags = 'r';
this.mode = 0666;
this.bufferSize = 4 * 1024;
this.bufferSize = 64 * 1024;
options = options || {};
@@ -618,11 +623,14 @@ var ReadStream = fs.ReadStream = function(path, options) {
this[key] = options[key];
}
if(this.start || this.end) {
if(this.start === undefined || this.end === undefined) {
self.emit('error', new Error('Both start and end are needed for range streaming.'));
} else if(this.start > this.end) {
self.emit('error', new Error('start must be <= end'));
if(this.encoding) this.setEncoding(this.encoding);
if (this.start !== undefined || this.end !== undefined) {
if (this.start === undefined || this.end === undefined) {
this.emit('error',
new Error('Both start and end are needed for range streaming.'));
} else if (this.start > this.end) {
this.emit('error', new Error('start must be <= end'));
} else {
this.firstRead = true;
}
@@ -632,7 +640,6 @@ var ReadStream = fs.ReadStream = function(path, options) {
return;
}
var self = this;
fs.open(this.path, this.flags, this.mode, function(err, fd) {
if (err) {
self.emit('error', err);
@@ -666,9 +673,8 @@ ReadStream.prototype._read = function () {
allocNewPool();
}
if(this.start && this.firstRead) {
this.pos = this.start;
this.firstRead = false;
if (self.start !== undefined && self.firstRead) {
self.pos = self.start;
}
// Grab another reference to the pool in the case that while we're in the
@@ -678,7 +684,7 @@ ReadStream.prototype._read = function () {
var toRead = Math.min(pool.length - pool.used, this.bufferSize);
var start = pool.used;
if(this.pos) {
if (this.pos !== undefined) {
toRead = Math.min(this.end - this.pos + 1, toRead);
}
@@ -714,9 +720,12 @@ ReadStream.prototype._read = function () {
self._read();
}
fs.read(self.fd, pool, pool.used, toRead, this.pos, afterRead);
// pass null for position after we've seeked to the start of a range read
// always pass null on a non-range read
fs.read(self.fd, pool, pool.used, toRead, (self.firstRead ? self.pos : null), afterRead);
self.firstRead = false;
if(self.pos) {
if (self.pos !== undefined) {
self.pos += toRead;
}
pool.used += toRead;
@@ -792,6 +801,8 @@ fs.createWriteStream = function(path, options) {
};
var WriteStream = fs.WriteStream = function(path, options) {
if (!(this instanceof WriteStream)) return new WriteStream(path, options);
events.EventEmitter.call(this);
this.path = path;
@@ -829,7 +840,10 @@ WriteStream.prototype.flush = function () {
var self = this;
var args = this._queue.shift();
if (!args) return self.emit('drain');
if (!args) {
if (this.drainable) { self.emit('drain'); }
return;
}
this.busy = true;
@@ -885,6 +899,8 @@ WriteStream.prototype.write = function (data) {
throw new Error('stream not writeable');
}
this.drainable = true;
var cb;
if (typeof(arguments[arguments.length-1]) == 'function') {
cb = arguments[arguments.length-1];
@@ -934,22 +950,27 @@ WriteStream.prototype.forceClose = function (cb) {
};
WriteStream.prototype.forceClose = function (cb) {
WriteStream.prototype.destroy = function (cb) {
var self = this;
this.writeable = false;
fs.close(self.fd, function(err) {
if (err) {
if (cb) {
cb(err);
function close() {
fs.close(self.fd, function(err) {
if (err) {
if (cb) { cb(err); }
self.emit('error', err);
return;
}
self.emit('error', err);
return;
}
if (cb) { cb(null); }
self.emit('close');
});
}
if (cb) {
cb(null);
}
self.emit('close');
});
if (this.fd) {
close();
} else {
this.addListener('open', close);
}
};

View File

@@ -519,7 +519,7 @@ OutgoingMessage.prototype.end = function (data, encoding) {
if (!hot) {
if (this.chunkedEncoding) {
ret = this._send('0\r\n\r\n'); // Last chunk.
} else if (!data) {
} else {
// Force a flush, HACK.
ret = this._send('');
}
@@ -713,6 +713,7 @@ function httpSocketSetup (socket) {
function Server (requestListener) {
if (!(this instanceof Server)) return new Server(requestListener);
net.Server.call(this);
if(requestListener){
@@ -834,60 +835,25 @@ function connectionListener (socket) {
function Client ( ) {
if (!(this instanceof Client)) return new Client();
net.Stream.call(this);
var self = this;
httpSocketSetup(self);
var parser;
function initParser () {
if (!parser) parser = parsers.alloc();
parser.reinitialize('response');
parser.socket = self;
parser.onIncoming = function (res) {
debug("incoming response!");
var req = self._outgoing[0];
// Responses to HEAD requests are AWFUL. Ask Ryan.
// A major oversight in HTTP. Hence this nastiness.
var isHeadResponse = req.method == "HEAD";
debug('isHeadResponse ' + isHeadResponse);
res.addListener('end', function ( ) {
debug("request complete disconnecting. readyState = " + self.readyState);
// For the moment we reconnect for every request. FIXME!
// All that should be required for keep-alive is to not reconnect,
// but outgoingFlush instead.
if (req.shouldKeepAlive) {
outgoingFlush(self)
self._outgoing.shift()
outgoingFlush(self)
} else {
self.end();
}
});
req.emit("response", res);
return isHeadResponse;
};
};
self.ondata = function (d, start, end) {
if (!parser) {
function onData(d, start, end) {
if (!self.parser) {
throw new Error("parser not initialized prior to Client.ondata call");
}
var ret = parser.execute(d, start, end - start);
var ret = self.parser.execute(d, start, end - start);
if (ret instanceof Error) {
self.destroy(ret);
} else if (parser.incoming && parser.incoming.upgrade) {
} else if (self.parser.incoming && self.parser.incoming.upgrade) {
var bytesParsed = ret;
self.ondata = null;
self.onend = null
var req = self._outgoing[0];
var req = self.parser.incoming;
var upgradeHead = d.slice(start + bytesParsed + 1, end);
@@ -901,23 +867,27 @@ function Client ( ) {
self.addListener("connect", function () {
debug('client connected');
self.ondata = onData;
self.onend = onEnd;
if (this.https) {
this.setSecure(this.credentials);
} else {
initParser();
self._initParser();
debug('requests: ' + sys.inspect(self._outgoing));
outgoingFlush(self);
}
});
self.addListener("secure", function () {
initParser();
self._initParser();
debug('requests: ' + sys.inspect(self._outgoing));
outgoingFlush(self);
});
self.onend = function () {
if (parser) parser.finish();
function onEnd() {
if (self.parser) self.parser.finish();
debug("self got end closing. readyState = " + self.readyState);
self.end();
};
@@ -933,9 +903,9 @@ function Client ( ) {
// If there are more requests to handle, reconnect.
if (self._outgoing.length) {
self._reconnect();
} else if (parser) {
parsers.free(parser);
parser = null;
} else if (self.parser) {
parsers.free(self.parser);
self.parser = null;
}
});
};
@@ -953,6 +923,46 @@ exports.createClient = function (port, host, https, credentials) {
};
Client.prototype._initParser = function () {
var self = this;
if (!self.parser) self.parser = parsers.alloc();
self.parser.reinitialize('response');
self.parser.socket = self;
self.parser.onIncoming = function (res) {
debug("incoming response!");
var req = self._outgoing[0];
// Responses to HEAD requests are AWFUL. Ask Ryan.
// A major oversight in HTTP. Hence this nastiness.
var isHeadResponse = req.method == "HEAD";
debug('isHeadResponse ' + isHeadResponse);
if (req.shouldKeepAlive && res.headers.connection === 'close') {
req.shouldKeepAlive = false;
}
res.addListener('end', function ( ) {
debug("request complete disconnecting. readyState = " + self.readyState);
// For the moment we reconnect for every request. FIXME!
// All that should be required for keep-alive is to not reconnect,
// but outgoingFlush instead.
if (req.shouldKeepAlive) {
outgoingFlush(self)
self._outgoing.shift()
outgoingFlush(self)
} else {
self.end();
}
});
req.emit("response", res);
return isHeadResponse;
};
};
// This is called each time a request has been pushed completely to the
// socket. The message that was sent is still sitting at client._outgoing[0]
// it is our responsibility to shift it off.

View File

@@ -513,6 +513,7 @@ function initStream (self) {
}
function Stream (fd, type) {
if (!(this instanceof Stream)) return new Stream(fd, type);
events.EventEmitter.call(this);
this.fd = null;
@@ -637,13 +638,20 @@ Object.defineProperty(Stream.prototype, 'readyState', {
// something was queued. If data was queued, then the "drain" event will
// signal when it has been finally flushed to socket.
Stream.prototype.write = function (data, encoding, fd) {
if (this._writeQueue && this._writeQueue.length) {
if (this._connecting || (this._writeQueue && this._writeQueue.length)) {
if (!this._writeQueue) {
this._writeQueue = [];
this._writeQueueEncoding = [];
this._writeQueueFD = [];
}
// Slow. There is already a write queue, so let's append to it.
if (this._writeQueueLast() === END_OF_FILE) {
throw new Error('Stream.end() called already; cannot write.');
}
if (typeof data == 'string' &&
this._writeQueueEncoding.length &&
this._writeQueueEncoding[this._writeQueueEncoding.length-1] === encoding) {
// optimization - concat onto last
this._writeQueue[this._writeQueue.length-1] += data;
@@ -849,13 +857,21 @@ function doConnect (socket, port, host) {
socket.destroy(e);
return;
}
if (socket._writeQueue && socket._writeQueue.length) {
// Flush socket in case any writes are queued up while connecting.
// ugly
_doFlush.call(socket._writeWatcher);
}
} else if (errno != EINPROGRESS) {
socket.destroy(errnoException(errno, 'connect'));
}
};
}
function isPort (x) { return parseInt(x) >= 0; }
function toPort (x) { return (x = Number(x)) >= 0 ? x : false }
// var stream = new Stream();
@@ -871,10 +887,18 @@ Stream.prototype.connect = function () {
timeout.active(socket);
self._connecting = true; // set false in doConnect
self.writable = true;
if (isPort(arguments[0])) {
var port = toPort(arguments[0])
if (port === false) {
// UNIX
self.fd = socket('unix');
self.type = 'unix';
setImplmentationMethods(this);
doConnect(self, arguments[0]);
} else {
// TCP
var port = arguments[0];
dns.lookup(arguments[1], function (err, ip, addressType) {
if (err) {
self.emit('error', err);
@@ -884,13 +908,6 @@ Stream.prototype.connect = function () {
doConnect(self, port, ip);
}
});
} else {
// UNIX
self.fd = socket('unix');
self.type = 'unix';
setImplmentationMethods(this);
doConnect(self, arguments[0]);
}
};
@@ -1025,13 +1042,16 @@ Stream.prototype.end = function (data, encoding) {
if (data) this.write(data, encoding);
if (this._writeQueueLast() !== END_OF_FILE) {
this._writeQueue.push(END_OF_FILE);
this.flush();
if (!this._connecting) {
this.flush();
}
}
}
};
function Server (listener) {
if (!(this instanceof Server)) return new Server(listener);
events.EventEmitter.call(this);
var self = this;
@@ -1041,6 +1061,25 @@ function Server (listener) {
self.connections = 0;
self.paused = false;
self.pauseTimeout = 1000;
function pause () {
// We've hit the maximum file limit. What to do?
// Let's try again in 1 second.
self.watcher.stop();
// If we're already paused, don't do another timeout.
if (self.paused) return;
setTimeout(function () {
self.paused = false;
// Make sure we haven't closed in the interim
if (typeof self.fd != 'number') return;
self.watcher.start();
}, self.pauseTimeout);
}
self.watcher = new IOWatcher();
self.watcher.host = self;
self.watcher.callback = function () {
@@ -1048,7 +1087,10 @@ function Server (listener) {
try {
var peerInfo = accept(self.fd);
} catch (e) {
if (e.errno == EMFILE) return;
if (e.errno == EMFILE) {
pause();
return;
}
throw e;
}
if (!peerInfo) return;
@@ -1107,7 +1149,8 @@ Server.prototype.listen = function () {
self.addListener('listening', lastArg);
}
if (!isPort(arguments[0])) {
var port = toPort(arguments[0])
if (port === false) {
// the first argument specifies a path
self.fd = socket('unix');
self.type = 'unix';
@@ -1142,13 +1185,12 @@ Server.prototype.listen = function () {
// The port can be found with server.address()
self.type = 'tcp4';
self.fd = socket(self.type);
bind(self.fd, arguments[0]);
bind(self.fd, port);
process.nextTick(function () {
self._doListen();
});
} else {
// the first argument is the port, the second an IP
var port = arguments[0];
dns.lookup(arguments[1], function (err, ip, addressType) {
if (err) {
self.emit('error', err);

View File

@@ -15,24 +15,26 @@ var EventEmitter = require('events').EventEmitter;
var stdio = process.binding('stdio');
exports.createInterface = function (output, completer) {
return new Interface(output, completer);
};
function Interface (output, completer) {
if (!(this instanceof Interface)) return new Interface(output, completer);
EventEmitter.call(this);
this.output = output;
this.completer = completer;
this.setPrompt("node> ");
this.setPrompt("> ");
this._tty = output.fd < 3;
this.enabled = output.fd < 3; // Looks like a TTY.
if (parseInt(process.env['NODE_NO_READLINE'])) {
this._tty = false;
this.enabled = false;
}
if (this._tty) {
if (this.enabled) {
// input refers to stdin
// Current line
@@ -40,22 +42,28 @@ function Interface (output, completer) {
// Check process.env.TERM ?
stdio.setRawMode(true);
this._tty = true;
this.enabled = true;
// Cursor position on the line.
this.cursor = 0;
this.history = [];
this.historyIndex = -1;
exports.columns = process.binding('stdio').getColumns();
if (process.listeners("SIGWINCH").length === 0) {
process.on("SIGWINCH", function () {
exports.columns = process.binding('stdio').getColumns();
});
}
}
}
inherits(Interface, EventEmitter);
Interface.prototype.__defineGetter__("columns", function () {
if (this._tty) {
return stdio.getColumns();
}
return exports.columns;
});
Interface.prototype.setPrompt = function (prompt, length) {
@@ -65,7 +73,7 @@ Interface.prototype.setPrompt = function (prompt, length) {
Interface.prototype.prompt = function () {
if (this._tty) {
if (this.enabled) {
this.cursor = 0;
this._refreshLine();
} else {
@@ -111,7 +119,7 @@ Interface.prototype._refreshLine = function () {
Interface.prototype.close = function (d) {
if (this._tty) {
if (this.enabled) {
stdio.setRawMode(false);
}
this.emit('close');
@@ -121,7 +129,7 @@ Interface.prototype.close = function (d) {
Interface.prototype.write = function (d) {
if (this._closed) return;
return this._tty ? this._ttyWrite(d) : this._normalWrite(d);
return this.enabled ? this._ttyWrite(d) : this._normalWrite(d);
};
@@ -261,7 +269,12 @@ Interface.prototype._ttyWrite = function (b) {
/* ctrl+c */
case 3:
//process.kill(process.pid, "SIGINT");
this.close();
if (this.listeners('SIGINT').length) {
this.emit('SIGINT');
} else {
// default behavior, end the readline
this.close();
}
break;
case 4: // control-d, delete right or EOF
@@ -332,6 +345,17 @@ Interface.prototype._ttyWrite = function (b) {
this._historyNext();
break;
case 23: // control-w, delete backwards to a word boundary
if (this.cursor !== 0) {
var leading = this.line.slice(0, this.cursor);
var match = leading.match(/\s?((\W+|\w+)\s*)$/);
leading = leading.slice(0, leading.length - match[1].length);
this.line = leading + this.line.slice(this.cursor, this.line.length);
this.cursor = leading.length;
this._refreshLine();
}
break;
case 9: // tab, completion
if (this.completer) {
this._tabComplete();
@@ -347,34 +371,104 @@ Interface.prototype._ttyWrite = function (b) {
return;
case 27: /* escape sequence */
if (b[1] === 98 && this.cursor > 0) { // meta-b - backward word
var next_word, next_non_word, previous_word, previous_non_word;
} else if (b[1] === 102 && this.cursor < this.line.length) { // meta-f - forward word
if (b[1] === 98 && this.cursor > 0) {
// meta-b - backward word
previous_word = this.line.slice(0, this.cursor)
.split('').reverse().join('')
.search(/\w/);
if (previous_word !== -1) {
previous_non_word = this.line.slice(0, this.cursor - previous_word)
.split('').reverse().join('')
.search(/\W/);
if (previous_non_word !== -1) {
this.cursor -= previous_word + previous_non_word;
this._refreshLine();
break;
}
}
this.cursor = 0;
this._refreshLine();
} else if (b[1] === 91 && b[2] === 68) { // left arrow
} else if (b[1] === 102 && this.cursor < this.line.length) {
// meta-f - forward word
next_word = this.line.slice(this.cursor, this.line.length).search(/\w/);
if (next_word !== -1) {
next_non_word =
this.line.slice(this.cursor + next_word, this.line.length)
.search(/\W/);
if (next_non_word !== -1) {
this.cursor += next_word + next_non_word;
this._refreshLine();
break;
}
}
this.cursor = this.line.length;
this._refreshLine();
} else if (b[1] === 100 && this.cursor < this.line.length) {
// meta-d delete forward word
next_word = this.line.slice(this.cursor, this.line.length).search(/\w/);
if (next_word !== -1) {
next_non_word =
this.line.slice(this.cursor + next_word, this.line.length)
.search(/\W/);
if (next_non_word !== -1) {
this.line =
this.line.slice(this.cursor + next_word + next_non_word);
this.cursor = 0;
this._refreshLine();
break;
}
}
this.line = '';
this.cursor = 0;
this._refreshLine();
} else if (b[1] === 91 && b[2] === 68) {
// left arrow
if (this.cursor > 0) {
this.cursor--;
this.output.write('\x1b[0D');
}
} else if (b[1] === 91 && b[2] === 67) { // right arrow
} else if (b[1] === 91 && b[2] === 67) {
// right arrow
if (this.cursor != this.line.length) {
this.cursor++;
this.output.write('\x1b[0C');
}
} else if (b[1] === 91 && b[2] === 72) { // home
} else if ((b[1] === 91 && b[2] === 72) ||
(b[1] === 79 && b[2] === 72) ||
(b[1] === 91 && b[2] === 55) ||
(b[1] === 91 && b[2] === 49 && (b[3] && b[3] === 126))) {
// home
this.cursor = 0;
this._refreshLine();
} else if (b[1] === 91 && b[2] === 70) { // end
} else if ((b[1] === 91 && b[2] === 70) ||
(b[1] === 79 && b[2] === 70) ||
(b[1] === 91 && b[2] === 56) ||
(b[1] === 91 && b[2] === 52 && (b[3] && b[3] === 126))) {
// end
this.cursor = this.line.length;
this._refreshLine();
} else if (b[1] === 91 && b[2] === 65) { // up arrow
} else if (b[1] === 91 && b[2] === 65) {
// up arrow
this._historyPrev();
} else if (b[1] === 91 && b[2] === 66) { // down arrow
} else if (b[1] === 91 && b[2] === 66) {
// down arrow
this._historyNext();
} else if (b[1] === 91 && b[2] === 51 && this.cursor < this.line.length) { // delete right
} else if (b[1] === 91 && b[2] === 51 && this.cursor < this.line.length) {
// delete right
this.line = this.line.slice(0, this.cursor) +
this.line.slice(this.cursor+1, this.line.length);
this._refreshLine();
}
break;

View File

@@ -20,6 +20,8 @@ var fs = require("fs");
var rl = require('readline');
var context;
var disableColors = process.env.NODE_DISABLE_COLORS ? true : false;
function cwdRequire (id) {
if (id.match(/^\.\.\//) || id.match(/^\.\//)) {
id = path.join(process.cwd(), id);
@@ -48,13 +50,31 @@ function REPLServer(prompt, stream) {
self.buffered_cmd = '';
self.stream = stream || process.openStdin();
self.prompt = prompt || "node> ";
self.prompt = prompt || "> ";
var rli = self.rli = rl.createInterface(self.stream, function (text) {
return self.complete(text);
});
if (rli.enabled && !disableColors) {
// Turn on ANSI coloring.
exports.writer = function(obj, showHidden, depth) {
return sys.inspect(obj, showHidden, depth, true);
}
}
rli.setPrompt(self.prompt);
rli.on("SIGINT", function () {
if (self.buffered_cmd && self.buffered_cmd.length > 0) {
rli.write("\n");
self.buffered_cmd = '';
self.displayPrompt();
} else {
rli.close();
}
});
self.stream.addListener("data", function (chunk) {
rli.write(chunk);
});
@@ -130,7 +150,7 @@ exports.start = function (prompt, source) {
};
REPLServer.prototype.displayPrompt = function () {
this.rli.setPrompt(this.buffered_cmd.length ? '... ' : this.prompt);
this.rli.setPrompt(this.buffered_cmd.length ? '... ' : this.prompt);
this.rli.prompt();
};
@@ -300,7 +320,8 @@ REPLServer.prototype.complete = function (line) {
if (typeof obj === "object" || typeof obj === "function") {
memberGroups.push(Object.getOwnPropertyNames(obj));
}
var p = obj.constructor.prototype; // works for non-objects
// works for non-objects
var p = obj.constructor ? obj.constructor.prototype : null;
try {
var sentinel = 5;
while (p !== null) {
@@ -380,7 +401,8 @@ REPLServer.prototype.parseREPLKeyword = function (cmd) {
var self = this;
switch (cmd) {
case ".break":
case ".break":
// TODO remove me after 0.3.x
self.buffered_cmd = '';
self.displayPrompt();
return true;
@@ -394,7 +416,6 @@ REPLServer.prototype.parseREPLKeyword = function (cmd) {
self.stream.destroy();
return true;
case ".help":
self.stream.write(".break\tSometimes you get stuck in a place you can't get out... This will get you out.\n");
self.stream.write(".clear\tBreak, and also clear the local context.\n");
self.stream.write(".exit\tExit the prompt\n");
self.stream.write(".help\tShow repl options\n");

View File

@@ -33,10 +33,51 @@ var error = exports.error = function (x) {
*
* @param {Object} value The object to print out
* @param {Boolean} showHidden Flag that shows hidden (not enumerable)
* properties of objects.
* properties of objects.
* @param {Number} depth Depth in which to descend in object. Default is 2.
* @param {Boolean} colors Flag to turn on ANSI escape codes to color the
* output. Default is false (no coloring).
*/
exports.inspect = function (obj, showHidden, depth) {
exports.inspect = function (obj, showHidden, depth, colors) {
var seen = [];
var stylize = function (str, styleType) {
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
var styles = { 'bold' : [1, 22]
, 'italic' : [3, 23]
, 'underline' : [4, 24]
, 'inverse' : [7, 27]
, 'white' : [37, 39]
, 'grey' : [90, 39]
, 'black' : [30, 39]
, 'blue' : [34, 39]
, 'cyan' : [36, 39]
, 'green' : [32, 39]
, 'magenta' : [35, 39]
, 'red' : [31, 39]
, 'yellow' : [33, 39]
};
var style = { "special": "grey"
, "number": "blue"
, "boolean": "blue"
, "undefined": "red"
, "null": "red"
, "string": "green"
, "date": "magenta"
//, "name": intentionally not styling
, "regexp": "cyan"
}[styleType];
if (style) {
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
} else {
return str;
}
};
if (! colors) {
stylize = function(str, styleType) { return str; };
}
function format(value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
@@ -50,39 +91,36 @@ exports.inspect = function (obj, showHidden, depth) {
// Primitive types cannot have properties
switch (typeof value) {
case 'undefined': return 'undefined';
case 'string': return JSON.stringify(value).replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
case 'number': return '' + value;
case 'boolean': return '' + value;
case 'undefined': return stylize('undefined', 'undefined');
case 'string': return stylize(
JSON.stringify(value).replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'"),
'string');
case 'number': return stylize('' + value, 'number');
case 'boolean': return stylize('' + value, 'boolean');
}
// For some reason typeof null is "object", so special case here.
if (value === null) {
return 'null';
return stylize('null', 'null');
}
// Look up the keys of the object.
if (showHidden) {
var keys = Object.getOwnPropertyNames(value).map(function (key) { return '' + key; });
} else {
var keys = Object.keys(value);
}
var visible_keys = Object.keys(value);
var keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys;
// Functions without properties can be shortcutted.
if (typeof value === 'function' && keys.length === 0) {
if (isRegExp(value)) {
return '' + value;
return stylize('' + value, 'regexp');
} else {
return '[Function]';
return stylize('[Function'+ (value.name ? ': '+ value.name : '')+ ']', 'special');
}
}
// Dates without properties can be shortcutted
if (isDate(value) && keys.length === 0) {
return value.toUTCString();
return stylize(value.toUTCString(), 'date');
}
var base, type, braces;
@@ -97,7 +135,7 @@ exports.inspect = function (obj, showHidden, depth) {
// Make functions say that they are functions
if (typeof value === 'function') {
base = (isRegExp(value)) ? ' ' + value : ' [Function]';
base = (isRegExp(value)) ? ' ' + value : ' [Function'+ (value.name ? ': '+ value.name : '')+ ']';
} else {
base = "";
}
@@ -115,24 +153,24 @@ exports.inspect = function (obj, showHidden, depth) {
if (recurseTimes < 0) {
if (isRegExp(value)) {
return '' + value;
return stylize('' + value, "regexp");
} else {
return "[Object]";
return stylize("[Object]", "special");
}
}
output = keys.map(function (key) {
var output = keys.map(function (key) {
var name, str;
if (value.__lookupGetter__) {
if (value.__lookupGetter__(key)) {
if (value.__lookupSetter__(key)) {
str = "[Getter/Setter]";
str = stylize("[Getter/Setter]", "special");
} else {
str = "[Getter]";
str = stylize("[Getter]", "special");
}
} else {
if (value.__lookupSetter__(key)) {
str = "[Setter]";
str = stylize("[Setter]", "special");
}
}
}
@@ -160,7 +198,7 @@ exports.inspect = function (obj, showHidden, depth) {
}
}
} else {
str = '[Circular]';
str = stylize('[Circular]', 'special');
}
}
if (typeof name === 'undefined') {
@@ -170,11 +208,13 @@ exports.inspect = function (obj, showHidden, depth) {
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length-2);
name = stylize(name, "name");
}
else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = stylize(name, "string");
}
}
@@ -283,6 +323,15 @@ exports.exec = function () {
exports.pump = function (readStream, writeStream, callback) {
var callbackCalled = false;
function call (a, b, c) {
if (callback && !callbackCalled) {
callback(a, b, c);
callbackCalled = true;
}
}
if (!readStream.pause) readStream.pause = function () {readStream.emit("pause")};
if (!readStream.resume) readStream.resume = function () {readStream.emit("resume")};
@@ -307,7 +356,17 @@ exports.pump = function (readStream, writeStream, callback) {
});
readStream.addListener("close", function () {
if (callback) callback();
call();
});
readStream.addListener("error", function (err) {
writeStream.end();
call(err);
});
writeStream.addListener("error", function (err) {
readStream.destroy();
call(err);
});
};

View File

@@ -18,7 +18,7 @@ var protocolPattern = /^([a-z0-9]+:)/,
path = require("path"), // internal module, guaranteed to be loaded already.
querystring = require('querystring');
function urlParse (url, parseQueryString) {
function urlParse (url, parseQueryString, slashesDenoteHost) {
if (url && typeof(url) === "object" && url.href) return url;
var out = { href : url },
@@ -32,10 +32,15 @@ function urlParse (url, parseQueryString) {
}
// figure out if it's got a host
var slashes = rest.substr(0, 2) === "//";
if (slashes && !(proto && hostlessProtocol[proto])) {
rest = rest.substr(2);
out.slashes = true;
// user@server is *always* interpreted as a hostname, and url
// resolution will treat //foo/bar as host=foo,path=bar because that's
// how the browser resolves relative URLs.
if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
var slashes = rest.substr(0, 2) === "//";
if (slashes && !(proto && hostlessProtocol[proto])) {
rest = rest.substr(2);
out.slashes = true;
}
}
if (!hostlessProtocol[proto] && (slashes || (proto && !slashedProtocol[proto]))) {
// there's a hostname.
@@ -133,8 +138,8 @@ function urlResolve (source, relative) {
function urlResolveObject (source, relative) {
if (!source) return relative;
source = urlParse(urlFormat(source));
relative = urlParse(urlFormat(relative));
source = urlParse(urlFormat(source), false, true);
relative = urlParse(urlFormat(relative), false, true);
// hash is always overridden, no matter what.
source.hash = relative.hash;

View File

@@ -49,7 +49,12 @@
using namespace v8;
# ifdef __APPLE__
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
# else
extern char **environ;
# endif
namespace node {
@@ -68,12 +73,16 @@ static Persistent<String> listeners_symbol;
static Persistent<String> uncaught_exception_symbol;
static Persistent<String> emit_symbol;
static char *eval_string = NULL;
static int option_end_index = 0;
static bool use_debug_agent = false;
static bool debug_wait_connect = false;
static int debug_port=5858;
static int max_stack_size = 0;
static ev_prepare next_tick_watcher;
static ev_check check_tick_watcher;
static ev_prepare prepare_tick_watcher;
static ev_idle tick_spinner;
static bool need_tick_cb;
static Persistent<String> tick_callback_sym;
@@ -164,6 +173,11 @@ static void Check(EV_P_ ev_check *watcher, int revents) {
static Handle<Value> NeedTickCallback(const Arguments& args) {
HandleScope scope;
need_tick_cb = true;
// TODO: this tick_spinner shouldn't be necessary. An ev_prepare should be
// sufficent, the problem is only in the case of the very last "tick" -
// there is nothing left to do in the event loop and libev will exit. The
// ev_prepare callback isn't called before exiting. Thus we start this
// tick_spinner to keep the event loop alive long enough to handle it.
ev_idle_start(EV_DEFAULT_UC_ &tick_spinner);
return Undefined();
}
@@ -175,10 +189,7 @@ static void Spin(EV_P_ ev_idle *watcher, int revents) {
}
static void Tick(EV_P_ ev_prepare *watcher, int revents) {
assert(watcher == &next_tick_watcher);
assert(revents == EV_PREPARE);
static void Tick(void) {
// Avoid entering a V8 scope.
if (!need_tick_cb) return;
@@ -207,6 +218,20 @@ static void Tick(EV_P_ ev_prepare *watcher, int revents) {
}
static void PrepareTick(EV_P_ ev_prepare *watcher, int revents) {
assert(watcher == &prepare_tick_watcher);
assert(revents == EV_PREPARE);
Tick();
}
static void CheckTick(EV_P_ ev_check *watcher, int revents) {
assert(watcher == &check_tick_watcher);
assert(revents == EV_CHECK);
Tick();
}
static void DoPoll(EV_P_ ev_idle *watcher, int revents) {
assert(watcher == &eio_poller);
assert(revents == EV_IDLE);
@@ -1495,6 +1520,7 @@ static Handle<Value> Binding(const Arguments& args) {
exports->Set(String::New("tcp"), String::New(native_tcp));
exports->Set(String::New("url"), String::New(native_url));
exports->Set(String::New("utils"), String::New(native_utils));
exports->Set(String::New("util"), String::New(native_sys));
exports->Set(String::New("path"), String::New(native_path));
exports->Set(String::New("string_decoder"), String::New(native_string_decoder));
binding_cache->Set(module, exports);
@@ -1595,6 +1621,11 @@ static void Load(int argc, char *argv[]) {
process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
// -e, --eval
if (eval_string) {
process->Set(String::NewSymbol("_eval"), String::New(eval_string));
}
size_t size = 2*PATH_MAX;
char execPath[size];
if (OS::GetExecutablePath(execPath, &size) != 0) {
@@ -1707,21 +1738,23 @@ static void ParseDebugOpt(const char* arg) {
static void PrintHelp() {
printf("Usage: node [options] script.js [arguments] \n"
"Options:\n"
" -v, --version print node's version\n"
" --debug[=port] enable remote debugging via given TCP port\n"
" without stopping the execution\n"
" --debug-brk[=port] as above, but break in script.js and\n"
" wait for remote debugger to connect\n"
" --v8-options print v8 command line options\n"
" --vars print various compiled-in variables\n"
" -v, --version print node's version\n"
" --debug[=port] enable remote debugging via given TCP port\n"
" without stopping the execution\n"
" --debug-brk[=port] as above, but break in script.js and\n"
" wait for remote debugger to connect\n"
" --v8-options print v8 command line options\n"
" --vars print various compiled-in variables\n"
" --max-stack-size=val set max v8 stack size (bytes)\n"
"\n"
"Enviromental variables:\n"
"NODE_PATH ':'-separated list of directories\n"
" prefixed to the module search path,\n"
" require.paths.\n"
"NODE_DEBUG Print additional debugging output.\n"
"NODE_MODULE_CONTEXTS Set to 1 to load modules in their own\n"
" global contexts.\n"
"NODE_PATH ':'-separated list of directories\n"
" prefixed to the module search path,\n"
" require.paths.\n"
"NODE_DEBUG Print additional debugging output.\n"
"NODE_MODULE_CONTEXTS Set to 1 to load modules in their own\n"
" global contexts.\n"
"NODE_DISABLE_COLORS Set to 1 to disable colors in the REPL\n"
"\n"
"Documentation can be found at http://nodejs.org/api.html"
" or with 'man node'\n");
@@ -1744,9 +1777,21 @@ static void ParseArgs(int *argc, char **argv) {
printf("NODE_PREFIX: %s\n", NODE_PREFIX);
printf("NODE_CFLAGS: %s\n", NODE_CFLAGS);
exit(0);
} else if (strstr(arg, "--max-stack-size=") == arg) {
const char *p = 0;
p = 1 + strchr(arg, '=');
max_stack_size = atoi(p);
argv[i] = const_cast<char*>("");
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
PrintHelp();
exit(0);
} else if (strcmp(arg, "--eval") == 0 || strcmp(arg, "-e") == 0) {
if (*argc <= i + 1) {
fprintf(stderr, "Error: --eval requires an argument\n");
exit(1);
}
argv[i] = const_cast<char*>("");
eval_string = argv[++i];
} else if (strcmp(arg, "--v8-options") == 0) {
argv[i] = const_cast<char*>("--help");
} else if (argv[i][0] != '-') {
@@ -1758,6 +1803,21 @@ static void ParseArgs(int *argc, char **argv) {
}
static void SignalExit(int signal) {
exit(1);
}
static int RegisterSignalHandler(int signal, void (*handler)(int)) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigfillset(&sa.sa_mask);
return sigaction(signal, &sa, NULL);
}
static void AtExit() {
node::Stdio::Flush();
node::Stdio::DisableRawMode(STDIN_FILENO);
@@ -1788,13 +1848,26 @@ int main(int argc, char *argv[]) {
v8argv[node::option_end_index] = const_cast<char*>("--expose_debug_as");
v8argv[node::option_end_index + 1] = const_cast<char*>("v8debug");
}
// For the normal stack which moves from high to low addresses when frames
// are pushed, we can compute the limit as stack_size bytes below the
// the address of a stack variable (e.g. &stack_var) as an approximation
// of the start of the stack (we're assuming that we haven't pushed a lot
// of frames yet).
if (node::max_stack_size != 0) {
uint32_t stack_var;
ResourceConstraints constraints;
uint32_t *stack_limit = &stack_var - (node::max_stack_size / sizeof(uint32_t));
constraints.set_stack_limit(stack_limit);
SetResourceConstraints(&constraints); // Must be done before V8::Initialize
}
V8::SetFlagsFromCommandLine(&v8argc, v8argv, false);
// Ignore SIGPIPE
struct sigaction sa;
bzero(&sa, sizeof(sa));
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
node::RegisterSignalHandler(SIGPIPE, SIG_IGN);
node::RegisterSignalHandler(SIGINT, node::SignalExit);
node::RegisterSignalHandler(SIGTERM, node::SignalExit);
// Initialize the default ev loop.
@@ -1802,14 +1875,18 @@ int main(int argc, char *argv[]) {
// TODO(Ryan) I'm experiencing abnormally high load using Solaris's
// EVBACKEND_PORT. Temporarally forcing select() until I debug.
ev_default_loop(EVBACKEND_POLL);
#elif defined(__APPLE_CC__) && __APPLE_CC__ >= 5659
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
ev_default_loop(EVBACKEND_KQUEUE);
#else
ev_default_loop(EVFLAG_AUTO);
#endif
ev_prepare_init(&node::next_tick_watcher, node::Tick);
ev_prepare_start(EV_DEFAULT_UC_ &node::next_tick_watcher);
ev_prepare_init(&node::prepare_tick_watcher, node::PrepareTick);
ev_prepare_start(EV_DEFAULT_UC_ &node::prepare_tick_watcher);
ev_unref(EV_DEFAULT_UC);
ev_check_init(&node::check_tick_watcher, node::CheckTick);
ev_check_start(EV_DEFAULT_UC_ &node::check_tick_watcher);
ev_unref(EV_DEFAULT_UC);
ev_idle_init(&node::tick_spinner, node::Spin);

View File

@@ -25,7 +25,8 @@ namespace node {
#define NODE_DEFINE_CONSTANT(target, constant) \
(target)->Set(v8::String::NewSymbol(#constant), \
v8::Integer::New(constant))
v8::Integer::New(constant), \
static_cast<v8::PropertyAttribute>(v8::ReadOnly|v8::DontDelete))
#define NODE_SET_METHOD(obj, name, callback) \
obj->Set(v8::String::NewSymbol(name), \

View File

@@ -49,9 +49,20 @@ var nextTickQueue = [];
process._tickCallback = function () {
var l = nextTickQueue.length;
if (l === 0) return;
for (var i = 0; i < l; i++) {
nextTickQueue[i]();
try {
for (var i = 0; i < l; i++) {
nextTickQueue[i]();
}
}
catch(e) {
nextTickQueue.splice(0, i+1);
if (i+1 < l) {
process._needTickCallback();
}
throw e;
}
nextTickQueue.splice(0, l);
};
@@ -187,17 +198,6 @@ var module = (function () {
return;
}
/* if (dirs.length == 0) {
if (callback) {
callback();
} else {
return; // sync returns null
}
} //no need for this, eventually move simpler if to traverser
// question: what with /absolute/id when dirs.length is 0?
// if "load it anyway", then this ^^^ code is wrong, but omitting it
// makes it right*/
var nextLoc = traverser(id, id.charAt(0) === '/' ? [''] : dirs);
var fs = requireNative('fs');
@@ -433,6 +433,7 @@ var module = (function () {
sandbox.__filename = filename;
sandbox.__dirname = dirname;
sandbox.module = self;
sandbox.global = sandbox;
sandbox.root = root;
Script.runInNewContext(content, sandbox, filename);
@@ -533,8 +534,8 @@ var events = module.requireNative('events');
// Signal Handlers
(function() {
var signalWatchers = {};
addListener = process.addListener,
removeListener = process.removeListener;
var addListener = process.addListener;
var removeListener = process.removeListener;
function isSignal (event) {
return event.slice(0, 3) === 'SIG' && process.hasOwnProperty(event);
@@ -596,12 +597,13 @@ global.setTimeout = function (callback, after) {
global.setInterval = function (callback, repeat) {
var timer = new process.Timer();
addTimerListener.apply(timer, arguments);
timer.start(repeat, repeat);
timer.start(repeat, repeat ? repeat : 1);
return timer;
};
global.clearTimeout = function (timer) {
if (timer instanceof process.Timer) {
timer.callback = null;
timer.stop();
}
};
@@ -744,16 +746,22 @@ if (process.argv[0].indexOf('/') > 0) {
}
if (process.argv[1]) {
// Load module
if (process.argv[1].charAt(0) != "/" && !(/^http:\/\//).exec(process.argv[1])) {
process.argv[1] = path.join(cwd, process.argv[1]);
}
// REMOVEME: nextTick should not be necessary. This hack to get
// test/simple/test-exception-handler2.js working.
process.nextTick(function() {
module.runMain();
});
module.runMain();
} else if (process._eval) {
// -e, --eval
if (process._eval) console.log(eval(process._eval));
} else {
// No arguments, run the repl
var repl = module.requireNative('repl');
console.log("Type '.help' for options.");
repl.start();
// REPL
module.requireNative('repl').start();
}
// All our arguments are loaded. We've evaluated all of the scripts. We

View File

@@ -156,6 +156,16 @@ Buffer* Buffer::New(size_t size) {
Handle<Value> Buffer::New(const Arguments &args) {
HandleScope scope;
if (!args.IsConstructCall()) {
Local<Value> argv[10];
for (int i = 0; i < MIN(args.Length(), 10); i++) {
argv[i] = args[i];
}
Local<Object> instance =
constructor_template->GetFunction()->NewInstance(args.Length(), argv);
return scope.Close(instance);
}
Buffer *buffer;
if (args[0]->IsInt32()) {
// var buffer = new Buffer(1024);
@@ -701,6 +711,22 @@ Handle<Value> Buffer::ByteLength(const Arguments &args) {
}
Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
HandleScope scope;
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
Local<Object> fast_buffer = args[1]->ToObject();;
uint32_t offset = args[2]->Uint32Value();
uint32_t length = args[3]->Uint32Value();
fast_buffer->SetIndexedPropertiesToPixelData((uint8_t*)buffer->data() + offset,
length);
return Undefined();
}
void Buffer::Initialize(Handle<Object> target) {
HandleScope scope;
@@ -731,6 +757,9 @@ void Buffer::Initialize(Handle<Object> target) {
NODE_SET_METHOD(constructor_template->GetFunction(),
"byteLength",
Buffer::ByteLength);
NODE_SET_METHOD(constructor_template->GetFunction(),
"makeFastBuffer",
Buffer::MakeFastBuffer);
target->Set(String::NewSymbol("Buffer"), constructor_template->GetFunction());
}

View File

@@ -61,6 +61,7 @@ class Buffer : public ObjectWrap {
static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);
static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args);
static v8::Handle<v8::Value> MakeFastBuffer(const v8::Arguments &args);
static v8::Handle<v8::Value> Unpack(const v8::Arguments &args);
static v8::Handle<v8::Value> Copy(const v8::Arguments &args);

View File

@@ -13,7 +13,12 @@
#include <sys/wait.h>
#endif
# ifdef __APPLE__
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
# else
extern char **environ;
# endif
namespace node {
@@ -286,8 +291,7 @@ int ChildProcess::Spawn(const char *file,
close(stdin_pipe[0]);
stdio_fds[0] = stdin_pipe[1];
SetNonBlocking(stdin_pipe[1]);
}
else {
} else {
stdio_fds[0] = custom_fds[0];
}
@@ -295,8 +299,7 @@ int ChildProcess::Spawn(const char *file,
close(stdout_pipe[1]);
stdio_fds[1] = stdout_pipe[0];
SetNonBlocking(stdout_pipe[0]);
}
else {
} else {
stdio_fds[1] = custom_fds[1];
}
@@ -304,8 +307,7 @@ int ChildProcess::Spawn(const char *file,
close(stderr_pipe[1]);
stdio_fds[2] = stderr_pipe[0];
SetNonBlocking(stderr_pipe[0]);
}
else {
} else {
stdio_fds[2] = custom_fds[2];
}

View File

@@ -25,6 +25,7 @@ static Persistent<String> subject_symbol;
static Persistent<String> issuer_symbol;
static Persistent<String> valid_from_symbol;
static Persistent<String> valid_to_symbol;
static Persistent<String> fingerprint_symbol;
static Persistent<String> name_symbol;
static Persistent<String> version_symbol;
@@ -540,6 +541,28 @@ Handle<Value> SecureStream::GetPeerCertificate(const Arguments& args) {
BIO_free(bio);
info->Set(valid_to_symbol, String::New(buf));
unsigned int md_size, i;
unsigned char md[EVP_MAX_MD_SIZE];
if (X509_digest(peer_cert, EVP_sha1(), md, &md_size)) {
const char hex[] = "0123456789ABCDEF";
char fingerprint[EVP_MAX_MD_SIZE * 3];
for (i=0; i<md_size; i++) {
fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
fingerprint[(3*i)+2] = ':';
}
if (md_size > 0) {
fingerprint[(3*(md_size-1))+2] = '\0';
}
else {
fingerprint[0] = '\0';
}
info->Set(fingerprint_symbol, String::New(fingerprint));
}
X509_free(peer_cert);
}
return scope.Close(info);
@@ -2296,6 +2319,7 @@ void InitCrypto(Handle<Object> target) {
issuer_symbol = NODE_PSYMBOL("issuer");
valid_from_symbol = NODE_PSYMBOL("valid_from");
valid_to_symbol = NODE_PSYMBOL("valid_to");
fingerprint_symbol = NODE_PSYMBOL("fingerprint");
name_symbol = NODE_PSYMBOL("name");
version_symbol = NODE_PSYMBOL("version");
}

View File

@@ -12,38 +12,39 @@ class ObjectWrap {
refs_ = 0;
}
virtual ~ObjectWrap ( ) {
if (!handle_.IsEmpty()) {
assert(handle_.IsNearDeath());
handle_.ClearWeak();
handle_->SetInternalField(0, v8::Undefined());
handle_.Dispose();
handle_.Clear();
}
}
template <class T>
static inline T* Unwrap (v8::Handle<v8::Object> handle)
{
static inline T* Unwrap (v8::Handle<v8::Object> handle) {
assert(!handle.IsEmpty());
assert(handle->InternalFieldCount() > 0);
return static_cast<T*>(v8::Handle<v8::External>::Cast(
handle->GetInternalField(0))->Value());
return static_cast<T*>(handle->GetPointerFromInternalField(0));
}
v8::Persistent<v8::Object> handle_; // ro
protected:
inline void Wrap (v8::Handle<v8::Object> handle)
{
inline void Wrap (v8::Handle<v8::Object> handle) {
assert(handle_.IsEmpty());
assert(handle->InternalFieldCount() > 0);
handle_ = v8::Persistent<v8::Object>::New(handle);
handle_->SetInternalField(0, v8::External::New(this));
handle_->SetPointerInInternalField(0, this);
MakeWeak();
}
inline void MakeWeak (void)
{
inline void MakeWeak (void) {
handle_.MakeWeak(this, WeakCallback);
}
@@ -73,15 +74,17 @@ class ObjectWrap {
if (--refs_ == 0) { MakeWeak(); }
}
int refs_; // ro
private:
static void WeakCallback (v8::Persistent<v8::Value> value, void *data)
{
static void WeakCallback (v8::Persistent<v8::Value> value, void *data) {
ObjectWrap *obj = static_cast<ObjectWrap*>(data);
assert(value == obj->handle_);
assert(!obj->refs_);
if (value.IsNearDeath()) delete obj;
assert(value.IsNearDeath());
delete obj;
}
};

View File

@@ -212,6 +212,7 @@ template <node::Script::EvalInputFlags iFlag,
for (i = 0; i < keys->Length(); i++) {
Handle<String> key = keys->Get(Integer::New(i))->ToString();
Handle<Value> value = sandbox->Get(key);
if (value == sandbox) { value = context->Global(); }
context->Global()->Set(key, value);
}
}
@@ -264,6 +265,7 @@ template <node::Script::EvalInputFlags iFlag,
for (i = 0; i < keys->Length(); i++) {
Handle<String> key = keys->Get(Integer::New(i))->ToString();
Handle<Value> value = context->Global()->Get(key);
if (value == context->Global()) { value = sandbox; }
sandbox->Set(key, value);
}
}

View File

@@ -104,6 +104,18 @@ static Handle<Value> GetRows (const Arguments& args) {
return scope.Close(Integer::NewFromUnsigned(ws.ws_row));
}
static Handle<Value> IsATTY (const Arguments& args) {
HandleScope scope;
int fd = args[0]->IntegerValue();
int r = isatty(fd);
return scope.Close(r ? True() : False());
}
/* STDERR IS ALWAY SYNC ALWAYS UTF8 */
static Handle<Value>
WriteError (const Arguments& args)
@@ -219,6 +231,7 @@ void Stdio::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_METHOD(target, "setRawMode", SetRawMode);
NODE_SET_METHOD(target, "getColumns", GetColumns);
NODE_SET_METHOD(target, "getRows", GetRows);
NODE_SET_METHOD(target, "isatty", IsATTY);
struct sigaction sa = {0};
sa.sa_handler = HandleSIGCONT;

View File

@@ -6,7 +6,7 @@
#define NODE_MAJOR_VERSION 0
#define NODE_MINOR_VERSION 2
#define NODE_PATCH_VERSION 0
#define NODE_PATCH_VERSION 4
#ifndef NODE_STRINGIFY
#define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n)

View File

@@ -47,11 +47,26 @@ int OS::GetMemory(size_t *rss, size_t *vsize) {
int itmp;
char ctmp;
size_t page_size = getpagesize();
char *cbuf;
bool foundExeEnd;
/* PID */
if (fscanf(f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Exec file */
if (fscanf (f, "%s ", buf) == 0) goto error; /* coverity[secure_coding] */
cbuf = buf;
foundExeEnd = false;
if (fscanf (f, "%c", cbuf++) == 0) goto error; // (
while (1) {
if (fscanf(f, "%c", cbuf) == 0) goto error;
if (*cbuf == ')') {
foundExeEnd = true;
} else if (foundExeEnd && *cbuf == ' ') {
*cbuf = 0;
break;
}
cbuf++;
}
/* State */
if (fscanf (f, "%c ", &ctmp) == 0) goto error; /* coverity[secure_coding] */
/* Parent process */

View File

@@ -3,6 +3,7 @@ var path = require("path");
exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, "fixtures");
exports.libDir = path.join(exports.testDir, "../lib");
exports.tmpDir = path.join(exports.testDir, "tmp");
exports.PORT = 12346;
exports.assert = require('assert');

View File

@@ -12,7 +12,12 @@ var client = net.createConnection(443, "www.microsoft.com");
var caPem = fs.readFileSync(common.fixturesDir+"/msca.pem");
//var caPem = fs.readFileSync("ca.pem");
var credentials = crypto.createCredentials({ca:caPem});
try{
var credentials = crypto.createCredentials({ca:caPem});
} catch (e) {
console.log("Not compiled with OPENSSL support.");
process.exit();
}
client.setEncoding("UTF8");
client.addListener("connect", function () {

View File

@@ -9,7 +9,12 @@ var crypto=require('crypto');
var keyPem = fs.readFileSync(common.fixturesDir + "/cert.pem");
var certPem = fs.readFileSync(common.fixturesDir + "/cert.pem");
var credentials = crypto.createCredentials({key:keyPem, cert:certPem});
try{
var credentials = crypto.createCredentials({key:keyPem, cert:certPem});
} catch (e) {
console.log("Not compiled with OPENSSL support.");
process.exit();
}
var i = 0;
var server = net.createServer(function (connection) {
connection.setSecure(credentials);

View File

@@ -1,6 +1,4 @@
foo = "foo";
global.bar = "bar";
exports.fooBar = function () {
return {foo: global.foo, bar: bar};
};
exports.fooBar = {foo: global.foo, bar:bar};

View File

@@ -1,13 +0,0 @@
foo1 = "foo1";
global.bar1 = "bar1";
var sub2 = require('./sub2');
exports.subGlobalKeys = function () {
return sub2.globalKeys();
};
exports.subAllFooBars = function () {
return sub2.allFooBars();
};

View File

@@ -1,18 +0,0 @@
foo2 = "foo2";
global.bar2 = "bar2";
exports.globalKeys = function () {
return Object.getOwnPropertyNames(global);
};
exports.allFooBars = function () {
return {
foo0: global.foo0,
bar0: bar0,
foo1: global.foo1,
bar1: bar1,
foo2: global.foo2,
bar2: bar2
};
};

1
test/fixtures/semicolon.js vendored Normal file
View File

@@ -0,0 +1 @@
;

View File

@@ -35,10 +35,10 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class SimpleTestCase(test.TestCase):
class InternetTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config):
super(SimpleTestCase, self).__init__(context, path)
super(InternetTestCase, self).__init__(context, path)
self.file = file
self.config = config
self.mode = mode
@@ -68,10 +68,10 @@ class SimpleTestCase(test.TestCase):
return open(self.file).read()
class SimpleTestConfiguration(test.TestConfiguration):
class InternetTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(SimpleTestConfiguration, self).__init__(context, root)
super(InternetTestConfiguration, self).__init__(context, root)
def Ls(self, path):
def SelectTest(name):
@@ -91,7 +91,7 @@ class SimpleTestConfiguration(test.TestConfiguration):
for test in all_tests:
if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(SimpleTestCase(test, file_path, mode, self.context, self))
result.append(InternetTestCase(test, file_path, mode, self.context, self))
return result
def GetBuildRequirements(self):
@@ -105,4 +105,4 @@ class SimpleTestConfiguration(test.TestConfiguration):
def GetConfiguration(context, root):
return SimpleTestConfiguration(context, root)
return InternetTestConfiguration(context, root)

View File

@@ -35,7 +35,7 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
class MessageTestCase(test.TestCase):
def __init__(self, path, file, expected, mode, context, config):
super(MessageTestCase, self).__init__(context, path)
super(MessageTestCase, self).__init__(context, path, mode)
self.file = file
self.expected = expected
self.config = config
@@ -105,10 +105,7 @@ class MessageTestConfiguration(test.TestConfiguration):
return []
def ListTests(self, current_path, path, mode):
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
#regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
#bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
all_tests = mjsunit #+ regress + bugs
all_tests = [current_path + [t] for t in self.Ls(self.root)]
result = []
for test in all_tests:
if self.Contains(path, test):

View File

@@ -1,9 +1,8 @@
before
*.js:*
*cript.runIn*Context(*);
*^
node.js:*
throw e;
^
ReferenceError: foo is not defined
at evalmachine.<anonymous>:*
at *test/message/undefined_reference_in_new_context.js:*
@@ -11,4 +10,6 @@ ReferenceError: foo is not defined
at Module._loadScriptSync (node.js:*)
at Module.loadSync (node.js:*)
at Object.runMain (node.js:*)
at Array.<anonymous> (node.js:*)
at EventEmitter._tickCallback (node.js:*)
at node.js:*

View File

@@ -74,7 +74,14 @@ setInterval(function(param1, param2){
clearInterval(this);
}, 1000, "param1", "param2");
// setInterval(cb, 0) should be called multiple times.
count4 = 0;
interval4 = setInterval(function () {
if (++count4 > 10) clearInterval(interval4);
}, 0);
process.addListener("exit", function () {
assert.equal(true, setTimeout_called);
assert.equal(3, interval_count);
assert.equal(11, count4);
});

View File

@@ -27,6 +27,10 @@
import test
import os
import shutil
from shutil import rmtree
from os import mkdir
from glob import glob
from os.path import join, dirname, exists
import re
@@ -35,14 +39,33 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class SimpleTestCase(test.TestCase):
class PummelTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config):
super(SimpleTestCase, self).__init__(context, path)
super(PummelTestCase, self).__init__(context, path, mode)
self.file = file
self.config = config
self.mode = mode
self.tmpdir = join(dirname(self.config.root), 'tmp')
def AfterRun(self, result):
# delete the whole tmp dir
try:
rmtree(self.tmpdir)
except:
pass
# make it again.
mkdir(self.tmpdir)
def BeforeRun(self):
# delete the whole tmp dir
try:
rmtree(self.tmpdir)
except:
pass
# make it again.
mkdir(self.tmpdir)
def GetLabel(self):
return "%s %s" % (self.mode, self.GetName())
@@ -68,10 +91,10 @@ class SimpleTestCase(test.TestCase):
return open(self.file).read()
class SimpleTestConfiguration(test.TestConfiguration):
class PummelTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(SimpleTestConfiguration, self).__init__(context, root)
super(PummelTestConfiguration, self).__init__(context, root)
def Ls(self, path):
def SelectTest(name):
@@ -79,19 +102,12 @@ class SimpleTestConfiguration(test.TestConfiguration):
return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def ListTests(self, current_path, path, mode):
simple = [current_path + [t] for t in self.Ls(self.root)]
#simple = [current_path + ['simple', t] for t in self.Ls(join(self.root, 'simple'))]
#pummel = [current_path + ['pummel', t] for t in self.Ls(join(self.root, 'pummel'))]
#internet = [current_path + ['internet', t] for t in self.Ls(join(self.root, 'internet'))]
#regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
#bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
#tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))]
all_tests = simple # + regress + bugs + tools
all_tests = [current_path + [t] for t in self.Ls(join(self.root))]
result = []
for test in all_tests:
if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(SimpleTestCase(test, file_path, mode, self.context, self))
result.append(PummelTestCase(test, file_path, mode, self.context, self))
return result
def GetBuildRequirements(self):
@@ -105,4 +121,4 @@ class SimpleTestConfiguration(test.TestConfiguration):
def GetConfiguration(context, root):
return SimpleTestConfiguration(context, root)
return PummelTestConfiguration(context, root)

View File

@@ -4,7 +4,7 @@ assert = require("assert");
var Buffer = require('buffer').Buffer;
var b = new Buffer(1024);
var b = Buffer(1024); // safe constructor
console.log("b.length == " + b.length);
assert.strictEqual(1024, b.length);

View File

@@ -0,0 +1,17 @@
common = require("../common");
assert = common.assert;
var stdout_write = global.process.stdout.write;
var strings = [];
global.process.stdout.write = function(string) {
strings.push(string);
};
console.log('foo');
console.log('foo', 'bar');
console.log('%s %s', 'foo', 'bar', 'hop');
global.process.stdout.write = stdout_write;
assert.equal('foo\n', strings.shift());
assert.equal('foo bar\n', strings.shift());
assert.equal('foo bar hop\n', strings.shift());

View File

@@ -17,7 +17,12 @@ var caPem = fs.readFileSync(common.fixturesDir+"/test_ca.pem", 'ascii');
var certPem = fs.readFileSync(common.fixturesDir+"/test_cert.pem", 'ascii');
var keyPem = fs.readFileSync(common.fixturesDir+"/test_key.pem", 'ascii');
var credentials = crypto.createCredentials({key:keyPem, cert:certPem, ca:caPem});
try{
var credentials = crypto.createCredentials({key:keyPem, cert:certPem, ca:caPem});
} catch (e) {
console.log("Not compiled with OPENSSL support.");
process.exit();
}
// Test HMAC
//var h1 = (new crypto.Hmac).init("sha1", "Node").update("some data").update("to hmac").digest("hex");

View File

@@ -1,56 +1,48 @@
common = require("../common");
assert = common.assert
var Buffer = require("buffer").Buffer,
fs = require("fs"),
dgram = require("dgram"), server, client,
server_path = "/tmp/dgram_server_sock",
client_path = "/tmp/dgram_client_sock",
message_to_send = new Buffer("A message to send"),
timer;
fs = require("fs");
dgram = require("dgram");
serverPath = "/tmp/dgram_server_sock";
clientPath = "/tmp/dgram_client_sock";
msgToSend = new Buffer("A message to send");
server = dgram.createSocket("unix_dgram");
server.on("message", function (msg, rinfo) {
console.log("server got: " + msg + " from " + rinfo.address);
assert.strictEqual(rinfo.address, client_path);
assert.strictEqual(msg.toString(), message_to_send.toString());
assert.strictEqual(rinfo.address, clientPath);
assert.strictEqual(msg.toString(), msgToSend.toString());
server.send(msg, 0, msg.length, rinfo.address);
});
server.on("listening", function () {
console.log("server is listening");
client = dgram.createSocket("unix_dgram");
client.on("message", function (msg, rinfo) {
console.log("client got: " + msg + " from " + rinfo.address);
assert.strictEqual(rinfo.address, server_path);
assert.strictEqual(msg.toString(), message_to_send.toString());
assert.strictEqual(rinfo.address, serverPath);
assert.strictEqual(msg.toString(), msgToSend.toString());
client.close();
server.close();
});
client.on("listening", function () {
console.log("client is listening");
client.send(message_to_send, 0, message_to_send.length, server_path, function (err, bytes) {
client.send(msgToSend, 0, msgToSend.length, serverPath, function (err, bytes) {
if (err) {
console.log("Caught error in client send.");
throw err;
}
console.log("client wrote " + bytes + " bytes.");
assert.strictEqual(bytes, message_to_send.length);
assert.strictEqual(bytes, msgToSend.length);
});
});
client.on("close", function () {
if (server.fd === null) {
clearTimeout(timer);
}
});
client.bind(client_path);
});
server.on("close", function () {
if (client.fd === null) {
clearTimeout(timer);
}
});
server.bind(server_path);
timer = setTimeout(function () {
throw new Error("Timeout");
}, 200);
client.bind(clientPath);
});
server.bind(serverPath);

View File

@@ -0,0 +1,21 @@
common = require("../common");
assert = common.assert
process.on('uncaughtException', function (err) {
console.log('Caught exception: ' + err);
});
var timeoutFired = false;
setTimeout(function () {
console.log('This will still run.');
timeoutFired = true;
}, 500);
process.on('exit', function() {
assert.ok(timeoutFired);
});
// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');

View File

@@ -35,16 +35,53 @@ exec("ls /DOES_NOT_EXIST", function (err, stdout, stderr) {
}
});
exec("sleep 10", { timeout: 50 }, function (err, stdout, stderr) {
var sleeperStart = new Date();
exec("sleep 3", { timeout: 50 }, function (err, stdout, stderr) {
var diff = (new Date()) - sleeperStart;
console.log("sleep 3 with timeout 50 took %d ms", diff);
assert.ok(diff < 500);
assert.ok(err);
assert.ok(err.killed);
assert.equal(err.signal, 'SIGKILL');
assert.equal(err.signal, 'SIGTERM');
});
var startSleep3 = new Date();
var killMeTwice = exec("sleep 3", { timeout: 1000 }, killMeTwiceCallback);
process.nextTick(function(){
console.log("kill pid %d", killMeTwice.pid);
// make sure there is no race condition in starting the process
// the PID SHOULD exist directly following the exec() call.
assert.equal('number', typeof killMeTwice._internal.pid);
// Kill the process
killMeTwice.kill();
});
function killMeTwiceCallback(err, stdout, stderr) {
var diff = (new Date()) - startSleep3;
// We should have already killed this process. Assert that
// the timeout still works and that we are getting the proper callback
// parameters.
assert.ok(err);
assert.ok(err.killed);
assert.equal(err.signal, 'SIGTERM');
// the timeout should still be in effect
console.log("'sleep 3' was already killed. Took %d ms", diff);
assert.ok(diff < 1500);
}
exec('python -c "print 200000*\'C\'"', { maxBuffer: 1000 }, function (err, stdout, stderr) {
assert.ok(err);
assert.ok(err.killed);
assert.equal(err.signal, 'SIGKILL');
assert.equal(err.signal, 'SIGTERM');
});
process.addListener("exit", function () {

View File

@@ -4,7 +4,7 @@ assert = common.assert
var
path = require('path'),
fs = require('fs'),
fn = path.join(common.fixturesDir, "write.txt"),
fn = path.join(common.tmpDir, "write.txt"),
file = fs.createWriteStream(fn),
EXPECTED = '012345678910',

View File

@@ -15,7 +15,7 @@ callbacks = { open: 0, end: 0, close: 0, destroy: 0 };
paused = false;
file = fs.createReadStream(fn);
file = fs.ReadStream(fn);
file.addListener('open', function(fd) {
file.length = 0;
@@ -60,9 +60,8 @@ file2.destroy(function(err) {
callbacks.destroy++;
});
var file3 = fs.createReadStream(fn);
var file3 = fs.createReadStream(fn, {encoding: 'utf8'});
file3.length = 0;
file3.setEncoding('utf8');
file3.addListener('data', function(data) {
assert.equal("string", typeof(data));
file3.length += data.length;
@@ -96,3 +95,28 @@ file4.addListener('data', function(data) {
file4.addListener('end', function(data) {
assert.equal(contentRead, 'yz');
});
try {
fs.createReadStream(rangeFile, {start: 10, end: 2});
assert.fail('Creating a ReadStream with incorrect range limits must throw.');
} catch(e) {
assert.equal(e.message, 'start must be <= end');
}
try {
fs.createReadStream(rangeFile, {start: 2});
assert.fail('Creating a ReadStream with a only one range limits must throw.');
} catch(e) {
assert.equal(e.message, 'Both start and end are needed for range streaming.');
}
var stream = fs.createReadStream(rangeFile, { start: 0, end: 0 });
stream.data = '';
stream.on('data', function(chunk){
stream.data += chunk;
});
stream.on('end', function(){
assert.equal('x', stream.data);
});

View File

@@ -9,3 +9,7 @@ var
fs.readFile(fn, function(err, data) {
assert.ok(data);
});
fs.readFile(fn, 'utf8', function(err, data) {
assert.strictEqual('', data);
});

View File

@@ -2,16 +2,16 @@ common = require("../common");
assert = common.assert
var fs = require('fs');
var path = require('path');
var exec = require('child_process').exec;
var async_completed = 0, async_expected = 0, unlink = [];
function asynctest(testBlock, args, callback, assertBlock) {
async_expected++;
testBlock.apply(testBlock, args.concat([function(err){
testBlock.apply(testBlock, args.concat(function(err){
var ignoreError = false;
if (assertBlock) {
try {
ignoreError = assertBlock.apply(assertBlock,
Array.prototype.slice.call(arguments));
ignoreError = assertBlock.apply(assertBlock, arguments);
}
catch (e) {
err = e;
@@ -19,11 +19,11 @@ function asynctest(testBlock, args, callback, assertBlock) {
}
async_completed++;
callback(ignoreError ? null : err);
}]));
}));
}
function bashRealpath(path, callback) {
common.exec("cd '"+path.replace("'","\\'")+"' && pwd -P",function
exec("cd '"+path.replace("'","\\'")+"' && pwd -P",function
(err, o) {
callback(err, o.trim());
});
@@ -227,6 +227,69 @@ function test_non_symlinks(callback) {
});
}
var upone = path.join(process.cwd(), "..");
function test_escape_cwd (cb) {
asynctest(fs.realpath, [".."], cb, function(er, uponeActual){
assert.equal(upone, uponeActual,
"realpath('..') expected: "+upone+" actual:"+uponeActual);
})
}
var uponeActual = fs.realpathSync("..");
assert.equal(upone, uponeActual,
"realpathSync('..') expected: "+upone+" actual:"+uponeActual);
// absolute symlinks with children.
// .
// `-- a/
// |-- b/
// | `-- c/
// | `-- x.txt
// `-- link -> /tmp/node-test-realpath-abs-kids/a/b/
// realpath(root+'/a/link/c/x.txt') ==> root+'/a/b/c/x.txt'
function test_abs_with_kids (cb) {
bashRealpath(common.fixturesDir, function(err, fixturesAbsDir) {
var root = fixturesAbsDir+'/node-test-realpath-abs-kids';
function cleanup () {
;['/a/b/c/x.txt'
, '/a/link'
].forEach(function (file) {
try {fs.unlinkSync(root+file)} catch (ex) {}
});
;['/a/b/c'
, '/a/b'
, '/a'
, ''
].forEach(function (folder) {
try {fs.rmdirSync(root+folder)} catch (ex) {}
});
}
function setup () {
cleanup()
;[''
, '/a'
, '/a/b'
, '/a/b/c'
].forEach(function (folder) {
console.log("mkdir "+root+folder)
fs.mkdirSync(root+folder, 0700);
});
fs.writeFileSync(root+'/a/b/c/x.txt', 'foo');
fs.symlinkSync(root+'/a/b', root+'/a/link');
}
setup();
var linkPath = root+'/a/link/c/x.txt';
var expectPath = root+'/a/b/c/x.txt';
var actual = fs.realpathSync(linkPath);
// console.log({link:linkPath,expect:expectPath,actual:actual},'sync');
assert.equal(actual, expectPath);
asynctest(fs.realpath, [linkPath], cb, function (er, actual) {
// console.log({link:linkPath,expect:expectPath,actual:actual},'async');
assert.equal(actual, expectPath);
cleanup();
});
})
}
// ----------------------------------------------------------------------------
var tests = [
@@ -238,6 +301,8 @@ var tests = [
test_relative_input_cwd,
test_deep_symlink_mix,
test_non_symlinks,
test_escape_cwd,
test_abs_with_kids
];
var numtests = tests.length;
function runNextTest(err) {
@@ -248,6 +313,15 @@ function runNextTest(err) {
}
runNextTest();
assert.equal('/', fs.realpathSync('/'));
fs.realpath('/', function (err, result) {
assert.equal(null, err);
assert.equal('/', result);
});
process.addListener("exit", function () {
unlink.forEach(function(path){ try {fs.unlinkSync(path);}catch(e){} });
assert.equal(async_completed, async_expected);

View File

@@ -1,13 +1,12 @@
common = require("../common");
assert = common.assert
var assert = common.assert;
var path = require('path');
var fs = require('fs');
var completed = 0;
// test creating and reading symbolic link
var linkData = "../../cycles/root.js";
var linkPath = path.join(common.fixturesDir, "nested-index", 'one', 'symlink1.js');
try {fs.unlinkSync(linkPath);}catch(e){}
var linkData = path.join(common.fixturesDir, "/cycles/root.js");
var linkPath = path.join(common.tmpDir, 'symlink1.js');
fs.symlink(linkData, linkPath, function(err){
if (err) throw err;
console.log('symlink done');
@@ -21,8 +20,7 @@ fs.symlink(linkData, linkPath, function(err){
// test creating and reading hard link
var srcPath = path.join(common.fixturesDir, "cycles", 'root.js');
var dstPath = path.join(common.fixturesDir, "nested-index", 'one', 'link1.js');
try {fs.unlinkSync(dstPath);}catch(e){}
var dstPath = path.join(common.tmpDir, 'link1.js');
fs.link(srcPath, dstPath, function(err){
if (err) throw err;
console.log('hard link done');
@@ -33,8 +31,6 @@ fs.link(srcPath, dstPath, function(err){
});
process.addListener("exit", function () {
try {fs.unlinkSync(linkPath);}catch(e){}
try {fs.unlinkSync(dstPath);}catch(e){}
assert.equal(completed, 2);
});

View File

@@ -3,7 +3,7 @@ assert = common.assert
var path = require('path'),
Buffer = require('buffer').Buffer,
fs = require('fs'),
filename = path.join(common.fixturesDir, 'write.txt'),
filename = path.join(common.tmpDir, 'write.txt'),
expected = new Buffer('hello'),
openCalled = 0,
writeCalled = 0;

View File

@@ -0,0 +1,28 @@
common = require("../common");
assert = common.assert
var path = require('path'),
fs = require('fs');
var file = path.join(common.tmpDir, "write.txt");
(function() {
var stream = fs.WriteStream(file),
_fs_close = fs.close;
fs.close = function(fd) {
assert.ok(fd, "fs.close must not be called without an undefined fd.")
fs.close = _fs_close;
}
stream.destroy();
})();
(function() {
var stream = fs.createWriteStream(file);
stream.addListener('drain', function () {
assert.fail('"drain" event must not be emitted before stream.write() has been called at least once.')
});
stream.destroy();
})();

View File

@@ -3,7 +3,7 @@ assert = common.assert
path = require('path'),
Buffer = require('buffer').Buffer
fs = require('fs')
fn = path.join(common.fixturesDir, 'write.txt');
fn = path.join(common.tmpDir, 'write.txt');
foo = 'foo'

View File

@@ -3,7 +3,7 @@ assert = common.assert
var path = require('path');
var Buffer = require('buffer').Buffer;
var fs = require('fs');
var fn = path.join(common.fixturesDir, "write.txt");
var fn = path.join(common.tmpDir, "write.txt");
var expected = "ümlaut.";
var found;
@@ -11,7 +11,7 @@ fs.open(fn, 'w', 0644, function (err, fd) {
if (err) throw err;
console.log('open done');
fs.write(fd, '', 0, 'utf8', function(err, written) {
assert.fail('zero length write should not go through to callback');
assert.equal(0, written);
});
fs.write(fd, expected, 0, "utf8", function (err, written) {
console.log('write done');

View File

@@ -1,21 +0,0 @@
common = require("../common");
assert = common.assert
foo0 = "foo0";
global.bar0 = "bar0";
var module = require("../fixtures/global/sub1"),
keys = module.subGlobalKeys();
var fooBarKeys = keys.filter(
function (x) { return x.match(/^foo/) || x.match(/^bar/); }
);
fooBarKeys.sort();
assert.equal("bar0,bar1,bar2,foo0,foo1,foo2", fooBarKeys.join(), "global keys not as expected: "+JSON.stringify(keys));
var fooBars = module.subAllFooBars();
assert.equal("foo0", fooBars.foo0, "x from base level not visible in deeper levels.");
assert.equal("bar0", fooBars.bar0, "global.x from base level not visible in deeper levels.");
assert.equal("foo1", fooBars.foo1, "x from medium level not visible in deeper levels.");
assert.equal("bar1", fooBars.bar1, "global.x from medium level not visible in deeper levels.");

View File

@@ -0,0 +1,32 @@
var assert = require('assert');
var knownGlobals = [ setTimeout
, setInterval
, clearTimeout
, clearInterval
, console
, Buffer
, process
, global
, __module
, include
, puts
, print
, p
];
for (var x in global) {
var found = false;
for (var y in knownGlobals) {
if (global[x] === knownGlobals[y]) {
found = true;
break;
}
}
if (!found) {
console.error("Unknown global: %s", x);
assert.ok(false);
}
}

View File

@@ -9,7 +9,7 @@ assert.equal("foo", global.baseFoo, "x -> global.x in base level not working");
assert.equal("bar", baseBar, "global.x -> x in base level not working");
var module = require("../fixtures/global/plain"),
fooBar = module.fooBar();
fooBar = module.fooBar;
assert.equal("foo", fooBar.foo, "x -> global.x in sub level not working");

View File

@@ -0,0 +1,35 @@
var common = require("../common");
var assert = require('assert');
var http = require('http');
var net = require('net');
// Create a TCP server
var srv = net.createServer(function(c) {
c.write('bad http - should trigger parse error\r\n');
console.log("connection");
c.addListener('end', function() { c.end(); });
});
var parseError = false;
srv.listen(common.PORT, '127.0.0.1', function () {
var hc = http.createClient(common.PORT, '127.0.0.1');
hc.request('GET', '/').end();
hc.on('error', function (e) {
console.log("got error from client");
srv.close();
assert.ok(e.message.indexOf("Parse Error") >= 0);
parseError = true;
});
});
process.addListener('exit', function() {
assert.ok(parseError);
});

View File

@@ -0,0 +1,49 @@
common = require("../common");
assert = common.assert
assert = require("assert");
http = require("http");
sys = require("sys");
body = "hello world\n";
headers = {'connection':'keep-alive'}
server = http.createServer(function (req, res) {
res.writeHead(200, {"Content-Length": body.length, "Connection":"close"});
res.write(body);
res.end();
});
connectCount = 0;
server.listen(common.PORT, function () {
var client = http.createClient(common.PORT);
client.addListener("connect", function () {
common.error("CONNECTED")
connectCount++;
})
var request = client.request("GET", "/", headers);
request.end();
request.addListener('response', function (response) {
common.error('response start');
response.addListener("end", function () {
common.error('response end');
var req = client.request("GET", "/", headers);
req.addListener('response', function (response) {
response.addListener("end", function () {
client.end();
server.close();
})
})
req.end();
});
});
});
process.addListener('exit', function () {
assert.equal(2, connectCount);
});

View File

@@ -15,7 +15,7 @@ var buffer = new Buffer(1024);
var request = "GET /hello HTTP/1.1\r\n\r\n";
buffer.asciiWrite(request, 0, request.length);
buffer.write(request, 0, 'ascii');
var callbacks = 0;
@@ -39,7 +39,7 @@ parser.onURL = function (b, off, len) {
parser.onPath = function (b, off, length) {
console.log("path [" + off + ", " + length + "]");
var path = b.asciiSlice(off, off+length);
var path = b.toString('ascii', off, off+length);
console.log("path = '" + path + "'");
assert.equal('/hello', path);
callbacks++;

View File

@@ -27,7 +27,13 @@ var caPem = fs.readFileSync(common.fixturesDir+"/test_ca.pem", 'ascii');
var certPem = fs.readFileSync(common.fixturesDir+"/test_cert.pem", 'ascii');
var keyPem = fs.readFileSync(common.fixturesDir+"/test_key.pem", 'ascii');
var credentials = crypto.createCredentials({key:keyPem, cert:certPem, ca:caPem});
try{
var credentials = crypto.createCredentials({key:keyPem, cert:certPem, ca:caPem});
} catch (e) {
console.log("Not compiled with OPENSSL support.");
process.exit();
}
var https_server = http.createServer(function (req, res) {
res.id = request_number;
@@ -41,7 +47,8 @@ var https_server = http.createServer(function (req, res) {
+ '"issuer":"/C=UK/ST=Acknack Ltd/L=Rhys Jones/O=node.js'
+ '/OU=Test TLS Certificate/CN=localhost","valid_from":'
+ '"Nov 11 09:52:22 2009 GMT","valid_to":'
+ '"Nov 6 09:52:22 2029 GMT"}');
+ '"Nov 6 09:52:22 2029 GMT",'
+ '"fingerprint":"2A:7A:C2:DD:E5:F9:CC:53:72:35:99:7A:02:5A:71:38:52:EC:8A:DF"}');
if (req.id == 0) {
assert.equal("GET", req.method);
@@ -92,7 +99,8 @@ https_server.addListener("listening", function() {
+ '"issuer":"/C=UK/ST=Acknack Ltd/L=Rhys Jones/O=node.js'
+ '/OU=Test TLS Certificate/CN=localhost","valid_from":'
+ '"Nov 11 09:52:22 2009 GMT","valid_to":'
+ '"Nov 6 09:52:22 2029 GMT"}');
+ '"Nov 6 09:52:22 2029 GMT",'
+ '"fingerprint":"2A:7A:C2:DD:E5:F9:CC:53:72:35:99:7A:02:5A:71:38:52:EC:8A:DF"}');
c.write( "GET /hello?hello=world&foo=b==ar HTTP/1.1\r\n\r\n" );
requests_sent += 1;
});

View File

@@ -8,69 +8,49 @@ assert = common.assert
var http = require('http');
var net = require('net');
// Parse a string of data, returning an object if headers are complete, and
// undefined otherwise
var parseHeaders = function(data) {
var m = data.search(/\r\n\r\n/);
if (!m) {
return;
}
var o = {};
data.substring(0, m.index).split('\r\n').forEach(function(h) {
var foo = h.split(':');
if (foo.length < 2) {
return;
}
o[foo[0].trim().toLowerCase()] = foo[1].trim().toLowerCase();
});
return o;
};
// Create a TCP server
var srv = net.createServer(function(c) {
var data = '';
c.addListener('data', function(d) {
data += d.toString('utf8');
// We found the end of the headers; make sure that we have an 'upgrade'
// header and send back a response
var headers = parseHeaders(data);
if (!headers) {
return;
}
assert.ok('upgrade' in headers);
c.write('HTTP/1.1 101\r\n');
c.write('hello: world\r\n');
c.write('connection: upgrade\r\n');
c.write('upgrade: ' + headers.upgrade + '\r\n');
c.write('upgrade: websocket\r\n');
c.write('\r\n');
c.write('nurtzo');
});
c.addListener('end', function() {
c.end();
});
});
srv.listen(common.PORT, '127.0.0.1');
var gotUpgrade = false;
var hc = http.createClient(common.PORT, '127.0.0.1');
hc.addListener('upgrade', function(req, socket, upgradeHead) {
// XXX: This test isn't fantastic, as it assumes that the entire response
// from the server will arrive in a single data callback
assert.equal(upgradeHead, 'nurtzo');
socket.end();
srv.close();
srv.listen(common.PORT, '127.0.0.1', function () {
gotUpgrade = true;
var hc = http.createClient(common.PORT, '127.0.0.1');
hc.addListener('upgrade', function(res, socket, upgradeHead) {
// XXX: This test isn't fantastic, as it assumes that the entire response
// from the server will arrive in a single data callback
assert.equal(upgradeHead, 'nurtzo');
console.log(res.headers);
var expectedHeaders = { "hello": "world"
, "connection": "upgrade"
, "upgrade": "websocket"
};
assert.deepEqual(expectedHeaders, res.headers);
socket.end();
srv.close();
gotUpgrade = true;
});
hc.request('GET', '/').end();
});
hc.request('/', {
'Connection' : 'Upgrade',
'Upgrade' : 'WebSocket'
}).end();
process.addListener('exit', function() {
assert.ok(gotUpgrade);

View File

@@ -0,0 +1,68 @@
var common = require("../common");
var assert = common.assert
var http = require('http'),
CRLF = '\r\n';
var server = http.createServer();
server.on('upgrade', function(req, socket, head) {
socket.write('HTTP/1.1 101 Ok' + CRLF +
'Connection: Upgrade' + CRLF +
'Upgrade: Test' + CRLF + CRLF + 'head');
socket.on('end', function () {
socket.end();
});
});
server.listen(common.PORT, function () {
var client = http.createClient(common.PORT);
function upgradeRequest(fn) {
var request = client.request('GET', '/', {
'Connection': 'Upgrade',
'Upgrade': 'Test'
});
var wasUpgrade = false;
function onUpgrade(res, socket, head) {
wasUpgrade = true;
client.removeListener('upgrade', onUpgrade);
socket.end();
}
client.on('upgrade', onUpgrade);
function onEnd() {
client.removeListener('end', onEnd);
if (!wasUpgrade) {
throw new Error('hasn\'t received upgrade event');
} else {
fn && process.nextTick(fn);
}
}
client.on('end', onEnd);
request.write('head');
}
successCount = 0;
upgradeRequest(function() {
successCount++;
upgradeRequest(function() {
successCount++;
// Test pass
console.log('Pass!');
client.end();
client.destroy();
server.close();
});
});
});
process.on('exit', function () {
assert.equal(2, successCount);
});

View File

@@ -12,7 +12,7 @@ var responses_recvd = 0;
var body0 = "";
var body1 = "";
var server = http.createServer(function (req, res) {
var server = http.Server(function (req, res) {
if (responses_sent == 0) {
assert.equal("GET", req.method);
assert.equal("/hello", url.parse(req.url).pathname);

View File

@@ -4,8 +4,7 @@ var path = require('path');
var fs = require('fs');
var dirname = path.dirname(__filename);
var fixtures = path.join(dirname, "../fixtures");
var d = path.join(fixtures, "dir");
var d = path.join(common.tmpDir, "dir");
var mkdir_error = false;
var rmdir_error = false;

View File

@@ -1,6 +1,6 @@
common = require("../common");
assert = common.assert
tcp = require("tcp");
net = require("net");
binaryString = "";
for (var i = 255; i >= 0; i--) {
@@ -19,7 +19,8 @@ for (var i = 255; i >= 0; i--) {
binaryString += S;
}
var echoServer = tcp.createServer(function (connection) {
// safe constructor
var echoServer = net.Server(function (connection) {
connection.setEncoding("binary");
connection.addListener("data", function (chunk) {
common.error("recved: " + JSON.stringify(chunk));
@@ -35,7 +36,7 @@ var recv = "";
echoServer.addListener("listening", function() {
var j = 0;
var c = tcp.createConnection(common.PORT);
var c = net.createConnection(common.PORT);
c.setEncoding("binary");
c.addListener("data", function (chunk) {

View File

@@ -0,0 +1,47 @@
var common = require('../common');
var assert = require('assert');
var net = require('net');
var tcpPort = common.PORT;
var tcp = net.Server(function (s) {
tcp.close();
console.log("tcp server connection");
var buf = "";
s.on('data', function (d) {
buf += d;
});
s.on('end', function () {
assert.equal("foobar", buf);
console.log("tcp socket disconnect");
s.end();
});
s.on('error', function (e) {
console.log("tcp server-side error: " + e.message);
process.exit(1);
});
});
tcp.listen(tcpPort, startClient);
function startClient () {
var socket = net.Stream();
console.log("Connecting to socket");
socket.connect(tcpPort);
socket.on('connect', function () {
console.log('socket connected');
});
assert.equal("opening", socket.readyState);
assert.equal(false, socket.write("foo"));
socket.end("bar");
assert.equal("opening", socket.readyState);
}

View File

@@ -18,7 +18,12 @@ var caPem = fs.readFileSync(common.fixturesDir+"/test_ca.pem", 'ascii');
var certPem = fs.readFileSync(common.fixturesDir+"/test_cert.pem", 'ascii');
var keyPem = fs.readFileSync(common.fixturesDir+"/test_key.pem", 'ascii');
var credentials = crypto.createCredentials({key:keyPem, cert:certPem, ca:caPem});
try{
var credentials = crypto.createCredentials({key:keyPem, cert:certPem, ca:caPem});
} catch (e) {
console.log("Not compiled with OPENSSL support.");
process.exit();
}
var testData = "TEST123";
var serverData = '';
@@ -41,7 +46,8 @@ var secureServer = net.createServer(function (connection) {
+ '"issuer":"/C=UK/ST=Acknack Ltd/L=Rhys Jones/O=node.js'
+ '/OU=Test TLS Certificate/CN=localhost","valid_from":'
+ '"Nov 11 09:52:22 2009 GMT","valid_to":'
+ '"Nov 6 09:52:22 2029 GMT"}');
+ '"Nov 6 09:52:22 2029 GMT",'
+ '"fingerprint":"2A:7A:C2:DD:E5:F9:CC:53:72:35:99:7A:02:5A:71:38:52:EC:8A:DF"}');
});
@@ -76,7 +82,8 @@ secureServer.addListener("listening", function() {
+ '"issuer":"/C=UK/ST=Acknack Ltd/L=Rhys Jones/O=node.js'
+ '/OU=Test TLS Certificate/CN=localhost","valid_from":'
+ '"Nov 11 09:52:22 2009 GMT","valid_to":'
+ '"Nov 6 09:52:22 2029 GMT"}');
+ '"Nov 6 09:52:22 2029 GMT",'
+ '"fingerprint":"2A:7A:C2:DD:E5:F9:CC:53:72:35:99:7A:02:5A:71:38:52:EC:8A:DF"}');
secureClient.write(testData);
secureClient.end();
@@ -94,4 +101,4 @@ secureServer.addListener("listening", function() {
process.addListener("exit", function () {
assert.ok(gotSecureServer, "Did not get secure event for server");
assert.ok(gotSecureClient, "Did not get secure event for clientr");
});
});

View File

@@ -0,0 +1,36 @@
common = require("../common");
assert = common.assert
var order = [],
exceptionHandled = false;
// This nextTick function will throw an error. It should only be called once.
// When it throws an error, it should still get removed from the queue.
process.nextTick(function() {
order.push('A');
// cause an error
what();
});
// This nextTick function should remain in the queue when the first one
// is removed. It should be called if the error in the first one is
// caught (which we do in this test).
process.nextTick(function() {
order.push('C');
});
process.addListener('uncaughtException', function() {
if (!exceptionHandled) {
exceptionHandled = true;
order.push('B');
}
else {
// If we get here then the first process.nextTick got called twice
order.push('OOPS!');
}
});
process.addListener('exit', function() {
assert.deepEqual(['A','B','C'], order);
});

View File

@@ -0,0 +1,17 @@
common = require("../common");
assert = common.assert
var order = [];
process.nextTick(function () {
setTimeout(function() {
order.push('setTimeout');
}, 0);
process.nextTick(function() {
order.push('nextTick');
});
})
process.addListener('exit', function () {
assert.deepEqual(order, ['nextTick', 'setTimeout']);
});

View File

@@ -0,0 +1,52 @@
common = require("../common");
assert = common.assert
net = require("net");
fs = require("fs");
sys = require("sys");
path = require("path");
fn = path.join(common.fixturesDir, 'does_not_exist.txt');
var got_error = false;
var conn_closed = false;
server = net.createServer(function (stream) {
common.error('pump!');
sys.pump(fs.createReadStream(fn), stream, function (err) {
common.error("sys.pump's callback fired");
if (err) {
got_error = true;
} else {
common.debug("sys.pump's callback fired with no error");
common.debug("this shouldn't happen as the file doesn't exist...");
assert.equal(true, false);
}
server.close();
});
});
server.listen(common.PORT, function () {
conn = net.createConnection(common.PORT);
conn.setEncoding('utf8');
conn.addListener("data", function (chunk) {
common.error('recv data! nchars = ' + chunk.length);
buffer += chunk;
});
conn.addListener("end", function () {
conn.end();
});
conn.addListener("close", function () {
common.error('client connection close');
conn_closed = true;
});
});
var buffer = '';
count = 0;
process.addListener('exit', function () {
assert.equal(true, got_error);
assert.equal(true, conn_closed);
console.log("exiting");
});

View File

@@ -0,0 +1,108 @@
common = require("../common");
assert = common.assert;
var readline = require("readline");
var key = {
xterm: {
home: [27, 91, 72],
end: [27, 91, 70],
metab: [27, 98],
metaf: [27, 102],
metad: [27, 100]
},
gnome: {
home: [27, 79, 72],
end: [27, 79, 70]
},
rxvt: {
home: [27, 91, 55],
end: [27, 91, 56]
},
putty: {
home: [27, 91, 49, 126],
end: [27, 91, 52, 126]
}
};
var readlineFakeStream = function() {
var written_bytes = [];
var rl = readline.createInterface({
fd: 1,
write: function(b) {
written_bytes.push(b);
}}, function (text) {
return [[], ""];
});
rl.written_bytes = written_bytes;
return rl;
};
var rl = readlineFakeStream();
var written_bytes_length, refreshed;
rl.write('foo');
assert.equal(3, rl.cursor);
rl.write(key.xterm.home);
assert.equal(0, rl.cursor);
rl.write(key.xterm.end);
assert.equal(3, rl.cursor);
rl.write(key.rxvt.home);
assert.equal(0, rl.cursor);
rl.write(key.rxvt.end);
assert.equal(3, rl.cursor);
rl.write(key.gnome.home);
assert.equal(0, rl.cursor);
rl.write(key.gnome.end);
assert.equal(3, rl.cursor);
rl.write(key.putty.home);
assert.equal(0, rl.cursor);
rl.write(key.putty.end);
assert.equal(3, rl.cursor);
rl = readlineFakeStream();
rl.write('foo bar.hop/zoo');
rl.write(key.xterm.home);
written_bytes_length = rl.written_bytes.length;
rl.write(key.xterm.metaf);
assert.equal(3, rl.cursor);
refreshed = written_bytes_length !== rl.written_bytes.length;
assert.equal(true, refreshed);
rl.write(key.xterm.metaf);
assert.equal(7, rl.cursor);
rl.write(key.xterm.metaf);
assert.equal(11, rl.cursor);
written_bytes_length = rl.written_bytes.length;
rl.write(key.xterm.metaf);
assert.equal(15, rl.cursor);
refreshed = written_bytes_length !== rl.written_bytes.length;
assert.equal(true, refreshed);
written_bytes_length = rl.written_bytes.length;
rl.write(key.xterm.metab);
assert.equal(12, rl.cursor);
refreshed = written_bytes_length !== rl.written_bytes.length;
assert.equal(true, refreshed);
rl.write(key.xterm.metab);
assert.equal(8, rl.cursor);
rl.write(key.xterm.metab);
assert.equal(4, rl.cursor);
written_bytes_length = rl.written_bytes.length;
rl.write(key.xterm.metab);
assert.equal(0, rl.cursor);
refreshed = written_bytes_length !== rl.written_bytes.length;
assert.equal(true, refreshed);
rl = readlineFakeStream();
rl.write('foo bar.hop/zoo');
rl.write(key.xterm.home);
rl.write(key.xterm.metad);
assert.equal(0, rl.cursor);
assert.equal(' bar.hop/zoo', rl.line);
rl.write(key.xterm.metad);
assert.equal(0, rl.cursor);
assert.equal('.hop/zoo', rl.line);
rl.write(key.xterm.metad);
assert.equal(0, rl.cursor);
assert.equal('/zoo', rl.line);
rl.write(key.xterm.metad);
assert.equal(0, rl.cursor);
assert.equal('', rl.line);

View File

@@ -60,7 +60,7 @@ function tcp_test() {
});
client_tcp.addListener('data', function (data) {
read_buffer += data.asciiSlice(0, data.length);
read_buffer += data.toString('ascii', 0, data.length);
common.error("TCP data: " + JSON.stringify(read_buffer) + ", expecting " + JSON.stringify(client_tcp.expect));
if (read_buffer.indexOf(prompt_tcp) !== -1) {
assert.strictEqual(client_tcp.expect, read_buffer);
@@ -121,7 +121,7 @@ function unix_test() {
});
client_unix.addListener('data', function (data) {
read_buffer += data.asciiSlice(0, data.length);
read_buffer += data.toString('ascii', 0, data.length);
common.error("Unix data: " + JSON.stringify(read_buffer) + ", expecting " + JSON.stringify(client_unix.expect));
if (read_buffer.indexOf(prompt_unix) !== -1) {
assert.strictEqual(client_unix.expect, read_buffer);

View File

@@ -0,0 +1,36 @@
// This test is to assert that we can SIGINT a script which loops forever.
// ref: http://groups.google.com/group/nodejs-dev/browse_thread/thread/e20f2f8df0296d3f
var common = require('../common');
var assert = require('assert');
var spawn = require('child_process').spawn;
console.log("start");
var c = spawn(process.execPath, ['-e', 'while(true) { console.log("hi"); }']);
var sentKill = false;
var gotChildExit = true;
c.stdout.on('data', function (s) {
// Prevent race condition:
// Wait for the first bit of output from the child process
// so that we're sure that it's in the V8 event loop and not
// just in the startup phase of execution.
if (!sentKill) {
c.kill('SIGINT')
console.log("SIGINT infinite-loop.js");
sentKill = true;
}
});
c.on('exit', function (code) {
assert.ok(code !== 0);
console.log("killed infinite-loop.js");
gotChildExit = true;
});
process.on('exit', function () {
assert.ok(sentKill);
assert.ok(gotChildExit);
});

View File

@@ -7,6 +7,10 @@ var url = require("url"),
// URLs to parse, and expected data
// { url : parsed }
var parseTests = {
"//some_path" : {
"href": "//some_path",
"pathname": "//some_path"
},
"http://www.narwhaljs.org/blog/categories?id=news" : {
"href": "http://www.narwhaljs.org/blog/categories?id=news",
"protocol": "http:",

View File

@@ -0,0 +1,41 @@
// Serving up a zero-length buffer should work.
var common = require("../common");
var assert = common.assert;
var http = require('http');
var server = http.createServer(function (req, res) {
var buffer = new Buffer(0);
res.writeHead(200, {'Content-Type': 'text/html',
'Content-Length': buffer.length});
res.end(buffer);
});
var gotResponse = false;
var resBodySize = 0;
server.listen(common.PORT, function () {
var client = http.createClient(common.PORT);
var req = client.request('GET', '/');
req.end();
req.on('response', function (res) {
gotResponse = true;
res.on('data', function (d) {
resBodySize += d.length;
});
res.on('end', function (d) {
server.close();
});
});
});
process.on('exit', function () {
assert.ok(gotResponse);
assert.equal(0, resBodySize);
});

View File

@@ -27,6 +27,10 @@
import test
import os
import shutil
from shutil import rmtree
from os import mkdir
from glob import glob
from os.path import join, dirname, exists
import re
@@ -38,11 +42,30 @@ FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class SimpleTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config):
super(SimpleTestCase, self).__init__(context, path)
super(SimpleTestCase, self).__init__(context, path, mode)
self.file = file
self.config = config
self.mode = mode
self.tmpdir = join(dirname(self.config.root), 'tmp')
def AfterRun(self, result):
# delete the whole tmp dir
try:
rmtree(self.tmpdir)
except:
pass
# make it again.
mkdir(self.tmpdir)
def BeforeRun(self):
# delete the whole tmp dir
try:
rmtree(self.tmpdir)
except:
pass
# make it again.
mkdir(self.tmpdir)
def GetLabel(self):
return "%s %s" % (self.mode, self.GetName())
@@ -79,14 +102,7 @@ class SimpleTestConfiguration(test.TestConfiguration):
return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def ListTests(self, current_path, path, mode):
simple = [current_path + [t] for t in self.Ls(self.root)]
#simple = [current_path + ['simple', t] for t in self.Ls(join(self.root, 'simple'))]
#pummel = [current_path + ['pummel', t] for t in self.Ls(join(self.root, 'pummel'))]
#internet = [current_path + ['internet', t] for t in self.Ls(join(self.root, 'internet'))]
#regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
#bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
#tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))]
all_tests = simple # + regress + bugs + tools
all_tests = [current_path + [t] for t in self.Ls(join(self.root))]
result = []
for test in all_tests:
if self.Contains(path, test):

View File

@@ -326,15 +326,16 @@ class CommandOutput(object):
self.timed_out = timed_out
self.stdout = stdout
self.stderr = stderr
self.failed = None
class TestCase(object):
def __init__(self, context, path):
def __init__(self, context, path, mode):
self.path = path
self.context = context
self.failed = None
self.duration = None
self.mode = mode
def IsNegative(self):
return False
@@ -343,9 +344,9 @@ class TestCase(object):
return cmp(other.duration, self.duration)
def DidFail(self, output):
if self.failed is None:
self.failed = self.IsFailureOutput(output)
return self.failed
if output.failed is None:
output.failed = self.IsFailureOutput(output)
return output.failed
def IsFailureOutput(self, output):
return output.exit_code != 0
@@ -355,29 +356,55 @@ class TestCase(object):
def RunCommand(self, command):
full_command = self.context.processor(command)
output = Execute(full_command, self.context, self.context.timeout)
return TestOutput(self, full_command, output)
output = Execute(full_command,
self.context,
self.context.GetTimeout(self.mode))
self.Cleanup()
return TestOutput(self,
full_command,
output,
self.context.store_unexpected_output)
def BeforeRun(self):
pass
def AfterRun(self, result):
pass
def Run(self):
return self.RunCommand(self.GetCommand())
self.BeforeRun()
try:
result = self.RunCommand(self.GetCommand())
finally:
self.AfterRun(result)
return result
def Cleanup(self):
return
class TestOutput(object):
def __init__(self, test, command, output):
def __init__(self, test, command, output, store_unexpected_output):
self.test = test
self.command = command
self.output = output
self.store_unexpected_output = store_unexpected_output
def UnexpectedOutput(self):
if self.HasCrashed():
outcome = CRASH
elif self.HasTimedOut():
outcome = TIMEOUT
elif self.HasFailed():
outcome = FAIL
else:
outcome = PASS
return not outcome in self.test.outcomes
def HasPreciousOutput(self):
return self.UnexpectedOutput() and self.store_unexpected_output
def HasCrashed(self):
if utils.IsWindows():
return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.output.exit_code)
@@ -390,7 +417,7 @@ class TestOutput(object):
def HasTimedOut(self):
return self.output.timed_out;
def HasFailed(self):
execution_failed = self.test.DidFail(self.output)
if self.test.IsNegative():
@@ -471,6 +498,13 @@ def PrintError(str):
sys.stderr.write('\n')
def CheckedUnlink(name):
try:
os.unlink(name)
except OSError, e:
PrintError("os.unlink() " + str(e))
def Execute(args, context, timeout=None):
(fd_out, outname) = tempfile.mkstemp()
(fd_err, errname) = tempfile.mkstemp()
@@ -485,11 +519,6 @@ def Execute(args, context, timeout=None):
os.close(fd_err)
output = file(outname).read()
errors = file(errname).read()
def CheckedUnlink(name):
try:
os.unlink(name)
except OSError, e:
PrintError("os.unlink() " + str(e))
CheckedUnlink(outname)
CheckedUnlink(errname)
return CommandOutput(exit_code, timed_out, output, errors)
@@ -538,6 +567,11 @@ class TestSuite(object):
return self.name
# Use this to run several variants of the tests, e.g.:
# VARIANT_FLAGS = [[], ['--always_compact', '--noflush_code']]
VARIANT_FLAGS = [[]]
class TestRepository(TestSuite):
def __init__(self, path):
@@ -564,8 +598,12 @@ class TestRepository(TestSuite):
def GetBuildRequirements(self, path, context):
return self.GetConfiguration(context).GetBuildRequirements()
def ListTests(self, current_path, path, context, mode):
return self.GetConfiguration(context).ListTests(current_path, path, mode)
def AddTestsToList(self, result, current_path, path, context, mode):
for v in VARIANT_FLAGS:
tests = self.GetConfiguration(context).ListTests(current_path, path, mode)
for t in tests: t.variant_flags = v
result += tests
def GetTestStatus(self, context, sections, defs):
self.GetConfiguration(context).GetTestStatus(sections, defs)
@@ -592,7 +630,7 @@ class LiteralTestSuite(TestSuite):
test_name = test.GetName()
if not name or name.match(test_name):
full_path = current_path + [test_name]
result += test.ListTests(full_path, path, context, mode)
test.AddTestsToList(result, full_path, path, context, mode)
return result
def GetTestStatus(self, context, sections, defs):
@@ -600,12 +638,20 @@ class LiteralTestSuite(TestSuite):
test.GetTestStatus(context, sections, defs)
SUFFIX = {'debug': '_g', 'release': ''}
SUFFIX = {
'debug' : '_g',
'release' : '' }
FLAGS = {
'debug' : ['--enable-slow-asserts', '--debug-code', '--verify-heap'],
'release' : []}
TIMEOUT_SCALEFACTOR = {
'debug' : 4,
'release' : 1 }
class Context(object):
def __init__(self, workspace, buildspace, verbose, vm, timeout, processor, suppress_dialogs):
def __init__(self, workspace, buildspace, verbose, vm, timeout, processor, suppress_dialogs, store_unexpected_output):
self.workspace = workspace
self.buildspace = buildspace
self.verbose = verbose
@@ -613,20 +659,28 @@ class Context(object):
self.timeout = timeout
self.processor = processor
self.suppress_dialogs = suppress_dialogs
self.store_unexpected_output = store_unexpected_output
def GetVm(self, mode):
if mode == 'debug':
name = 'build/debug/node_g'
else:
name = 'build/default/node'
if utils.IsWindows() and not name.endswith('.exe'):
name = name + '.exe'
return name
def RunTestCases(all_cases, progress, tasks):
def DoSkip(case):
return SKIP in c.outcomes or SLOW in c.outcomes
cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
def GetVmCommand(self, testcase, mode):
return [self.GetVm(mode)] + self.GetVmFlags(testcase, mode)
def GetVmFlags(self, testcase, mode):
return testcase.variant_flags + FLAGS[mode]
def GetTimeout(self, mode):
return self.timeout * TIMEOUT_SCALEFACTOR[mode]
def RunTestCases(cases_to_run, progress, tasks):
progress = PROGRESS_INDICATORS[progress](cases_to_run)
return progress.Run(tasks)
@@ -1079,6 +1133,8 @@ def BuildOptions():
choices=PROGRESS_INDICATORS.keys(), default="mono")
result.add_option("--no-build", help="Don't build requirements",
default=True, action="store_true")
result.add_option("--build-only", help="Only build requirements, don't run the tests",
default=False, action="store_true")
result.add_option("--report", help="Print a summary of the tests to be run",
default=False, action="store_true")
result.add_option("-s", "--suite", help="A test suite",
@@ -1087,6 +1143,8 @@ def BuildOptions():
default=60, type="int")
result.add_option("--arch", help='The architecture to run tests for',
default='none')
result.add_option("--snapshot", help="Run the tests with snapshot turned on",
default=False, action="store_true")
result.add_option("--simulator", help="Run tests with architecture simulator",
default='none')
result.add_option("--special-command", default=None)
@@ -1104,7 +1162,13 @@ def BuildOptions():
dest="suppress_dialogs", default=True, action="store_true")
result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests",
dest="suppress_dialogs", action="store_false")
result.add_option("--shell", help="Path to V8 shell", default="shell");
result.add_option("--shell", help="Path to V8 shell", default="shell")
result.add_option("--store-unexpected-output",
help="Store the temporary JS files from tests that fails",
dest="store_unexpected_output", default=True, action="store_true")
result.add_option("--no-store-unexpected-output",
help="Deletes the temporary JS files from tests that fails",
dest="store_unexpected_output", action="store_false")
return result
@@ -1131,6 +1195,9 @@ def ProcessOptions(options):
# was found, set the arch to the guess.
if options.arch == 'none':
options.arch = ARCH_GUESS
options.scons_flags.append("arch=" + options.arch)
if options.snapshot:
options.scons_flags.append("snapshot=on")
return True
@@ -1238,11 +1305,13 @@ def Main():
shell = abspath(options.shell)
buildspace = dirname(shell)
context = Context(workspace, buildspace, VERBOSE,
shell,
options.timeout,
GetSpecialCommandProcessor(options.special_command),
options.suppress_dialogs)
options.suppress_dialogs,
options.store_unexpected_output)
# First build the required targets
if not options.no_build:
reqs = [ ]
@@ -1255,6 +1324,10 @@ def Main():
if not BuildRequirements(context, reqs, options.mode, options.scons_flags):
return 1
# Just return if we are only building the targets for running the tests.
if options.build_only:
return 0
# Get status for tests
sections = [ ]
defs = { }
@@ -1308,13 +1381,16 @@ def Main():
PrintReport(all_cases)
result = None
if len(all_cases) == 0:
def DoSkip(case):
return SKIP in case.outcomes or SLOW in case.outcomes
cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
if len(cases_to_run) == 0:
print "No tests to run."
return 0
else:
try:
start = time.time()
if RunTestCases(all_cases, options.progress, options.j):
if RunTestCases(cases_to_run, options.progress, options.j):
result = 0
else:
result = 1
@@ -1328,7 +1404,7 @@ def Main():
# test output.
print
sys.stderr.write("--- Total time: %s ---\n" % FormatTime(duration))
timed_tests = [ t.case for t in all_cases if not t.case.duration is None ]
timed_tests = [ t.case for t in cases_to_run if not t.case.duration is None ]
timed_tests.sort(lambda a, b: a.CompareTime(b))
index = 1
for entry in timed_tests[:20]:

View File

@@ -1,4 +1,4 @@
# git log --pretty='format:%ae %an' | tail -r | awk -f updateAuthors.awk
# git log --pretty='format:%ae %an' | tac | awk -f tools/updateAuthors.awk
{
if (!x[$1]++) {
#print $0

58
wscript
View File

@@ -18,12 +18,7 @@ blddir = 'build'
jobs=1
if os.environ.has_key('JOBS'):
jobs = int(os.environ['JOBS'])
else:
try:
import multiprocessing
jobs = multiprocessing.cpu_count()
except:
pass
def set_options(opt):
# the gcc module provides a --debug-level option
@@ -162,18 +157,19 @@ def configure(conf):
if Options.options.efence:
conf.check(lib='efence', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='EFENCE')
if not conf.check(lib="execinfo", includes=['/usr/include', '/usr/local/include'], libpath=['/usr/lib', '/usr/local/lib'], uselib_store="EXECINFO"):
# Note on Darwin/OS X: This will fail, but will still be used as the
# execinfo stuff are part of the standard library.
if sys.platform.startswith("freebsd"):
conf.fatal("Install the libexecinfo port from /usr/ports/devel/libexecinfo.")
if sys.platform.startswith("freebsd"):
if not conf.check(lib="execinfo",
includes=['/usr/include', '/usr/local/include'],
libpath=['/usr/lib', '/usr/local/lib'],
uselib_store="EXECINFO"):
conf.fatal("Install the libexecinfo port from /usr/ports/devel/libexecinfo.")
if not Options.options.without_ssl:
if conf.check_cfg(package='openssl',
args='--cflags --libs',
uselib_store='OPENSSL'):
Options.options.use_openssl = conf.env["USE_OPENSSL"] = True
conf.env.append_value("CXXFLAGS", "-DHAVE_OPENSSL=1")
conf.env.append_value("CPPFLAGS", "-DHAVE_OPENSSL=1")
else:
libssl = conf.check_cc(lib='ssl',
header_name='openssl/ssl.h',
@@ -185,7 +181,13 @@ def configure(conf):
uselib_store='OPENSSL')
if libcrypto and libssl:
conf.env["USE_OPENSSL"] = Options.options.use_openssl = True
conf.env.append_value("CXXFLAGS", "-DHAVE_OPENSSL=1")
conf.env.append_value("CPPFLAGS", "-DHAVE_OPENSSL=1")
else:
conf.fatal("Could not autodetect OpenSSL support. " +
"Make sure OpenSSL development packages are installed. " +
"Use configure --without-ssl to disable this message.")
else:
Options.options.use_openssl = conf.env["USE_OPENSSL"] = False
conf.check(lib='rt', uselib_store='RT')
@@ -264,13 +266,11 @@ def configure(conf):
# used by platform_darwin_*.cc
conf.env.append_value('LINKFLAGS', ['-framework','Carbon'])
conf.env.append_value("CCFLAGS", "-DX_STACKSIZE=%d" % (1024*64))
# Needed for getaddrinfo in libeio
conf.env.append_value("CPPFLAGS", "-DX_STACKSIZE=%d" % (1024*64))
# LFS
conf.env.append_value('CCFLAGS', '-D_LARGEFILE_SOURCE')
conf.env.append_value('CXXFLAGS', '-D_LARGEFILE_SOURCE')
conf.env.append_value('CCFLAGS', '-D_FILE_OFFSET_BITS=64')
conf.env.append_value('CXXFLAGS', '-D_FILE_OFFSET_BITS=64')
conf.env.append_value('CPPFLAGS', '-D_LARGEFILE_SOURCE')
conf.env.append_value('CPPFLAGS', '-D_FILE_OFFSET_BITS=64')
## needed for node_file.cc fdatasync
## Strangely on OSX 10.6 the g++ doesn't see fdatasync but gcc does?
@@ -284,14 +284,12 @@ def configure(conf):
}
"""
if conf.check_cxx(msg="Checking for fdatasync(2) with c++", fragment=code):
conf.env.append_value('CXXFLAGS', '-DHAVE_FDATASYNC=1')
conf.env.append_value('CPPFLAGS', '-DHAVE_FDATASYNC=1')
else:
conf.env.append_value('CXXFLAGS', '-DHAVE_FDATASYNC=0')
conf.env.append_value('CPPFLAGS', '-DHAVE_FDATASYNC=0')
# platform
platform_def = '-DPLATFORM="' + conf.env['DEST_OS'] + '"'
conf.env.append_value('CCFLAGS', platform_def)
conf.env.append_value('CXXFLAGS', platform_def)
conf.env.append_value('CPPFLAGS', '-DPLATFORM="' + conf.env['DEST_OS'] + '"')
# Split off debug variant before adding variant specific defines
debug_env = conf.env.copy()
@@ -300,14 +298,18 @@ def configure(conf):
# Configure debug variant
conf.setenv('debug')
debug_env.set_variant('debug')
debug_env.append_value('CCFLAGS', ['-DDEBUG', '-g', '-O0', '-Wall', '-Wextra'])
debug_env.append_value('CXXFLAGS', ['-DDEBUG', '-g', '-O0', '-Wall', '-Wextra'])
debug_env.append_value('CPPFLAGS', '-DDEBUG')
debug_compile_flags = ['-g', '-O0', '-Wall', '-Wextra']
debug_env.append_value('CCFLAGS', debug_compile_flags)
debug_env.append_value('CXXFLAGS', debug_compile_flags)
conf.write_config_header("config.h")
# Configure default variant
conf.setenv('default')
conf.env.append_value('CCFLAGS', ['-DNDEBUG', '-g', '-O3'])
conf.env.append_value('CXXFLAGS', ['-DNDEBUG', '-g', '-O3'])
conf.env.append_value('CPPFLAGS', '-DNDEBUG')
default_compile_flags = ['-g', '-O3']
conf.env.append_value('CCFLAGS', default_compile_flags)
conf.env.append_value('CXXFLAGS', default_compile_flags)
conf.write_config_header("config.h")