diff --git a/.gitignore b/.gitignore index 48513041d2..6eb3b0a398 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ - +core +vgcore.* .waf* tags .lock-wscript diff --git a/AUTHORS b/AUTHORS index 1fa19d3b27..51e0c7dba7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -235,3 +235,12 @@ Jacob H.C. Kragh Benjamin Pasero Scott Anderson Yoji SHIDARA +Mathias Bynens +Łukasz Walukiewicz +Artur Adib +E. Azer Koçulu +Roman Shtylman +Kyle Robinson Young +Tim Oxley +Ingmar Runge +Russ Bradberry diff --git a/ChangeLog b/ChangeLog index 9a544f0ea1..cccdbf2a24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,27 @@ -2011.12.04, Version 0.6.5 (stable) +2011.12.14, Version 0.6.6 (stable) + +* npm update to 1.1.0-beta-4 (Isaac Z. Schlueter) + +* cli: fix output of --help (Ben Noordhuis) + +* new website + +* pause/resume semantics for stdin (Isaac Z. Schlueter) + +* Travis CI integration (Maciej Małecki) + +* child_process: Fix bug regarding closed stdin (Ben Noordhuis) + +* Enable upgrades in MSI. (Igor Zinkovsky) + +* net: Fixes memory leak (Ben Noordhuis) + +* fs: handle fractional or NaN ReadStream buffer size (Ben Noordhuis) + +* crypto: fix memory leaks in PBKDF2 error path (Ben Noordhuis) + + +2011.12.04, Version 0.6.5 (stable), 6cc94db653a2739ab28e33b2d6a63c51bd986a9f * npm workaround Windows antivirus software (isaacs) diff --git a/Makefile b/Makefile index bf10701be3..b195f2e66a 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ test-internet: all apidoc_sources = $(wildcard doc/api/*.markdown) apidocs = $(addprefix out/,$(apidoc_sources:.markdown=.html)) -apidoc_dirs = out/doc out/doc/api/ out/doc/api/assets +apidoc_dirs = out/doc out/doc/api/ out/doc/api/assets out/doc/about out/doc/community out/doc/logos apiassets = $(subst api_assets,api/assets,$(addprefix out/,$(wildcard doc/api_assets/*))) @@ -75,8 +75,22 @@ website_files = \ out/doc/sh_vim-dark.css \ out/doc/logo.png \ out/doc/sponsored.png \ - out/doc/favicon.ico \ - out/doc/pipe.css + 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/download-logo.png \ + out/doc/ebay-logo.png \ + out/doc/footer-logo.png \ + out/doc/icons.png \ + out/doc/linkedin-logo.png \ + out/doc/logos/index.html \ + out/doc/microsoft-logo.png \ + out/doc/platform-icons.png \ + out/doc/ryan-speaker.jpg \ + out/doc/yahoo-logo.png doc: out/Release/node $(apidoc_dirs) $(website_files) $(apiassets) $(apidocs) @@ -95,7 +109,7 @@ out/doc/api/%.html: doc/api/%.markdown out/Release/node $(apidoc_dirs) $(apiasse out/doc/%: website-upload: doc - scp -r out/doc/* $(web_root) + rsync -r out/doc/ node@nodejs.org:~/web/nodejs.org/ docopen: out/doc/api/all.html -google-chrome out/doc/api/all.html diff --git a/deps/npm/.gitmodules b/deps/npm/.gitmodules index c705633663..169c87505c 100644 --- a/deps/npm/.gitmodules +++ b/deps/npm/.gitmodules @@ -36,19 +36,25 @@ url = https://github.com/mikeal/request.git [submodule "node_modules/tar"] path = node_modules/tar - url = git://github.com/isaacs/node-tar.git + url = https://github.com/isaacs/node-tar.git [submodule "node_modules/fstream"] path = node_modules/fstream - url = git://github.com/isaacs/fstream.git + url = https://github.com/isaacs/fstream.git [submodule "node_modules/inherits"] path = node_modules/inherits - url = git://github.com/isaacs/inherits.git + url = https://github.com/isaacs/inherits.git [submodule "node_modules/block-stream"] path = node_modules/block-stream - url = git://github.com/isaacs/block-stream.git + url = https://github.com/isaacs/block-stream.git [submodule "node_modules/mkdirp"] path = node_modules/mkdirp - url = git://github.com/isaacs/node-mkdirp.git + url = https://github.com/isaacs/node-mkdirp.git [submodule "node_modules/fast-list"] path = node_modules/fast-list - url = git://github.com/isaacs/fast-list.git + url = https://github.com/isaacs/fast-list.git +[submodule "node_modules/read"] + path = node_modules/read + url = https://github.com/isaacs/read.git +[submodule "node_modules/lru-cache"] + path = node_modules/lru-cache + url = https://github.com/isaacs/node-lru-cache.git diff --git a/deps/npm/.travis.yml b/deps/npm/.travis.yml new file mode 100644 index 0000000000..698bc9abdf --- /dev/null +++ b/deps/npm/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +before_install: "make &>out || cat out; rm out" +node_js: + - 0.6 diff --git a/deps/npm/Makefile b/deps/npm/Makefile index e10381baf7..20686da009 100644 --- a/deps/npm/Makefile +++ b/deps/npm/Makefile @@ -110,7 +110,7 @@ version: link publish: link git tag -s -m v$(shell npm -v) v$(shell npm -v) &&\ - git push origin master --tags &&\ + git push origin --tags &&\ npm publish &&\ make doc-publish diff --git a/deps/npm/bin/npm-cli.js b/deps/npm/bin/npm-cli.js index db6db2fbd2..e0b9f20bb8 100755 --- a/deps/npm/bin/npm-cli.js +++ b/deps/npm/bin/npm-cli.js @@ -12,6 +12,9 @@ if (typeof WScript !== "undefined") { return } + +process.title = "npm" + var log = require("../lib/utils/log.js") log.waitForConfig() log.info("ok", "it worked if it ends with") diff --git a/deps/npm/doc/cli/config.md b/deps/npm/doc/cli/config.md index e380e65eff..e70acc258a 100644 --- a/deps/npm/doc/cli/config.md +++ b/deps/npm/doc/cli/config.md @@ -225,6 +225,14 @@ The location of npm's cache directory. See `npm-cache(1)` If false, never shows colors. If `"always"` then always shows colors. If true, then only prints color codes for tty file descriptors. +### coverage + +* Default: false +* Type: Boolean + +A flag to tell test-harness to run with their coverage options enabled, +if they respond to the `npm_config_coverage` environment variable. + ### depth * Default: Infinity @@ -379,13 +387,16 @@ The location to write log output. ### loglevel -* Default: "warn" +* Default: "http" * Type: String -* Values: "silent", "win", "error", "warn", "info", "verbose", "silly" +* Values: "silent", "win", "error", "warn", "http", "info", "verbose", "silly" What level of logs to report. On failure, *all* logs are written to `npm-debug.log` in the current working directory. +Any logs of a higher level than the setting are shown. +The default is "http", which shows http, warn, and error output. + ### logprefix * Default: true on Posix, false on Windows @@ -537,6 +548,16 @@ Space-separated options that are always passed to search. Space-separated options that limit the results from search. +### searchsort + +* Default: "name" +* Type: String +* Values: "name", "-name", "date", "-date", "description", + "-description", "keywords", "-keywords" + +Indication of which field to sort search results by. Prefix with a `-` +character to indicate reverse sort. + ### shell * Default: SHELL environment variable, or "bash" on Posix, or "cmd" on diff --git a/deps/npm/doc/cli/developers.md b/deps/npm/doc/cli/developers.md index 0f0f94c588..9123f35a33 100644 --- a/deps/npm/doc/cli/developers.md +++ b/deps/npm/doc/cli/developers.md @@ -150,8 +150,8 @@ You can give publish a url to a tarball, or a filename of a tarball, or a path to a folder. Note that pretty much **everything in that folder will be exposed** -by default. So, if you have secret stuff in there, use a `.npminclude` -or `.npmignore` file to list out the globs to include/ignore, or publish +by default. So, if you have secret stuff in there, use a +`.npmignore` file to list out the globs to ignore, or publish from a fresh checkout. ## Brag about it diff --git a/deps/npm/doc/cli/search.md b/deps/npm/doc/cli/search.md index 3b15e9b073..e9e408c677 100644 --- a/deps/npm/doc/cli/search.md +++ b/deps/npm/doc/cli/search.md @@ -9,28 +9,9 @@ npm-search(1) -- Search for packages Search the registry for packages matching the search terms. -## CONFIGURATION - -### description - -* Default: true -* Type: Boolean - -Show the description in `npm search` - -### searchopts - -* Default: "" -* Type: String - -Space-separated options that are always passed to search. - -### searchexclude - -* Default: "" -* Type: String - -Space-separated options that limit the results from search. +If a term starts with `/`, then it's interpreted as a regular expression. +A trailing `/` will be ignored in this case. (Note that many regular +expression characters must be escaped or quoted in most shells.) ## SEE ALSO diff --git a/deps/npm/html/api/bin.html b/deps/npm/html/api/bin.html index accd17cc85..599096912c 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/api/fs.markdown b/doc/api/fs.markdown index 76ae6a2463..445fd59c2b 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -170,12 +170,14 @@ the completion callback. Synchronous link(2). -### fs.symlink(linkdata, path, [callback]) +### fs.symlink(linkdata, path, [type], [callback]) Asynchronous symlink(2). No arguments other than a possible exception are given to the completion callback. +`type` argument can be either `'dir'` or `'file'` (default is `'file'`). It is only +used on Windows (ignored on other platforms). -### fs.symlinkSync(linkdata, path) +### fs.symlinkSync(linkdata, path, [type]) Synchronous symlink(2). diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 8ed79ebc1c..330ea27710 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -103,16 +103,18 @@ IPv4 address (`INADDR_ANY`). To listen to a unix socket, supply a filename instead of port and hostname. -This function is asynchronous. The last parameter `callback` will be called -when the server has been bound to the port. +This function is asynchronous. The last parameter `callback` will be added as +a listener for the ['listening'](net.html#event_listening_) event. +See also [net.Server.listen()](net.html#server.listen). ### server.listen(path, [callback]) Start a UNIX socket server listening for connections on the given `path`. -This function is asynchronous. The last parameter `callback` will be called -when the server has been bound. +This function is asynchronous. The last parameter `callback` will be added as +a listener for the ['listening'](net.html#event_listening_) event. +See also [net.Server.listen()](net.html#server.listen). ### server.close() diff --git a/doc/api/util.markdown b/doc/api/util.markdown index 2430d8a70d..ee0622ae5e 100644 --- a/doc/api/util.markdown +++ b/doc/api/util.markdown @@ -50,7 +50,7 @@ Output with timestamp on `stdout`. require('util').log('Timestamped message.'); -### util.inspect(object, showHidden=false, depth=2) +### util.inspect(object, showHidden=false, depth=2, colors=false) Return a string representation of `object`, which is useful for debugging. @@ -63,6 +63,8 @@ formatting the object. This is useful for inspecting large complicated objects. The default is to only recurse twice. To make it recurse indefinitely, pass in `null` for `depth`. +If `colors` is `true`, the output will be styled with ANSI color codes. + Example of inspecting all properties of the `util` object: var util = require('util'); diff --git a/doc/close-downloads.png b/doc/close-downloads.png new file mode 100644 index 0000000000..ba72523f7b Binary files /dev/null and b/doc/close-downloads.png differ diff --git a/doc/community/index.html b/doc/community/index.html new file mode 100644 index 0000000000..5348c875d9 --- /dev/null +++ b/doc/community/index.html @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + 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. + + +

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 contirbuting + 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.

+ +

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/community/not-invented-here.png b/doc/community/not-invented-here.png new file mode 100644 index 0000000000..5d4efa0532 Binary files /dev/null and b/doc/community/not-invented-here.png differ diff --git a/doc/download-logo.png b/doc/download-logo.png new file mode 100644 index 0000000000..253235f4c3 Binary files /dev/null and b/doc/download-logo.png differ diff --git a/doc/ebay-logo.png b/doc/ebay-logo.png new file mode 100644 index 0000000000..8cb3db006d Binary files /dev/null and b/doc/ebay-logo.png differ diff --git a/doc/footer-logo.png b/doc/footer-logo.png new file mode 100644 index 0000000000..19a4eaadcb Binary files /dev/null and b/doc/footer-logo.png differ diff --git a/doc/full-white-stripe.bmp b/doc/full-white-stripe.bmp new file mode 100644 index 0000000000..bb2bf9c493 Binary files /dev/null and b/doc/full-white-stripe.bmp differ diff --git a/doc/icons.png b/doc/icons.png new file mode 100644 index 0000000000..421dfdaf11 Binary files /dev/null and b/doc/icons.png differ diff --git a/doc/index.html b/doc/index.html index d0829b83a3..95c3aeeb77 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,5 +1,5 @@ - - + + - - - - - - + + + + - + href="http://feeds.feedburner.com/nodejs/123123123"> + node.js - -
+
+ - -

- +

Node.js is a platform built on Chrome's JavaScript runtime + for easily building fast, scalable network applications. Node.js + uses an event-driven, non-blocking I/O model that makes it + lightweight and efficient, perfect for data-intensive real-time + applications that run across distributed devices.

-

- Evented I/O for - V8 JavaScript. -

+ Download +
+
+

Node.js in the Industry

+
    +
  • +

    Node gives Azure users the first end-to-end JavaScript + experience for the development of a whole new class of real-time + applications. +
    + Claudio Caldato +
    + Principal Program Manager, Interoperability Strategy

  • + +
  • +

    Node’s evented I/O model freed us from worrying about locking + and concurrency issues that are common with multithreaded async + I/O. +
    + Subbu Allamarju +
    + Principal Member, Technical Staff

  • + +
  • +

    On the server side, our entire mobile software stack is + completely built in Node. One reason was scale. The second is + Node showed us huge performance gains. +
    + Kiran Prasad +
    + Director of Engineering, Mobile

  • + +
  • +

    Node.js is the execution core of Manhattan. Allowing + developers to build one code base using one language – that is + the nirvana for developers. +
    + Renaud Waldura +
    + Sr. Product Manger, Cocktail

  • +
+
-

- An example of a web server written in Node which responds with - "Hello World" for every request. -

+
+ X + + + +
-
+    
+
+    
+
+

An example: Webserver

+

This simple web server written in Node responds with "Hello World" for every request.

+
 var http = require('http');
 http.createServer(function (req, res) {
   res.writeHead(200, {'Content-Type': 'text/plain'});
   res.end('Hello World\n');
 }).listen(1337, "127.0.0.1");
-console.log('Server running at http://127.0.0.1:1337/');
-
- -

- To run the server, put the code into a file - example.js and execute it with the node - program: -

-
+console.log('Server running at http://127.0.0.1:1337/');
+ +

To run the server, put the code into a file example.js and execute it with the node program:

+
 % node example.js
 Server running at http://127.0.0.1:1337/
-

- Here is an example of a simple TCP server which listens on port 1337 - and echoes whatever you send it: -

+

Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:

-
+                
 var net = require('net');
 
 var server = net.createServer(function (socket) {
@@ -84,146 +171,36 @@ var server = net.createServer(function (socket) {
   socket.pipe(socket);
 });
 
-server.listen(1337, "127.0.0.1");
-
- -

- See the API documentation for more - examples. -

- - -

- Go to the Wiki for lots more information. -

- -

Introduction

- - - -

Download

- -

2011.12.04 v0.6.5 -

- - -

Historical: versions, docs

- -

- git repository -

- - -

About

- -

- Node's goal is to provide an easy way to build scalable network - programs. In the "hello world" web server example above, many - client connections can be handled concurrently. Node tells the - operating system (through epoll, kqueue, - /dev/poll, or select) - that it should be notified when a new connection is made, and - then it goes to sleep. If someone new connects, then it executes - the callback. Each connection is only a small heap allocation. -

- -

- This is in contrast to today's more common concurrency model where - OS threads are employed. Thread-based networking is relatively - inefficient and very difficult to use. See: - this and - this. - - Node will show much better memory efficiency under high-loads - - than systems which allocate 2mb thread stacks for each connection. - - Furthermore, users of Node are free from worries of dead-locking - the process—there are no locks. Almost no function in Node - directly performs I/O, so the process never blocks. Because - nothing blocks, less-than-expert programmers are able to develop - fast systems. -

- -

- Node is similar in design to and influenced by systems like Ruby's Event Machine or Python's Twisted. Node takes the event - model a bit further—it presents the event loop as a language - construct instead of as a library. In other systems there is always - a blocking call to start the event-loop. Typically one defines - behavior through callbacks at the beginning of a script and at the - end starts a server through a blocking call like - EventMachine::run(). In Node there is no such - start-the-event-loop call. Node simply enters the event loop after - executing the input script. Node exits the event loop when there are - no more callbacks to perform. This behavior is like browser - javascript—the event loop is hidden from the user. -

- -

- HTTP is a first class protocol in Node. Node's HTTP library has - grown out of the author's experiences developing and working with - web servers. For example, streaming data through most web frameworks - is impossible. Node attempts to correct these problems in its HTTP - parser - and API. Coupled with Node's purely evented infrastructure, it makes - a good foundation for web libraries or frameworks. -

- -

- - But what about multiple-processor concurrency? Aren't threads - necessary to scale programs to multi-core computers? - - You can start new processes via - child_process.fork() - these other processes will be scheduled in parallel. - For load balancing incoming connections across multiple processes - use the - cluster module -

- -

- See also: -

    -
  • slides from JSConf 2009
  • -
  • slides from JSConf 2010
  • -
  • video from a talk at Yahoo in May 2010
  • -
-

- - +server.listen(1337, "127.0.0.1");
+ + +
+
+

Featured

+ + A guided introduction to Node + +

Explore Node.js

+
+
-
- JS String match + - - -
- Copyright 2010 Joyent, Inc -
- Node.js is a trademark of Joyent, Inc. - See the trademark policy - for more information. -
+ + + - + } catch(err) {} + diff --git a/doc/linkedin-logo.png b/doc/linkedin-logo.png new file mode 100644 index 0000000000..2ad9fb2c0c Binary files /dev/null and b/doc/linkedin-logo.png differ diff --git a/doc/logo.png b/doc/logo.png index 4ca766d486..ef3494efa8 100644 Binary files a/doc/logo.png and b/doc/logo.png differ diff --git a/doc/logos/index.html b/doc/logos/index.html index 0d9d2a3f91..250cd72750 100644 --- a/doc/logos/index.html +++ b/doc/logos/index.html @@ -1,82 +1,79 @@ - - + + + + - - - + + + - - - Node.js Logos + + + 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

- - - - - - - - - - - - - - - - - -
Node.js darkNode.js dark
Node.js standard EPSNode.js reversed EPS
Node.js darkNode.js dark
Node.js bright EPSNode.js 1 color EPS
-

Desktop Background

-

Screensavers

-

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

- -

 

-

- - + +
+
+
+
+

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

+ + + + + + + + + + + + + + + + + +
Node.js darkNode.js dark
Node.js standard EPSNode.js reversed EPS
Node.js darkNode.js dark
Node.js bright EPSNode.js 1 color EPS
+

Desktop Background

+

Screensavers

+

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

+
+
+
+
+ - -
- Copyright 2010 Joyent, Inc -
- Node.js is a trademark of Joyent, Inc. - See the trademark policy - for more information. -
+ - - + } catch(err) {} + + diff --git a/doc/microsoft-logo.png b/doc/microsoft-logo.png new file mode 100644 index 0000000000..6dac0f39b6 Binary files /dev/null and b/doc/microsoft-logo.png differ diff --git a/doc/pipe.css b/doc/pipe.css index 4f576e7aea..b1ed7584a1 100644 --- a/doc/pipe.css +++ b/doc/pipe.css @@ -3,80 +3,313 @@ html { } body { - background: #353129; + background: #46483e; color: #eee; - font-size: 14pt; - line-height: 150%; - font-family: Georgia, "Times New Roman", Times, serif; - max-width: 30em; - margin: 0 0 5em 9em; + font-size: 12px; + line-height: 180%; + font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Verdana, Tahoma, sans-serif; + margin: 0; + padding-top: 40px; + border-top: 6px #8cc84b solid; } + img { border: 0; } -#toc { - position: absolute; - top: 2em; - left: 0; - width: 10em; - font-family: Helvetica, Arial, sans-serif; - font-size: 12pt; - line-height: 150%; -} @media all and (min-height: 650px) { #toc { position: fixed; }} #toctitle { display: none; } -#toc ol { - list-style: none; -} -#toc ol, .toclevel2 { - margin: 0; - padding: 0; - padding-left: 1em; -} -#toc ol li { - margin: 0; - padding: 0; -} -#toc a { - color: #8BC84B; -} - h1, h2, h3, h4 { - color: #CCD2BC; + color: #d2d8ba; font-family: Helvetica, Arial, sans-serif; margin-top: 2em; margin-right: 0; margin-bottom: 10px; margin-left: 0; + text-transform: uppercase; +} + +h2 { + font-size: 12px; + font-weight: normal; +} + +h1 code, h2 code, h3 code, h4 code, +h1 a, h2 a, h3 a, h4 a +{ + color: inherit; + font-size: inherit; +} + +#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: -1000px -1000px; +} + +#intro p { + width: 680px; + line-height: 180%; + padding-top: 30px; + margin: 0 auto 30px auto; + font-size: 14px; +} + +#intro #downloadbutton { + background-color: #8BC84B; + color: #46483e; + font-weight: bold; + font-size: 14px; + text-transform: uppercase; + padding: 7px 10px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + + +#intro #downloadbutton:hover { + text-decoration: none; + background-color: #73a53e; +} + +#quotes { + text-align: center; + width: 100%; + background-color: #33342d; + margin-top: 40px; + padding-top: 20px; + padding-bottom: 20px; +} + +#quotes h2 { + margin-top: 0; +} + +#quotes ul { + display: block; + width: 775px; + margin: 0 auto; + padding-top: 20px; +} + +#quotes ul li { + display: block; + text-align: left; + width: 180px; + float: left; + padding-right: 15px; + font-size: 11px; +} + +#quotes ul li.ebay { + margin-top: -10px; +} + +#quotes ul li.linkedin { + margin-top: -4px; +} + +#quotes ul li.yahoo { + margin-top: -4px; + padding-right: 0; +} + +#quotes ul li p span { + font-size: 10px; +} + +#content { + width: 775px; + margin: 0 auto; +} + +#content #column1 { + width: 420px; + float: left; +} + +#content #column2 { + width: 260px; + float: right; +} + +#content #column1.interior { + width: 510px; + float: right; } -#toc ol ol { - font-size: 8pt; - line-height: 110%; - list-style: circle; +#content #column2.interior { } -h1 code, h2 code, h3 code, h4 code, -h1 a, h2 a, h3 a, h4 a -{ - color: inherit; - font-size: inherit; +#explore { + background: url(icons.png) no-repeat left 15px; +} + +#explore li { + list-style-type: none; + color: #d2d8ba; + line-height: 14px; + padding: 10px 0 10px 40px; + border-top: 1px solid #626557; +} + +#explore li span { +} + +#explore li a.explore { + text-transform: uppercase; +} + +#explore ol.jobs { + padding: 0; +} + +#explore ol.jobs li { + display: inline; + padding: 0; + border: none; +} + +#explore ol.jobs li:after { + content: ', '; +} + +#explore ol.jobs li:last-child:after { + content: ''; +} + +#footer { + width: 775px; + border-top: 1px solid #626557; + margin: 50px auto 30px auto; + padding-top: 15px; +} + +#footer p { + color: #8BC84B; + height: 32px; + padding-top: 3px; + background: url(footer-logo.png) left top no-repeat; + padding-left: 130px; +} + +#footer p a { + text-decoration: underline; +} + +div#download { + position: absolute; + width: 580px; + text-align: center; + top: 0; + left: 50%; + margin-left: -290px; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + padding-top: 40px; + -webkit-box-shadow: 0 0 32px #000; + -moz-box-shadow: 0 0 32px #000; + box-shadow: 0 0 32px #000; + background:white; + display: none; +} + +div#download:target { + display: block; +} + +#download-close { + background: url(close-downloads.png) no-repeat top right; + width: 64px; + height: 64px; + position: absolute; + display: block; + top:0; + right:0; + text-indent:-999em; +} + +div#download ul#installers { + width: 550px; + text-align: center; + margin: 0 auto; + background: url(platform-icons.png) no-repeat top center; + padding-top: 65px; + padding-bottom: 50px; +} + +div#download ul#installers li { + list-style-type: none; + width: 165px; + padding-left: 18px; + float: left; + display: block; + color: #33342d; + font-size: 10px; +} + +div#download ul#installers li#source { + padding-left: 0; +} + +div#download ul#installers li a { + font-size: 16px; + padding-top: 50px; + margin-top: -50px; +} + +div#download ul#documentation { + background-color: #d4d7c3; + padding: 20px 0 20px 40px; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} + +div#download ul#documentation li { + margin-left: 40px; + text-align: left; + color: #33342d; + font-size: 14px; + font-weight: bold; + padding-bottom: 5px; +} + +div#download ul#documentation li a { + color: #76a83f; +} + +#download-logo { + margin-bottom: 37px; } pre, code { font-family: Monaco, 'Andale Mono', 'Lucida Console', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; - ; - font-size: 11pt; - color: #C3CC88; + font-size: 12px; + color: #d2d8ba; } pre { padding-left: 1em; + margin-left: -1em; border-left-width: 1px; border-left-style: solid; - border-left-color: #8BC84B; + border-left-color: #626557; } dd { @@ -95,9 +328,20 @@ a:hover { text-decoration: underline; } padding: 0.2em 0; } .desktops { - font-size: 14px; + font-size: 12px; } .release { margin: 0 0 0 2em; } + +/* simpler clearfix */ +.clearfix { + /* be an independent layout island */ + overflow:hidden; + /* but don't actually cut anything off */ + height:auto; + /* trigger hasLayout in IE */ + zoom:1; + /* fin. */ +} diff --git a/doc/platform-icons.png b/doc/platform-icons.png new file mode 100644 index 0000000000..d6624a5a64 Binary files /dev/null and b/doc/platform-icons.png differ diff --git a/doc/ryan-speaker.jpg b/doc/ryan-speaker.jpg new file mode 100644 index 0000000000..c0f6263441 Binary files /dev/null and b/doc/ryan-speaker.jpg differ diff --git a/doc/sh_vim-dark.css b/doc/sh_vim-dark.css index 34a526c533..59b3021572 100644 --- a/doc/sh_vim-dark.css +++ b/doc/sh_vim-dark.css @@ -15,7 +15,7 @@ .sh_sourceCode .sh_string, .sh_sourceCode .sh_regexp, .sh_sourceCode .sh_number, .sh_sourceCode .sh_specialchar { - color: #B9CCC5; + color: #a0c874; } .sh_sourceCode .sh_comment { diff --git a/doc/template.html b/doc/template.html index 377cae8b3c..60826dcab2 100644 --- a/doc/template.html +++ b/doc/template.html @@ -1,20 +1,20 @@ - - {{section}}Node.js v0.6.5 Manual & Documentation - - - + + {{section}}Node.js v0.6.6 Manual & Documentation + + +
-

Node.js v0.6.5 Manual & Documentation

+

Node.js v0.6.6 Manual & Documentation

-
+
{{content}}
diff --git a/doc/thin-white-stripe.bmp b/doc/thin-white-stripe.bmp new file mode 100644 index 0000000000..8130a843c4 Binary files /dev/null and b/doc/thin-white-stripe.bmp differ diff --git a/doc/windows_banner_nodejs_installer_logo.jpg b/doc/windows_banner_nodejs_installer_logo.jpg deleted file mode 100644 index 2dfb59a647..0000000000 Binary files a/doc/windows_banner_nodejs_installer_logo.jpg and /dev/null differ diff --git a/doc/windows_dialog_nodejs_installer_logo.jpg b/doc/windows_dialog_nodejs_installer_logo.jpg deleted file mode 100644 index 716791d647..0000000000 Binary files a/doc/windows_dialog_nodejs_installer_logo.jpg and /dev/null differ diff --git a/doc/yahoo-logo.png b/doc/yahoo-logo.png new file mode 100644 index 0000000000..05d75b3513 Binary files /dev/null and b/doc/yahoo-logo.png differ diff --git a/lib/child_process.js b/lib/child_process.js index dcff85ab3e..a34313f61e 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -25,7 +25,6 @@ var Process = process.binding('process_wrap').Process; var inherits = require('util').inherits; var constants; // if (!constants) constants = process.binding('constants'); -var LF = '\n'.charCodeAt(0); var Pipe; @@ -76,8 +75,8 @@ function setupChannel(target, channel) { if (isWindows) { var setSimultaneousAccepts = function(handle) { - var simultaneousAccepts = (process.env.NODE_MANY_ACCEPTS - && process.env.NODE_MANY_ACCEPTS != '0') ? true : false; + var simultaneousAccepts = (process.env.NODE_MANY_ACCEPTS && + process.env.NODE_MANY_ACCEPTS != '0') ? true : false; if (handle._simultaneousAccepts != simultaneousAccepts) { handle.setSimultaneousAccepts(simultaneousAccepts); @@ -101,7 +100,7 @@ function setupChannel(target, channel) { var message = JSON.parse(json); target.emit('message', message, recvHandle); - start = i+1; + start = i + 1; } jsonBuffer = jsonBuffer.slice(start); @@ -112,7 +111,7 @@ function setupChannel(target, channel) { }; target.send = function(message, sendHandle) { - if (!target._channel) throw new Error("channel closed"); + if (!target._channel) throw new Error('channel closed'); // For overflow protection don't write if channel queue is too deep. if (channel.writeQueueSize > 1024 * 1024) { @@ -129,7 +128,7 @@ function setupChannel(target, channel) { var writeReq = channel.write(buffer, 0, buffer.length, sendHandle); if (!writeReq) { - throw new Error(errno + " cannot write to IPC channel."); + throw new Error(errno + 'cannot write to IPC channel.'); } writeReq.oncomplete = nop; @@ -151,16 +150,16 @@ exports.fork = function(modulePath, args, options) { args.unshift(modulePath); if (options.stdinStream) { - throw new Error("stdinStream not allowed for fork()"); + throw new Error('stdinStream not allowed for fork()'); } if (options.customFds) { - throw new Error("customFds not allowed for fork()"); + throw new Error('customFds not allowed for fork()'); } // Leave stdin open for the IPC channel. stdout and stderr should be the // same as the parent's. - options.customFds = [ -1, 1, 2 ]; + options.customFds = [-1, 1, 2]; // Just need to set this - child process won't actually use the fd. // For backwards compat - this can be changed to 'NODE_CHANNEL' before v0.6. @@ -331,7 +330,6 @@ var spawn = exports.spawn = function(file, args, options) { var env = (options ? options.env : null) || process.env; var envPairs = []; - var keys = Object.keys(env); for (var key in env) { envPairs.push(key + '=' + env[key]); } diff --git a/lib/cluster.js b/lib/cluster.js index cc2f98cd5b..6c7d2dfa83 100644 --- a/lib/cluster.js +++ b/lib/cluster.js @@ -81,11 +81,11 @@ function startMaster() { // Quickly try to kill all the workers. // TODO: be session leader - will cause auto SIGHUP to the children. eachWorker(function(worker) { - debug("kill worker " + worker.pid); + debug('kill worker ' + worker.pid); worker.kill(); - }) + }); - console.error("Exception in cluster master process: " + + console.error('Exception in cluster master process: ' + e.message + '\n' + e.stack); process.exit(1); }); @@ -96,21 +96,21 @@ function handleWorkerMessage(worker, message) { // This can only be called from the master. assert(cluster.isMaster); - debug("recv " + JSON.stringify(message)); + debug('recv ' + JSON.stringify(message)); switch (message.cmd) { case 'online': - debug("Worker " + worker.pid + " online"); + debug('Worker ' + worker.pid + ' online'); worker.online = true; break; case 'queryServer': - var key = message.address + ":" + - message.port + ":" + + var key = message.address + ':' + + message.port + ':' + message.addressType; var response = { _queryId: message._queryId }; - if (key in servers == false) { + if (!(key in servers)) { // Create a new server. debug('create new server ' + key); servers[key] = net._createServerHandle(message.address, @@ -136,7 +136,7 @@ function eachWorker(cb) { cb(workers[id]); } } -}; +} cluster.fork = function() { @@ -176,19 +176,19 @@ cluster.fork = function() { // Internal function. Called from src/node.js when worker process starts. cluster._startWorker = function() { assert(cluster.isWorker); - workerId = parseInt(process.env.NODE_WORKER_ID); + workerId = parseInt(process.env.NODE_WORKER_ID, 10); queryMaster({ cmd: 'online' }); // Make callbacks from queryMaster() process.on('message', function(msg, handle) { - debug("recv " + JSON.stringify(msg)); + debug('recv ' + JSON.stringify(msg)); if (msg._queryId && msg._queryId in queryCallbacks) { var cb = queryCallbacks[msg._queryId]; if (typeof cb == 'function') { cb(msg, handle); } - delete queryCallbacks[msg._queryId] + delete queryCallbacks[msg._queryId]; } }); }; @@ -219,7 +219,7 @@ cluster._getServer = function(address, port, addressType, cb) { assert(cluster.isWorker); queryMaster({ - cmd: "queryServer", + cmd: 'queryServer', address: address, port: port, addressType: addressType diff --git a/lib/fs.js b/lib/fs.js index e9efece32b..7b61c8984c 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -422,17 +422,17 @@ fs.readlinkSync = function(path) { return binding.readlink(pathModule._makeLong(path)); }; -fs.symlink = function(destination, path, mode_, callback) { - var mode = (typeof(mode_) == 'string' ? mode_ : null); +fs.symlink = function(destination, path, type_, callback) { + var type = (typeof(type_) == 'string' ? type_ : null); var callback_ = arguments[arguments.length - 1]; callback = (typeof(callback_) == 'function' ? callback_ : null); binding.symlink(pathModule._makeLong(destination), - pathModule._makeLong(path), mode, callback); + pathModule._makeLong(path), type, callback); }; -fs.symlinkSync = function(destination, path, mode) { +fs.symlinkSync = function(destination, path, type) { return binding.symlink(pathModule._makeLong(destination), - pathModule._makeLong(path), mode); + pathModule._makeLong(path), type); }; fs.link = function(srcpath, dstpath, callback) { @@ -1092,7 +1092,7 @@ ReadStream.prototype._read = function() { // thread pool another read() finishes up the pool, and allocates a new // one. var thisPool = pool; - var toRead = Math.min(pool.length - pool.used, this.bufferSize); + var toRead = Math.min(pool.length - pool.used, ~~this.bufferSize); var start = pool.used; if (this.pos !== undefined) { diff --git a/lib/net.js b/lib/net.js index 19858e80df..e182173953 100644 --- a/lib/net.js +++ b/lib/net.js @@ -465,7 +465,11 @@ function afterWrite(status, handle, req, buffer) { if (self.destroyed) { return; } - // TODO check status. + + if (status) { + self.destroy(errnoException(errno, 'write')); + return; + } timers.active(this); diff --git a/lib/os.js b/lib/os.js index fa8ac01513..f226e3ecbf 100644 --- a/lib/os.js +++ b/lib/os.js @@ -37,12 +37,8 @@ exports.platform = function() { return process.platform; }; -var warnNetworkInterfaces = true; exports.getNetworkInterfaces = function() { - if (warnNetworkInterfaces) { - console.error("os.getNetworkInterfaces() is deprecated - use os.networkInterfaces()"); - console.trace(); - warnNetworkInterfaces = false; - } + require('util')._deprecationWarning('os', + 'os.getNetworkInterfaces() is deprecated - use os.networkInterfaces()'); return exports.networkInterfaces(); }; diff --git a/lib/sys.js b/lib/sys.js index d53a3dd95e..0039b89d20 100644 --- a/lib/sys.js +++ b/lib/sys.js @@ -21,15 +21,8 @@ var util = require('util'); -var sysWarning; -if (!sysWarning) { - sysWarning = 'The "sys" module is now called "util". ' + - 'It should have a similar interface.'; - if (process.env.NODE_DEBUG && process.env.NODE_DEBUG.indexOf('sys') != -1) - console.trace(sysWarning); - else - console.error(sysWarning); -} +util._deprecationWarning('sys', + 'The "sys" module is now called "util". It should have a similar interface.'); exports.print = util.print; exports.puts = util.puts; diff --git a/lib/util.js b/lib/util.js index b00da2de9d..cd4cc0e964 100644 --- a/lib/util.js +++ b/lib/util.js @@ -518,3 +518,19 @@ exports.inherits = function(ctor, superCtor) { } }); }; + +var deprecationWarnings; + +exports._deprecationWarning = function(moduleId, message) { + if (!deprecationWarnings) + deprecationWarnings = {}; + else if (message in deprecationWarnings) + return; + + deprecationWarnings[message] = true; + + if ((new RegExp('\\b' + moduleId + '\\b')).test(process.env.NODE_DEBUG)) + console.trace(message); + else + console.error(message); +}; diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index a18a148a55..48cdabc00e 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -133,18 +133,30 @@ void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename, assert(wrap->object_.IsEmpty() == false); + // We're in a bind here. libuv can set both UV_RENAME and UV_CHANGE but + // the Node API only lets us pass a single event to JS land. + // + // The obvious solution is to run the callback twice, once for each event. + // However, since the second event is not allowed to fire if the handle is + // closed after the first event, and since there is no good way to detect + // closed handles, that option is out. + // + // For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the + // assumption that a rename implicitly means an attribute change. Not too + // unreasonable, right? Still, we should revisit this before v1.0. if (status) { SetErrno(uv_last_error(uv_default_loop())); eventStr = String::Empty(); - } else { - switch (events) { - case UV_RENAME: - eventStr = String::New("rename"); - break; - case UV_CHANGE: - eventStr = String::New("change"); - break; - } + } + else if (events & UV_RENAME) { + eventStr = String::New("rename"); + } + else if (events & UV_CHANGE) { + eventStr = String::New("change"); + } + else { + assert(0 && "bad fs events flag"); + abort(); } Local argv[3] = { diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 83a66e3122..eb040ebc8c 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -1683,9 +1683,20 @@ static void HexEncode(unsigned char *md_value, int* md_hex_len) { *md_hex_len = (2*(md_len)); *md_hexdigest = new char[*md_hex_len + 1]; - for (int i = 0; i < md_len; i++) { - snprintf((char *)(*md_hexdigest + (i*2)), 3, "%02x", md_value[i]); + + char* buff = *md_hexdigest; + const int len = *md_hex_len; + for (int i = 0; i < len; i += 2) { + // nibble nibble + const int index = i / 2; + const char msb = (md_value[index] >> 4) & 0x0f; + const char lsb = md_value[index] & 0x0f; + + buff[i] = (msb < 10) ? msb + '0' : (msb - 10) + 'a'; + buff[i + 1] = (lsb < 10) ? lsb + '0' : (lsb - 10) + 'a'; } + // null terminator + buff[*md_hex_len] = '\0'; } #define hex2i(c) ((c) <= '9' ? ((c) - '0') : (c) <= 'Z' ? ((c) - 'A' + 10) \ @@ -2092,54 +2103,49 @@ class Cipher : public ObjectWrap { if (out_len==0) { outString=String::New(""); } else { - if (args.Length() <= 2 || !args[2]->IsString()) { - // Binary - outString = Encode(out, out_len, BINARY); - } else { - char* out_hexdigest; - int out_hex_len; - String::Utf8Value encoding(args[2]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - HexEncode(out, out_len, &out_hexdigest, &out_hex_len); - outString = Encode(out_hexdigest, out_hex_len, BINARY); - delete [] out_hexdigest; - } else if (strcasecmp(*encoding, "base64") == 0) { - // Base64 encoding - // Check to see if we need to add in previous base64 overhang - if (cipher->incomplete_base64!=NULL){ - unsigned char* complete_base64 = new unsigned char[out_len+cipher->incomplete_base64_len+1]; - memcpy(complete_base64, cipher->incomplete_base64, cipher->incomplete_base64_len); - memcpy(&complete_base64[cipher->incomplete_base64_len], out, out_len); - delete [] out; - - delete [] cipher->incomplete_base64; - cipher->incomplete_base64=NULL; - - out=complete_base64; - out_len += cipher->incomplete_base64_len; - } + char* out_hexdigest; + int out_hex_len; + enum encoding enc = ParseEncoding(args[2], BINARY); + if (enc == HEX) { + // Hex encoding + HexEncode(out, out_len, &out_hexdigest, &out_hex_len); + outString = Encode(out_hexdigest, out_hex_len, BINARY); + delete [] out_hexdigest; + } else if (enc == BASE64) { + // Base64 encoding + // Check to see if we need to add in previous base64 overhang + if (cipher->incomplete_base64!=NULL){ + unsigned char* complete_base64 = new unsigned char[out_len+cipher->incomplete_base64_len+1]; + memcpy(complete_base64, cipher->incomplete_base64, cipher->incomplete_base64_len); + memcpy(&complete_base64[cipher->incomplete_base64_len], out, out_len); + delete [] out; - // Check to see if we need to trim base64 stream - if (out_len%3!=0){ - cipher->incomplete_base64_len = out_len%3; - cipher->incomplete_base64 = new char[cipher->incomplete_base64_len+1]; - memcpy(cipher->incomplete_base64, - &out[out_len-cipher->incomplete_base64_len], - cipher->incomplete_base64_len); - out_len -= cipher->incomplete_base64_len; - out[out_len]=0; - } + delete [] cipher->incomplete_base64; + cipher->incomplete_base64=NULL; - base64(out, out_len, &out_hexdigest, &out_hex_len); - outString = Encode(out_hexdigest, out_hex_len, BINARY); - delete [] out_hexdigest; - } else if (strcasecmp(*encoding, "binary") == 0) { - outString = Encode(out, out_len, BINARY); - } else { - fprintf(stderr, "node-crypto : Cipher .update encoding " - "can be binary, hex or base64\n"); + out=complete_base64; + out_len += cipher->incomplete_base64_len; + } + + // Check to see if we need to trim base64 stream + if (out_len%3!=0){ + cipher->incomplete_base64_len = out_len%3; + cipher->incomplete_base64 = new char[cipher->incomplete_base64_len+1]; + memcpy(cipher->incomplete_base64, + &out[out_len-cipher->incomplete_base64_len], + cipher->incomplete_base64_len); + out_len -= cipher->incomplete_base64_len; + out[out_len]=0; } + + base64(out, out_len, &out_hexdigest, &out_hex_len); + outString = Encode(out_hexdigest, out_hex_len, BINARY); + delete [] out_hexdigest; + } else if (enc == BINARY) { + outString = Encode(out, out_len, BINARY); + } else { + fprintf(stderr, "node-crypto : Cipher .update encoding " + "can be binary, hex or base64\n"); } } @@ -2168,40 +2174,36 @@ class Cipher : public ObjectWrap { return scope.Close(String::New("")); } - if (args.Length() == 0 || !args[0]->IsString()) { - // Binary + enum encoding enc = ParseEncoding(args[0], BINARY); + if (enc == HEX) { + // Hex encoding + HexEncode(out_value, out_len, &out_hexdigest, &out_hex_len); + outString = Encode(out_hexdigest, out_hex_len, BINARY); + delete [] out_hexdigest; + } else if (enc == BASE64) { + // Check to see if we need to add in previous base64 overhang + if (cipher->incomplete_base64!=NULL){ + unsigned char* complete_base64 = new unsigned char[out_len+cipher->incomplete_base64_len+1]; + memcpy(complete_base64, cipher->incomplete_base64, cipher->incomplete_base64_len); + memcpy(&complete_base64[cipher->incomplete_base64_len], out_value, out_len); + delete [] out_value; + + delete [] cipher->incomplete_base64; + cipher->incomplete_base64=NULL; + + out_value=complete_base64; + out_len += cipher->incomplete_base64_len; + } + base64(out_value, out_len, &out_hexdigest, &out_hex_len); + outString = Encode(out_hexdigest, out_hex_len, BINARY); + delete [] out_hexdigest; + } else if (enc == BINARY) { outString = Encode(out_value, out_len, BINARY); } else { - String::Utf8Value encoding(args[0]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - HexEncode(out_value, out_len, &out_hexdigest, &out_hex_len); - outString = Encode(out_hexdigest, out_hex_len, BINARY); - delete [] out_hexdigest; - } else if (strcasecmp(*encoding, "base64") == 0) { - // Check to see if we need to add in previous base64 overhang - if (cipher->incomplete_base64!=NULL){ - unsigned char* complete_base64 = new unsigned char[out_len+cipher->incomplete_base64_len+1]; - memcpy(complete_base64, cipher->incomplete_base64, cipher->incomplete_base64_len); - memcpy(&complete_base64[cipher->incomplete_base64_len], out_value, out_len); - delete [] out_value; - - delete [] cipher->incomplete_base64; - cipher->incomplete_base64=NULL; - - out_value=complete_base64; - out_len += cipher->incomplete_base64_len; - } - base64(out_value, out_len, &out_hexdigest, &out_hex_len); - outString = Encode(out_hexdigest, out_hex_len, BINARY); - delete [] out_hexdigest; - } else if (strcasecmp(*encoding, "binary") == 0) { - outString = Encode(out_value, out_len, BINARY); - } else { - fprintf(stderr, "node-crypto : Cipher .final encoding " - "can be binary, hex or base64\n"); - } + fprintf(stderr, "node-crypto : Cipher .final encoding " + "can be binary, hex or base64\n"); } + delete [] out_value; return scope.Close(outString); } @@ -2243,8 +2245,8 @@ class Decipher : public ObjectWrap { NODE_SET_PROTOTYPE_METHOD(t, "init", DecipherInit); NODE_SET_PROTOTYPE_METHOD(t, "initiv", DecipherInitIv); NODE_SET_PROTOTYPE_METHOD(t, "update", DecipherUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "final", DecipherFinal); - NODE_SET_PROTOTYPE_METHOD(t, "finaltol", DecipherFinalTolerate); + NODE_SET_PROTOTYPE_METHOD(t, "final", DecipherFinal); + NODE_SET_PROTOTYPE_METHOD(t, "finaltol", DecipherFinal); target->Set(String::NewSymbol("Decipher"), t->GetFunction()); } @@ -2314,7 +2316,12 @@ class Decipher : public ObjectWrap { } int DecipherUpdate(char* data, int len, unsigned char** out, int* out_len) { - if (!initialised_) return 0; + if (!initialised_) { + *out_len = 0; + *out = NULL; + return 0; + } + *out_len=len+EVP_CIPHER_CTX_block_size(&ctx); *out= new unsigned char[*out_len]; @@ -2323,10 +2330,16 @@ class Decipher : public ObjectWrap { } // coverity[alloc_arg] - int DecipherFinal(unsigned char** out, int *out_len, bool tolerate_padding) { - if (!initialised_) return 0; + template + int DecipherFinal(unsigned char** out, int *out_len) { + if (!initialised_) { + *out_len = 0; + *out = NULL; + return 0; + } + *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)]; - if (tolerate_padding) { + if (TOLERATE_PADDING) { local_EVP_DecryptFinal_ex(&ctx,*out,out_len); } else { EVP_CipherFinal_ex(&ctx,*out,out_len); @@ -2469,56 +2482,52 @@ class Decipher : public ObjectWrap { char* ciphertext; int ciphertext_len; - if (args.Length() <= 1 || !args[1]->IsString()) { - // Binary - do nothing - } else { - String::Utf8Value encoding(args[1]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - // Do we have a previous hex carry over? - if (cipher->incomplete_hex_flag) { - char* complete_hex = new char[len+2]; - memcpy(complete_hex, &cipher->incomplete_hex, 1); - memcpy(complete_hex+1, buf, len); - if (alloc_buf) { - delete [] buf; - alloc_buf = false; - } - buf = complete_hex; - len += 1; - } - // Do we have an incomplete hex stream? - if ((len>0) && (len % 2 !=0)) { - len--; - cipher->incomplete_hex=buf[len]; - cipher->incomplete_hex_flag=true; - buf[len]=0; - } - HexDecode((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len); - - if (alloc_buf) { - delete [] buf; - } - buf = ciphertext; - len = ciphertext_len; - alloc_buf = true; - - } else if (strcasecmp(*encoding, "base64") == 0) { - unbase64((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len); + enum encoding enc = ParseEncoding(args[1], BINARY); + if (enc == HEX) { + // Hex encoding + // Do we have a previous hex carry over? + if (cipher->incomplete_hex_flag) { + char* complete_hex = new char[len+2]; + memcpy(complete_hex, &cipher->incomplete_hex, 1); + memcpy(complete_hex+1, buf, len); if (alloc_buf) { delete [] buf; + alloc_buf = false; } - buf = ciphertext; - len = ciphertext_len; - alloc_buf = true; + buf = complete_hex; + len += 1; + } + // Do we have an incomplete hex stream? + if ((len>0) && (len % 2 !=0)) { + len--; + cipher->incomplete_hex=buf[len]; + cipher->incomplete_hex_flag=true; + buf[len]=0; + } + HexDecode((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len); - } else if (strcasecmp(*encoding, "binary") == 0) { - // Binary - do nothing + if (alloc_buf) { + delete [] buf; + } + buf = ciphertext; + len = ciphertext_len; + alloc_buf = true; - } else { - fprintf(stderr, "node-crypto : Decipher .update encoding " - "can be binary, hex or base64\n"); + } else if (enc == BASE64) { + unbase64((unsigned char*)buf, len, (char **)&ciphertext, &ciphertext_len); + if (alloc_buf) { + delete [] buf; } + buf = ciphertext; + len = ciphertext_len; + alloc_buf = true; + + } else if (enc == BINARY) { + // Binary - do nothing + + } else { + fprintf(stderr, "node-crypto : Decipher .update encoding " + "can be binary, hex or base64\n"); } unsigned char *out=0; @@ -2534,10 +2543,8 @@ class Decipher : public ObjectWrap { Local outString; if (out_len==0) { outString=String::New(""); - } else if (args.Length() <= 2 || !args[2]->IsString()) { - outString = Encode(out, out_len, BINARY); } else { - enum encoding enc = ParseEncoding(args[2]); + enum encoding enc = ParseEncoding(args[2], BINARY); if (enc == UTF8) { // See if we have any overhang from last utf8 partial ending if (cipher->incomplete_utf8!=NULL) { @@ -2572,6 +2579,7 @@ class Decipher : public ObjectWrap { } + template static Handle DecipherFinal(const Arguments& args) { HandleScope scope; @@ -2581,16 +2589,16 @@ class Decipher : public ObjectWrap { int out_len = -1; Local outString; - int r = cipher->DecipherFinal(&out_value, &out_len, false); + int r = cipher->DecipherFinal(&out_value, &out_len); assert(out_value != NULL); assert(out_len != -1); if (out_len == 0 || r == 0) { + delete[] out_value; return scope.Close(String::New("")); } - if (args.Length() == 0 || !args[0]->IsString()) { outString = Encode(out_value, out_len, BINARY); } else { @@ -2618,51 +2626,6 @@ class Decipher : public ObjectWrap { return scope.Close(outString); } - static Handle DecipherFinalTolerate(const Arguments& args) { - Decipher *cipher = ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - unsigned char* out_value; - int out_len; - Local outString ; - - out_value = NULL; - int r = cipher->DecipherFinal(&out_value, &out_len, true); - - if (out_len == 0 || r == 0) { - delete [] out_value; - return scope.Close(String::New("")); - } - - - if (args.Length() == 0 || !args[0]->IsString()) { - outString = Encode(out_value, out_len, BINARY); - } else { - enum encoding enc = ParseEncoding(args[0]); - if (enc == UTF8) { - // See if we have any overhang from last utf8 partial ending - if (cipher->incomplete_utf8!=NULL) { - char* complete_out = new char[cipher->incomplete_utf8_len + out_len]; - memcpy(complete_out, cipher->incomplete_utf8, cipher->incomplete_utf8_len); - memcpy((char *)complete_out+cipher->incomplete_utf8_len, out_value, out_len); - - delete [] cipher->incomplete_utf8; - cipher->incomplete_utf8 = NULL; - - outString = Encode(complete_out, cipher->incomplete_utf8_len+out_len, enc); - delete [] complete_out; - } else { - outString = Encode(out_value, out_len, enc); - } - } else { - outString = Encode(out_value, out_len, enc); - } - } - delete [] out_value; - return scope.Close(outString); - } - Decipher () : ObjectWrap () { initialised_ = false; } @@ -2845,26 +2808,21 @@ class Hmac : public ObjectWrap { return scope.Close(String::New("")); } - if (args.Length() == 0 || !args[0]->IsString()) { - // Binary + enum encoding enc = ParseEncoding(args[0], BINARY); + if (enc == HEX) { + // Hex encoding + HexEncode(md_value, md_len, &md_hexdigest, &md_hex_len); + outString = Encode(md_hexdigest, md_hex_len, BINARY); + delete [] md_hexdigest; + } else if (enc == BASE64) { + base64(md_value, md_len, &md_hexdigest, &md_hex_len); + outString = Encode(md_hexdigest, md_hex_len, BINARY); + delete [] md_hexdigest; + } else if (enc == BINARY) { outString = Encode(md_value, md_len, BINARY); } else { - String::Utf8Value encoding(args[0]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - HexEncode(md_value, md_len, &md_hexdigest, &md_hex_len); - outString = Encode(md_hexdigest, md_hex_len, BINARY); - delete [] md_hexdigest; - } else if (strcasecmp(*encoding, "base64") == 0) { - base64(md_value, md_len, &md_hexdigest, &md_hex_len); - outString = Encode(md_hexdigest, md_hex_len, BINARY); - delete [] md_hexdigest; - } else if (strcasecmp(*encoding, "binary") == 0) { - outString = Encode(md_value, md_len, BINARY); - } else { - fprintf(stderr, "node-crypto : Hmac .digest encoding " - "can be binary, hex or base64\n"); - } + fprintf(stderr, "node-crypto : Hmac .digest encoding " + "can be binary, hex or base64\n"); } delete [] md_value; return scope.Close(outString); @@ -3001,30 +2959,25 @@ class Hash : public ObjectWrap { Local outString; - if (args.Length() == 0 || !args[0]->IsString()) { - // Binary + enum encoding enc = ParseEncoding(args[0], BINARY); + if (enc == HEX) { + // Hex encoding + char* md_hexdigest; + int md_hex_len; + HexEncode(md_value, md_len, &md_hexdigest, &md_hex_len); + outString = Encode(md_hexdigest, md_hex_len, BINARY); + delete [] md_hexdigest; + } else if (enc == BASE64) { + char* md_hexdigest; + int md_hex_len; + base64(md_value, md_len, &md_hexdigest, &md_hex_len); + outString = Encode(md_hexdigest, md_hex_len, BINARY); + delete [] md_hexdigest; + } else if (enc == BINARY) { outString = Encode(md_value, md_len, BINARY); } else { - String::Utf8Value encoding(args[0]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - char* md_hexdigest; - int md_hex_len; - HexEncode(md_value, md_len, &md_hexdigest, &md_hex_len); - outString = Encode(md_hexdigest, md_hex_len, BINARY); - delete [] md_hexdigest; - } else if (strcasecmp(*encoding, "base64") == 0) { - char* md_hexdigest; - int md_hex_len; - base64(md_value, md_len, &md_hexdigest, &md_hex_len); - outString = Encode(md_hexdigest, md_hex_len, BINARY); - delete [] md_hexdigest; - } else if (strcasecmp(*encoding, "binary") == 0) { - outString = Encode(md_value, md_len, BINARY); - } else { - fprintf(stderr, "node-crypto : Hash .digest encoding " - "can be binary, hex or base64\n"); - } + fprintf(stderr, "node-crypto : Hash .digest encoding " + "can be binary, hex or base64\n"); } return scope.Close(outString); @@ -3212,27 +3165,22 @@ class Sign : public ObjectWrap { return scope.Close(String::New("")); } - if (args.Length() == 1 || !args[1]->IsString()) { - // Binary + enum encoding enc = ParseEncoding(args[1], BINARY); + if (enc == HEX) { + // Hex encoding + HexEncode(md_value, md_len, &md_hexdigest, &md_hex_len); + outString = Encode(md_hexdigest, md_hex_len, BINARY); + delete [] md_hexdigest; + } else if (enc == BASE64) { + base64(md_value, md_len, &md_hexdigest, &md_hex_len); + outString = Encode(md_hexdigest, md_hex_len, BINARY); + delete [] md_hexdigest; + } else if (enc == BINARY) { outString = Encode(md_value, md_len, BINARY); } else { - String::Utf8Value encoding(args[1]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - HexEncode(md_value, md_len, &md_hexdigest, &md_hex_len); - outString = Encode(md_hexdigest, md_hex_len, BINARY); - delete [] md_hexdigest; - } else if (strcasecmp(*encoding, "base64") == 0) { - base64(md_value, md_len, &md_hexdigest, &md_hex_len); - outString = Encode(md_hexdigest, md_hex_len, BINARY); - delete [] md_hexdigest; - } else if (strcasecmp(*encoding, "binary") == 0) { - outString = Encode(md_value, md_len, BINARY); - } else { - outString = String::New(""); - fprintf(stderr, "node-crypto : Sign .sign encoding " - "can be binary, hex or base64\n"); - } + outString = String::New(""); + fprintf(stderr, "node-crypto : Sign .sign encoding " + "can be binary, hex or base64\n"); } delete [] md_value; @@ -3468,27 +3416,22 @@ class Verify : public ObjectWrap { int r=-1; - if (args.Length() == 2 || !args[2]->IsString()) { - // Binary + enum encoding enc = ParseEncoding(args[2], BINARY); + if (enc == HEX) { + // Hex encoding + HexDecode(hbuf, hlen, (char **)&dbuf, &dlen); + r = verify->VerifyFinal(kbuf, klen, dbuf, dlen); + delete [] dbuf; + } else if (enc == BASE64) { + // Base64 encoding + unbase64(hbuf, hlen, (char **)&dbuf, &dlen); + r = verify->VerifyFinal(kbuf, klen, dbuf, dlen); + delete [] dbuf; + } else if (enc == BINARY) { r = verify->VerifyFinal(kbuf, klen, hbuf, hlen); } else { - String::Utf8Value encoding(args[2]->ToString()); - if (strcasecmp(*encoding, "hex") == 0) { - // Hex encoding - HexDecode(hbuf, hlen, (char **)&dbuf, &dlen); - r = verify->VerifyFinal(kbuf, klen, dbuf, dlen); - delete [] dbuf; - } else if (strcasecmp(*encoding, "base64") == 0) { - // Base64 encoding - unbase64(hbuf, hlen, (char **)&dbuf, &dlen); - r = verify->VerifyFinal(kbuf, klen, dbuf, dlen); - delete [] dbuf; - } else if (strcasecmp(*encoding, "binary") == 0) { - r = verify->VerifyFinal(kbuf, klen, hbuf, hlen); - } else { - fprintf(stderr, "node-crypto : Verify .verify encoding " - "can be binary, hex or base64\n"); - } + fprintf(stderr, "node-crypto : Verify .verify encoding " + "can be binary, hex or base64\n"); } delete [] kbuf; @@ -3565,8 +3508,7 @@ class DiffieHellman : public ObjectWrap { if (args.Length() > 0) { if (args[0]->IsInt32()) { - diffieHellman->Init(args[0]->Int32Value()); - initialized = true; + initialized = diffieHellman->Init(args[0]->Int32Value()); } else { if (args[0]->IsString()) { char* buf; @@ -3582,16 +3524,15 @@ class DiffieHellman : public ObjectWrap { return ThrowException(Exception::Error( String::New("Invalid argument"))); } else { - diffieHellman->Init(reinterpret_cast(buf), len); + initialized = diffieHellman->Init( + reinterpret_cast(buf), len); delete[] buf; - initialized = true; } } else if (Buffer::HasInstance(args[0])) { Local buffer = args[0]->ToObject(); - diffieHellman->Init( + initialized = diffieHellman->Init( reinterpret_cast(Buffer::Data(buffer)), Buffer::Length(buffer)); - initialized = true; } } } @@ -3964,23 +3905,23 @@ class DiffieHellman : public ObjectWrap { return len; } - static int DecodeWithEncoding(Handle str, Handle enc, + static int DecodeWithEncoding(Handle str, Handle encoding_v, char** buf) { int len = DecodeBinary(str, buf); if (len == -1) { return len; } - String::Utf8Value encoding(enc->ToString()); + enum encoding enc = ParseEncoding(encoding_v, (enum encoding) -1); char* retbuf = 0; int retlen; - if (strcasecmp(*encoding, "hex") == 0) { + if (enc == HEX) { HexDecode((unsigned char*)*buf, len, &retbuf, &retlen); - } else if (strcasecmp(*encoding, "base64") == 0) { + } else if (enc == BASE64) { unbase64((unsigned char*)*buf, len, &retbuf, &retlen); - } else if (strcasecmp(*encoding, "binary") == 0) { + } else if (enc == BINARY) { // Binary - do nothing } else { fprintf(stderr, "node-crypto : Diffie-Hellman parameter encoding " @@ -3996,24 +3937,25 @@ class DiffieHellman : public ObjectWrap { return len; } - static Local EncodeWithEncoding(Handle enc, char* buf, + static Local EncodeWithEncoding(Handle encoding_v, char* buf, int len) { HandleScope scope; Local outString; - String::Utf8Value encoding(enc->ToString()); + enum encoding enc = ParseEncoding(encoding_v, (enum encoding) -1); char* retbuf; int retlen; - if (strcasecmp(*encoding, "hex") == 0) { + + if (enc == HEX) { // Hex encoding HexEncode(reinterpret_cast(buf), len, &retbuf, &retlen); outString = Encode(retbuf, retlen, BINARY); delete [] retbuf; - } else if (strcasecmp(*encoding, "base64") == 0) { + } else if (enc == BASE64) { base64(reinterpret_cast(buf), len, &retbuf, &retlen); outString = Encode(retbuf, retlen, BINARY); delete [] retbuf; - } else if (strcasecmp(*encoding, "binary") == 0) { + } else if (enc == BINARY) { outString = Encode(buf, len, BINARY); } else { fprintf(stderr, "node-crypto : Diffie-Hellman parameter encoding " @@ -4090,43 +4032,79 @@ Handle PBKDF2(const Arguments& args) { HandleScope scope; - if (args.Length() != 5) - return ThrowException(Exception::TypeError(String::New("Bad parameter"))); + const char* type_error = NULL; + char* pass = NULL; + char* salt = NULL; + char* key = NULL; + ssize_t passlen = -1; + ssize_t saltlen = -1; + ssize_t keylen = -1; + ssize_t pass_written = -1; + ssize_t salt_written = -1; + ssize_t iter = -1; + Local callback; + pbkdf2_req* request = NULL; + uv_work_t* req = NULL; + + if (args.Length() != 5) { + type_error = "Bad parameter"; + goto err; + } ASSERT_IS_STRING_OR_BUFFER(args[0]); - ssize_t passlen = DecodeBytes(args[0], BINARY); - if (passlen < 0) - return ThrowException(Exception::TypeError(String::New("Bad password"))); - char* pass = new char[passlen]; - ssize_t pass_written = DecodeWrite(pass, passlen, args[0], BINARY); + passlen = DecodeBytes(args[0], BINARY); + if (passlen < 0) { + type_error = "Bad password"; + goto err; + } + + pass = new char[passlen]; + pass_written = DecodeWrite(pass, passlen, args[0], BINARY); assert(pass_written == passlen); ASSERT_IS_STRING_OR_BUFFER(args[1]); - ssize_t saltlen = DecodeBytes(args[1], BINARY); - if (saltlen < 0) - return ThrowException(Exception::TypeError(String::New("Bad salt"))); - char* salt = new char[saltlen]; - ssize_t salt_written = DecodeWrite(salt, saltlen, args[1], BINARY); + saltlen = DecodeBytes(args[1], BINARY); + if (saltlen < 0) { + type_error = "Bad salt"; + goto err; + } + + salt = new char[saltlen]; + salt_written = DecodeWrite(salt, saltlen, args[1], BINARY); assert(salt_written == saltlen); - if (!args[2]->IsNumber()) - return ThrowException(Exception::TypeError(String::New("Iterations not a number"))); - ssize_t iter = args[2]->Int32Value(); - if (iter < 0) - return ThrowException(Exception::TypeError(String::New("Bad iterations"))); + if (!args[2]->IsNumber()) { + type_error = "Iterations not a number"; + goto err; + } + + iter = args[2]->Int32Value(); + if (iter < 0) { + type_error = "Bad iterations"; + goto err; + } + + if (!args[3]->IsNumber()) { + type_error = "Key length not a number"; + goto err; + } + + keylen = args[3]->Int32Value(); + if (keylen < 0) { + type_error = "Bad key length"; + goto err; + } + + key = new char[keylen]; - if (!args[3]->IsNumber()) - return ThrowException(Exception::TypeError(String::New("Key length not a number"))); - ssize_t keylen = args[3]->Int32Value(); - if (keylen < 0) - return ThrowException(Exception::TypeError(String::New("Bad key length"))); - char* key = new char[keylen]; + if (!args[4]->IsFunction()) { + type_error = "Callback not a function"; + goto err; + } - if (!args[4]->IsFunction()) - return ThrowException(Exception::TypeError(String::New("Callback not a function"))); - Local callback = Local::Cast(args[4]); + callback = Local::Cast(args[4]); - pbkdf2_req* request = new pbkdf2_req; + request = new pbkdf2_req; request->err = 0; request->pass = pass; request->passlen = passlen; @@ -4137,11 +4115,16 @@ PBKDF2(const Arguments& args) { request->keylen = keylen; request->callback = Persistent::New(callback); - uv_work_t* req = new uv_work_t(); + req = new uv_work_t(); req->data = request; uv_queue_work(uv_default_loop(), req, EIO_PBKDF2, EIO_PBKDF2After); - return Undefined(); + +err: + delete[] key; + delete[] salt; + delete[] pass; + return ThrowException(Exception::TypeError(String::New(type_error))); } diff --git a/src/node_file.cc b/src/node_file.cc index 7c46f3dd78..4913b699c3 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -773,7 +773,7 @@ static Handle Read(const Arguments& args) { len = args[3]->Int32Value(); if (off + len > buffer_length) { return ThrowException(Exception::Error( - String::New("Length is extends beyond buffer"))); + String::New("Length extends beyond buffer"))); } pos = GET_OFFSET(args[4]); diff --git a/src/v8constants.h b/src/v8constants.h new file mode 100644 index 0000000000..70c26a208f --- /dev/null +++ b/src/v8constants.h @@ -0,0 +1,83 @@ +/* + * The following offsets are derived from the V8 3.6.6.14 source. A future + * version of this helper will automatically generate this file based on the + * debug metadata included in libv8. See v8ustack.d for details on how these + * values are used. + */ + +#ifndef V8_CONSTANTS_H +#define V8_CONSTANTS_H + +#if defined(__i386) + +/* + * Frame pointer offsets + */ +#define V8_OFF_FP_FUNC (-0x8) +#define V8_OFF_FP_CONTEXT (-0x4) +#define V8_OFF_FP_MARKER (-0x8) + +/* + * Heap class->field offsets + */ +#define V8_OFF_HEAP(off) ((off) - 1) + +#define V8_OFF_FUNC_SHARED V8_OFF_HEAP(0x14) +#define V8_OFF_SHARED_NAME V8_OFF_HEAP(0x4) +#define V8_OFF_SHARED_INFERRED V8_OFF_HEAP(0x24) +#define V8_OFF_SHARED_SCRIPT V8_OFF_HEAP(0x1c) +#define V8_OFF_SHARED_FUNTOK V8_OFF_HEAP(0x4c) +#define V8_OFF_SCRIPT_NAME V8_OFF_HEAP(0x8) +#define V8_OFF_SCRIPT_LENDS V8_OFF_HEAP(0x28) +#define V8_OFF_STR_LENGTH V8_OFF_HEAP(0x4) +#define V8_OFF_STR_CHARS V8_OFF_HEAP(0xc) +#define V8_OFF_CONSSTR_CAR V8_OFF_HEAP(0xc) +#define V8_OFF_CONSSTR_CDR V8_OFF_HEAP(0x10) +#define V8_OFF_EXTSTR_RSRC V8_OFF_HEAP(0xc) +#define V8_OFF_FA_SIZE V8_OFF_HEAP(0x4) +#define V8_OFF_FA_DATA V8_OFF_HEAP(0x8) +#define V8_OFF_HEAPOBJ_MAP V8_OFF_HEAP(0x0) +#define V8_OFF_MAP_ATTRS V8_OFF_HEAP(0x8) + +#define NODE_OFF_EXTSTR_DATA 0x4 + +/* + * Stack frame types + */ +#define V8_FT_ENTRY 0x1 +#define V8_FT_ENTRYCONSTRUCT 0x2 +#define V8_FT_EXIT 0x3 +#define V8_FT_JAVASCRIPT 0x4 +#define V8_FT_OPTIMIZED 0x5 +#define V8_FT_INTERNAL 0x6 +#define V8_FT_CONSTRUCT 0x7 +#define V8_FT_ADAPTOR 0x8 + +/* + * Instance types + */ +#define V8_IT_FIXEDARRAY 0x9f + +/* + * Identification masks and tags + */ +#define V8_SmiTagMask 0x1 +#define V8_SmiTag 0x0 +#define V8_SmiValueShift V8_SmiTagMask + +#define V8_IsNotStringMask 0x80 +#define V8_StringTag 0x0 + +#define V8_StringEncodingMask 0x4 +#define V8_AsciiStringTag 0x4 + +#define V8_StringRepresentationMask 0x3 +#define V8_SeqStringTag 0x0 +#define V8_ConsStringTag 0x1 +#define V8_ExternalStringTag 0x2 + +#else +#error "only i386 is supported for DTrace ustack helper" +#endif + +#endif /* V8_CONSTANTS_H */ diff --git a/src/v8ustack.d b/src/v8ustack.d new file mode 100644 index 0000000000..d559523556 --- /dev/null +++ b/src/v8ustack.d @@ -0,0 +1,626 @@ +/* + * V8 DTrace ustack helper for annotating native stack traces with JavaScript + * function names. We start with a frame pointer (arg1) and emit a string + * describing the current function. We do this by chasing pointers to extract + * the function's name (if any) and the filename and line number where the + * function is defined. + * + * To use the helper, run node, then use the jstack() DTrace action to capture + * a JavaScript stacktrace. You may need to tune the dtrace_helper_actions_max + * kernel variable to 128. + */ + +#include + +/* + * V8 represents small integers (SMI) using the upper 31 bits of a 32-bit + * value. To extract the actual integer value, we must shift it over. + */ +#define IS_SMI(value) ((value & V8_SmiTagMask) == V8_SmiTag) +#define SMI_VALUE(value) ((int32_t)(value) >> V8_SmiValueShift) + +/* + * Determine the encoding and representation of a V8 string. + */ +#define V8_TYPE_STRING(type) (((type) & V8_IsNotStringMask) == V8_StringTag) + +#define V8_STRENC_ASCII(type) \ + (((type) & V8_StringEncodingMask) == V8_AsciiStringTag) + +#define V8_STRREP_SEQ(type) \ + (((type) & V8_StringRepresentationMask) == V8_SeqStringTag) +#define V8_STRREP_CONS(type) \ + (((type) & V8_StringRepresentationMask) == V8_ConsStringTag) +#define V8_STRREP_EXT(type) \ + (((type) & V8_StringRepresentationMask) == V8_ExternalStringTag) + +/* + * String type predicates + */ +#define ASCII_SEQSTR(value) \ + (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value)) + +#define ASCII_CONSSTR(value) \ + (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_CONS(value)) + +#define ASCII_EXTSTR(value) \ + (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_EXT(value)) + +/* + * General helper macros + */ +#define COPYIN_UINT8(addr) (*(uint8_t *)copyin((addr), sizeof (uint8_t))) +#define COPYIN_UINT32(addr) (*(uint32_t *)copyin((addr), sizeof (uint32_t))) + +#define APPEND_CHR(c) (this->buf[this->off++] = (c)) + +#define APPEND_DGT(i, d) \ + (((i) / (d)) ? APPEND_CHR('0' + ((i)/(d) % 10)) : 0) + +#define APPEND_NUM(i) \ + APPEND_DGT((i), 10000); \ + APPEND_DGT((i), 1000); \ + APPEND_DGT((i), 100); \ + APPEND_DGT((i), 10); \ + APPEND_DGT((i), 1); + +/* + * The following macros are used to output ASCII SeqStrings, ConsStrings, and + * Node.js ExternalStrings. To represent each string, we use three fields: + * + * "str": a pointer to the string itself + * + * "len": the string length + * + * "attrs": the type identifier for the string, which indicates the + * encoding and representation. We're only interested in ASCII + * encoded strings whose representation is one of: + * + * SeqString stored directly as a char array inside the object + * + * ConsString pointer to two strings that should be concatenated + * + * ExternalString pointer to a char* outside the V8 heap + */ + +/* + * Load "len" and "attrs" for the given "str". + */ +#define LOAD_STRFIELDS(str, len, attrs) \ + len = SMI_VALUE(COPYIN_UINT32(str + V8_OFF_STR_LENGTH)); \ + this->map = COPYIN_UINT32(str + V8_OFF_HEAPOBJ_MAP); \ + attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); + +/* + * Print out the given SeqString, or do nothing if the string is not an ASCII + * SeqString. + */ +#define APPEND_SEQSTR(str, len, attrs) \ +dtrace:helper:ustack: \ +/!this->done && len > 0 && ASCII_SEQSTR(attrs)/ \ +{ \ + copyinto(str + V8_OFF_STR_CHARS, len, this->buf + this->off); \ + this->off += len; \ +} + +/* + * Print out the given Node.js ExternalString, or do nothing if the string is + * not an ASCII ExternalString. + */ +#define APPEND_NODESTR(str, len, attrs) \ +dtrace:helper:ustack: \ +/!this->done && len > 0 && ASCII_EXTSTR(attrs)/ \ +{ \ + this->resource = COPYIN_UINT32(str + V8_OFF_EXTSTR_RSRC); \ + this->dataptr = COPYIN_UINT32(this->resource + NODE_OFF_EXTSTR_DATA); \ + copyinto(this->dataptr, len, this->buf + this->off); \ + this->off += len; \ +} + +/* + * Recall that each ConsString points to two other strings which are + * semantically concatenated. Of course, these strings may themselves by + * ConsStrings, but in D we can only expand this recursion to a finite level. + * Thankfully, function and script names are generally not more than a few + * levels deep, so we unroll the expansion up to three levels. Even this is + * pretty hairy: we use strings "s0", ..., "s13", (each with "str", "len", and + * "attr" fields -- see above) to store the expanded strings. We expand the + * original string into s0 and s7, then s0 into s1 and s4, etc: + * + * + * +---- str ----+ + * / \ <-- 1st expansion + * / \ + * s0 s7 + * / \ / \ + * / \ / \ <-- 2nd expansion + * / \ / \ + * s1 s4 s8 s11 + * / \ / \ / \ / \ <-- 3rd expansion + * s2 s3 s5 s6 s9 s10 s12 s13 + * + * Of course, for a given string, any of these expansions may not be needed. + * For example, we may expand str and find that s0 is already a SeqString, + * while s7 requires further expansion. So when we expand a ConsString, we + * zero the length of the string itself, and then at the end we print out + * all non-zero-length strings in order (including both internal nodes and + * leafs in the tree above) to get the final output. + */ +#define EXPAND_START() \ +dtrace:helper:ustack: \ +/!this->done/ \ +{ \ + this->s0str = this->s1str = this->s2str = 0; \ + this->s3str = this->s4str = this->s5str = 0; \ + this->s6str = this->s7str = this->s8str = 0; \ + this->s9str = this->s10str = this->s11str = 0; \ + this->s12str = this->s13str = 0; \ + \ + this->s0len = this->s1len = this->s2len = 0; \ + this->s3len = this->s4len = this->s5len = 0; \ + this->s6len = this->s7len = this->s8len = 0; \ + this->s9len = this->s10len = this->s11len = 0; \ + this->s12len = this->s13len = 0; \ + \ + this->s0attrs = this->s1attrs = this->s2attrs = 0; \ + this->s3attrs = this->s4attrs = this->s5attrs = 0; \ + this->s6attrs = this->s7attrs = this->s8attrs = 0; \ + this->s9attrs = this->s10attrs = this->s11attrs = 0; \ + this->s12attrs = this->s13attrs = 0; \ +} + +/* + * Expand the ConsString "str" (represensted by "str", "len", and "attrs") into + * strings "s1" (represented by "s1s", "s1l", and "s1a") and "s2" (represented + * by "s2s", "s2l", "s2a"). If "str" is not a ConsString, do nothing. + */ +#define EXPAND_STR(str, len, attrs, s1s, s1l, s1a, s2s, s2l, s2a) \ +dtrace:helper:ustack: \ +/!this->done && len > 0 && ASCII_CONSSTR(attrs)/ \ +{ \ + len = 0; \ + \ + s1s = COPYIN_UINT32(str + V8_OFF_CONSSTR_CAR); \ + LOAD_STRFIELDS(s1s, s1l, s1a) \ + \ + s2s = COPYIN_UINT32(str + V8_OFF_CONSSTR_CDR); \ + LOAD_STRFIELDS(s2s, s2l, s2a) \ +} + +/* + * Print out a ConsString by expanding it up to three levels and printing out + * the resulting SeqStrings. + */ +#define APPEND_CONSSTR(str, len, attrs) \ + EXPAND_START() \ + EXPAND_STR(str, len, attrs, \ + this->s0str, this->s0len, this->s0attrs, \ + this->s7str, this->s7len, this->s7attrs) \ + EXPAND_STR(this->s0str, this->s0len, this->s0attrs, \ + this->s1str, this->s1len, this->s1attrs, \ + this->s4str, this->s4len, this->s4attrs) \ + EXPAND_STR(this->s1str, this->s1len, this->s1attrs, \ + this->s2str, this->s2len, this->s2attrs, \ + this->s3str, this->s3len, this->s3attrs) \ + EXPAND_STR(this->s4str, this->s4len, this->s4attrs, \ + this->s5str, this->s5len, this->s5attrs, \ + this->s6str, this->s6len, this->s6attrs) \ + EXPAND_STR(this->s7str, this->s7len, this->s7attrs, \ + this->s8str, this->s8len, this->s8attrs, \ + this->s11str, this->s11len, this->s11attrs) \ + EXPAND_STR(this->s8str, this->s8len, this->s8attrs, \ + this->s9str, this->s9len, this->s9attrs, \ + this->s10str, this->s10len, this->s10attrs) \ + EXPAND_STR(this->s11str, this->s11len, this->s11attrs, \ + this->s12str, this->s12len, this->s12attrs, \ + this->s13str, this->s13len, this->s13attrs) \ + \ + APPEND_SEQSTR(str, len, attrs) \ + APPEND_SEQSTR(this->s0str, this->s0len, this->s0attrs) \ + APPEND_SEQSTR(this->s1str, this->s1len, this->s1attrs) \ + APPEND_SEQSTR(this->s2str, this->s2len, this->s2attrs) \ + APPEND_SEQSTR(this->s3str, this->s3len, this->s3attrs) \ + APPEND_SEQSTR(this->s4str, this->s4len, this->s4attrs) \ + APPEND_SEQSTR(this->s5str, this->s5len, this->s5attrs) \ + APPEND_SEQSTR(this->s6str, this->s6len, this->s6attrs) \ + APPEND_SEQSTR(this->s7str, this->s7len, this->s7attrs) \ + APPEND_SEQSTR(this->s8str, this->s8len, this->s8attrs) \ + APPEND_SEQSTR(this->s9str, this->s9len, this->s9attrs) \ + APPEND_SEQSTR(this->s10str, this->s10len, this->s10attrs) \ + APPEND_SEQSTR(this->s11str, this->s11len, this->s11attrs) \ + APPEND_SEQSTR(this->s12str, this->s12len, this->s12attrs) \ + APPEND_SEQSTR(this->s13str, this->s13len, this->s13attrs) \ + + +/* + * Print out the given SeqString, ConsString, or ExternalString. + * APPEND_CONSSTR implicitly handles SeqStrings as the degenerate case of an + * expanded ConsString. + */ +#define APPEND_V8STR(str, len, attrs) \ + APPEND_CONSSTR(str, len, attrs) \ + APPEND_NODESTR(str, len, attrs) + +/* + * In this first clause we initialize all variables. We must explicitly clear + * them because they may contain values left over from previous iterations. + */ +dtrace:helper:ustack: +{ + /* input */ + this->fp = arg1; + + /* output/flow control */ + this->buf = (char *)alloca(128); + this->off = 0; + this->done = 0; + + /* program state */ + this->ctx = 0; + this->marker = 0; + this->func = 0; + this->shared = 0; + this->map = 0; + this->funcnamestr = 0; + this->funcnamelen = 0; + this->funcnameattrs = 0; + this->script = 0; + this->scriptnamestr = 0; + this->scriptnamelen = 0; + this->scriptnameattrs = 0; + this->position = 0; + this->line_ends = 0; + this->le_attrs = 0; + + /* binary search fields */ + this->bsearch_min = 0; + this->bsearch_max = 0; + this->ii = 0; +} + +/* + * Like V8, we first check if we've got an ArgumentsAdaptorFrame. We've got + * nothing to add for such frames, so we bail out quickly. + */ +dtrace:helper:ustack: +{ + this->ctx = COPYIN_UINT32(this->fp + V8_OFF_FP_CONTEXT); +} + +dtrace:helper:ustack: +/IS_SMI(this->ctx) && SMI_VALUE(this->ctx) == V8_FT_ADAPTOR/ +{ + this->done = 1; + APPEND_CHR('<'); + APPEND_CHR('<'); + APPEND_CHR(' '); + APPEND_CHR('a'); + APPEND_CHR('d'); + APPEND_CHR('a'); + APPEND_CHR('p'); + APPEND_CHR('t'); + APPEND_CHR('o'); + APPEND_CHR('r'); + APPEND_CHR(' '); + APPEND_CHR('>'); + APPEND_CHR('>'); + APPEND_CHR('\0'); + stringof(this->buf); +} + +/* + * Check for other common frame types for which we also have nothing to add. + */ +dtrace:helper:ustack: +/!this->done/ +{ + this->marker = COPYIN_UINT32(this->fp + V8_OFF_FP_MARKER); +} + +dtrace:helper:ustack: +/!this->done && IS_SMI(this->marker) && + SMI_VALUE(this->marker) == V8_FT_ENTRY/ +{ + this->done = 1; + APPEND_CHR('<'); + APPEND_CHR('<'); + APPEND_CHR(' '); + APPEND_CHR('e'); + APPEND_CHR('n'); + APPEND_CHR('t'); + APPEND_CHR('r'); + APPEND_CHR('y'); + APPEND_CHR(' '); + APPEND_CHR('>'); + APPEND_CHR('>'); + APPEND_CHR('\0'); + stringof(this->buf); +} + +dtrace:helper:ustack: +/!this->done && IS_SMI(this->marker) && + SMI_VALUE(this->marker) == V8_FT_ENTRYCONSTRUCT/ +{ + this->done = 1; + APPEND_CHR('<'); + APPEND_CHR('<'); + APPEND_CHR(' '); + APPEND_CHR('e'); + APPEND_CHR('n'); + APPEND_CHR('t'); + APPEND_CHR('r'); + APPEND_CHR('y'); + APPEND_CHR('_'); + APPEND_CHR('c'); + APPEND_CHR('o'); + APPEND_CHR('n'); + APPEND_CHR('s'); + APPEND_CHR('t'); + APPEND_CHR('r'); + APPEND_CHR('u'); + APPEND_CHR('c'); + APPEND_CHR('t'); + APPEND_CHR(' '); + APPEND_CHR('>'); + APPEND_CHR('>'); + APPEND_CHR('\0'); + stringof(this->buf); +} + +dtrace:helper:ustack: +/!this->done && IS_SMI(this->marker) && + SMI_VALUE(this->marker) == V8_FT_EXIT/ +{ + this->done = 1; + APPEND_CHR('<'); + APPEND_CHR('<'); + APPEND_CHR(' '); + APPEND_CHR('e'); + APPEND_CHR('x'); + APPEND_CHR('i'); + APPEND_CHR('t'); + APPEND_CHR(' '); + APPEND_CHR('>'); + APPEND_CHR('>'); + APPEND_CHR('\0'); + stringof(this->buf); +} + +dtrace:helper:ustack: +/!this->done && IS_SMI(this->marker) && + SMI_VALUE(this->marker) == V8_FT_INTERNAL/ +{ + this->done = 1; + APPEND_CHR('<'); + APPEND_CHR('<'); + APPEND_CHR(' '); + APPEND_CHR('i'); + APPEND_CHR('n'); + APPEND_CHR('t'); + APPEND_CHR('e'); + APPEND_CHR('r'); + APPEND_CHR('n'); + APPEND_CHR('a'); + APPEND_CHR('l'); + APPEND_CHR(' '); + APPEND_CHR('>'); + APPEND_CHR('>'); + APPEND_CHR('\0'); + stringof(this->buf); +} + +dtrace:helper:ustack: +/!this->done && IS_SMI(this->marker) && + SMI_VALUE(this->marker) == V8_FT_CONSTRUCT/ +{ + this->done = 1; + APPEND_CHR('<'); + APPEND_CHR('<'); + APPEND_CHR(' '); + APPEND_CHR('c'); + APPEND_CHR('o'); + APPEND_CHR('n'); + APPEND_CHR('s'); + APPEND_CHR('t'); + APPEND_CHR('r'); + APPEND_CHR('u'); + APPEND_CHR('c'); + APPEND_CHR('t'); + APPEND_CHR('o'); + APPEND_CHR('r'); + APPEND_CHR(' '); + APPEND_CHR('>'); + APPEND_CHR('>'); + APPEND_CHR('\0'); + stringof(this->buf); +} + +/* + * At this point, we're either looking at a JavaScriptFrame or an + * OptimizedFrame. For now, we assume JavaScript and start by grabbing the + * function name. + */ +dtrace:helper:ustack: +/!this->done/ +{ + this->func = COPYIN_UINT32(this->fp + V8_OFF_FP_FUNC); + this->shared = COPYIN_UINT32(this->func + V8_OFF_FUNC_SHARED); + this->funcnamestr = COPYIN_UINT32(this->shared + V8_OFF_SHARED_NAME); + LOAD_STRFIELDS(this->funcnamestr, this->funcnamelen, + this->funcnameattrs); +} + +dtrace:helper:ustack: +/!this->done && this->funcnamelen == 0/ +{ + /* + * This is an anonymous function, but if it was invoked as a method of + * some object then V8 will have computed an inferred name that we can + * include in the stack trace. + */ + APPEND_CHR('('); + APPEND_CHR('a'); + APPEND_CHR('n'); + APPEND_CHR('o'); + APPEND_CHR('n'); + APPEND_CHR(')'); + APPEND_CHR(' '); + APPEND_CHR('a'); + APPEND_CHR('s'); + APPEND_CHR(' '); + + this->funcnamestr = COPYIN_UINT32(this->shared + V8_OFF_SHARED_INFERRED); + LOAD_STRFIELDS(this->funcnamestr, this->funcnamelen, + this->funcnameattrs); +} + +dtrace:helper:ustack: +/!this->done && this->funcnamelen == 0/ +{ + APPEND_CHR('('); + APPEND_CHR('a'); + APPEND_CHR('n'); + APPEND_CHR('o'); + APPEND_CHR('n'); + APPEND_CHR(')'); +} + +APPEND_V8STR(this->funcnamestr, this->funcnamelen, this->funcnameattrs) + +/* + * Now look for the name of the script where the function was defined. + */ +dtrace:helper:ustack: +/!this->done/ +{ + this->script = COPYIN_UINT32(this->shared + V8_OFF_SHARED_SCRIPT); + this->scriptnamestr = COPYIN_UINT32(this->script + + V8_OFF_SCRIPT_NAME); + LOAD_STRFIELDS(this->scriptnamestr, this->scriptnamelen, + this->scriptnameattrs); + + APPEND_CHR(' '); + APPEND_CHR('a'); + APPEND_CHR('t'); + APPEND_CHR(' '); +} + +APPEND_V8STR(this->scriptnamestr, this->scriptnamelen, this->scriptnameattrs) + +/* + * Now look for file position and line number information. + */ +dtrace:helper:ustack: +/!this->done/ +{ + this->position = COPYIN_UINT32(this->shared + V8_OFF_SHARED_FUNTOK); + this->line_ends = COPYIN_UINT32(this->script + V8_OFF_SCRIPT_LENDS); + this->map = COPYIN_UINT32(this->line_ends + V8_OFF_HEAPOBJ_MAP); + this->le_attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); +} + +dtrace:helper:ustack: +/!this->done && this->le_attrs != V8_IT_FIXEDARRAY/ +{ + /* + * If the line number array was not a valid FixedArray, it's probably + * undefined because V8 has not had to compute it yet. In this case we + * just show the raw position and call it a day. + */ + APPEND_CHR(' '); + APPEND_CHR('p'); + APPEND_CHR('o'); + APPEND_CHR('s'); + APPEND_CHR('i'); + APPEND_CHR('t'); + APPEND_CHR('i'); + APPEND_CHR('o'); + APPEND_CHR('n'); + APPEND_CHR(' '); + APPEND_NUM(this->position); + APPEND_CHR('\0'); + this->done = 1; + stringof(this->buf); +} + +/* + * At this point, we've got both a position in the script and an array + * describing where each line of the file ends. We can use this to compute the + * line number by binary searching the array. (This is also what V8 does when + * computing stack traces.) + */ +dtrace:helper:ustack: +/!this->done/ +{ + /* initialize binary search */ + this->bsearch_line = this->position < COPYIN_UINT32( + this->line_ends + V8_OFF_FA_DATA) ? 1 : 0; + this->bsearch_min = 0; + this->bsearch_max = this->bsearch_line != 0 ? 0 : + SMI_VALUE(COPYIN_UINT32(this->line_ends + V8_OFF_FA_SIZE)) - 1; +} + +/* + * Of course, we can't iterate the binary search indefinitely, so we hardcode 15 + * iterations. That's enough to precisely identify the line number in files up + * to 32768 lines of code. + */ +#define BSEARCH_LOOP \ +dtrace:helper:ustack: \ +/!this->done && this->bsearch_max >= 1/ \ +{ \ + this->ii = (this->bsearch_min + this->bsearch_max) >> 1; \ +} \ + \ +dtrace:helper:ustack: \ +/!this->done && this->bsearch_max >= 1 && \ + this->position > COPYIN_UINT32(this->line_ends + V8_OFF_FA_DATA + \ + this->ii * sizeof (uint32_t))/ \ +{ \ + this->bsearch_min = this->ii + 1; \ +} \ + \ +dtrace:helper:ustack: \ +/!this->done && this->bsearch_max >= 1 && \ + this->position <= COPYIN_UINT32(this->line_ends + V8_OFF_FA_DATA + \ + (this->ii - 1) * sizeof (uint32_t))/ \ +{ \ + this->bsearch_max = this->ii - 1; \ +} + +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP +BSEARCH_LOOP + +dtrace:helper:ustack: +/!this->done && !this->bsearch_line/ +{ + this->bsearch_line = this->ii + 1; +} + +dtrace:helper:ustack: +/!this->done/ +{ + APPEND_CHR(' '); + APPEND_CHR('l'); + APPEND_CHR('i'); + APPEND_CHR('n'); + APPEND_CHR('e'); + APPEND_CHR(' '); + APPEND_NUM(this->bsearch_line); + APPEND_CHR('\0'); + this->done = 1; + stringof(this->buf); +} diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index 1469b11166..cbccc72dad 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -385,6 +385,14 @@ var secret3 = dh3.computeSecret(key2, 'hex', 'base64'); assert.equal(secret1, secret3); +// https://github.com/joyent/node/issues/2338 +assert.throws(function() { + var p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + + '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' + + '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' + + 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'; + crypto.createDiffieHellman(p, 'hex'); +}); // Test RSA key signing/verification var rsaSign = crypto.createSign('RSA-SHA1'); @@ -474,3 +482,8 @@ crypto.pbkdf2('passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt' crypto.pbkdf2('pass\0word', 'sa\0lt', 4096, 16, function(err, result) { assert.equal(result, '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3', 'pbkdf1 test vector 6'); }); + +// Error path should not leak memory (check with valgrind). +assert.throws(function() { + crypto.pbkdf2('password', 'salt', 1, 20, null); +}); diff --git a/test/simple/test-fs-read-stream.js b/test/simple/test-fs-read-stream.js index 63e9b1ae41..dbb5fbf847 100644 --- a/test/simple/test-fs-read-stream.js +++ b/test/simple/test-fs-read-stream.js @@ -133,6 +133,15 @@ file5.on('end', function() { assert.equal(file5.data, 'yz\n'); }); +// https://github.com/joyent/node/issues/2320 +var file6 = fs.createReadStream(rangeFile, {bufferSize: 1.23, start: 1}); +file6.data = ''; +file6.on('data', function(data) { + file6.data += data.toString('utf-8'); +}); +file6.on('end', function() { + assert.equal(file6.data, 'yz\n'); +}); assert.throws(function() { fs.createReadStream(rangeFile, {start: 10, end: 2}); diff --git a/test/simple/test-http-bind-twice.js b/test/simple/test-http-bind-twice.js new file mode 100644 index 0000000000..59d69efaa2 --- /dev/null +++ b/test/simple/test-http-bind-twice.js @@ -0,0 +1,47 @@ +// 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 http = require('http'); + +var gotError = false; + +process.on('exit', function() { + assert(gotError); +}); + +function dontCall() { + assert(false); +} + +var server1 = http.createServer(dontCall); +server1.listen(common.PORT, '127.0.0.1', function() {}); + +var server2 = http.createServer(dontCall); +server2.listen(common.PORT, '127.0.0.1', dontCall); + +server2.on('error', function(e) { + assert.equal(e.code, 'EADDRINUSE'); + server1.close(); + gotError = true; +}); + diff --git a/test/simple/test-net-bind-twice.js b/test/simple/test-net-bind-twice.js new file mode 100644 index 0000000000..58086cc966 --- /dev/null +++ b/test/simple/test-net-bind-twice.js @@ -0,0 +1,46 @@ +// 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 net = require('net'); + +var gotError = false; + +process.on('exit', function() { + assert(gotError); +}); + +function dontCall() { + assert(false); +} + +var server1 = net.createServer(dontCall); +server1.listen(common.PORT, '127.0.0.1', function() {}); + +var server2 = net.createServer(dontCall); +server2.listen(common.PORT, '127.0.0.1', dontCall); + +server2.on('error', function(e) { + assert.equal(e.code, 'EADDRINUSE'); + server1.close(); + gotError = true; +}); diff --git a/tools/msvs/msi/nodemsi.wixproj b/tools/msvs/msi/nodemsi.wixproj index e45372457b..d7a3b62dd5 100644 --- a/tools/msvs/msi/nodemsi.wixproj +++ b/tools/msvs/msi/nodemsi.wixproj @@ -33,13 +33,25 @@ WixUIExtension + + + + + + + + + + - + + + + + + + + diff --git a/tools/msvs/msi/product.wxs b/tools/msvs/msi/product.wxs index d924a4dfef..bdf28a587a 100644 --- a/tools/msvs/msi/product.wxs +++ b/tools/msvs/msi/product.wxs @@ -4,7 +4,7 @@ - + + @@ -111,8 +114,8 @@ - - + +