--- a/netwerk/protocol/http/InterceptedChannel.cpp
+++ b/netwerk/protocol/http/InterceptedChannel.cpp
@@ -89,28 +89,28 @@ InterceptedChannelBase::DoSynthesizeStat
// Always assume HTTP 1.1 for synthesized responses.
nsAutoCString statusLine;
statusLine.AppendLiteral("HTTP/1.1 ");
statusLine.AppendInt(aStatus);
statusLine.AppendLiteral(" ");
statusLine.Append(aReason);
- (*mSynthesizedResponseHead)->ParseStatusLine(statusLine.get());
+ (*mSynthesizedResponseHead)->ParseStatusLine(statusLine);
return NS_OK;
}
nsresult
InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, const nsACString& aValue)
{
EnsureSynthesizedResponse();
nsAutoCString header = aName + NS_LITERAL_CSTRING(": ") + aValue;
// Overwrite any existing header.
- nsresult rv = (*mSynthesizedResponseHead)->ParseHeaderLine(header.get());
+ nsresult rv = (*mSynthesizedResponseHead)->ParseHeaderLine(header);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
InterceptedChannelBase::GetConsoleReportCollector(nsIConsoleReportCollector** aCollectorOut)
{
MOZ_ASSERT(aCollectorOut);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3554,17 +3554,17 @@ nsHttpChannel::OnCacheEntryCheck(nsICach
// line and headers in the form Firefox uses them internally (no dupicate
// headers, etc.).
rv = entry->GetMetaDataElement("response-head", getter_Copies(buf));
NS_ENSURE_SUCCESS(rv, rv);
// Parse string stored in a "response-head" metadata element.
// These response headers will be merged with the orignal headers (i.e. the
// headers stored in a "original-response-headers" metadata element).
- rv = mCachedResponseHead->ParseCachedHead((char *) buf.get());
+ rv = mCachedResponseHead->ParseCachedHead(buf.get());
NS_ENSURE_SUCCESS(rv, rv);
buf.Adopt(0);
bool isCachedRedirect = WillRedirect(mCachedResponseHead);
// Do not return 304 responses from the cache, and also do not return
// any other non-redirect 3xx responses from the cache (see bug 759043).
NS_ENSURE_TRUE((mCachedResponseHead->Status() / 100 != 3) ||
--- a/netwerk/protocol/http/nsHttpChunkedDecoder.cpp
+++ b/netwerk/protocol/http/nsHttpChunkedDecoder.cpp
@@ -108,17 +108,17 @@ nsHttpChunkedDecoder::ParseChunkRemainin
if (mWaitEOF) {
if (*buf) {
LOG(("got trailer: %s\n", buf));
// allocate a header array for the trailers on demand
if (!mTrailers) {
mTrailers = new nsHttpHeaderArray();
}
- mTrailers->ParseHeaderLine(buf);
+ mTrailers->ParseHeaderLine(nsDependentCSubstring(buf, count));
}
else {
mWaitEOF = false;
mReachedEOF = true;
LOG(("reached end of chunked-body\n"));
}
}
else if (*buf) {
--- a/netwerk/protocol/http/nsHttpHeaderArray.cpp
+++ b/netwerk/protocol/http/nsHttpHeaderArray.cpp
@@ -303,66 +303,68 @@ nsHttpHeaderArray::VisitHeaders(nsIHttpH
if NS_FAILED(rv) {
return rv;
}
}
return NS_OK;
}
/*static*/ nsresult
-nsHttpHeaderArray::ParseHeaderLine(const char *line,
+nsHttpHeaderArray::ParseHeaderLine(const nsACString& line,
nsHttpAtom *hdr,
- char **val)
+ nsACString *val)
{
//
// BNF from section 4.2 of RFC 2616:
//
// message-header = field-name ":" [ field-value ]
// field-name = token
// field-value = *( field-content | LWS )
// field-content = <the OCTETs making up the field-value
// and consisting of either *TEXT or combinations
// of token, separators, and quoted-string>
//
// We skip over mal-formed headers in the hope that we'll still be able to
// do something useful with the response.
- char *p = (char *) strchr(line, ':');
- if (!p) {
- LOG(("malformed header [%s]: no colon\n", line));
+ int32_t split = line.FindChar(':');
+
+ if (split == kNotFound) {
+ LOG(("malformed header [%s]: no colon\n",
+ PromiseFlatCString(line).get()));
return NS_ERROR_FAILURE;
}
+ const nsACString& sub = Substring(line, 0, split);
+ const nsACString& sub2 = Substring(
+ line, split + 1, line.Length() - split - 1);
+
// make sure we have a valid token for the field-name
- if (!nsHttp::IsValidToken(line, p)) {
- LOG(("malformed header [%s]: field-name not a token\n", line));
+ if (!nsHttp::IsValidToken(sub)) {
+ LOG(("malformed header [%s]: field-name not a token\n",
+ PromiseFlatCString(line).get()));
return NS_ERROR_FAILURE;
}
- *p = 0; // null terminate field-name
-
- nsHttpAtom atom = nsHttp::ResolveAtom(line);
+ nsHttpAtom atom = nsHttp::ResolveAtom(sub);
if (!atom) {
- LOG(("failed to resolve atom [%s]\n", line));
+ LOG(("failed to resolve atom [%s]\n", PromiseFlatCString(line).get()));
return NS_ERROR_FAILURE;
}
// skip over whitespace
- p = net_FindCharNotInSet(++p, HTTP_LWS);
+ char *p = net_FindCharNotInSet(
+ sub2.BeginReading(), sub2.EndReading(), HTTP_LWS);
// trim trailing whitespace - bug 86608
- char *p2 = net_RFindCharNotInSet(p, HTTP_LWS);
-
- *++p2 = 0; // null terminate header value; if all chars starting at |p|
- // consisted of LWS, then p2 would have pointed at |p-1|, so
- // the prefix increment is always valid.
+ char *p2 = net_RFindCharNotInSet(p, sub2.EndReading(), HTTP_LWS);
// assign return values
if (hdr) *hdr = atom;
- if (val) *val = p;
+ if (val) val->Assign(p, p2 - p + 1);
return NS_OK;
}
void
nsHttpHeaderArray::Flatten(nsACString &buf, bool pruneProxyHeaders,
bool pruneTransients)
{
--- a/netwerk/protocol/http/nsHttpHeaderArray.h
+++ b/netwerk/protocol/http/nsHttpHeaderArray.h
@@ -91,19 +91,19 @@ public:
eFilterResponse,
eFilterResponseOriginal
};
nsresult VisitHeaders(nsIHttpHeaderVisitor *visitor, VisitorFilter filter = eFilterAll);
// parse a header line, return the header atom and a pointer to the
// header value (the substring of the header line -- do not free).
- static nsresult ParseHeaderLine(const char *line,
+ static nsresult ParseHeaderLine(const nsACString& line,
nsHttpAtom *header=nullptr,
- char **value=nullptr);
+ nsACString* value=nullptr);
void Flatten(nsACString &, bool pruneProxyHeaders, bool pruneTransients);
void FlattenOriginalHeader(nsACString &);
uint32_t Count() const { return mHeaders.Length(); }
const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header) const;
--- a/netwerk/protocol/http/nsHttpRequestHead.cpp
+++ b/netwerk/protocol/http/nsHttpRequestHead.cpp
@@ -244,31 +244,32 @@ nsHttpRequestHead::ParsedMethod()
bool
nsHttpRequestHead::EqualsMethod(ParsedMethodType aType)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mParsedMethod == aType;
}
void
-nsHttpRequestHead::ParseHeaderSet(char *buffer)
+nsHttpRequestHead::ParseHeaderSet(const char *buffer)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsHttpAtom hdr;
- char *val;
+ nsAutoCString val;
while (buffer) {
- char *eof = strchr(buffer, '\r');
+ const char *eof = strchr(buffer, '\r');
if (!eof) {
break;
}
- *eof = '\0';
- if (NS_SUCCEEDED(nsHttpHeaderArray::ParseHeaderLine(buffer,
- &hdr,
- &val))) {
- mHeaders.SetHeaderFromNet(hdr, nsDependentCString(val), false);
+ if (NS_SUCCEEDED(nsHttpHeaderArray::ParseHeaderLine(
+ nsDependentCSubstring(buffer, eof - buffer),
+ &hdr,
+ &val))) {
+
+ mHeaders.SetHeaderFromNet(hdr, val, false);
}
buffer = eof + 1;
if (*buffer == '\n') {
buffer++;
}
}
}
--- a/netwerk/protocol/http/nsHttpRequestHead.h
+++ b/netwerk/protocol/http/nsHttpRequestHead.h
@@ -93,34 +93,34 @@ public:
bool EqualsMethod(ParsedMethodType aType);
bool IsGet() { return EqualsMethod(kMethod_Get); }
bool IsPost() { return EqualsMethod(kMethod_Post); }
bool IsOptions() { return EqualsMethod(kMethod_Options); }
bool IsConnect() { return EqualsMethod(kMethod_Connect); }
bool IsHead() { return EqualsMethod(kMethod_Head); }
bool IsPut() { return EqualsMethod(kMethod_Put); }
bool IsTrace() { return EqualsMethod(kMethod_Trace); }
- void ParseHeaderSet(char *buffer);
+ void ParseHeaderSet(const char *buffer);
private:
// All members must be copy-constructable and assignable
nsHttpHeaderArray mHeaders;
nsCString mMethod;
nsHttpVersion mVersion;
// mRequestURI and mPath are strings instead of an nsIURI
// because this is used off the main thread
nsCString mRequestURI;
nsCString mPath;
nsCString mOrigin;
ParsedMethodType mParsedMethod;
bool mHTTPS;
// We are using ReentrantMonitor instead of a Mutex because VisitHeader
- // function calls nsIHttpHeaderVisitor::VisitHeader while under lock.
+ // function calls nsIHttpHeaderVisitor::VisitHeader while under lock.
ReentrantMonitor mReentrantMonitor;
// During VisitHeader we sould not allow cal to SetHeader.
bool mInVisitHeaders;
};
} // namespace net
} // namespace mozilla
--- a/netwerk/protocol/http/nsHttpResponseHead.cpp
+++ b/netwerk/protocol/http/nsHttpResponseHead.cpp
@@ -265,43 +265,41 @@ nsHttpResponseHead::FlattenNetworkOrigin
if (mVersion == NS_HTTP_VERSION_0_9) {
return;
}
mHeaders.FlattenOriginalHeader(buf);
}
nsresult
-nsHttpResponseHead::ParseCachedHead(char *block)
+nsHttpResponseHead::ParseCachedHead(const char *block)
{
ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
LOG(("nsHttpResponseHead::ParseCachedHead [this=%p]\n", this));
// this command works on a buffer as prepared by Flatten, as such it is
// not very forgiving ;-)
char *p = PL_strstr(block, "\r\n");
if (!p)
return NS_ERROR_UNEXPECTED;
- *p = 0;
- ParseStatusLine_locked(block);
+ ParseStatusLine_locked(nsDependentCSubstring(block, p - block));
do {
block = p + 2;
if (*block == 0)
break;
p = PL_strstr(block, "\r\n");
if (!p)
return NS_ERROR_UNEXPECTED;
- *p = 0;
- ParseHeaderLine_locked(block, false);
+ ParseHeaderLine_locked(nsDependentCSubstring(block, p - block), false);
} while (1);
return NS_OK;
}
nsresult
nsHttpResponseHead::ParseCachedOriginalHeaders(char *block)
@@ -313,36 +311,38 @@ nsHttpResponseHead::ParseCachedOriginalH
// as such it is not very forgiving ;-)
if (!block) {
return NS_ERROR_UNEXPECTED;
}
char *p = block;
nsHttpAtom hdr = {0};
- char *val;
+ nsAutoCString val;
nsresult rv;
do {
block = p;
if (*block == 0)
break;
p = PL_strstr(block, "\r\n");
if (!p)
return NS_ERROR_UNEXPECTED;
*p = 0;
- if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(block, &hdr, &val))) {
+ if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(
+ nsDependentCString(block, p - block), &hdr, &val))) {
+
return NS_OK;
}
rv = mHeaders.SetResponseHeaderFromCache(hdr,
- nsDependentCString(val),
+ val,
nsHttpHeaderArray::eVarietyResponseNetOriginal);
if (NS_FAILED(rv)) {
return rv;
}
p = p + 2;
} while (1);
@@ -500,111 +500,122 @@ nsHttpResponseHead::AssignDefaultStatusT
break;
default:
mStatusText.AssignLiteral("No Reason Phrase");
break;
}
}
void
-nsHttpResponseHead::ParseStatusLine(const char *line)
+nsHttpResponseHead::ParseStatusLine(const nsACString &line)
{
+
ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
ParseStatusLine_locked(line);
}
void
-nsHttpResponseHead::ParseStatusLine_locked(const char *line)
+nsHttpResponseHead::ParseStatusLine_locked(const nsACString &line)
{
//
// Parse Status-Line:: HTTP-Version SP Status-Code SP Reason-Phrase CRLF
//
+ const char *start = line.BeginReading();
+ const char *end = line.EndReading();
+ const char *p = start;
+
// HTTP-Version
- ParseVersion(line);
+ ParseVersion(start);
- if ((mVersion == NS_HTTP_VERSION_0_9) || !(line = PL_strchr(line, ' '))) {
+ int32_t index = line.FindChar(' ');
+
+ if ((mVersion == NS_HTTP_VERSION_0_9) || (index == -1)) {
mStatus = 200;
AssignDefaultStatusText();
}
else {
// Status-Code
- mStatus = (uint16_t) atoi(++line);
+ p += index + 1;
+ mStatus = (uint16_t) atoi(p);
if (mStatus == 0) {
LOG(("mal-formed response status; assuming status = 200\n"));
mStatus = 200;
}
// Reason-Phrase is whatever is remaining of the line
- if (!(line = PL_strchr(line, ' '))) {
+ index = line.FindChar(' ', p - start);
+ if (index == -1) {
AssignDefaultStatusText();
}
- else
- mStatusText = nsDependentCString(++line);
+ else {
+ p = start + index + 1;
+ mStatusText = nsDependentCSubstring(p, end - p);
+ }
}
LOG(("Have status line [version=%u status=%u statusText=%s]\n",
unsigned(mVersion), unsigned(mStatus), mStatusText.get()));
}
nsresult
-nsHttpResponseHead::ParseHeaderLine(const char *line)
+nsHttpResponseHead::ParseHeaderLine(const nsACString &line)
{
ReentrantMonitorAutoEnter monitor(mReentrantMonitor);
return ParseHeaderLine_locked(line, true);
}
nsresult
-nsHttpResponseHead::ParseHeaderLine_locked(const char *line, bool originalFromNetHeaders)
+nsHttpResponseHead::ParseHeaderLine_locked(const nsACString &line, bool originalFromNetHeaders)
{
nsHttpAtom hdr = {0};
- char *val;
+ nsAutoCString val;
if (NS_FAILED(nsHttpHeaderArray::ParseHeaderLine(line, &hdr, &val))) {
return NS_OK;
}
nsresult rv;
if (originalFromNetHeaders) {
rv = mHeaders.SetHeaderFromNet(hdr,
- nsDependentCString(val),
+ val,
true);
} else {
rv = mHeaders.SetResponseHeaderFromCache(hdr,
- nsDependentCString(val),
+ val,
nsHttpHeaderArray::eVarietyResponse);
}
if (NS_FAILED(rv)) {
return rv;
}
// leading and trailing LWS has been removed from |val|
// handle some special case headers...
if (hdr == nsHttp::Content_Length) {
int64_t len;
const char *ignored;
// permit only a single value here.
- if (nsHttp::ParseInt64(val, &ignored, &len)) {
+ if (nsHttp::ParseInt64(val.get(), &ignored, &len)) {
mContentLength = len;
}
else {
// If this is a negative content length then just ignore it
- LOG(("invalid content-length! %s\n", val));
+ LOG(("invalid content-length! %s\n", val.get()));
}
}
else if (hdr == nsHttp::Content_Type) {
- LOG(("ParseContentType [type=%s]\n", val));
+ LOG(("ParseContentType [type=%s]\n", val.get()));
bool dummy;
- net_ParseContentType(nsDependentCString(val),
+ net_ParseContentType(val,
mContentType, mContentCharset, &dummy);
}
else if (hdr == nsHttp::Cache_Control)
- ParseCacheControl(val);
+ ParseCacheControl(val.get());
else if (hdr == nsHttp::Pragma)
- ParsePragma(val);
+ ParsePragma(val.get());
return NS_OK;
}
// From section 13.2.3 of RFC2616, we compute the current age of a cached
// response as follows:
//
// currentAge = max(max(0, responseTime - dateValue), ageValue)
// + now - requestTime
--- a/netwerk/protocol/http/nsHttpResponseHead.h
+++ b/netwerk/protocol/http/nsHttpResponseHead.h
@@ -84,25 +84,25 @@ public:
void FlattenNetworkOriginalHeaders(nsACString &buf);
// The next 2 functions parse flattened response head and original net headers.
// They are used when we are reading an entry from the cache.
//
// To keep proper order of the original headers we MUST call
// ParseCachedOriginalHeaders FIRST and then ParseCachedHead.
//
- // block must be null terminated. parsing is destructive.
- nsresult ParseCachedHead(char *block);
+ // block must be null terminated.
+ nsresult ParseCachedHead(const char *block);
nsresult ParseCachedOriginalHeaders(char *block);
- // parse the status line. line must be null terminated.
- void ParseStatusLine(const char *line);
+ // parse the status line.
+ void ParseStatusLine(const nsACString &line);
- // parse a header line. line must be null terminated. parsing is destructive.
- nsresult ParseHeaderLine(const char *line);
+ // parse a header line.
+ nsresult ParseHeaderLine(const nsACString &line);
// cache validation support methods
nsresult ComputeFreshnessLifetime(uint32_t *);
nsresult ComputeCurrentAge(uint32_t now, uint32_t requestTime,
uint32_t *result);
bool MustValidate();
bool MustValidateIfExpired();
@@ -139,18 +139,18 @@ public:
private:
nsresult SetHeader_locked(nsHttpAtom h, const nsACString &v,
bool m=false);
void AssignDefaultStatusText();
void ParseVersion(const char *);
void ParseCacheControl(const char *);
void ParsePragma(const char *);
- void ParseStatusLine_locked(const char *line);
- nsresult ParseHeaderLine_locked(const char *line, bool originalFromNetHeaders);
+ void ParseStatusLine_locked(const nsACString &line);
+ nsresult ParseHeaderLine_locked(const nsACString &line, bool originalFromNetHeaders);
// these return failure if the header does not exist.
nsresult ParseDateHeader(nsHttpAtom header, uint32_t *result) const;
bool ExpiresInPast_locked() const;
nsresult GetAgeValue_locked(uint32_t *result) const;
nsresult GetExpiresValue_locked(uint32_t *result) const;
nsresult GetMaxAgeValue_locked(uint32_t *result) const;
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -1361,19 +1361,19 @@ nsHttpTransaction::LocateHttpStart(char
firstByte = false;
buf++;
len--;
}
return 0;
}
nsresult
-nsHttpTransaction::ParseLine(char *line)
+nsHttpTransaction::ParseLine(nsACString &line)
{
- LOG(("nsHttpTransaction::ParseLine [%s]\n", line));
+ LOG(("nsHttpTransaction::ParseLine [%s]\n", PromiseFlatCString(line).get()));
nsresult rv = NS_OK;
if (!mHaveStatusLine) {
mResponseHead->ParseStatusLine(line);
mHaveStatusLine = true;
// XXX this should probably never happen
if (mResponseHead->Version() == NS_HTTP_VERSION_0_9)
mHaveAllHeaders = true;
@@ -1391,17 +1391,17 @@ nsHttpTransaction::ParseLineSegment(char
if (!mLineBuf.IsEmpty() && mLineBuf.Last() == '\n') {
// trim off the new line char, and if this segment is
// not a continuation of the previous or if we haven't
// parsed the status line yet, then parse the contents
// of mLineBuf.
mLineBuf.Truncate(mLineBuf.Length() - 1);
if (!mHaveStatusLine || (*segment != ' ' && *segment != '\t')) {
- nsresult rv = ParseLine(mLineBuf.BeginWriting());
+ nsresult rv = ParseLine(mLineBuf);
mLineBuf.Truncate();
if (NS_FAILED(rv)) {
gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
mConnInfo, nsHttpConnectionMgr::RedCorruptedContent,
nullptr, 0);
return rv;
}
}
@@ -1470,17 +1470,17 @@ nsHttpTransaction::ParseHead(char *buf,
// tolerate only minor junk before the status line
mHttpResponseMatched = true;
char *p = LocateHttpStart(buf, std::min<uint32_t>(count, 11), true);
if (!p) {
// Treat any 0.9 style response of a put as a failure.
if (mRequestHead->IsPut())
return NS_ERROR_ABORT;
- mResponseHead->ParseStatusLine("");
+ mResponseHead->ParseStatusLine(EmptyCString());
mHaveStatusLine = true;
mHaveAllHeaders = true;
return NS_OK;
}
if (p > buf) {
// skip over the junk
mInvalidResponseBytesRead += p - buf;
*countRead = p - buf;
--- a/netwerk/protocol/http/nsHttpTransaction.h
+++ b/netwerk/protocol/http/nsHttpTransaction.h
@@ -169,17 +169,17 @@ public:
private:
friend class DeleteHttpTransaction;
virtual ~nsHttpTransaction();
nsresult Restart();
nsresult RestartInProgress();
char *LocateHttpStart(char *buf, uint32_t len,
bool aAllowPartialMatch);
- nsresult ParseLine(char *line);
+ nsresult ParseLine(nsACString &line);
nsresult ParseLineSegment(char *seg, uint32_t len);
nsresult ParseHead(char *, uint32_t count, uint32_t *countRead);
nsresult HandleContentStart();
nsresult HandleContent(char *, uint32_t count, uint32_t *contentRead, uint32_t *contentRemaining);
nsresult ProcessData(char *, uint32_t, uint32_t *);
void DeleteSelfOnConsumerThread();
void ReleaseBlockingTransaction();
--- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp
@@ -1210,19 +1210,18 @@ nsMultiMixedConv::ParseHeaders(nsIChanne
done = true;
break;
}
char tmpChar = *newLine;
*newLine = '\0'; // cursor is now null terminated
if (mResponseHead) {
- // ParseHeaderLine is destructive. We create a copy
nsAutoCString tmpHeader(cursor);
- mResponseHead->ParseHeaderLine(tmpHeader.get());
+ mResponseHead->ParseHeaderLine(tmpHeader);
}
char *colon = (char *) strchr(cursor, ':');
if (colon) {
*colon = '\0';
nsAutoCString headerStr(cursor);
headerStr.CompressWhitespace();
*colon = ':';
@@ -1345,9 +1344,8 @@ NS_NewMultiMixedConv(nsMultiMixedConv**
*aMultiMixedConv = new nsMultiMixedConv();
if (! *aMultiMixedConv)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aMultiMixedConv);
return NS_OK;
}
-
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -12527,16 +12527,20 @@
"path": "XMLHttpRequest/getresponseheader-special-characters.htm",
"url": "/XMLHttpRequest/getresponseheader-special-characters.htm"
},
{
"path": "XMLHttpRequest/getresponseheader-unsent-opened-state.htm",
"url": "/XMLHttpRequest/getresponseheader-unsent-opened-state.htm"
},
{
+ "path": "XMLHttpRequest/headers-normalize-response.htm",
+ "url": "/XMLHttpRequest/headers-normalize-response.htm"
+ },
+ {
"path": "XMLHttpRequest/interfaces.html",
"url": "/XMLHttpRequest/interfaces.html"
},
{
"path": "XMLHttpRequest/open-after-abort.htm",
"url": "/XMLHttpRequest/open-after-abort.htm"
},
{
deleted file mode 100644
--- a/testing/web-platform/meta/cors/allow-headers.htm.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[allow-headers.htm]
- type: testharness
- [Disallow origin: http://web-platform.test:8000\\0]
- expected: FAIL
-
- [Disallow origin: *\\0]
- expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/cors/origin.htm.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[origin.htm]
- type: testharness
- [Disallow origin: http://web-platform.test:8000\\0]
- expected: FAIL
-
- [Disallow origin: *\\0]
- expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/cors/remote-origin.htm.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[remote-origin.htm]
- type: testharness
- [Disallow origin: http://www1.web-platform.test:8000\\0]
- expected: FAIL
-
- [Disallow origin: *\\0]
- expected: FAIL
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/XMLHttpRequest/headers-normalize-response.htm
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Whitespace and null in header values</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=support.js?pipe=sub></script>
+
+<h1>Whitespace and null in response header values</h1>
+
+<div id=log></div>
+
+<script>
+
+function matchHeaderValue(val) {
+ test(function () {
+ var client = new XMLHttpRequest();
+ var trimmed = val.trim();
+ client.open("GET", "resources/parse-headers.py?my-custom-header="+encodeURIComponent(val), false);
+ client.send();
+ var r = client.getResponseHeader("My-Custom-Header");
+
+ assert_equals(r, trimmed);
+ }, "Header value: " + val.replace(/\t/g, "[tab]").replace(/ /g, "_").replace("\0", "\\0"));
+}
+
+matchHeaderValue("hello world\0");
+matchHeaderValue("\0hello world");
+matchHeaderValue("hello\0world");
+matchHeaderValue(" hello world");
+matchHeaderValue("hello world ");
+matchHeaderValue(" hello world ");
+matchHeaderValue("\thello world");
+matchHeaderValue("hello world\t");
+matchHeaderValue("\thello world\t");
+matchHeaderValue("hello world");
+matchHeaderValue("hello\tworld");
+matchHeaderValue("\0");
+matchHeaderValue(" ");
+matchHeaderValue("\t");
+matchHeaderValue("");
+
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/XMLHttpRequest/resources/parse-headers.py
@@ -0,0 +1,12 @@
+import json
+
+def main(request, response):
+
+ content = ""
+ if "my-custom-header" in request.GET:
+ val = request.GET.first("my-custom-header")
+ print "header is about to be set to '{}'".format(val)
+ response.headers.set("My-Custom-Header", val)
+ print "header was set"
+
+ return content