Changeset 195625 in webkit
- Timestamp:
- Jan 26, 2016 2:48:15 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 26 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r195624 r195625 1 2016-01-26 Brady Eidson <beidson@apple.com> 2 3 History.pushState causes intense memory pressure. 4 https://bugs.webkit.org/show_bug.cgi?id=153435 5 6 Reviewed by Sam Weinig, Oliver Hunt, and Geoff Garen. 7 8 * TestExpectations: Mark some of the new tests as slow. 9 10 * fast/loader/stateobjects/pushstate-frequency-expected.txt: Added. 11 * fast/loader/stateobjects/pushstate-frequency-iframe-expected.txt: Added. 12 * fast/loader/stateobjects/pushstate-frequency-iframe.html: Added. 13 * fast/loader/stateobjects/pushstate-frequency-with-user-gesture-expected.txt: Added. 14 * fast/loader/stateobjects/pushstate-frequency-with-user-gesture.html: Added. 15 * fast/loader/stateobjects/pushstate-frequency.html: Added. 16 * fast/loader/stateobjects/replacestate-frequency-expected.txt: Added. 17 * fast/loader/stateobjects/replacestate-frequency-iframe-expected.txt: Added. 18 * fast/loader/stateobjects/replacestate-frequency-iframe.html: Added. 19 * fast/loader/stateobjects/replacestate-frequency-with-user-gesture-expected.txt: Added. 20 * fast/loader/stateobjects/replacestate-frequency-with-user-gesture.html: Added. 21 * fast/loader/stateobjects/replacestate-frequency.html: Added. 22 * fast/loader/stateobjects/resources/pushstate-iframe.html: Added. 23 * fast/loader/stateobjects/resources/replacestate-iframe.html: Added. 24 * loader/stateobjects/pushstate-size-expected.txt: Added. 25 * loader/stateobjects/pushstate-size-iframe-expected.txt: Added. 26 * loader/stateobjects/pushstate-size-iframe.html: Added. 27 * loader/stateobjects/pushstate-size.html: Added. 28 * loader/stateobjects/replacestate-size-expected.txt: Added. 29 * loader/stateobjects/replacestate-size-iframe-expected.txt: Added. 30 * loader/stateobjects/replacestate-size-iframe.html: Added. 31 * loader/stateobjects/replacestate-size.html: Added. 32 * loader/stateobjects/resources/pushstate-iframe.html: Added. 33 * loader/stateobjects/resources/replacestate-iframe.html: Added. 34 1 35 2016-01-26 Ryan Haddad <ryanhaddad@apple.com> 2 36 -
trunk/LayoutTests/TestExpectations
r195394 r195625 848 848 http/tests/security/contentSecurityPolicy/1.1/scripthash-default-src.html # Needs expected file. 849 849 http/tests/security/contentSecurityPolicy/1.1/stylehash-default-src.html # Needs expected file. 850 851 # These state object tests purposefully stress a resource limit, and take multiple seconds to run. 852 loader/stateobjects/pushstate-size-iframe.html [ Slow ] 853 loader/stateobjects/pushstate-size.html [ Slow ] 854 loader/stateobjects/replacestate-size-iframe.html [ Slow ] 855 loader/stateobjects/replacestate-size.html [ Slow ] -
trunk/Source/WebCore/ChangeLog
r195616 r195625 1 2016-01-26 Brady Eidson <beidson@apple.com> 2 3 History.pushState causes intense memory pressure. 4 https://bugs.webkit.org/show_bug.cgi?id=153435 5 6 Reviewed by Sam Weinig, Oliver Hunt, and Geoff Garen. 7 8 Tests: fast/loader/stateobjects/pushstate-frequency-iframe.html 9 fast/loader/stateobjects/pushstate-frequency-with-user-gesture.html 10 fast/loader/stateobjects/pushstate-frequency.html 11 fast/loader/stateobjects/replacestate-frequency-iframe.html 12 fast/loader/stateobjects/replacestate-frequency-with-user-gesture.html 13 fast/loader/stateobjects/replacestate-frequency.html 14 loader/stateobjects/pushstate-size-iframe.html 15 loader/stateobjects/pushstate-size.html 16 loader/stateobjects/replacestate-size-iframe.html 17 loader/stateobjects/replacestate-size.html 18 19 Add restrictions on how frequently push/replaceState can be called, 20 as well as how much of a cumulative payload they can deliver. 21 22 * bindings/js/JSHistoryCustom.cpp: 23 (WebCore::JSHistory::pushState): 24 (WebCore::JSHistory::replaceState): 25 26 * page/History.cpp: 27 (WebCore::History::stateObjectAdded): 28 * page/History.h: 29 1 30 2016-01-26 Anders Carlsson <andersca@apple.com> 2 31 -
trunk/Source/WebCore/bindings/js/JSHistoryCustom.cpp
r191887 r195625 30 30 #include "JSHistory.h" 31 31 32 #include "ExceptionCode.h" 32 33 #include "Frame.h" 33 34 #include "JSDOMBinding.h" … … 140 141 } 141 142 142 ExceptionCode ec = 0;143 ExceptionCodeWithMessage ec; 143 144 wrapped().stateObjectAdded(historyState.release(), title, url, History::StateObjectType::Push, ec); 144 145 setDOMException(&state, ec); … … 169 170 } 170 171 171 ExceptionCode ec = 0;172 ExceptionCodeWithMessage ec; 172 173 wrapped().stateObjectAdded(historyState.release(), title, url, History::StateObjectType::Replace, ec); 173 174 setDOMException(&state, ec); -
trunk/Source/WebCore/page/History.cpp
r185231 r195625 35 35 #include "HistoryController.h" 36 36 #include "HistoryItem.h" 37 #include "MainFrame.h" 37 38 #include "Page.h" 39 #include "ScriptController.h" 38 40 #include "SecurityOrigin.h" 39 41 #include "SerializedScriptValue.h" 42 #include <wtf/CheckedArithmetic.h> 40 43 #include <wtf/MainThread.h> 41 44 … … 137 140 } 138 141 139 void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCode& ec) 140 { 142 void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCodeWithMessage& ec) 143 { 144 // Each unique main-frame document is only allowed to send 64mb of state object payload to the UI client/process. 145 static uint32_t totalStateObjectPayloadLimit = 0x4000000; 146 static unsigned perUserGestureStateObjectLimit = 100; 147 141 148 if (!m_frame || !m_frame->page()) 142 149 return; 143 150 144 151 URL fullURL = urlForState(urlString); 145 152 if (!fullURL.isValid() || !m_frame->document()->securityOrigin()->canRequest(fullURL)) { 146 ec = SECURITY_ERR; 147 return; 148 } 153 ec.code = SECURITY_ERR; 154 return; 155 } 156 157 Document* mainDocument = m_frame->page()->mainFrame().document(); 158 History* mainHistory = nullptr; 159 if (mainDocument) { 160 if (auto* mainDOMWindow = mainDocument->domWindow()) 161 mainHistory = mainDOMWindow->history(); 162 } 163 164 if (!mainHistory) 165 return; 166 167 bool processingUserGesture = ScriptController::processingUserGesture(); 168 if (!processingUserGesture && mainHistory->m_nonUserGestureObjectsAdded >= perUserGestureStateObjectLimit) { 169 ec.code = SECURITY_ERR; 170 if (stateObjectType == StateObjectType::Replace) 171 ec.message = String::format("Attempt to use history.replaceState() more than %u times without a user gesture", perUserGestureStateObjectLimit); 172 else 173 ec.message = String::format("Attempt to use history.pushState() more than %u times without a user gesture", perUserGestureStateObjectLimit); 174 return; 175 } 176 177 double userGestureTimestamp = mainDocument->lastHandledUserGestureTimestamp(); 178 if (processingUserGesture) { 179 if (mainHistory->m_currentUserGestureTimestamp < userGestureTimestamp) { 180 mainHistory->m_currentUserGestureTimestamp = userGestureTimestamp; 181 mainHistory->m_currentUserGestureObjectsAdded = 0; 182 } 183 184 if (mainHistory->m_currentUserGestureObjectsAdded >= perUserGestureStateObjectLimit) { 185 ec.code = SECURITY_ERR; 186 if (stateObjectType == StateObjectType::Replace) 187 ec.message = String::format("Attempt to use history.replaceState() more than %u times per gesture", perUserGestureStateObjectLimit); 188 else 189 ec.message = String::format("Attempt to use history.pushState() more than %u times per user gesture", perUserGestureStateObjectLimit); 190 return; 191 } 192 } 193 194 Checked<unsigned> titleSize = title.length(); 195 titleSize *= 2; 196 197 Checked<unsigned> urlSize = fullURL.string().length(); 198 urlSize *= 2; 199 200 Checked<uint64_t> payloadSize = titleSize; 201 payloadSize += urlSize; 202 payloadSize += data ? data->data().size() : 0; 203 204 Checked<uint64_t> newTotalUsage = mainHistory->m_totalStateObjectUsage; 205 206 if (stateObjectType == StateObjectType::Replace) 207 newTotalUsage -= m_mostRecentStateObjectUsage; 208 newTotalUsage += payloadSize; 209 210 if (newTotalUsage > totalStateObjectPayloadLimit) { 211 ec.code = QUOTA_EXCEEDED_ERR; 212 if (stateObjectType == StateObjectType::Replace) 213 ec.message = ASCIILiteral("Attempt to store more data than allowed using history.replaceState()"); 214 else 215 ec.message = ASCIILiteral("Attempt to store more data than allowed using history.pushState()"); 216 return; 217 } 218 219 m_mostRecentStateObjectUsage = payloadSize.unsafeGet(); 220 221 mainHistory->m_totalStateObjectUsage = newTotalUsage.unsafeGet(); 222 if (processingUserGesture) 223 ++mainHistory->m_currentUserGestureObjectsAdded; 224 else 225 ++mainHistory->m_nonUserGestureObjectsAdded; 149 226 150 227 if (!urlString.isEmpty()) -
trunk/Source/WebCore/page/History.h
r184066 r195625 39 39 class Frame; 40 40 class ScriptExecutionContext; 41 struct ExceptionCodeWithMessage; 41 42 typedef int ExceptionCode; 42 43 … … 62 63 Replace 63 64 }; 64 void stateObjectAdded(PassRefPtr<SerializedScriptValue>, const String& title, const String& url, StateObjectType, ExceptionCode &);65 void stateObjectAdded(PassRefPtr<SerializedScriptValue>, const String& title, const String& url, StateObjectType, ExceptionCodeWithMessage&); 65 66 66 67 private: … … 72 73 73 74 RefPtr<SerializedScriptValue> m_lastStateObjectRequested; 75 76 unsigned m_nonUserGestureObjectsAdded { 0 }; 77 unsigned m_currentUserGestureObjectsAdded { 0 }; 78 double m_currentUserGestureTimestamp { 0 }; 79 80 // For the main frame's History object to keep track of all state object usage. 81 uint64_t m_totalStateObjectUsage { 0 }; 82 83 // For each individual History object to keep track of the most recent state object added. 84 uint64_t m_mostRecentStateObjectUsage { 0 }; 74 85 }; 75 86
Note: See TracChangeset
for help on using the changeset viewer.