1
1
var hterr_grabber = {
2
- pageData : '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml" lang="{%HTML_LANG%}">\n <head>\n <title>{%HTML_TITLE%}</title>\n <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />\n <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHRleHQgeD0iMCIgeT0iMTQiPuKaoO+4jzwvdGV4dD48L3N2Zz4=" type="image/svg+xml" />\n <script>\n function goBackThis(buttonEl)\n {\n try\n {\n history.go(-1);\n }\n catch(e) {}\n buttonEl.disabled = true;\n }\n function retryThis(buttonEl)\n {\n try \n {\n location.reload();\n }\n catch(e) {}\n buttonEl.disabled = true;\n }\n </script>\n </head>\n <body dir="{%LOCALE_DIR%}">\n <div id="errorPageContainer">\n <div id="errorTitle"><h1 id="errorTitleText">{%HTTP_ERROR_TITLE%}</h1></div>\n <div id="errorLongContent">\n <div id="errorShortDesc"><p id="errorShortDescText">{%HTTP_ERROR_DESCRIPTION%}</p></div>\n <div id="errorLongDesc">{%HTTP_ERROR_DETAILS%}</div>\n </div>\n <button id="errorTryAgain" autocomplete="off" onclick="retryThis(this);">{%RETRY_LABEL%}</button>\n <button id="errorGoBack" autocomplete="off" onclick="goBackThis(this);">{%BACK_LABEL%}</button>\n <script>\n // Only do autofocus if we\'re the toplevel frame; otherwise we\n // don\'t want to call attention to ourselves! The key part is\n // that autofocus happens on insertion into the tree, so we\n // can remove the button, add @autofocus, and reinsert the\n // button.\n if (2 > history.length)\n {\n var button = document.getElementById("errorGoBack");\n var parent = button.parentNode;\n parent.removeChild(button);\n }\n var noRetry = {%HTTP_ERROR_RETRY_BLOCKED%};\n if (noRetry)\n {\n var button = document.getElementById("errorTryAgain");\n var parent = button.parentNode;\n parent.removeChild(button);\n var button2 = document.getElementById("errorGoBack");\n if (button2 !== null)\n button2.setAttribute("id", "errorTryAgain");\n }\n if (window.top == window)\n {\n var button = document.getElementById("errorTryAgain");\n if (button !== null)\n {\n var nextSibling = button.nextSibling;\n var parent = button.parentNode;\n parent.removeChild(button);\n button.setAttribute("autofocus", "true");\n parent.insertBefore(button, nextSibling);\n }\n }\n </script>\n </div>\n </body>\n</html>' ,
2
+ pageData : '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml" lang="{%HTML_LANG%}">\n <head>\n <title>{%HTML_TITLE%}</title>\n <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />\n <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHRleHQgeD0iMCIgeT0iMTQiPuKaoO+4jzwvdGV4dD48L3N2Zz4=" type="image/svg+xml" />\n <script>\n function goBackThis(buttonEl)\n {\n try\n {\n history.go(-1);\n }\n catch(e) {}\n buttonEl.disabled = true;\n }\n function retryThis(buttonEl)\n {\n try \n {\n {%RETRY_SCOPE%}location.reload();\n }\n catch(e) {}\n buttonEl.disabled = true;\n }\n </script>{%STYLE%}\n </head>\n <body dir="{%LOCALE_DIR%}">\n <div id="errorPageContainer">\n <div id="errorTitle"><h1 id="errorTitleText">{%HTTP_ERROR_TITLE%}</h1></div>\n <div id="errorLongContent">\n <div id="errorShortDesc"><p id="errorShortDescText">{%HTTP_ERROR_DESCRIPTION%}</p></div>\n <div id="errorLongDesc">{%HTTP_ERROR_DETAILS%}</div>\n </div>\n <button id="errorTryAgain" autocomplete="off" onclick="retryThis(this);">{%RETRY_LABEL%}</button>\n <button id="errorGoBack" autocomplete="off" onclick="goBackThis(this);">{%BACK_LABEL%}</button>\n <script>\n // Only do autofocus if we\'re the toplevel frame; otherwise we\n // don\'t want to call attention to ourselves! The key part is\n // that autofocus happens on insertion into the tree, so we\n // can remove the button, add @autofocus, and reinsert the\n // button.\n if (2 > history.length)\n {\n var button = document.getElementById("errorGoBack");\n var parent = button.parentNode;\n parent.removeChild(button);\n }\n var noRetry = {%HTTP_ERROR_RETRY_BLOCKED%};\n if (noRetry)\n {\n var button = document.getElementById("errorTryAgain");\n var parent = button.parentNode;\n parent.removeChild(button);\n var button2 = document.getElementById("errorGoBack");\n if (button2 !== null)\n button2.setAttribute("id", "errorTryAgain");\n }\n if (window.top == window)\n {\n var button = document.getElementById("errorTryAgain");\n if (button !== null)\n {\n var nextSibling = button.nextSibling;\n var parent = button.parentNode;\n parent.removeChild(button);\n button.setAttribute("autofocus", "true");\n parent.insertBefore(button, nextSibling);\n }\n }\n </script>\n </div>\n </body>\n</html>' ,
3
3
plainData : '{%HTML_TITLE%}\n\n{%HTTP_ERROR_TITLE%}\n{%HTTP_ERROR_DESCRIPTION%}\n\n{%HTTP_ERROR_DETAILS%}' ,
4
4
hideReload : [ 400 , 403 , 410 , 414 , 415 , 418 , 421 , 422 , 423 , 426 , 428 , 431 , 444 , 449 , 450 , 451 , 494 , 497 , 499 , 501 , 505 , 506 , 507 , 508 , 509 , 510 , 518 , 523 , 526 , 530 ] ,
5
5
nullData : { } ,
@@ -66,6 +66,8 @@ var hterr_grabber = {
66
66
}
67
67
if ( hterr_grabber . hideReload . includes ( code ) )
68
68
errNoRetry = 'true' ;
69
+ data = data . replace ( / { % S T Y L E % } / g, '' ) ;
70
+ data = data . replace ( / { % R E T R Y _ S C O P E % } / g, '' ) ;
69
71
data = data . replace ( / { % L O C A L E _ D I R % } / g, localeDir ) ;
70
72
data = data . replace ( / { % H T M L _ L A N G % } / g, htmlLang ) ;
71
73
@@ -88,6 +90,168 @@ var hterr_grabber = {
88
90
data = data . replace ( / < [ ^ > ] + > / gi, '' ) ;
89
91
return String . fromCodePoint ( 0xEF , 0xBB , 0xBF ) + data ;
90
92
} ,
93
+ BlankBuilder : function ( sConsole )
94
+ {
95
+ let data = hterr_grabber . pageData ;
96
+ let localeDir = 'ltr' ;
97
+ let htmlLang = 'en' ;
98
+
99
+ let htmlTitle = 'Problem loading page' ;
100
+ let cmdBack = 'Go Back' ;
101
+ let cmdRetry = 'Try Again' ;
102
+
103
+ let errTitle = 'Blank Page Detected' ;
104
+ let errDesc = 'There was an error rendering this website.' ;
105
+ let errDetail = '<p>The page you are visiting did not render correctly. The error console may provide more details.</p>' ;
106
+ let errNoRetry = 'false' ;
107
+ let gBundle = Components . classes [ '@mozilla.org/intl/stringbundle;1' ] . getService ( Components . interfaces . nsIStringBundleService ) ;
108
+ let locale = gBundle . createBundle ( 'chrome://hterr/locale/hterr.properties' ) ;
109
+ try { localeDir = locale . GetStringFromName ( 'locale.dir' ) ; }
110
+ catch ( e ) { localeDir = 'ltr' ; }
111
+ try { htmlLang = locale . GetStringFromName ( 'html.lang' ) ; }
112
+ catch ( e ) { htmlLang = 'en' ; }
113
+
114
+ try { htmlTitle = locale . GetStringFromName ( 'html.title' ) ; }
115
+ catch ( e ) { htmlTitle = 'Problem loading page' ; }
116
+ try { cmdBack = locale . GetStringFromName ( 'back.label' ) ; }
117
+ catch ( e ) { cmdBack = 'Go Back' ; }
118
+ try { cmdRetry = locale . GetStringFromName ( 'retry.label' ) ; }
119
+ catch ( e ) { cmdRetry = 'Try Again' ; }
120
+
121
+ try { errTitle = locale . GetStringFromName ( 'error.blank.title' ) ; }
122
+ catch ( e ) { errTitle = 'Blank Page Detected' ; }
123
+ try { errDesc = locale . GetStringFromName ( 'error.blank.desc' ) ; }
124
+ catch ( e ) { errDesc = 'There was an error rendering this website.' ; }
125
+ try { errDetail = locale . GetStringFromName ( 'error.blank.longDesc' ) ; }
126
+ catch ( e ) { errDetail = '<p>The page you are visiting did not render correctly. The error console may provide more details.</p>' ; }
127
+ if ( sConsole !== '' )
128
+ errDetail += '<textarea id="console" readonly="readonly" wrap="off">' + sConsole + '</textarea>' ;
129
+
130
+ let sStyle = '\n <style>' +
131
+ '\n #console' +
132
+ '\n {' +
133
+ '\n background-color: inherit;' +
134
+ '\n color: inherit;' +
135
+ '\n min-width: 100%;' +
136
+ '\n max-width: 100%;' +
137
+ '\n min-height: 6em;' +
138
+ '\n max-height: 30em;' +
139
+ '\n }' +
140
+ '\n </style>' ;
141
+
142
+ data = data . replace ( / { % S T Y L E % } / g, sStyle ) ;
143
+ data = data . replace ( / { % R E T R Y _ S C O P E % } / g, 'window.top.' ) ;
144
+ data = data . replace ( / { % L O C A L E _ D I R % } / g, localeDir ) ;
145
+ data = data . replace ( / { % H T M L _ L A N G % } / g, htmlLang ) ;
146
+
147
+ data = data . replace ( / { % H T M L _ T I T L E % } / g, htmlTitle ) ;
148
+ data = data . replace ( / { % B A C K _ L A B E L % } / g, cmdBack ) ;
149
+ data = data . replace ( / { % R E T R Y _ L A B E L % } / g, cmdRetry ) ;
150
+
151
+ data = data . replace ( / { % H T T P _ E R R O R _ T I T L E % } / g, errTitle ) ;
152
+ data = data . replace ( / { % H T T P _ E R R O R _ D E S C R I P T I O N % } / g, errDesc ) ;
153
+ data = data . replace ( / { % H T T P _ E R R O R _ D E T A I L S % } / g, errDetail ) ;
154
+ data = data . replace ( / { % H T T P _ E R R O R _ R E T R Y _ B L O C K E D % } / g, errNoRetry ) ;
155
+ return data ;
156
+ } ,
157
+ BlankPageChecker : function ( wnd )
158
+ {
159
+ if ( ! wnd )
160
+ return ;
161
+ if ( wnd . contentWindow . hterrTimer )
162
+ wnd . contentWindow . clearTimeout ( wnd . hterrTimer ) ;
163
+ if ( wnd . contentDocument . body . scrollHeight > wnd . contentDocument . documentElement . clientHeight )
164
+ return ;
165
+ if ( wnd . contentDocument . body . scrollWidth > wnd . contentDocument . documentElement . clientWidth )
166
+ return ;
167
+ const canvas = wnd . contentDocument . createElementNS ( 'http://www.w3.org/1999/xhtml' , 'canvas' ) ;
168
+ canvas . width = wnd . contentDocument . documentElement . clientWidth ;
169
+ canvas . height = wnd . contentDocument . documentElement . clientHeight ;
170
+ const ctx = canvas . getContext ( '2d' ) ;
171
+ ctx . drawWindow ( wnd . contentWindow , 0 , 0 , canvas . width , canvas . height , 'rgb(255,255,255)' , ctx . DRAWWINDOW_DRAW_VIEW ) ;
172
+ const dt = ctx . getImageData ( 0 , 0 , canvas . width , canvas . height ) ;
173
+ let r = dt . data . filter ( b => b !== 255 ) ;
174
+ if ( r . length > 0 )
175
+ return ;
176
+ let consoleService = Components . classes [ "@mozilla.org/consoleservice;1" ] . getService ( Components . interfaces . nsIConsoleService ) ;
177
+ let consoleLines = consoleService . getMessageArray ( ) ;
178
+ let sConsole = '' ;
179
+ let waitForBlank = 10 ;
180
+ let prefs = Components . classes [ '@mozilla.org/preferences-service;1' ] . getService ( Components . interfaces . nsIPrefBranch ) ;
181
+ if ( prefs . prefHasUserValue ( 'extensions.hterr.blankwait' ) )
182
+ waitForBlank = prefs . getIntPref ( 'extensions.hterr.blankwait' ) ;
183
+ if ( waitForBlank < 1 )
184
+ waitForBlank = 1 ;
185
+ if ( waitForBlank > 60 )
186
+ waitForBlank = 60 ;
187
+ for ( let i = 0 ; i < consoleLines . length ; i ++ )
188
+ {
189
+ try
190
+ {
191
+ let oErr = consoleLines [ i ] . QueryInterface ( Components . interfaces . nsIScriptError ) ;
192
+ let wndUtil = wnd . contentWindow . QueryInterface ( Components . interfaces . nsIInterfaceRequestor ) . getInterface ( Components . interfaces . nsIDOMWindowUtils ) ;
193
+ if ( wndUtil . currentInnerWindowID !== oErr . innerWindowID )
194
+ continue ;
195
+ if ( ( oErr . flags & 2 ) === 0 )
196
+ continue ;
197
+ let sMsg = oErr . errorMessage ;
198
+ if ( oErr . sourceName !== '' )
199
+ sMsg += '\n ' + oErr . sourceName ;
200
+ if ( oErr . lineNumber > 0 )
201
+ {
202
+ sMsg += '\n line ' + oErr . lineNumber ;
203
+ if ( oErr . columnNumber > 0 )
204
+ sMsg += ', column ' + oErr . columnNumber ;
205
+ }
206
+ if ( oErr . sourceLine !== '' )
207
+ sMsg += '\n> ...' + oErr . sourceLine + '...' ;
208
+ if ( sConsole === '' )
209
+ sConsole = sMsg ;
210
+ else
211
+ sConsole += '\n\n' + sMsg ;
212
+ }
213
+ catch ( ex ) { continue ; }
214
+ }
215
+ let sHTML = hterr_grabber . BlankBuilder ( sConsole ) ;
216
+ let doc = wnd . contentDocumentAsCPOW ;
217
+ let d = doc . createElement ( 'iframe' ) ;
218
+ d . setAttribute ( 'frameborder' , '0' ) ;
219
+ d . setAttribute ( 'style' , 'position: absolute; top: 0; left: 0; width: 100%; height: 100%;' ) ;
220
+ d . srcdoc = sHTML ;
221
+ doc . body . appendChild ( d ) ;
222
+ } ,
223
+ DocumentFinder : function ( request , mustBeReady )
224
+ {
225
+ let mainDoc = false ;
226
+ if ( gBrowser . browsers === undefined || gBrowser . browsers . length < 1 )
227
+ return mainDoc ;
228
+ for ( let i = 0 ; i < gBrowser . browsers . length ; i ++ )
229
+ {
230
+ if ( mustBeReady )
231
+ {
232
+ if ( gBrowser . browsers [ i ] . contentDocument . readyState === 'complete' )
233
+ continue ;
234
+ if ( gBrowser . browsers [ i ] . contentDocument . readyState === 'uninitialized' )
235
+ continue ;
236
+ if ( gBrowser . browsers [ i ] . contentDocument . readyState !== 'loading' && gBrowser . browsers [ i ] . contentDocument . readyState !== 'interactive' )
237
+ console . log ( 'Unknown readyState:' , gBrowser . browsers [ i ] . contentDocument . readyState , '(Risking it as something to compare)' ) ;
238
+ }
239
+ if ( request . originalURI !== undefined )
240
+ {
241
+ if ( gBrowser . browsers [ i ] . contentDocument . location . href === request . originalURI . spec )
242
+ {
243
+ mainDoc = gBrowser . browsers [ i ] ;
244
+ break ;
245
+ }
246
+ }
247
+ if ( gBrowser . browsers [ i ] . contentDocument . location . href === request . name )
248
+ {
249
+ mainDoc = gBrowser . browsers [ i ] ;
250
+ break ;
251
+ }
252
+ }
253
+ return mainDoc ;
254
+ } ,
91
255
ResponseObserver :
92
256
{
93
257
observe : function ( aSubject , aTopic , aData )
@@ -127,6 +291,12 @@ hterr_grabber.TracingListener.prototype = {
127
291
} ,
128
292
onStartRequest : function ( request , context )
129
293
{
294
+ let mainDoc = hterr_grabber . DocumentFinder ( request , false ) ;
295
+ if ( mainDoc !== false )
296
+ {
297
+ if ( mainDoc . contentWindow . hterrTimer )
298
+ mainDoc . contentWindow . clearTimeout ( mainDoc . hterrTimer ) ;
299
+ }
130
300
request . QueryInterface ( Components . interfaces . nsIHttpChannel ) ;
131
301
hterr_grabber . nullData [ request . channelId ] = true ;
132
302
try
@@ -139,6 +309,19 @@ hterr_grabber.TracingListener.prototype = {
139
309
{
140
310
try
141
311
{
312
+ let mainDoc = hterr_grabber . DocumentFinder ( request , true ) ;
313
+ if ( ! mainDoc )
314
+ return ;
315
+ if ( mainDoc . contentWindow . hterrTimer )
316
+ mainDoc . contentWindow . clearTimeout ( mainDoc . contentWindow . hterrTimer ) ;
317
+ let waitForBlank = 10 ;
318
+ let prefs = Components . classes [ '@mozilla.org/preferences-service;1' ] . getService ( Components . interfaces . nsIPrefBranch ) ;
319
+ if ( prefs . prefHasUserValue ( 'extensions.hterr.blankwait' ) )
320
+ waitForBlank = prefs . getIntPref ( 'extensions.hterr.blankwait' ) ;
321
+ if ( waitForBlank > 60 )
322
+ waitForBlank = 60 ;
323
+ if ( waitForBlank > 0 )
324
+ mainDoc . contentWindow . hterrTimer = mainDoc . contentWindow . setTimeout ( hterr_grabber . BlankPageChecker , waitForBlank * 1000 , mainDoc ) ;
142
325
request . QueryInterface ( Components . interfaces . nsIHttpChannel ) ;
143
326
if ( ! hterr_grabber . nullData [ request . channelId ] )
144
327
return ;
@@ -162,28 +345,6 @@ hterr_grabber.TracingListener.prototype = {
162
345
let cEnc = mime . substring ( mime . indexOf ( '/' ) + 1 ) ;
163
346
if ( ! ( cType === 'text' || ( cType === 'application' && ( cEnc . includes ( 'html' ) || cEnc . includes ( 'xml' ) ) ) || mime === 'image/svg+xml' ) )
164
347
return ;
165
- let mainDoc = false ;
166
- for ( let i = 0 ; i < gBrowser . browsers . length ; i ++ )
167
- {
168
- if ( gBrowser . browsers [ i ] . contentDocument . readyState === 'complete' )
169
- continue ;
170
- if ( gBrowser . browsers [ i ] . contentDocument . readyState === 'uninitialized' )
171
- continue ;
172
- if ( gBrowser . browsers [ i ] . contentDocument . readyState !== 'loading' && gBrowser . browsers [ i ] . contentDocument . readyState !== 'interactive' )
173
- console . log ( 'Unknown readyState:' , gBrowser . browsers [ i ] . contentDocument . readyState , '(Risking it as something to compare)' ) ;
174
- if ( gBrowser . browsers [ i ] . contentDocument . location . href === request . originalURI . spec )
175
- {
176
- mainDoc = true ;
177
- break ;
178
- }
179
- if ( gBrowser . browsers [ i ] . contentDocument . location . href === request . name )
180
- {
181
- mainDoc = true ;
182
- break ;
183
- }
184
- }
185
- if ( ! mainDoc )
186
- return ;
187
348
let extraParam = null ;
188
349
try
189
350
{
0 commit comments