Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

XMLHttpRequest piped in a writable file stream hangs next request #2263

Closed
gabipetrovay opened this issue Dec 4, 2011 · 9 comments
Closed

Comments

@gabipetrovay
Copy link

Hi,

This is the thread where I came across this problem:
http://groups.google.com/group/nodejs/browse_thread/thread/5691a9fd25a6a65d

In that thread there was also another bug of mine but now I managed to minimize the remaining problem here:
http://dl.dropbox.com/u/2161705/test.zip

  1. Run the test app and open http://localhost.com:3000/test.html in your browser.
  2. An alert should tell you that an XMLHttpRequest POST request was made in the background.
  3. Click the Reload link and the page should hang (2 minutes in Chrome or Firefox)

I also paste the code here if somebody can directly see a flaw in it:

app.js

var express = require('express');

var app = module.exports = express.createServer();

app.configure(function(){
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.post('/test', function(req, res) {
    var fs = require('fs');
    var fileStream = fs.createWriteStream('./test.txt');

    req.on('end', function() {
        res.send(200);
    });
    req.pipe(fileStream);
});

app.listen(3000);

test.html

<html>
    <body>
        <script type="text/javascript">

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4)
        alert('XMLHttpRequest POST request performed.');
};

xhr.open("POST", '/test', true);
xhr.send('12345');

        </script>
        <a href="/test.html">Reload</a> (This will only work every second click)
    </body>
</html>

Gabriel

@bnoordhuis
Copy link
Member

Thanks for the report. Your test case depends on express however and we don't support third-party modules. I'll have to ask you to either rewrite it or contact the express people.

@gabipetrovay
Copy link
Author

Hi Ben,

Thanks for the short reply, but I don't agree with you here since it looks like you stopped parsing at line 1. Express was used as a way to make the example cleaner. And I guess it's pretty obvious the problem has probably nothing to do with express. Neither do have: "XMLHttpRequest", "pipe", "writable file stream", "request".

But because of that probably, I went back and minimized it further for you:

http.createServer(function (req, res) {
  console.log(req.url);
  if (req.url == '/test') {
    var fs = require('fs');
    var fileStream = fs.createWriteStream('./test.txt');

    req.on('end', function() {
        res.writeHead(200);
        res.end();
    });
    req.pipe(fileStream);
  } else {
    var response = '<html><body><script type="text/javascript">var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) alert("XMLHttpRequest POST request performed."); }; xhr.open("POST", "/test", true); xhr.send("12345");</script><a href="/test.html">Reload</a> (This will only work every second click)</body></html>'
    res.end(response);
  }
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');

@gabipetrovay
Copy link
Author

"You don't have permission to reopen this issue."

Do you mind reopening it?

Thanks!

@bnoordhuis bnoordhuis reopened this Dec 5, 2011
@koichik
Copy link

koichik commented Dec 5, 2011

@gabipetrovay: Thanks, I confirmed it.
This problem occurs by the following steps:

  • http.ServerRequest emits 'data' event.
  • pipe() calls fs.WriteStream.write(), it always returns false.
  • pipe() calls http.ServerRequest.pause(), and it calls net.Socket.pause().
  • However, because the request body has been already received, http.ServerRequest emits 'end' event (see also Avoid 'data' and/or 'end' events after pause() was called #1040).
  • pipe() calls fs.WriteStream.end(), and destroys the pipeline.

Therefore, because nobody calls http.ServerRequest.resume(), net.Socket is still paused. This is the reason why the second request to use Connection: Keep-Alive is not handled.
So, we should resume the socket.

@koichik
Copy link

koichik commented Dec 5, 2011

Can someone review koichik/node@b4da500?

@koichik
Copy link

koichik commented Dec 26, 2011

@bnoordhuis Can you review koichik/node@b4da500?

@bnoordhuis
Copy link
Member

@koichik: LGTM. I ran some http_simple benchmarks and didn't notice a performance difference (nothing above the level of noise anyway) but can you double-check that before you merge it?

@koichik
Copy link

koichik commented Dec 27, 2011

@bnoordhuis Thanks!

can you double-check that before you merge it?

I confirmed it. I did not find the difference, too. Merging.

@koichik
Copy link

koichik commented Dec 27, 2011

@gabipetrovay Thanks for the report, fixed in a337ac7.

isaacs added a commit to isaacs/node-v0.x-archive that referenced this issue Jan 6, 2012
* Upgrade V8 to 3.6.6.15

* Upgrade npm to 1.1.0-beta-10 (isaacs)

* many doc updates (Ben Noordhuis, Jeremy Martin, koichik, Dave Irvine,
  Seong-Rak Choi, Shannen, Adam Malcontenti-Wilson, koichik)

* nodejs#2438 segfault in node v0.6.6

* dgram, timers: fix memory leaks (Ben Noordhuis, Yoshihiro Kukuchi)

* repl: fix repl.start not passing the `ignoreUndefined` arg (Damon Oehlman)

* nodejs#1980: Socket.pause null reference when called on a closed Stream (koichik)

* nodejs#2263: XMLHttpRequest piped in a writable file stream hang (koichik)

* nodejs#2069: http resource leak (koichik)

* buffer.readInt global pollution fix (Phil Sung)

* timers: fix performance regression (Ben Noordhuis)

* nodejs#2308, nodejs#2246: node swallows openssl error on request (koichik)

* nodejs#2114: timers: remove _idleTimeout from item in .unenroll() (James Hartig)

* nodejs#2379: debugger: Request backtrace w/o refs (Fedor Indutny)

* simple DTrace ustack helper (Dave Pacheco)

* crypto: rewrite HexDecode without snprintf (Roman Shtylman)

* crypto: add SecureContext.clearOptions() method (Ben Noordhuis)

* crypto: don't ignore DH init errors (Ben Noordhuis)
isaacs added a commit that referenced this issue Jan 7, 2012
* V8 hash collision fix (Breaks MIPS) (Bert Belder, Erik Corry)

* Upgrade V8 to 3.6.6.15

* Upgrade npm to 1.1.0-beta-10 (isaacs)

* many doc updates (Ben Noordhuis, Jeremy Martin, koichik, Dave Irvine,
  Seong-Rak Choi, Shannen, Adam Malcontenti-Wilson, koichik)

* Fix segfault in node_http_parser.cc

* dgram, timers: fix memory leaks (Ben Noordhuis, Yoshihiro Kukuchi)

* repl: fix repl.start not passing the `ignoreUndefined` arg (Damon Oehlman)

* #1980: Socket.pause null reference when called on a closed Stream (koichik)

* #2263: XMLHttpRequest piped in a writable file stream hang (koichik)

* #2069: http resource leak (koichik)

* buffer.readInt global pollution fix (Phil Sung)

* timers: fix performance regression (Ben Noordhuis)

* #2308, #2246: node swallows openssl error on request (koichik)

* #2114: timers: remove _idleTimeout from item in .unenroll() (James Hartig)

* #2379: debugger: Request backtrace w/o refs (Fedor Indutny)

* simple DTrace ustack helper (Dave Pacheco)

* crypto: rewrite HexDecode without snprintf (Roman Shtylman)

* crypto: don't ignore DH init errors (Ben Noordhuis)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants