Bug 468467 - If onInputStreamReady doesn't process all of the Request-Line the first time, httpd.js asserts. r=honzab
This commit is contained in:
Родитель
e59f981e30
Коммит
1f84fae036
|
@ -1118,7 +1118,7 @@ RequestReader.prototype =
|
|||
|
||||
// if we don't have a full line, wait until we do
|
||||
if (!readSuccess)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
// we have the first non-blank line
|
||||
try
|
||||
|
|
|
@ -159,6 +159,40 @@ function expectLines(iter, expectedLines)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spew a bunch of HTTP metadata from request into the body of response.
|
||||
*
|
||||
* @param request : nsIHttpRequestMetadata
|
||||
* the request whose metadata should be output
|
||||
* @param response : nsIHttpResponse
|
||||
* the response to which the metadata is written
|
||||
*/
|
||||
function writeDetails(request, response)
|
||||
{
|
||||
response.write("Method: " + request.method + "\r\n");
|
||||
response.write("Path: " + request.path + "\r\n");
|
||||
response.write("Query: " + request.queryString + "\r\n");
|
||||
response.write("Version: " + request.httpVersion + "\r\n");
|
||||
response.write("Scheme: " + request.scheme + "\r\n");
|
||||
response.write("Host: " + request.host + "\r\n");
|
||||
response.write("Port: " + request.port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances iter past all non-blank lines and a single blank line, after which
|
||||
* point the body of the response will be returned next from the iterator.
|
||||
*
|
||||
* @param iter : Iterator
|
||||
* an iterator over the CRLF-delimited lines in an HTTP response, currently
|
||||
* just after the Request-Line
|
||||
*/
|
||||
function skipHeaders(iter)
|
||||
{
|
||||
var line = iter.next();
|
||||
while (line !== "")
|
||||
line = iter.next();
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************
|
||||
* SIMPLE SUPPORT FOR LOADING/TESTING A SERIES OF URLS *
|
||||
|
@ -296,9 +330,11 @@ function runHttpTests(testArray, done)
|
|||
* the host to which a connection should be made
|
||||
* @param port : PRUint16
|
||||
* the port to use for the connection
|
||||
* @param data : string
|
||||
* the raw data to send, as a string of characters with codes in the range
|
||||
* 0-255
|
||||
* @param data : string or [string...]
|
||||
* either:
|
||||
* - the raw data to send, as a string of characters with codes in the
|
||||
* range 0-255, or
|
||||
* - an array of such strings whose concatenation forms the raw data
|
||||
* @param responseCheck : function(string) : void
|
||||
* a function which is provided with the data sent by the remote host which
|
||||
* conducts whatever tests it wants on that data; useful for tweaking the test
|
||||
|
@ -308,8 +344,12 @@ function RawTest(host, port, data, responseCheck)
|
|||
{
|
||||
if (0 > port || 65535 < port || port % 1 !== 0)
|
||||
throw "bad port";
|
||||
if (!/^[\x00-\xff]*$/.test(data))
|
||||
throw "bad data contains non-byte-valued character";
|
||||
if (!(data instanceof Array))
|
||||
data = [data];
|
||||
if (data.length <= 0)
|
||||
throw "bad data length";
|
||||
if (!data.every(function(v) { return /^[\x00-\xff]*$/.test(data); }))
|
||||
throw "bad data contained non-byte-valued character";
|
||||
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
@ -372,14 +412,17 @@ function runRawTests(testArray, done)
|
|||
|
||||
function waitToWriteOutput(stream)
|
||||
{
|
||||
stream.asyncWait(writer, 0, testArray[testIndex].data.length - dataIndex,
|
||||
stream.asyncWait(writer, 0, testArray[testIndex].data[dataIndex].length,
|
||||
currentThread);
|
||||
}
|
||||
|
||||
/** Index of the test being run. */
|
||||
var testIndex = -1;
|
||||
|
||||
/** Index of remaining data to be written to the socket in current test. */
|
||||
/**
|
||||
* Index of remaining data strings to be written to the socket in current
|
||||
* test.
|
||||
*/
|
||||
var dataIndex = 0;
|
||||
|
||||
/** Data received so far from the server. */
|
||||
|
@ -428,13 +471,16 @@ function runRawTests(testArray, done)
|
|||
{
|
||||
onOutputStreamReady: function(stream)
|
||||
{
|
||||
var data = testArray[testIndex].data.substring(dataIndex);
|
||||
var data = testArray[testIndex].data[dataIndex];
|
||||
|
||||
var written = 0;
|
||||
try
|
||||
{
|
||||
written = stream.write(data, data.length);
|
||||
dataIndex += written;
|
||||
if (written == data.length)
|
||||
dataIndex++;
|
||||
else
|
||||
testArray[testIndex].data = data.substring(written);
|
||||
}
|
||||
catch (e) { /* stream could have been closed, just ignore */ }
|
||||
|
||||
|
|
|
@ -252,40 +252,6 @@ function checkPrimariesThrow(id)
|
|||
do_check_true(threw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spew a bunch of HTTP metadata from request into the body of response.
|
||||
*
|
||||
* @param request : nsIHttpRequestMetadata
|
||||
* the request whose metadata should be output
|
||||
* @param response : nsIHttpResponse
|
||||
* the response to which the metadata is written
|
||||
*/
|
||||
function writeDetails(request, response)
|
||||
{
|
||||
response.write("Method: " + request.method + "\r\n");
|
||||
response.write("Path: " + request.path + "\r\n");
|
||||
response.write("Query: " + request.queryString + "\r\n");
|
||||
response.write("Version: " + request.httpVersion + "\r\n");
|
||||
response.write("Scheme: " + request.scheme + "\r\n");
|
||||
response.write("Host: " + request.host + "\r\n");
|
||||
response.write("Port: " + request.port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances iter past all non-blank lines and a single blank line, after which
|
||||
* point the body of the response will be returned next from the iterator.
|
||||
*
|
||||
* @param iter : Iterator
|
||||
* an iterator over the CRLF-delimited lines in an HTTP response, currently
|
||||
* just after the Request-Line
|
||||
*/
|
||||
function skipHeaders(iter)
|
||||
{
|
||||
var line = iter.next();
|
||||
while (line !== "")
|
||||
line = iter.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to check for a 400 response.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is httpd.js code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeff Walden <jwalden+code@mit.edu> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Tests that even when an incoming request's data for the Request-Line doesn't
|
||||
* all fit in a single onInputStreamReady notification, the request is handled
|
||||
* properly.
|
||||
*/
|
||||
|
||||
const PORT = 4444;
|
||||
|
||||
var srv;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
srv = createServer();
|
||||
srv.registerPathHandler("/lots-of-leading-blank-lines",
|
||||
lotsOfLeadingBlankLines);
|
||||
srv.registerPathHandler("/very-long-request-line",
|
||||
veryLongRequestLine);
|
||||
srv.start(PORT);
|
||||
|
||||
runRawTests(tests, function() { srv.stop(); });
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
* BEGIN TESTS *
|
||||
***************/
|
||||
|
||||
var test, data, str;
|
||||
var tests = [];
|
||||
|
||||
|
||||
function veryLongRequestLine(request, response)
|
||||
{
|
||||
writeDetails(request, response);
|
||||
response.setStatusLine(request.httpVersion, 200, "TEST PASSED");
|
||||
}
|
||||
var path = "/very-long-request-line?";
|
||||
var gibberish = "dfsasdbfjkbnsldkjnewiunfasjkn";
|
||||
for (var i = 0; i < 10; i++)
|
||||
gibberish += gibberish;
|
||||
str = "GET /very-long-request-line?" + gibberish + " HTTP/1.1\r\n" +
|
||||
"Host: localhost:4444\r\n" +
|
||||
"\r\n";
|
||||
data = [];
|
||||
for (var i = 0; i < str.length; i += 50)
|
||||
data.push(str.substr(i, 50));
|
||||
function checkVeryLongRequestLine(data)
|
||||
{
|
||||
var iter = LineIterator(data);
|
||||
|
||||
// Status-Line
|
||||
do_check_eq(iter.next(), "HTTP/1.1 200 TEST PASSED");
|
||||
|
||||
skipHeaders(iter);
|
||||
|
||||
// Okay, next line must be the data we expected to be written
|
||||
var body =
|
||||
[
|
||||
"Method: GET",
|
||||
"Path: /very-long-request-line",
|
||||
"Query: " + gibberish,
|
||||
"Version: 1.1",
|
||||
"Scheme: http",
|
||||
"Host: localhost",
|
||||
"Port: 4444",
|
||||
];
|
||||
|
||||
expectLines(iter, body);
|
||||
}
|
||||
test = new RawTest("localhost", PORT, data, checkVeryLongRequestLine),
|
||||
tests.push(test);
|
||||
|
||||
|
||||
function lotsOfLeadingBlankLines(request, response)
|
||||
{
|
||||
writeDetails(request, response);
|
||||
response.setStatusLine(request.httpVersion, 200, "TEST PASSED");
|
||||
}
|
||||
var blankLines = "\r\n";
|
||||
for (var i = 0; i < 13; i++)
|
||||
blankLines += blankLines;
|
||||
str = blankLines +
|
||||
"GET /lots-of-leading-blank-lines HTTP/1.1\r\n" +
|
||||
"Host: localhost:4444\r\n" +
|
||||
"\r\n";
|
||||
data = [];
|
||||
for (var i = 0; i < str.length; i += 100)
|
||||
data.push(str.substr(i, 100));
|
||||
function checkLotsOfLeadingBlankLines(data)
|
||||
{
|
||||
var iter = LineIterator(data);
|
||||
|
||||
// Status-Line
|
||||
do_check_eq(iter.next(), "HTTP/1.1 200 TEST PASSED");
|
||||
|
||||
skipHeaders(iter);
|
||||
|
||||
// Okay, next line must be the data we expected to be written
|
||||
var body =
|
||||
[
|
||||
"Method: GET",
|
||||
"Path: /lots-of-leading-blank-lines",
|
||||
"Query: ",
|
||||
"Version: 1.1",
|
||||
"Scheme: http",
|
||||
"Host: localhost",
|
||||
"Port: 4444",
|
||||
];
|
||||
|
||||
expectLines(iter, body);
|
||||
}
|
||||
test = new RawTest("localhost", PORT, data, checkLotsOfLeadingBlankLines),
|
||||
tests.push(test);
|
Загрузка…
Ссылка в новой задаче