diff --git a/AUTHORS b/AUTHORS index 8c2a9055b9..9c2969a614 100644 --- a/AUTHORS +++ b/AUTHORS @@ -258,3 +258,6 @@ Michael Bernstein Guillermo Rauch Dan Williams Brandon Benvie +Nicolas LaCasse +Dan VerWeire +Matthew Fitzsimmons diff --git a/ChangeLog b/ChangeLog index 3f330c6bde..f49b6d70ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,24 @@ * Bug fixes +2012.01.27, Version 0.6.9 (stable) + +* dgram: Bring back missing functionality for Unix (Dan VerWeire, Roman Shtylman, Ben Noordhuis) + - Note: Windows UDP support not yet complete. + +* http: Fix parser memory leak (koichik) + +* zlib: Fix #2365 crashes on invalid input (Nicolas LaCasse) + +* module: fix --debug-brk on symlinked scripts (Fedor Indutny) + +* Documentation Restyling (Matthew Fitzsimmons) + +* Update npm to 1.1.0-3 (isaacs) + +* Windows: fix regression in stat() calls to C:\ (Bert Belder) + + 2012.01.19, Version 0.6.8 (stable), d18cebaf8a7ac701dabd71a3aa4eb0571db6a645 * Update V8 to 3.6.6.19 diff --git a/Makefile b/Makefile index 0d191f7db8..8b4a15943d 100644 --- a/Makefile +++ b/Makefile @@ -102,23 +102,33 @@ website_files = \ out/doc/sh_main.js \ out/doc/sh_javascript.min.js \ out/doc/sh_vim-dark.css \ + out/doc/sh.css \ out/doc/logo.png \ - out/doc/sponsored.png \ out/doc/favicon.ico \ out/doc/pipe.css \ out/doc/about/index.html \ out/doc/close-downloads.png \ out/doc/community/index.html \ out/doc/community/not-invented-here.png \ + out/doc/logos/index.html \ + out/doc/microsoft-logo.png \ + out/doc/ryan-speaker.jpg \ out/doc/download-logo.png \ out/doc/ebay-logo.png \ + out/doc/footer-logo-alt.png \ out/doc/footer-logo.png \ + out/doc/icons-interior.png \ out/doc/icons.png \ + out/doc/home-icons.png \ + out/doc/joyent-logo_orange_nodeorg-01.png \ out/doc/linkedin-logo.png \ - out/doc/logos/index.html \ + out/doc/logo-light.png \ + out/doc/mac_osx_nodejs_installer_logo.png \ out/doc/microsoft-logo.png \ out/doc/platform-icons.png \ - out/doc/ryan-speaker.jpg \ + out/doc/sponsored.png \ + out/doc/twitter-bird.png \ + out/doc/community-icons.png \ out/doc/yahoo-logo.png doc: node $(apidoc_dirs) $(website_files) $(apiassets) $(apidocs) diff --git a/deps/npm/html/api/bin.html b/deps/npm/html/api/bin.html index c4392671df..17c19b073a 100644 --- a/deps/npm/html/api/bin.html +++ b/deps/npm/html/api/bin.html @@ -19,7 +19,7 @@

This function should not be used programmatically. Instead, just refer to the npm.bin member.

- + diff --git a/doc/anchor.png b/doc/anchor.png new file mode 100644 index 0000000000..1ed163ee1a Binary files /dev/null and b/doc/anchor.png differ diff --git a/doc/api_assets/anchor.png b/doc/api_assets/anchor.png new file mode 100644 index 0000000000..1ed163ee1a Binary files /dev/null and b/doc/api_assets/anchor.png differ diff --git a/doc/api_assets/footer-logo-alt.png b/doc/api_assets/footer-logo-alt.png new file mode 100644 index 0000000000..e6d9c2390e Binary files /dev/null and b/doc/api_assets/footer-logo-alt.png differ diff --git a/doc/api_assets/icons-interior.png b/doc/api_assets/icons-interior.png new file mode 100644 index 0000000000..6b3d483dc0 Binary files /dev/null and b/doc/api_assets/icons-interior.png differ diff --git a/doc/api_assets/logo-light.png b/doc/api_assets/logo-light.png new file mode 100644 index 0000000000..898fcecc96 Binary files /dev/null and b/doc/api_assets/logo-light.png differ diff --git a/doc/api_assets/platform-icons.png b/doc/api_assets/platform-icons.png new file mode 100644 index 0000000000..d6624a5a64 Binary files /dev/null and b/doc/api_assets/platform-icons.png differ diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index c47f3812b8..0ade5b2231 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -1,24 +1,28 @@ /*--------------------- Layout and Typography ----------------------------*/ +html { + -webkit-font-smoothing: antialiased; +} + body { -// font-family: "Helvetica Neue", Helvetica, FreeSans, Arial, sans-serif; - font-family: Georgia, FreeSerif, Times, serif; - font-size: 0.9375em; - line-height: 1.4667em; - color: #222; - margin: 0; padding: 0; + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif; + font-size: 14px; + line-height: 180%; + color: black; + margin: 0; padding: 49px 0 0 0; + border-top: 6px #8CC84B solid; } a { - color: #0050c0; + color: #690; text-decoration: underline; } a:visited { - color: #b950b7; + color: #46483e; text-decoration: underline; } a:hover, a:focus { text-decoration: none; } - + code a:hover { background: none; color: #b950b7; @@ -28,6 +32,23 @@ a { display: none; } +#gtoc p { + margin:0; + font-size:18px; + line-height: 30px; +} + +#gtoc a { + font-family: Georgia, FreeSerif, Times, serif; + text-decoration: none; + color: #46483e; +} + +#gtoc a:hover { + color: #669900; + text-decoration: underline; +} + .notice { display: block; padding: 1em; @@ -54,6 +75,13 @@ p { text-rendering: optimizeLegibility; } +.apidoc p { + font-size: 15px; + line-height: 22px; + color: #000; + font-family: Georgia, FreeSerif, Times, serif; +} + ol, ul, dl { margin: 0 0 1em 0; padding: 0; @@ -89,25 +117,34 @@ dd + dt.pre { } h1, h2, h3, h4, h5, h6 { - font-family: Georgia, FreeSerif, Times, serif; + font-family: Helvetica, Arial, sans-serif; color: #000; text-rendering: optimizeLegibility; position: relative; } h1 { - font-size: 2.55em; - line-height: 1.375em; + font-family: Georgia, FreeSerif, Times, serif; + font-size: 30px; + font-weight: normal; + line-height: 36px; + color: #690; + margin: 15px 0 11px; } h2 { - font-size: 1.9em; - line-height: 1.227em; - margin: 0 0 0.5em; + font-size: 29px; + line-height: 33px; + margin: 2em 0 15px; +} + +#toc + h2 { + margin-top:1em; + padding-top:0; } h3 { - font-size: 1.5em; + font-size: 1.4em; line-height: 1.0909em; margin: 1.5em 0 0.5em; } @@ -126,13 +163,35 @@ h4 + h4 { margin: 0 0 0.5em; } - h3 a, - h4 a { + h3, h4 { + position:relative; + padding-right:40px; + } + h2 span, h3 span, h4 span { + position:absolute; + display:block; + top:0; + right:0; + opacity: 0.3; + } + h2 span:hover, h3 span:hover, h4 span:hover { + opacity: 1; + } + h2 span a, h3 span a, h4 span a { font-size: 0.8em; - float: right; color: #000; text-decoration: none; - opacity: 0.3; + font-family: Helvetica, Arial, sans-serif; + font-weight:bold; + } + + h2 span a.top, h3 span a.top, h4 span a.top { + /* XXX Get an image and clean up these two links + * so that they look nice next to one another. + * http://www.chrisglass.com/work/nodejs/website/v05/docs.html + * -isaacs + */ + display:none; } h5 { @@ -146,7 +205,7 @@ h6 { } pre, tt, code { - font-size: 0.95em; + font-size: 14px; line-height: 1.5438em; font-family: Monaco, Consolas, "Lucida Console", monospace; margin: 0; padding: 0; @@ -159,12 +218,13 @@ h6 { } pre { - padding: 2em 1.6em 2em 1.2em; + padding: 1em 1.6em 1em 1.2em; vertical-align: top; background: #f8f8f8; border: 1px solid #e8e8e8; border-width: 1px 1px 1px 6px; margin: -0.5em 0 1.1em; + overflow-x:auto; } pre + h3 { @@ -175,37 +235,41 @@ code.pre { white-space: pre; } -#container { - position: relative; - padding: 6em; - max-width: 50em; - text-align: left; +#intro { + width: 775px; + margin: 0 auto; + text-align: center; + color: #d2d8ba; + + /* preload platform-icons.png */ + background-image: url(platform-icons.png); + background-repeat: no-repeat; + background-position: -999em -999em; } -#container header { - margin: 1.25em -0.5em 1.3em; - padding: 0 0.5em 0.225em; +#intro.interior #logo { + margin-left: -298px; + border:0; } hr { background: none; border: medium none; border-bottom: 1px solid #ccc; - margin: 5em 0 2em; -} - -#container header hr { - margin: 0; - padding: 0; + margin: 1em 0; } #toc { - + font-size:15px; + line-height:1.5em; + line-height: 22px; + padding-top:4px; } #toc h2 { - font-size: 1em; - line-height: 1.4em; + font-size: 15px; + line-height: 21px; + margin: 0 0 0.5em; } #toc h2 a { @@ -216,29 +280,209 @@ hr { margin: 1em 0 2em; } + #toc ul { + font-family: Georgia, FreeSerif, Times, serif; + } + + #toc ul a { + text-decoration:none; + border-bottom:1px dotted #690; + } + #toc ul a:hover, #toc ul a:focus { + border-bottom:1px dotted #fff; + color:#000; + } + + p tt, p code { background: #f8f8ff; border: 1px solid #dedede; padding: 0 0.2em; } -a.octothorpe { - text-decoration: none; - color: #777; - position: absolute; - top: 0; left: -1.4em; - padding: 1px 2px; - opacity: 0; - -webkit-transition: opacity 0.2s linear; -} - p:hover > a.octothorpe, - dt:hover > a.octothorpe, - dd:hover > a.octothorpe, - h1:hover > a.octothorpe, - h2:hover > a.octothorpe, - h3:hover > a.octothorpe, - h4:hover > a.octothorpe, - h5:hover > a.octothorpe, - h6:hover > a.octothorpe { - opacity: 1; - } +#content { + width: 953px; + margin: 0 auto; + overflow: visible; + clear: both; + display: block; +} + +#column1.interior { + width: 749px; + float: right; + padding-top: 7px; + padding-top: 11px; + font-size:18px; +} + +#column2.interior { + width: 140px; + float: left; + margin-top: -55px; + overflow: visible; +} + +#column2.interior ul { + margin-left: 0; +} + +#column2.interior li { + list-style-type: none; +} + +#column2.interior li a { + display: block; + padding: 0 0 0 35px; + color: #878b78; + text-transform: uppercase; + text-decoration: none; + font-size: 11px; + line-height: 23px; +} + +#column2.interior li a.home { background: url(icons-interior.png) no-repeat -156px 3px; } +#column2.interior li a.download { background: url(icons-interior.png) no-repeat -156px -21px; } +#column2.interior li a.about { background: url(icons-interior.png) no-repeat -156px -45px; } +#column2.interior li a.npm { background: url(icons-interior.png) no-repeat -156px -69px; } +#column2.interior li a.docs { background: url(icons-interior.png) no-repeat -156px -93px; } +#column2.interior li a.blog { background: url(icons-interior.png) no-repeat -156px -117px; } +#column2.interior li a.community { background: url(icons-interior.png) no-repeat -156px -141px; } +#column2.interior li a.logos { background: url(icons-interior.png) no-repeat -156px -165px; } +#column2.interior li a.jobs { background: url(icons-interior.png) no-repeat -156px -189px; } + +#column2.interior li a.home.current { background-position: 2px 3px; } +#column2.interior li a.download.current { background-position: 2px -21px; } +#column2.interior li a.about.current { background-position: 2px -45px; } +#column2.interior li a.npm.current { background-position: 2px -69px; } +#column2.interior li a.docs.current { background-position: 2px -93px; } +#column2.interior li a.blog.current { background-position: 2px -117px; } +#column2.interior li a.community.current { background-position: 2px -141px; } +#column2.interior li a.logos.current { background-position: 2px -165px; } +#column2.interior li a.jobs.current { background-position: 2px -189px; } +#column2.interior li a.current { color: #8cc84b; font-weight: bold; } + +#column2.interior li a.home:hover { background-position: -331px 3px; } +#column2.interior li a.download:hover { background-position: -331px -21px; } +#column2.interior li a.about:hover { background-position: -331px -45px; } +#column2.interior li a.npm:hover { background-position: -331px -69px; } +#column2.interior li a.docs:hover { background-position: -331px -93px; } +#column2.interior li a.blog:hover { background-position: -331px -117px; } +#column2.interior li a.community:hover { background-position: -331px -141px; } +#column2.interior li a.logos:hover { background-position: -331px -165px; } +#column2.interior li a.jobs:hover { background-position: -331px -189px; } +#column2.interior li a:hover { color: #000000; text-decoration: none; } + +#column2.interior li + li { + border-top: 1px solid #c1c7ac; +} +#column2.interior p.twitter { + padding-top: 20px; +} + +#column2.interior p.twitter a { + background: url(twitter-bird.png) no-repeat 0 4px; + padding-left: 37px; + text-decoration: none; +} + +#column2.interior p.twitter a:hover { + text-decoration: underline; +} + +a.totop { + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif; + font-weight: bold; + text-indent: -9999999px; + background: url(anchor.png) no-repeat top left; + margin-right: 7px; + display: block; + width: 13px; + border-bottom: 1px solid #cccccc; +} + +a.anchor { + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif; + font-weight: bold; + text-indent: -9999999px; + background: url(anchor.png) no-repeat top right; + display: block; + width: 13px; + border-bottom: 1px solid #cccccc; +} +#footer { + width: 942px; + margin: 150px auto 55px auto; + padding:0; +} + +#footer p { + font-size: 11px; + line-height:1em; + padding: 0 0 0 195px; + color: #666; + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif; +} + +#footer a { + text-decoration:none; + border:none; + color: #690; +} +#footer a:hover { + color:#000; +} + +#footer p a { + border-bottom:1px dotted #690; + color: #878b78; +} + +#footer ul { + background: url(footer-logo-alt.png) left 17px no-repeat; + padding: 23px 0 0 195px; + height: 26px; + margin-left: -1px; + border-top: 1px solid #626557; +} + +#footer ul li { + list-style-type: none; + float: left; + font-size: 12px; + margin:0!important; + padding:0; + height: 12px; +} + +#footer ul li a { + margin: 0; + padding: 0 6px 0 0; + display: block; + height:12px; + line-height:12px; +} + +#footer ul li + li { + margin-left: 3px; +} + +#footer ul li + li a { + padding: 0 6px 0 6px; + border-left: 1px solid #878b78; +} + +#footer ul li a.twitter { + background: url(twitter-bird.png) no-repeat 5px 0px; + padding-left: 25px; +} + +/* simpler clearfix */ +.clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + diff --git a/doc/api_assets/twitter-bird.png b/doc/api_assets/twitter-bird.png new file mode 100644 index 0000000000..b619b2a0d3 Binary files /dev/null and b/doc/api_assets/twitter-bird.png differ diff --git a/doc/community-icons.png b/doc/community-icons.png new file mode 100644 index 0000000000..b3d58f0f1e Binary files /dev/null and b/doc/community-icons.png differ diff --git a/doc/community/index.html b/doc/community/index.html index 3219f7bf84..ef9bac5ae1 100644 --- a/doc/community/index.html +++ b/doc/community/index.html @@ -20,135 +20,167 @@ href="http://feeds.feedburner.com/nodejs/123123123"> node.js - -
+ +
-
-

Node's most valuable feature is the friendly and colorful - community of developers. There are many places where - this group congregates on the internet. This page attempts - to highlight the best forums.

- -

Periodicals

- -

Planet Node is an - aggregator of Node developer blogs. NodeUp - is a podcast covering the latest Node news in the - community.

- -

Docs

- -

- Besides the official API - docs there are a number of sites new users should be - aware of. docs.nodejitsu.com - answers many of the common problems people come across. - How To Node has a - growing number of useful tutorials. - The Stack - Overflow node.js tag is collecting new information - every day. +

+
+

Node's most valuable feature is the friendly and colorful community of developers. There are many places where this group congregates on the internet. This page attempts to highlight the best forums.

-

GitHub

-

All development takes place at http://github.com/joyent/node. - The comments on commit messages are often source of heated - discussion regarding core development. The GitHub Node - wiki is full of useful links for newcomers. Don't - miss Projects, - Applications, and Companies Using Node or the very - long list of Node modules, many of which are - published in the npm - registry.

+
+
+

Documentation

+ +

Official API docs detail the node API.

+

docs.nodejitsu.com answers many of the common problems people come across.

+

How To Node has a growing number of useful tutorials.

+

Stack Overflow node.js tag collects new information every day.

+
+ + +
+

GitHub

+

All development takes place at http://github.com/joyent/node. + The comments on commit messages are often source of heated + discussion regarding core development.

The GitHub Node + wiki is full of useful links for newcomers. Don't + miss Projects, + Applications, and Companies Using Node or the very + long list of Node modules, many of which are + published in the npm + registry.

+
+
-

Bugs - should be reported to https://github.com/joyent/node/issues. - Fixes to the code are welcome! Please see our contributing - guidelines for information on how to submit a - patch.

- -

Mailing Lists

- -

The user - mailing list is used for announcements, discussion, - and flame wars about Node. The internal - development mailing list is used for discussion of - internal design and feature proposals.

- -

IRC

- -

For real-time chat about Node development go to - irc.freenode.net in the #node.js - channel with an IRC client or connect in - your web browser to the channel using freenode's - WebChat. Felix Geisendörfer keeps logs of the - channel for those who miss a day.

-

Conferences

- -

NodeConf - conferences are the main event in the United States; they - are organized by Mikeal Rogers. - NodeFest (東京Node学園祭) - is organized by the Node.js - Japan user group. NodeCamp.de in Cologne, - Germany is organized by Rails - Love. An Italian - Node.js Conference exists as well. Node Summit is a - conference in San Francisco focusing on the adoption of - Node in larger companies. JSConf organizes the main - JavaScript conferences.

+
+
+

Mailing Lists

+ +

The user + mailing list is used for announcements, discussion, + and flame wars about Node. The internal + development mailing list is used for discussion of + internal design and feature proposals.

+
+ +
+

Periodicals

+ +

Planet Node is an + aggregator of Node developer blogs.

NodeUp + is a podcast covering the latest Node news in the + community.

+
+
+ +
+
+

Conferences

+ +

NodeConf + conferences are the main event in the United States; they + are organized by Mikeal Rogers.

+

NodeFest (東京Node学園祭) + is organized by the Node.js + Japan user group.

+

NodeCamp.de in Cologne, + Germany is organized by Rails Love.

+

An Italian + Node.js Conference exists as well.

+

Node Summit is a + conference in San Francisco focusing on the adoption of + Node in larger companies.

+

JSConf organizes the main + JavaScript conferences.

+
+ +
+

Localized Sites

+ +

nodejs.org does not maintain any + translations into other languages. However there are + community websites in various languages with mailing lists + and translations of the website.

+ +

nodejs.ru Russian blog. +
+ nodejs.ir Iran group in Persian +
+ nodejs.jp Japan user group +
+ CNodeJS.org Chinese community +
+ nodejs.co.il Israeli wiki +
+ HKNoJ Hong Kong community +
+ nodejs.tw Taiwan community

+
+
+ +
+
+

IRC

+ +

For real-time chat about Node development go to + irc.freenode.net in the #node.js + channel with an IRC client or connect in + your web browser to the channel using freenode's + WebChat. Felix Geisendörfer keeps logs of the + channel for those who miss a day.

+
+
-

Localized Sites

- -

nodejs.org does not maintain any - translations into other languages. However there are - community websites in various languages with mailing lists - and translations of the website.

- -

nodejs.ru Russian blog. -
- nodejs.ir Iran group in Persian -
- nodejs.jp Japan user group -
- CNodeJS.org Chinese community -
- nodejs.co.il Israeli wiki -
- HKNoJ Hong Kong community -
- nodejs.tw Taiwan community

-

Go back to the home page

+

-
-
diff --git a/doc/logo-light.png b/doc/logo-light.png new file mode 100644 index 0000000000..898fcecc96 Binary files /dev/null and b/doc/logo-light.png differ diff --git a/doc/logos/index.html b/doc/logos/index.html index 1ff27b3859..8a84aebacd 100644 --- a/doc/logos/index.html +++ b/doc/logos/index.html @@ -21,15 +21,30 @@ node.js - -
+ +
+ +
-

To echo the evolutionary nature of Node, we've added some punch and playfulness to its identity. All it needs now is a good home with you, download and have fun!

Logo Downloads

@@ -54,17 +69,28 @@

Select your screen resolution:
1024 x 768
| 1280 x 1024 | 1440 x 900 | 1920 x 1200 | 2560 x 1440

-

Go back to the home page

-
-
+ diff --git a/doc/twitter-bird.png b/doc/twitter-bird.png new file mode 100644 index 0000000000..b619b2a0d3 Binary files /dev/null and b/doc/twitter-bird.png differ diff --git a/lib/dgram.js b/lib/dgram.js index d5c2e0da69..b5b0473de8 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -223,30 +223,46 @@ Socket.prototype.address = function() { Socket.prototype.setBroadcast = function(arg) { - if (this._handle.setBroadcast((arg) ? 1 : 0) == -1) { - throw errnoException(errno, 'setBroadcast'); + if (this._handle.setBroadcast((arg) ? 1 : 0)) { + throw errnoException(errno, 'setBroadcast'); } - - return true; }; Socket.prototype.setTTL = function(arg) { - throw new Error('not yet implemented'); + if (typeof arg !== 'number') { + throw new TypeError('Argument must be a number'); + } + + if (this._handle.setTTL(arg)) { + throw errnoException(errno, 'setTTL'); + } + + return arg; }; Socket.prototype.setMulticastTTL = function(arg) { - if (this._handle.setMulticastTTL(arg) == -1) { + if (typeof arg !== 'number') { + throw new TypeError('Argument must be a number'); + } + + if (this._handle.setMulticastTTL(arg)) { throw errnoException(errno, 'setMulticastTTL'); } - return true; + return arg; }; Socket.prototype.setMulticastLoopback = function(arg) { - throw new Error('not yet implemented'); + arg = arg ? 1 : 0; + + if (this._handle.setMulticastLoopback(arg)) { + throw errnoException(errno, 'setMulticastLoopback'); + } + + return arg; // 0.4 compatibility }; @@ -258,7 +274,9 @@ Socket.prototype.addMembership = function(multicastAddress, throw new Error('multicast address must be specified'); } - return this._handle.addMembership(multicastAddress, interfaceAddress); + if (this._handle.addMembership(multicastAddress, interfaceAddress)) { + throw new errnoException(errno, 'addMembership'); + } }; @@ -270,7 +288,9 @@ Socket.prototype.dropMembership = function(multicastAddress, throw new Error('multicast address must be specified'); } - return this._handle.dropMembership(multicastAddress, interfaceAddress); + if (this._handle.dropMembership(multicastAddress, interfaceAddress)) { + throw new errnoException(errno, 'dropMembership'); + } }; diff --git a/lib/http.js b/lib/http.js index f41b94d45c..f2fea5d540 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1238,7 +1238,11 @@ ClientRequest.prototype.onSocket = function(socket) { socket.destroy(); } freeParser(); - } else if (parser.incoming && parser.incoming.complete) { + } else if (parser.incoming && parser.incoming.complete && + // When the status code is 100 (Continue), the server will + // send a final response after this client sends a request + // body. So, we must not free the parser. + parser.incoming.statusCode !== 100) { freeParser(); } }; diff --git a/lib/module.js b/lib/module.js index b0ce0d2e3f..499530e4de 100644 --- a/lib/module.js +++ b/lib/module.js @@ -276,18 +276,16 @@ Module._load = function(request, parent, isMain) { debug('Module._load REQUEST ' + (request) + ' parent: ' + parent.id); } - var resolved = Module._resolveFilename(request, parent); - var id = resolved[0]; - var filename = resolved[1]; + var filename = Module._resolveFilename(request, parent); var cachedModule = Module._cache[filename]; if (cachedModule) { return cachedModule.exports; } - if (NativeModule.exists(id)) { + if (NativeModule.exists(filename)) { // REPL is a special case, because it needs the real require. - if (id == 'repl') { + if (filename == 'repl') { var replModule = new Module('repl'); replModule._compile(NativeModule.getSource('repl'), 'repl.js'); NativeModule._cache.repl = replModule; @@ -295,10 +293,10 @@ Module._load = function(request, parent, isMain) { } debug('load native module ' + request); - return NativeModule.require(id); + return NativeModule.require(filename); } - var module = new Module(id, parent); + var module = new Module(filename, parent); if (isMain) { process.mainModule = module; @@ -318,7 +316,7 @@ Module._load = function(request, parent, isMain) { Module._resolveFilename = function(request, parent) { if (NativeModule.exists(request)) { - return [request, request]; + return request; } var resolvedModule = Module._resolveLookupPaths(request, parent); @@ -335,8 +333,7 @@ Module._resolveFilename = function(request, parent) { err.code = 'MODULE_NOT_FOUND'; throw err; } - id = filename; - return [id, filename]; + return filename; }; @@ -376,7 +373,7 @@ Module.prototype._compile = function(content, filename) { } require.resolve = function(request) { - return Module._resolveFilename(request, self)[1]; + return Module._resolveFilename(request, self); }; Object.defineProperty(require, 'paths', { get: function() { @@ -472,11 +469,11 @@ Module._extensions['.json'] = function(module, filename) { }; -//Native extension for .node +//Native extension for .node and OS-specific equivalents Module._extensions['.node'] = function(module, filename) { process.dlopen(filename, module.exports); }; - +Module._extensions['.dylib'] = Module._extensions['.node']; // bootstrap main module. Module.runMain = function() { diff --git a/lib/timers.js b/lib/timers.js index 7a57d34277..c5592bf0a2 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -81,7 +81,21 @@ function insert(item, msecs) { } else { L.remove(first); assert(first !== L.peek(list)); - if (first._onTimeout) first._onTimeout(); + + if (!first._onTimeout) continue; + + // v0.4 compatibility: if the timer callback throws and the user's + // uncaughtException handler ignores the exception, other timers that + // expire on this tick should still run. If #2582 goes through, this + // hack should be removed. + // + // https://github.com/joyent/node/issues/2631 + try { + first._onTimeout(); + } catch (e) { + if (!process.listeners('uncaughtException').length) throw e; + process.emit('uncaughtException', e); + } } } diff --git a/src/node.js b/src/node.js index 8ca0da48d0..4df1e711f8 100644 --- a/src/node.js +++ b/src/node.js @@ -297,8 +297,9 @@ process.__defineGetter__('stdout', function() { if (stdout) return stdout; stdout = createWritableStdioStream(1); - stdout.end = stdout.destroy = stdout.destroySoon = function() { - throw new Error('process.stdout cannot be closed'); + stdout.destroy = stdout.destroySoon = function(er) { + er = er || new Error('process.stdout cannot be closed.'); + stdout.emit('error', er); }; return stdout; }); @@ -306,8 +307,9 @@ process.__defineGetter__('stderr', function() { if (stderr) return stderr; stderr = createWritableStdioStream(2); - stderr.end = stderr.destroy = stderr.destroySoon = function() { - throw new Error('process.stderr cannot be closed'); + stderr.destroy = stderr.destroySoon = function(er) { + er = er || new Error('process.stderr cannot be closed.'); + stderr.emit('error', er); }; return stderr; }); diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index cab42b3c27..5f4b7eed19 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -95,7 +95,9 @@ public: static Handle AddMembership(const Arguments& args); static Handle DropMembership(const Arguments& args); static Handle SetMulticastTTL(const Arguments& args); + static Handle SetMulticastLoopback(const Arguments& args); static Handle SetBroadcast(const Arguments& args); + static Handle SetTTL(const Arguments& args); private: static inline char* NewSlab(v8::Handle global, v8::Handle wrap_obj); @@ -157,7 +159,9 @@ void UDPWrap::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "addMembership", AddMembership); NODE_SET_PROTOTYPE_METHOD(t, "dropMembership", DropMembership); NODE_SET_PROTOTYPE_METHOD(t, "setMulticastTTL", SetMulticastTTL); + NODE_SET_PROTOTYPE_METHOD(t, "setMulticastLoopback", SetMulticastLoopback); NODE_SET_PROTOTYPE_METHOD(t, "setBroadcast", SetBroadcast); + NODE_SET_PROTOTYPE_METHOD(t, "setTTL", SetTTL); target->Set(String::NewSymbol("UDP"), Persistent::New(t)->GetFunction()); @@ -214,20 +218,25 @@ Handle UDPWrap::Bind6(const Arguments& args) { return DoBind(args, AF_INET6); } -Handle UDPWrap::SetBroadcast(const Arguments& args) { - HandleScope scope; - UNWRAP - assert(args.Length() == 1); +#define X(name, fn) \ + Handle UDPWrap::name(const Arguments& args) { \ + HandleScope scope; \ + UNWRAP \ + assert(args.Length() == 1); \ + int flag = args[0]->Int32Value(); \ + int r = fn(&wrap->handle_, flag); \ + if (r) SetErrno(uv_last_error(uv_default_loop())); \ + return scope.Close(Integer::New(r)); \ + } - int on = args[0]->Uint32Value(); - int r = uv_udp_set_broadcast(&wrap->handle_, on); +X(SetTTL, uv_udp_set_ttl) +X(SetBroadcast, uv_udp_set_broadcast) +X(SetMulticastTTL, uv_udp_set_multicast_ttl) +X(SetMulticastLoopback, uv_udp_set_multicast_loop) - if (r) - SetErrno(uv_last_error(uv_default_loop())); +#undef X - return scope.Close(Integer::New(r)); -} Handle UDPWrap::SetMembership(const Arguments& args, uv_membership membership) { @@ -263,20 +272,6 @@ Handle UDPWrap::DropMembership(const Arguments& args) { return SetMembership(args, UV_LEAVE_GROUP); } -Handle UDPWrap::SetMulticastTTL(const Arguments& args) { - HandleScope scope; - UNWRAP - - assert(args.Length() == 1); - - int ttl = args[0]->Uint32Value(); - int r = uv_udp_set_multicast_ttl(&wrap->handle_, ttl); - - if (r) - SetErrno(uv_last_error(uv_default_loop())); - - return scope.Close(Integer::New(r)); -} Handle UDPWrap::DoSend(const Arguments& args, int family) { HandleScope scope; diff --git a/test/fixtures/catch-stdout-error.js b/test/fixtures/catch-stdout-error.js new file mode 100644 index 0000000000..6f96ae9e35 --- /dev/null +++ b/test/fixtures/catch-stdout-error.js @@ -0,0 +1,38 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function write() { + try { + process.stdout.write('Hello, world\n'); + } catch (ex) { + throw new Error('this should never happen'); + } + process.nextTick(function () { + write(); + }); +} + +process.stdout.on('error', function (er) { + console.error(JSON.stringify(er)); + process.exit(42); +}); + +write(); diff --git a/test/simple/test-dgram-broadcast-multi-process.js b/test/simple/test-dgram-broadcast-multi-process.js index d0a98aa1cf..7ef4070581 100644 --- a/test/simple/test-dgram-broadcast-multi-process.js +++ b/test/simple/test-dgram-broadcast-multi-process.js @@ -21,12 +21,13 @@ var common = require('../common'), assert = require('assert'), - cluster = require('cluster'), dgram = require('dgram'), util = require('util'), assert = require('assert'), Buffer = require('buffer').Buffer, + fork = require('child_process').fork, LOCAL_BROADCAST_HOST = '255.255.255.255', + TIMEOUT = 5000, messages = [ new Buffer('First message to send'), new Buffer('Second message to send'), @@ -34,21 +35,54 @@ var common = require('../common'), new Buffer('Fourth message to send') ]; -if (cluster.isMaster) { +if (process.argv[2] !== 'child') { var workers = {}, listeners = 3, listening = 0, + dead = 0, i = 0, - done = 0; + done = 0, + timer = null; + + //exit the test if it doesn't succeed within TIMEOUT + timer = setTimeout(function () { + console.error('[PARENT] Responses were not received within %d ms.', TIMEOUT); + console.error('[PARENT] Fail'); + + killChildren(workers); + + process.exit(1); + }, TIMEOUT); //launch child processes for (var x = 0; x < listeners; x++) { (function () { - var worker = cluster.fork(); + var worker = fork(process.argv[1], ['child']); workers[worker.pid] = worker; worker.messagesReceived = []; + //handle the death of workers + worker.on('exit', function (code, signal) { + //don't consider this the true death if the worker has finished successfully + //or if the exit code is 0 + if (worker.isDone || code == 0) { + return; + } + + dead += 1; + console.error('[PARENT] Worker %d died. %d dead of %d', worker.pid, dead, listeners); + + if (dead === listeners) { + console.error('[PARENT] All workers have died.'); + console.error('[PARENT] Fail'); + + killChildren(workers); + + process.exit(1); + } + }); + worker.on('message', function (msg) { if (msg.listening) { listening += 1; @@ -63,12 +97,13 @@ if (cluster.isMaster) { if (worker.messagesReceived.length === messages.length) { done += 1; - console.error('%d received %d messages total.', worker.pid, + worker.isDone = true; + console.error('[PARENT] %d received %d messages total.', worker.pid, worker.messagesReceived.length); } if (done === listeners) { - console.error('All workers have received the required number of ' + console.error('[PARENT] All workers have received the required number of ' + 'messages. Will now compare.'); Object.keys(workers).forEach(function (pid) { @@ -85,12 +120,16 @@ if (cluster.isMaster) { } }); - console.error('%d received %d matching messges.', worker.pid + console.error('[PARENT] %d received %d matching messges.', worker.pid , count); assert.equal(count, messages.length ,'A worker received an invalid multicast message'); }); + + clearTimeout(timer); + console.error('[PARENT] Success'); + killChildren(workers); } } }); @@ -103,7 +142,7 @@ if (cluster.isMaster) { sendSocket.setBroadcast(true); sendSocket.on('close', function() { - console.error('sendSocket closed'); + console.error('[PARENT] sendSocket closed'); }); sendSocket.sendNext = function() { @@ -119,20 +158,27 @@ if (cluster.isMaster) { if (err) throw err; - console.error('sent %s to %s:%s', util.inspect(buf.toString()) + console.error('[PARENT] sent %s to %s:%s', util.inspect(buf.toString()) , LOCAL_BROADCAST_HOST, common.PORT); process.nextTick(sendSocket.sendNext); }); }; + + function killChildren(children) { + Object.keys(children).forEach(function(key) { + var child = children[key]; + child.kill(); + }); + } } -if (!cluster.isMaster) { +if (process.argv[2] === 'child') { var receivedMessages = []; var listenSocket = dgram.createSocket('udp4'); listenSocket.on('message', function(buf, rinfo) { - console.error('%s received %s from %j', process.pid + console.error('[CHILD] %s received %s from %j', process.pid , util.inspect(buf.toString()), rinfo); receivedMessages.push(buf); @@ -140,16 +186,19 @@ if (!cluster.isMaster) { process.send({ message : buf.toString() }); if (receivedMessages.length == messages.length) { - listenSocket.dropMembership(LOCAL_BROADCAST_HOST); - process.nextTick(function() { // TODO should be changed to below. - // listenSocket.dropMembership(LOCAL_BROADCAST_HOST, function() { + process.nextTick(function () { listenSocket.close(); }); } }); listenSocket.on('close', function() { - process.exit(); + //HACK: Wait to exit the process to ensure that the parent + //process has had time to receive all messages via process.send() + //This may be indicitave of some other issue. + setTimeout(function() { + process.exit(); + }, 1000); }); listenSocket.on('listening', function() { diff --git a/test/simple/test-dgram-multicast-multi-process.js b/test/simple/test-dgram-multicast-multi-process.js index 784bb6c094..d6f1c4793d 100644 --- a/test/simple/test-dgram-multicast-multi-process.js +++ b/test/simple/test-dgram-multicast-multi-process.js @@ -21,12 +21,13 @@ var common = require('../common'), assert = require('assert'), - cluster = require('cluster'), dgram = require('dgram'), util = require('util'), assert = require('assert'), Buffer = require('buffer').Buffer, - LOCAL_BROADCAST_HOST = '224.0.0.1', + fork = require('child_process').fork, + LOCAL_BROADCAST_HOST = '224.0.0.114', + TIMEOUT = 5000, messages = [ new Buffer('First message to send'), new Buffer('Second message to send'), @@ -34,21 +35,55 @@ var common = require('../common'), new Buffer('Fourth message to send') ]; -if (cluster.isMaster) { +if (process.argv[2] !== 'child') { var workers = {}, listeners = 3, listening = 0, + dead = 0, i = 0, - done = 0; + done = 0, + timer = null; + + //exit the test if it doesn't succeed within TIMEOUT + timer = setTimeout(function () { + console.error('[PARENT] Responses were not received within %d ms.', TIMEOUT); + console.error('[PARENT] Fail'); + + killChildren(workers); + + process.exit(1); + }, TIMEOUT); //launch child processes for (var x = 0; x < listeners; x++) { (function () { - var worker = cluster.fork(); + var worker = fork(process.argv[1], ['child']); workers[worker.pid] = worker; worker.messagesReceived = []; + //handle the death of workers + worker.on('exit', function (code, signal) { + //don't consider this the true death if the worker has finished successfully + + //or if the exit code is 0 + if (worker.isDone || code === 0) { + return; + } + + dead += 1; + console.error('[PARENT] Worker %d died. %d dead of %d', worker.pid, dead, listeners); + + if (dead === listeners) { + console.error('[PARENT] All workers have died.'); + console.error('[PARENT] Fail'); + + killChildren(workers); + + process.exit(1); + } + }); + worker.on('message', function (msg) { if (msg.listening) { listening += 1; @@ -63,12 +98,13 @@ if (cluster.isMaster) { if (worker.messagesReceived.length === messages.length) { done += 1; - console.error('%d received %d messages total.', worker.pid, + worker.isDone = true; + console.error('[PARENT] %d received %d messages total.', worker.pid, worker.messagesReceived.length); } if (done === listeners) { - console.error('All workers have received the required number of' + console.error('[PARENT] All workers have received the required number of ' + 'messages. Will now compare.'); Object.keys(workers).forEach(function (pid) { @@ -85,12 +121,16 @@ if (cluster.isMaster) { } }); - console.error('%d received %d matching messges.', worker.pid + console.error('[PARENT] %d received %d matching messages.', worker.pid , count); assert.equal(count, messages.length ,'A worker received an invalid multicast message'); }); + + clearTimeout(timer); + console.error('[PARENT] Success'); + killChildren(workers); } } }); @@ -98,13 +138,17 @@ if (cluster.isMaster) { } var sendSocket = dgram.createSocket('udp4'); + sendSocket.bind(); // FIXME a libuv limitation makes it necessary to bind() + // before calling any of the set*() functions - the bind() + // call is what creates the actual socket... - //sendSocket.setBroadcast(true); - //sendSocket.setMulticastTTL(1); - //sendSocket.setMulticastLoopback(true); + sendSocket.setTTL(1); + sendSocket.setBroadcast(true); + sendSocket.setMulticastTTL(1); + sendSocket.setMulticastLoopback(true); sendSocket.on('close', function() { - console.error('sendSocket closed'); + console.error('[PARENT] sendSocket closed'); }); sendSocket.sendNext = function() { @@ -118,21 +162,26 @@ if (cluster.isMaster) { sendSocket.send(buf, 0, buf.length, common.PORT, LOCAL_BROADCAST_HOST, function(err) { if (err) throw err; - console.error('sent %s to %s', util.inspect(buf.toString()), - LOCAL_BROADCAST_HOST + common.PORT); + console.error('[PARENT] sent %s to %s:%s', util.inspect(buf.toString()), + LOCAL_BROADCAST_HOST, common.PORT); process.nextTick(sendSocket.sendNext); }); }; + + function killChildren(children) { + Object.keys(children).forEach(function(key) { + var child = children[key]; + child.kill(); + }); + } } -if (!cluster.isMaster) { +if (process.argv[2] === 'child') { var receivedMessages = []; var listenSocket = dgram.createSocket('udp4'); - listenSocket.addMembership(LOCAL_BROADCAST_HOST); - listenSocket.on('message', function(buf, rinfo) { - console.error('%s received %s from %j', process.pid + console.error('[CHILD] %s received %s from %j', process.pid ,util.inspect(buf.toString()), rinfo); receivedMessages.push(buf); @@ -141,6 +190,7 @@ if (!cluster.isMaster) { if (receivedMessages.length == messages.length) { listenSocket.dropMembership(LOCAL_BROADCAST_HOST); + process.nextTick(function() { // TODO should be changed to below. // listenSocket.dropMembership(LOCAL_BROADCAST_HOST, function() { listenSocket.close(); @@ -149,7 +199,12 @@ if (!cluster.isMaster) { }); listenSocket.on('close', function() { - process.exit(); + //HACK: Wait to exit the process to ensure that the parent + //process has had time to receive all messages via process.send() + //This may be indicitave of some other issue. + setTimeout(function () { + process.exit(); + }, 1000); }); listenSocket.on('listening', function() { @@ -157,4 +212,6 @@ if (!cluster.isMaster) { }); listenSocket.bind(common.PORT); + + listenSocket.addMembership(LOCAL_BROADCAST_HOST); } diff --git a/test/simple/test-dgram-multicast-setTTL.js b/test/simple/test-dgram-multicast-setTTL.js index a2207a78d0..cb870efdcf 100644 --- a/test/simple/test-dgram-multicast-setTTL.js +++ b/test/simple/test-dgram-multicast-setTTL.js @@ -35,7 +35,7 @@ try { thrown = true; } -assert(thrown, 'Setting an invalid mutlicast TTL should throw some error'); +assert(thrown, 'Setting an invalid multicast TTL should throw some error'); //close the socket -socket.close(); \ No newline at end of file +socket.close(); diff --git a/test/simple/test-http-expect-continue.js b/test/simple/test-http-expect-continue.js index 3c3980a0ac..54c04cce0e 100644 --- a/test/simple/test-http-expect-continue.js +++ b/test/simple/test-http-expect-continue.js @@ -44,7 +44,9 @@ server.on('checkContinue', function(req, res) { common.debug('Server got Expect: 100-continue...'); res.writeContinue(); sent_continue = true; - handler(req, res); + setTimeout(function() { + handler(req, res); + }, 100); }); server.listen(common.PORT); diff --git a/test/simple/test-stdout-close-catch.js b/test/simple/test-stdout-close-catch.js new file mode 100644 index 0000000000..a8373c4047 --- /dev/null +++ b/test/simple/test-stdout-close-catch.js @@ -0,0 +1,56 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common'); +var assert = require('assert'); +var path = require('path'); +var child_process = require('child_process'); +var fs = require('fs'); + +var testScript = path.join(common.fixturesDir, 'catch-stdout-error.js'); + +var cmd = JSON.stringify(process.execPath) + ' ' + + JSON.stringify(testScript) + ' | ' + + JSON.stringify(process.execPath) + ' ' + + '-pe "process.exit(1);"'; + +var child = child_process.exec(cmd); +var output = ''; +var outputExpect = { 'code': 'EPIPE', + 'errno': 'EPIPE', + 'syscall': 'write' }; + +child.stderr.on('data', function (c) { + output += c; +}); + +child.on('exit', function(code) { + try { + output = JSON.parse(output); + } catch (er) { + console.error(output); + process.exit(1); + } + + assert.deepEqual(output, outputExpect); + console.log('ok'); +}); diff --git a/test/simple/test-timers-uncaught-exception.js b/test/simple/test-timers-uncaught-exception.js new file mode 100644 index 0000000000..0d2f488df0 --- /dev/null +++ b/test/simple/test-timers-uncaught-exception.js @@ -0,0 +1,52 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var exceptions = 0; +var timer1 = 0; +var timer2 = 0; + +// the first timer throws... +setTimeout(function() { + timer1++; + throw new Error('BAM!'); +}, 100); + +// ...but the second one should still run +setTimeout(function() { + assert.equal(timer1, 1); + timer2++; +}, 100); + +function uncaughtException(err) { + assert.equal(err.message, 'BAM!'); + exceptions++; +} +process.on('uncaughtException', uncaughtException); + +process.on('exit', function() { + process.removeListener('uncaughtException', uncaughtException); + assert.equal(exceptions, 1); + assert.equal(timer1, 1); + assert.equal(timer2, 1); +}); diff --git a/test/simple/test-tty-stdout-end.js b/test/simple/test-tty-stdout-end.js index 7c7f7feb2b..1fc2790683 100644 --- a/test/simple/test-tty-stdout-end.js +++ b/test/simple/test-tty-stdout-end.js @@ -30,7 +30,7 @@ try { } catch (e) { exceptionCaught = true; assert.ok(common.isError(e)); - assert.equal('process.stdout cannot be closed', e.message); + assert.equal('process.stdout cannot be closed.', e.message); } assert.ok(exceptionCaught); diff --git a/tools/doctool/doctool.js b/tools/doctool/doctool.js index 634d82c921..85acad2a36 100644 --- a/tools/doctool/doctool.js +++ b/tools/doctool/doctool.js @@ -42,7 +42,11 @@ function generateToc(data) { } if (level > last_level) { - toc.push("
    "); + var c = last_level - level; + do { + toc.push("
      "); + c ++; + } while (c < -1); } else if (level < last_level) { for(var c=last_level-level; 0 < c ; c-- ) { toc.push("
    "); @@ -61,7 +65,7 @@ function generateToc(data) { toc.push("
"); } - toc.push("
") + toc.push("
") toc.push(""); return toc.join(""); @@ -89,8 +93,14 @@ function convertData(data) { .replace(/(\([^<]+)(\<\/h[1-6]\>)/gmi, function(o, ts, c, te) { return ts+' id="'+formatIdString(c)+'">'+c+te; }) - .replace(/(\]+\>)([^<]+)(\<\/h[3-4]\>)/gmi, function(o, ts, c, te) { - return ts+c+' #'+te; + .replace(/(\]+\>)([^<]+)(\<\/h[2-4]\>)/gmi, + function(o, ts, c, te) { + var mark = ' ' + + '' + + '#'; + + return ts+c+mark+te; }); return html; @@ -119,6 +129,9 @@ if (argc > 3) { output = output.replace("{{section}}", filename+" - ") } else { + if (filename === "index") { + html = '
' + html + '
'; + } output = output.replace("{{section}}", ""); output = output.replace(/]*)>/, ''); }