summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMoonchild <mcwerewolf@wolfbeast.com>2019-03-12 18:29:14 +0100
committerGitHub <noreply@github.com>2019-03-12 18:29:14 +0100
commit709bc24e9110eba12f94cfcb8db00a8338ac4098 (patch)
tree8218d4f60d9eccacbf42df8cb88094a082d401b4
parent6b4d81521f0c7bef48a1e8c3e9254a81df27a9d2 (diff)
parent367d77ee9a6df15cacaf1a1f4032f834e972b335 (diff)
downloadUXP-709bc24e9110eba12f94cfcb8db00a8338ac4098.tar
UXP-709bc24e9110eba12f94cfcb8db00a8338ac4098.tar.gz
UXP-709bc24e9110eba12f94cfcb8db00a8338ac4098.tar.lz
UXP-709bc24e9110eba12f94cfcb8db00a8338ac4098.tar.xz
UXP-709bc24e9110eba12f94cfcb8db00a8338ac4098.zip
Merge pull request #995 from MoonchildProductions/httpaccept-work
Change the way http Accept: headers are used.
-rw-r--r--dom/fetch/FetchDriver.cpp10
-rw-r--r--dom/xslt/xslt/txMozillaStylesheetCompiler.cpp4
-rw-r--r--layout/style/Loader.cpp4
-rw-r--r--modules/libpref/init/all.js5
-rw-r--r--netwerk/protocol/http/AlternateServices.cpp7
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.cpp5
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.h3
-rw-r--r--netwerk/protocol/http/nsHttpChannel.cpp14
-rw-r--r--netwerk/protocol/http/nsHttpChannel.h3
-rw-r--r--netwerk/protocol/http/nsHttpHandler.cpp67
-rw-r--r--netwerk/protocol/http/nsHttpHandler.h20
-rw-r--r--netwerk/test/mochitests/mochitest.ini2
-rw-r--r--netwerk/test/mochitests/test_accept_header.html106
-rw-r--r--netwerk/test/mochitests/test_accept_header.sjs48
14 files changed, 260 insertions, 38 deletions
diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp
index 1791399b7..6294b0dc5 100644
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -903,11 +903,7 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
AutoTArray<InternalHeaders::Entry, 5> headers;
mRequest->Headers()->GetEntries(headers);
- bool hasAccept = false;
for (uint32_t i = 0; i < headers.Length(); ++i) {
- if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) {
- hasAccept = true;
- }
if (headers[i].mValue.IsEmpty()) {
aChannel->SetEmptyRequestHeader(headers[i].mName);
} else {
@@ -915,12 +911,6 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
}
}
- if (!hasAccept) {
- aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
- NS_LITERAL_CSTRING("*/*"),
- false /* merge */);
- }
-
if (mRequest->ForceOriginHeader()) {
nsAutoString origin;
if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) {
diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
index 726441757..c9bcc31ff 100644
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -462,10 +462,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
- httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
- NS_LITERAL_CSTRING("*/*"),
- false);
-
nsCOMPtr<nsIURI> referrerURI;
aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
if (referrerURI) {
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index a1a0fcfd9..0ce337e29 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1677,10 +1677,6 @@ Loader::LoadSheet(SheetLoadData* aLoadData,
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
- // Send a minimal Accept header for text/css
- httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
- NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
- false);
nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
if (referrerURI)
httpChannel->SetReferrerWithPolicy(referrerURI,
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 3666ca425..4111ca8a9 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1474,7 +1474,10 @@ pref("network.http.request.max-start-delay", 10);
pref("network.http.request.max-attempts", 10);
// Headers
-pref("network.http.accept.default", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+pref("network.http.accept.default", "*/*");
+pref("network.http.accept.navigation", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+pref("network.http.accept.image", "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5");
+pref("network.http.accept.style", "text/css,*/*;q=0.1");
// Prefs allowing granular control of referers
// 0=don't send any, 1=send only on clicks, 2=send on image requests as well
diff --git a/netwerk/protocol/http/AlternateServices.cpp b/netwerk/protocol/http/AlternateServices.cpp
index b3e6babe3..ee2fa9331 100644
--- a/netwerk/protocol/http/AlternateServices.cpp
+++ b/netwerk/protocol/http/AlternateServices.cpp
@@ -654,8 +654,13 @@ private:
{
nsID channelId;
nsLoadFlags flags;
+
+ nsContentPolicyType contentPolicyType =
+ loadInfo ? loadInfo->GetExternalContentPolicyType()
+ : nsIContentPolicy::TYPE_OTHER;
+
if (NS_FAILED(gHttpHandler->NewChannelId(&channelId)) ||
- NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId)) ||
+ NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId, contentPolicyType)) ||
NS_FAILED(chan->SetAllowAltSvc(false)) ||
NS_FAILED(chan->SetRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_ERROR)) ||
NS_FAILED(chan->SetLoadInfo(loadInfo)) ||
diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
index 9e43d89e0..86e177e71 100644
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -151,7 +151,8 @@ HttpBaseChannel::Init(nsIURI *aURI,
nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
- const nsID& aChannelId)
+ const nsID& aChannelId,
+ nsContentPolicyType aContentPolicyType)
{
LOG(("HttpBaseChannel::Init [this=%p]\n", this));
@@ -200,7 +201,7 @@ HttpBaseChannel::Init(nsIURI *aURI,
rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
if (NS_FAILED(rv)) return rv;
- rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS);
+ rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS, aContentPolicyType);
if (NS_FAILED(rv)) return rv;
nsAutoCString type;
diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h
index 9aa696a70..8def0f23c 100644
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -99,7 +99,8 @@ public:
virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
- const nsID& aChannelId);
+ const nsID& aChannelId,
+ nsContentPolicyType aContentPolicyType);
// nsIRequest
NS_IMETHOD GetName(nsACString& aName) override;
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index a890c51b3..481df5ff0 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -324,10 +324,16 @@ nsHttpChannel::Init(nsIURI *uri,
nsProxyInfo *proxyInfo,
uint32_t proxyResolveFlags,
nsIURI *proxyURI,
- const nsID& channelId)
-{
- nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo,
- proxyResolveFlags, proxyURI, channelId);
+ const nsID& channelId,
+ nsContentPolicyType aContentPolicyType)
+{
+ nsresult rv = HttpBaseChannel::Init(uri,
+ caps,
+ proxyInfo,
+ proxyResolveFlags,
+ proxyURI,
+ channelId,
+ aContentPolicyType);
if (NS_FAILED(rv))
return rv;
diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
index 554875b1c..0038e1f71 100644
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -123,7 +123,8 @@ public:
virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
- const nsID& aChannelId) override;
+ const nsID& aChannelId,
+ nsContentPolicyType aContentPolicyType) override;
nsresult OnPush(const nsACString &uri, Http2PushedStream *pushedStream);
diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
index 477961454..0f4c94202 100644
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -468,7 +468,9 @@ nsHttpHandler::InitConnectionMgr()
}
nsresult
-nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecure)
+nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request,
+ bool isSecure,
+ nsContentPolicyType aContentPolicyType)
{
nsresult rv;
@@ -481,7 +483,20 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecu
// Add the "Accept" header. Note, this is set as an override because the
// service worker expects to see it. The other "default" headers are
// hidden from service worker interception.
- rv = request->SetHeader(nsHttp::Accept, mAccept,
+ nsAutoCString accept;
+ if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+ aContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+ accept.Assign(mAcceptNavigation);
+ } else if (aContentPolicyType == nsIContentPolicy::TYPE_IMAGE ||
+ aContentPolicyType == nsIContentPolicy::TYPE_IMAGESET) {
+ accept.Assign(mAcceptImage);
+ } else if (aContentPolicyType == nsIContentPolicy::TYPE_STYLESHEET) {
+ accept.Assign(mAcceptStyle);
+ } else {
+ accept.Assign(mAcceptDefault);
+ }
+
+ rv = request->SetHeader(nsHttp::Accept, accept,
false, nsHttpHeaderArray::eVarietyRequestOverride);
if (NS_FAILED(rv)) return rv;
@@ -1268,12 +1283,36 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
mQoSBits = (uint8_t) clamped(val, 0, 0xff);
}
+ if (PREF_CHANGED(HTTP_PREF("accept.navigation"))) {
+ nsXPIDLCString accept;
+ rv = prefs->GetCharPref(HTTP_PREF("accept.navigation"),
+ getter_Copies(accept));
+ if (NS_SUCCEEDED(rv))
+ SetAccept(accept, ACCEPT_NAVIGATION);
+ }
+
+ if (PREF_CHANGED(HTTP_PREF("accept.image"))) {
+ nsXPIDLCString accept;
+ rv = prefs->GetCharPref(HTTP_PREF("accept.image"),
+ getter_Copies(accept));
+ if (NS_SUCCEEDED(rv))
+ SetAccept(accept, ACCEPT_IMAGE);
+ }
+
+ if (PREF_CHANGED(HTTP_PREF("accept.style"))) {
+ nsXPIDLCString accept;
+ rv = prefs->GetCharPref(HTTP_PREF("accept.style"),
+ getter_Copies(accept));
+ if (NS_SUCCEEDED(rv))
+ SetAccept(accept, ACCEPT_STYLE);
+ }
+
if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
nsXPIDLCString accept;
rv = prefs->GetCharPref(HTTP_PREF("accept.default"),
getter_Copies(accept));
if (NS_SUCCEEDED(rv))
- SetAccept(accept);
+ SetAccept(accept, ACCEPT_DEFAULT);
}
if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
@@ -1897,9 +1936,21 @@ nsHttpHandler::SetAcceptLanguages()
}
nsresult
-nsHttpHandler::SetAccept(const char *aAccept)
+nsHttpHandler::SetAccept(const char *aAccept, AcceptType aType)
{
- mAccept = aAccept;
+ switch (aType) {
+ case ACCEPT_NAVIGATION:
+ mAcceptNavigation = aAccept;
+ break;
+ case ACCEPT_IMAGE:
+ mAcceptImage = aAccept;
+ break;
+ case ACCEPT_STYLE:
+ mAcceptStyle = aAccept;
+ break;
+ case ACCEPT_DEFAULT:
+ mAcceptDefault = aAccept;
+ }
return NS_OK;
}
@@ -2057,7 +2108,11 @@ nsHttpHandler::NewProxiedChannel2(nsIURI *uri,
rv = NewChannelId(&channelId);
NS_ENSURE_SUCCESS(rv, rv);
- rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId);
+ nsContentPolicyType contentPolicyType =
+ aLoadInfo ? aLoadInfo->GetExternalContentPolicyType()
+ : nsIContentPolicy::TYPE_OTHER;
+
+ rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId, contentPolicyType);
if (NS_FAILED(rv))
return rv;
diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h
index f1ec0f947..67b9ebe0e 100644
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsWeakReference.h"
+#include "nsIContentPolicy.h"
#include "nsIHttpProtocolHandler.h"
#include "nsIObserver.h"
#include "nsISpeculativeConnect.h"
@@ -50,6 +51,14 @@ enum FrameCheckLevel {
FRAMECHECK_STRICT
};
+// Fetch spec different http Accept types
+enum AcceptType {
+ ACCEPT_NAVIGATION,
+ ACCEPT_IMAGE,
+ ACCEPT_STYLE,
+ ACCEPT_DEFAULT,
+};
+
//-----------------------------------------------------------------------------
// nsHttpHandler - protocol handler for HTTP and HTTPS
//-----------------------------------------------------------------------------
@@ -70,7 +79,7 @@ public:
nsHttpHandler();
nsresult Init();
- nsresult AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure);
+ nsresult AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure, nsContentPolicyType aContentPolicyType);
nsresult AddConnectionHeader(nsHttpRequestHead *,
uint32_t capabilities);
bool IsAcceptableEncoding(const char *encoding, bool isSecure);
@@ -385,7 +394,7 @@ private:
void InitUserAgentComponents();
void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
- nsresult SetAccept(const char *);
+ nsresult SetAccept(const char *, AcceptType aType);
nsresult SetAcceptLanguages();
nsresult SetAcceptEncodings(const char *, bool mIsSecure);
@@ -394,8 +403,8 @@ private:
void NotifyObservers(nsIHttpChannel *chan, const char *event);
static void TimerCallback(nsITimer * aTimer, void * aClosure);
+
private:
-
// cached services
nsMainThreadPtrHandle<nsIIOService> mIOService;
nsMainThreadPtrHandle<nsIStreamConverterService> mStreamConvSvc;
@@ -460,7 +469,10 @@ private:
bool mPipeliningOverSSL;
bool mEnforceAssocReq;
- nsCString mAccept;
+ nsCString mAcceptNavigation;
+ nsCString mAcceptImage;
+ nsCString mAcceptStyle;
+ nsCString mAcceptDefault;
nsCString mAcceptLanguages;
nsCString mHttpAcceptEncodings;
nsCString mHttpsAcceptEncodings;
diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini
index f8a919031..3cd5a674b 100644
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -25,3 +25,5 @@ support-files =
[test_viewsource_unlinkable.html]
[test_xhr_method_case.html]
[test_1396395.html]
+[test_accept_header.html]
+support-files = test_accept_header.sjs
diff --git a/netwerk/test/mochitests/test_accept_header.html b/netwerk/test/mochitests/test_accept_header.html
new file mode 100644
index 000000000..b8434230f
--- /dev/null
+++ b/netwerk/test/mochitests/test_accept_header.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Accept header</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+
+// All the requests are sent to test_accept_header.sjs which will return
+// different content based on the queryString. When the queryString is 'get',
+// test_accept_header.sjs returns a JSON object with the latest request and its
+// accept header value.
+
+function test_last_request_and_continue(query, expected) {
+ fetch("test_accept_header.sjs?get").then(r => r.json()).then(json => {
+ is(json.type, query, "Expected: " + query);
+ is(json.accept, expected, "Accept header: " + expected);
+ next();
+ });
+}
+
+function test_iframe() {
+ let observer = new PerformanceObserver(function(list, obj) {
+ obj.disconnect();
+
+ list.getEntries().forEach(entry => {
+ if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
+ obj.disconnect();
+ test_last_request_and_continue("iframe", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+ }
+ });
+ });
+
+ observer.observe({entryTypes: ["resource"]});
+
+ let ifr = document.createElement("iframe");
+ ifr.src = "test_accept_header.sjs?iframe";
+ document.body.appendChild(ifr);
+}
+
+function test_image() {
+ let i = new Image();
+ i.src = "test_accept_header.sjs?image";
+ i.onload = function() {
+ // Fetch spec says we should have: "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"
+ test_last_request_and_continue("image", "image/webp,image/png,image/*;q=0.8,*/*;q=0.5");
+ }
+}
+
+function test_style() {
+ let observer = new PerformanceObserver(function(list, obj) {
+ obj.disconnect();
+
+ list.getEntries().forEach(entry => {
+ if (entry.name.endsWith("test_accept_header.sjs?style")) {
+ obj.disconnect();
+ test_last_request_and_continue("style", "text/css,*/*;q=0.1");
+ }
+ });
+ });
+
+ observer.observe({entryTypes: ["resource"]});
+
+ let head = document.getElementsByTagName("head")[0];
+ let link = document.createElement("link");
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = "test_accept_header.sjs?style";
+ head.appendChild(link);
+}
+
+function test_worker() {
+ let w = new Worker("test_accept_header.sjs?worker");
+ w.onmessage = function() {
+ test_last_request_and_continue("worker", "*/*");
+ }
+}
+
+let tests = [
+ test_iframe,
+ test_image,
+ test_style,
+ test_worker,
+];
+
+function next() {
+ if (tests.length == 0) {
+ SimpleTest.finish();
+ return;
+ }
+
+ let test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({ "set": [
+ [ "dom.enable_performance_observer", true ]
+]}, next);
+
+</script>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_accept_header.sjs b/netwerk/test/mochitests/test_accept_header.sjs
new file mode 100644
index 000000000..035c886aa
--- /dev/null
+++ b/netwerk/test/mochitests/test_accept_header.sjs
@@ -0,0 +1,48 @@
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, "200", "OK");
+
+ if (request.queryString == "worker") {
+ response.setHeader("Content-Type", "application/json", false);
+ response.write("postMessage(42)");
+
+ setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "image") {
+ // A 1x1 PNG image.
+ // Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
+ const IMAGE = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
+ "ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
+
+ response.setHeader("Content-Type", "image/png", false);
+ response.write(IMAGE);
+
+ setState("data", JSON.stringify({type: "image", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "style") {
+ response.setHeader("Content-Type", "text/css", false);
+ response.write("");
+
+ setState("data", JSON.stringify({type: "style", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "iframe") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<h1>Hello world!</h1>");
+
+ setState("data", JSON.stringify({type: "iframe", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "get") {
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write(getState("data"));
+
+ setState("data", "");
+ return;
+ }
+}