~ubuntu-branches/ubuntu/karmic/firebug/karmic

« back to all changes in this revision

Viewing changes to content/firebug/net.js

  • Committer: Bazaar Package Importer
  • Author(s): Jared Greenwald
  • Date: 2008-02-21 17:34:24 UTC
  • Revision ID: james.westby@ubuntu.com-20080221173424-illircvfpyvnp4uo
Tags: upstream-1.1.0~b11+svn317
ImportĀ upstreamĀ versionĀ 1.1.0~b11+svn317

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* See license.txt for terms of usage */
 
2
 
 
3
FBL.ns(function() { with (FBL) {
 
4
 
 
5
// ************************************************************************************************
 
6
// Constants
 
7
 
 
8
const nsIWebProgressListener = CI("nsIWebProgressListener")
 
9
const nsIWebProgress = CI("nsIWebProgress")
 
10
const nsIRequest = CI("nsIRequest")
 
11
const nsIChannel = CI("nsIChannel")
 
12
const nsIHttpChannel = CI("nsIHttpChannel")
 
13
const nsICacheService = CI("nsICacheService")
 
14
const nsICache = CI("nsICache")
 
15
const nsIObserverService = CI("nsIObserverService")
 
16
const nsISupportsWeakReference = CI("nsISupportsWeakReference")
 
17
const nsISupports = CI("nsISupports")
 
18
const nsIIOService = CI("nsIIOService")
 
19
const imgIRequest = CI("imgIRequest");
 
20
 
 
21
const CacheService = CC("@mozilla.org/network/cache-service;1");
 
22
const ImgCache = CC("@mozilla.org/image/cache;1");
 
23
const IOService = CC("@mozilla.org/network/io-service;1");
 
24
 
 
25
const NOTIFY_ALL = nsIWebProgress.NOTIFY_ALL;
 
26
 
 
27
const STATE_IS_WINDOW = nsIWebProgressListener.STATE_IS_WINDOW;
 
28
const STATE_IS_DOCUMENT = nsIWebProgressListener.STATE_IS_DOCUMENT;
 
29
const STATE_IS_NETWORK = nsIWebProgressListener.STATE_IS_NETWORK;
 
30
const STATE_IS_REQUEST = nsIWebProgressListener.STATE_IS_REQUEST;
 
31
 
 
32
const STATE_START = nsIWebProgressListener.STATE_START;
 
33
const STATE_STOP = nsIWebProgressListener.STATE_STOP;
 
34
const STATE_TRANSFERRING = nsIWebProgressListener.STATE_TRANSFERRING;
 
35
 
 
36
const LOAD_BACKGROUND = nsIRequest.LOAD_BACKGROUND;
 
37
const LOAD_FROM_CACHE = nsIRequest.LOAD_FROM_CACHE;
 
38
const LOAD_DOCUMENT_URI = nsIChannel.LOAD_DOCUMENT_URI;
 
39
 
 
40
const ACCESS_READ = nsICache.ACCESS_READ;
 
41
const STORE_ANYWHERE = nsICache.STORE_ANYWHERE;
 
42
 
 
43
const NS_ERROR_CACHE_KEY_NOT_FOUND = 0x804B003D;
 
44
const NS_ERROR_CACHE_WAIT_FOR_VALIDATION = 0x804B0040;
 
45
 
 
46
 
 
47
const observerService = CCSV("@mozilla.org/observer-service;1", "nsIObserverService");
 
48
 
 
49
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
50
 
 
51
const maxPendingCheck = 200;
 
52
const maxQueueRequests = 50;
 
53
 
 
54
const mimeExtensionMap =
 
55
{
 
56
    "txt": "text/plain",
 
57
    "html": "text/html",
 
58
    "htm": "text/html",
 
59
    "xhtml": "text/html",
 
60
    "xml": "text/xml",
 
61
    "css": "text/css",
 
62
    "js": "application/x-javascript",
 
63
    "jss": "application/x-javascript",
 
64
    "jpg": "image/jpeg",
 
65
    "jpeg": "image/jpeg",
 
66
    "gif": "image/gif",
 
67
    "png": "image/png",
 
68
    "bmp": "image/bmp",
 
69
    "swf": "application/x-shockwave-flash"
 
70
};
 
71
 
 
72
const fileCategories =
 
73
{
 
74
    "undefined": 1,
 
75
    "html": 1,
 
76
    "css": 1,
 
77
    "js": 1,
 
78
    "xhr": 1,
 
79
    "image": 1,
 
80
    "flash": 1,
 
81
    "txt": 1,
 
82
    "bin": 1
 
83
};
 
84
 
 
85
const textFileCategories =
 
86
{
 
87
    "txt": 1,
 
88
    "html": 1,
 
89
    "xhr": 1,
 
90
    "css": 1,
 
91
    "js": 1
 
92
};
 
93
 
 
94
const binaryFileCategories =
 
95
{
 
96
    "bin": 1,
 
97
    "flash": 1
 
98
};
 
99
 
 
100
const mimeCategoryMap =
 
101
{
 
102
    "text/plain": "txt",
 
103
    "application/octet-stream": "bin",
 
104
    "text/html": "html",
 
105
    "text/xml": "html",
 
106
    "text/css": "css",
 
107
    "application/x-javascript": "js",
 
108
    "text/javascript": "js",
 
109
    "image/jpeg": "image",
 
110
    "image/gif": "image",
 
111
    "image/png": "image",
 
112
    "image/bmp": "image",
 
113
    "application/x-shockwave-flash": "flash"
 
114
};
 
115
 
 
116
const binaryCategoryMap =
 
117
{
 
118
    "image": 1,
 
119
    "flash" : 1
 
120
};
 
121
 
 
122
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
123
 
 
124
const reIgnore = /about:|javascript:|resource:|chrome:|jar:/;
 
125
 
 
126
const layoutInterval = 300;
 
127
const phaseInterval = 1000;
 
128
const indentWidth = 18;
 
129
 
 
130
var cacheSession = null;
 
131
 
 
132
// ************************************************************************************************
 
133
 
 
134
Firebug.NetMonitor = extend(Firebug.Module,
 
135
{
 
136
    clear: function(context)
 
137
    {
 
138
        var panel = context.getPanel("net", true);
 
139
        if (panel)
 
140
            panel.clear();
 
141
 
 
142
        if (context.netProgress)
 
143
            context.netProgress.clear();
 
144
    },
 
145
 
 
146
    onToggleFilter: function(context, filterCategory)
 
147
    {
 
148
        Firebug.setPref("netFilterCategory", filterCategory);
 
149
 
 
150
        var panel = context.getPanel("net", true);
 
151
        if (panel)
 
152
        {
 
153
            panel.setFilter(filterCategory);
 
154
            panel.updateSummaries(now(), true);
 
155
        }
 
156
    },
 
157
 
 
158
    syncFilterButtons: function(chrome)
 
159
    {
 
160
        var button = chrome.$("fbNetFilter-"+Firebug.netFilterCategory);
 
161
        button.checked = true;
 
162
    },
 
163
 
 
164
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
165
    // extends Module
 
166
 
 
167
    initialize: function()
 
168
    {
 
169
        this.syncFilterButtons(FirebugChrome);
 
170
    },
 
171
 
 
172
    initContext: function(context)
 
173
    {
 
174
        if (!Firebug.disableNetMonitor)
 
175
            monitorContext(context);
 
176
    },
 
177
 
 
178
    reattachContext: function(browser, context)
 
179
    {
 
180
        var chrome = context ? context.chrome : FirebugChrome;
 
181
        this.syncFilterButtons(chrome);
 
182
    },
 
183
 
 
184
    destroyContext: function(context)
 
185
    {
 
186
        if (context.netProgress)
 
187
            unmonitorContext(context);
 
188
    },
 
189
 
 
190
    showContext: function(browser, context)
 
191
    {
 
192
        /*if (context)
 
193
        {
 
194
            var panel = context.chrome.getSelectedPanel();
 
195
            if (panel && panel.name == "net")
 
196
                context.netProgress.panel = panel;
 
197
        }*/
 
198
    },
 
199
 
 
200
    loadedContext: function(context)
 
201
    {
 
202
        if (context.netProgress)
 
203
            context.netProgress.loaded = true;
 
204
    },
 
205
 
 
206
    showPanel: function(browser, panel)
 
207
    {
 
208
        var netButtons = browser.chrome.$("fbNetButtons");
 
209
        collapse(netButtons, !panel || panel.name != "net");
 
210
 
 
211
        if (panel && panel.context.netProgress)
 
212
        {
 
213
            if (panel.name == "net")
 
214
                panel.context.netProgress.activate(panel);
 
215
            else
 
216
                panel.context.netProgress.activate(null);
 
217
        }
 
218
    }
 
219
});
 
220
 
 
221
// ************************************************************************************************
 
222
 
 
223
function NetPanel() {}
 
224
 
 
225
NetPanel.prototype = domplate(Firebug.Panel,
 
226
{
 
227
    tableTag:
 
228
        TABLE({class: "netTable", cellpadding: 0, cellspacing: 0, onclick: "$onClick"},
 
229
            TBODY(
 
230
                TR(
 
231
                    TD({width: "15%"}),
 
232
                    TD({width: "12%"}),
 
233
                    TD({width: "4%"}),
 
234
                    TD({width: "65%"})
 
235
                )
 
236
            )
 
237
        ),
 
238
 
 
239
    fileTag:
 
240
        FOR("file", "$files",
 
241
            TR({class: "netRow $file.file|getCategory",
 
242
                $hasHeaders: "$file.file|hasResponseHeaders",
 
243
                $loaded: "$file.file.loaded", $responseError: "$file.file|isError",
 
244
                $fromCache: "$file.file.fromCache", $inFrame: "$file.file|getInFrame"},
 
245
                TD({class: "netHrefCol netCol"},
 
246
                    DIV({class: "netHrefLabel netLabel",
 
247
                         style: "margin-left: $file.file|getIndent\\px"},
 
248
                        "$file.file|getHref"
 
249
                    ),
 
250
                    DIV({class: "netFullHrefLabel netHrefLabel netLabel",
 
251
                         style: "margin-left: $file.file|getIndent\\px"},
 
252
                        "$file.file.href"
 
253
                    )
 
254
                ),
 
255
                TD({class: "netDomainCol netCol"},
 
256
                    DIV({class: "netDomainLabel netLabel"}, "$file.file|getDomain")
 
257
                ),
 
258
                TD({class: "netSizeCol netCol"},
 
259
                    DIV({class: "netSizeLabel netLabel"}, "$file.file|getSize")
 
260
                ),
 
261
                TD({class: "netTimeCol netCol"},
 
262
                    DIV({class: "netBar"},
 
263
                        " ",
 
264
                        DIV({class: "netTotalBar", style: "left: $file.offset"}),
 
265
                        DIV({class: "netTimeBar", style: "left: $file.offset; width: $file.width"},
 
266
                            SPAN({class: "netTimeLabel"}, "$file.elapsed|formatTime")
 
267
                        )
 
268
                    )
 
269
                )
 
270
            )
 
271
        ),
 
272
 
 
273
    headTag:
 
274
        TR({class: "netHeadRow"},
 
275
            TD({class: "netHeadCol", colspan: 4},
 
276
                DIV({class: "netHeadLabel"}, "$doc.rootFile.href")
 
277
            )
 
278
        ),
 
279
 
 
280
    netInfoTag:
 
281
        TR({class: "netInfoRow"},
 
282
            TD({class: "netInfoCol", colspan: 4})
 
283
        ),
 
284
 
 
285
    phaseTag:
 
286
        TR({class: "netRow netPhaseRow"},
 
287
            TD({class: "netPhaseCol", colspan: 4})
 
288
        ),
 
289
 
 
290
    summaryTag:
 
291
        TR({class: "netRow netSummaryRow"},
 
292
            TD({class: "netCol"},
 
293
                DIV({class: "netCountLabel netSummaryLabel"}, "-")
 
294
            ),
 
295
            TD({class: "netCol"}),
 
296
            TD({class: "netTotalSizeCol netCol"},
 
297
                DIV({class: "netTotalSizeLabel netSummaryLabel"}, "0KB")
 
298
            ),
 
299
            TD({class: "netTotalTimeCol netCol"},
 
300
                DIV({class: "netBar"},
 
301
                    DIV({class: "netCacheSizeLabel netSummaryLabel"},
 
302
                        "(",
 
303
                        SPAN("0KB"),
 
304
                        SPAN(" " + $STR("FromCache")),
 
305
                        ")"
 
306
                    ),
 
307
                    DIV({class: "netTotalBar"}),
 
308
                    DIV({class: "netTimeBar", style: "width: 100%"},
 
309
                        SPAN({class: "netTotalTimeLabel netSummaryLabel"}, "0ms")
 
310
                    )
 
311
                )
 
312
            )
 
313
        ),
 
314
 
 
315
    getCategory: function(file)
 
316
    {
 
317
        return "category-"+getFileCategory(file);
 
318
    },
 
319
 
 
320
    getInFrame: function(file)
 
321
    {
 
322
        return !!file.document.parent;
 
323
    },
 
324
 
 
325
    getIndent: function(file)
 
326
    {
 
327
        // XXXjoe Turn off indenting for now, it's confusing since we don't
 
328
        // actually place nested files directly below their parent
 
329
        //return file.document.level * indentWidth;
 
330
        return 0;
 
331
    },
 
332
 
 
333
    isError: function(file)
 
334
    {
 
335
        var errorRange = Math.floor(file.status/100);
 
336
        return errorRange == 4 || errorRange == 5;
 
337
    },
 
338
 
 
339
    summarizePhase: function(phase, rightNow)
 
340
    {
 
341
        var cachedSize = 0, totalSize = 0;
 
342
 
 
343
        var category = Firebug.netFilterCategory;
 
344
        if (category == "all")
 
345
            category = null;
 
346
 
 
347
        var fileCount = 0;
 
348
        var minTime = 0, maxTime = 0;
 
349
        for (var file = phase.phaseLastStart; file; file = file.previousFile)
 
350
        {
 
351
            if (!category || file.category == category)
 
352
            {
 
353
                ++fileCount;
 
354
 
 
355
                if (file.size > 0)
 
356
                {
 
357
                    totalSize += file.size;
 
358
                    if (file.fromCache)
 
359
                        cachedSize += file.size;
 
360
                }
 
361
 
 
362
                if (!minTime || file.startTime < minTime)
 
363
                    minTime = file.startTime;
 
364
                if (file.endTime > maxTime)
 
365
                    maxTime = file.endTime;
 
366
            }
 
367
 
 
368
            if (file == phase)
 
369
                break;
 
370
        }
 
371
 
 
372
        var totalTime = maxTime - minTime;
 
373
        return {cachedSize: cachedSize, totalSize: totalSize, totalTime: totalTime,
 
374
                fileCount: fileCount}
 
375
    },
 
376
 
 
377
    getHref: function(file)
 
378
    {
 
379
        if (file.status && file.status != 200)
 
380
            return getFileName(file.href) + " (" + file.status + ")";
 
381
        else
 
382
            return getFileName(file.href);
 
383
    },
 
384
 
 
385
    getDomain: function(file)
 
386
    {
 
387
        return getPrettyDomain(file.href);
 
388
    },
 
389
 
 
390
    getSize: function(file)
 
391
    {
 
392
        return this.formatSize(file.size);
 
393
    },
 
394
 
 
395
    hasResponseHeaders: function(file)
 
396
    {
 
397
        return !!file.responseHeaders;
 
398
    },
 
399
 
 
400
    formatSize: function(bytes)
 
401
    {
 
402
        if (bytes == -1 || bytes == undefined)
 
403
            return "?";
 
404
        else if (bytes < 1000)
 
405
            return bytes + " b";
 
406
        else if (bytes < 1000000)
 
407
            return Math.ceil(bytes/1000) + " KB";
 
408
        else
 
409
            return (Math.ceil(bytes/10000)/100) + " MB";
 
410
    },
 
411
 
 
412
    formatTime: function(elapsed)
 
413
    {
 
414
        if (elapsed == -1)
 
415
            return "_"; // should be &nbsp; but this will be escaped so we need something that is no whitespace
 
416
        else if (elapsed < 1000)
 
417
            return elapsed + "ms";
 
418
        else if (elapsed < 60000)
 
419
            return (Math.ceil(elapsed/10) / 100) + "s";
 
420
        else
 
421
            return (Math.ceil((elapsed/60000)*100)/100) + "m";
 
422
    },
 
423
 
 
424
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
425
 
 
426
    onClick: function(event)
 
427
    {
 
428
        if (isLeftClick(event))
 
429
        {
 
430
            var row = getAncestorByClass(event.target, "netRow");
 
431
            if (row)
 
432
            {
 
433
                this.toggleHeadersRow(row);
 
434
                cancelEvent(event);
 
435
            }
 
436
        }
 
437
    },
 
438
 
 
439
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
440
 
 
441
    clear: function()
 
442
    {
 
443
        this.panelNode.innerHTML = "";
 
444
        this.table = null;
 
445
        this.summaryRow = null;
 
446
 
 
447
        this.queue = [];
 
448
        this.invalidPhases = false;
 
449
    },
 
450
 
 
451
    setFilter: function(filterCategory)
 
452
    {
 
453
        this.filterCategory = filterCategory;
 
454
 
 
455
        var panelNode = this.panelNode;
 
456
        for (var category in fileCategories)
 
457
        {
 
458
            if (filterCategory != "all" && category != filterCategory)
 
459
                setClass(panelNode, "hideCategory-"+category);
 
460
            else
 
461
                removeClass(panelNode, "hideCategory-"+category);
 
462
        }
 
463
    },
 
464
 
 
465
    toggleHeadersRow: function(row)
 
466
    {
 
467
        if (!hasClass(row, "hasHeaders"))
 
468
            return;
 
469
 
 
470
        toggleClass(row, "opened");
 
471
 
 
472
        if (hasClass(row, "opened"))
 
473
        {
 
474
            var template = Firebug.NetMonitor.NetInfoBody;
 
475
 
 
476
            var netInfoRow = this.netInfoTag.insertRows({}, row)[0];
 
477
            var netInfo = template.tag.replace({file: row.repObject}, netInfoRow.firstChild);
 
478
            template.selectTabByName(netInfo, "Headers");
 
479
 
 
480
            setClass(netInfo, "category-"+getFileCategory(row.repObject));
 
481
        }
 
482
        else
 
483
        {
 
484
            row.parentNode.removeChild(row.nextSibling);
 
485
        }
 
486
    },
 
487
 
 
488
    copyParams: function(file)
 
489
    {
 
490
        var text = getPostText(file, this.context);
 
491
 
 
492
        var lines = text.split("\n");
 
493
        var params = parseURLEncodedText(lines[lines.length-1]);
 
494
 
 
495
        var args = [];
 
496
        for (var i = 0; i < params.length; ++i)
 
497
            args.push(escape(params[i].name)+"="+escape(params[i].value));
 
498
 
 
499
        var url = file.href;
 
500
        url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&");
 
501
 
 
502
        copyToClipboard(url);
 
503
    },
 
504
 
 
505
    copyHeaders: function(headers)
 
506
    {
 
507
        var lines = [];
 
508
        if (headers)
 
509
        {
 
510
            for (var i = 0; i < headers.length; ++i)
 
511
            {
 
512
                var header = headers[i];
 
513
                lines.push(header.name + ": " + header.value);
 
514
            }
 
515
        }
 
516
 
 
517
        var text = lines.join("\r\n");
 
518
        copyToClipboard(text);
 
519
    },
 
520
 
 
521
    copyResponse: function(file)
 
522
    {
 
523
        var text = file.responseText
 
524
            ? file.responseText
 
525
            : this.context.sourceCache.loadText(file.href);
 
526
 
 
527
        copyToClipboard(text);
 
528
    },
 
529
 
 
530
    stopLoading: function(file)
 
531
    {
 
532
        const NS_BINDING_ABORTED = 0x804b0002;
 
533
 
 
534
        file.request.cancel(NS_BINDING_ABORTED);
 
535
    },
 
536
 
 
537
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
538
    // extends Panel
 
539
 
 
540
    name: "net",
 
541
    searchable: true,
 
542
    editable: false,
 
543
 
 
544
    initialize: function()
 
545
    {
 
546
        this.queue = [];
 
547
 
 
548
        Firebug.Panel.initialize.apply(this, arguments);
 
549
    },
 
550
 
 
551
    destroy: function(state)
 
552
    {
 
553
        if (this.pendingInterval)
 
554
        {
 
555
            this.context.clearInterval(this.pendingInterval);
 
556
            delete this.pendingInterval;
 
557
        }
 
558
 
 
559
        Firebug.Panel.destroy.apply(this, arguments);
 
560
    },
 
561
 
 
562
    show: function(state)
 
563
    {
 
564
        if (!this.filterCategory)
 
565
            this.setFilter(Firebug.netFilterCategory);
 
566
 
 
567
        this.layout();
 
568
        this.layoutInterval = setInterval(bindFixed(this.updateLayout, this), layoutInterval);
 
569
 
 
570
        if (this.wasScrolledToBottom)
 
571
            scrollToBottom(this.panelNode);
 
572
    },
 
573
 
 
574
    hide: function()
 
575
    {
 
576
        this.wasScrolledToBottom = isScrolledToBottom(this.panelNode);
 
577
 
 
578
        clearInterval(this.layoutInterval);
 
579
        delete this.layoutInterval;
 
580
    },
 
581
 
 
582
    updateOption: function(name, value)
 
583
    {
 
584
        if (name == "disableNetMonitor")
 
585
            TabWatcher.iterateContexts(value ? monitorContext : unmonitorContext);
 
586
        else if (name == "netFilterCategory")
 
587
        {
 
588
            Firebug.NetMonitor.syncFilterButtons(this.context.chrome);
 
589
            for (var i = 0; i < TabWatcher.contexts.length; ++i)
 
590
            {
 
591
                var context = TabWatcher.contexts[i];
 
592
                Firebug.NetMonitor.onToggleFilter(context, value);
 
593
            }
 
594
        }
 
595
    },
 
596
 
 
597
    getOptionsMenuItems: function()
 
598
    {
 
599
        return [
 
600
            optionMenu("DisableNetMonitor", "disableNetMonitor")
 
601
        ];
 
602
    },
 
603
 
 
604
    getContextMenuItems: function(nada, target)
 
605
    {
 
606
        var items = [];
 
607
 
 
608
        var file = Firebug.getRepObject(target);
 
609
        if (!file)
 
610
            return items;
 
611
 
 
612
        var object = Firebug.getObjectByURL(this.context, file.href);
 
613
        var isPost = isURLEncodedFile(file, getPostText(file, this.context));
 
614
 
 
615
        items.push(
 
616
            {label: "CopyLocation", command: bindFixed(copyToClipboard, FBL, file.href) }
 
617
        );
 
618
 
 
619
        if (isPost)
 
620
        {
 
621
            items.push(
 
622
                {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, file) }
 
623
            );
 
624
        }
 
625
 
 
626
        items.push(
 
627
            {label: "CopyRequestHeaders",
 
628
                command: bindFixed(this.copyHeaders, this, file.requestHeaders) },
 
629
            {label: "CopyResponseHeaders",
 
630
                command: bindFixed(this.copyHeaders, this, file.responseHeaders) }
 
631
        );
 
632
 
 
633
        if (file.category in textFileCategories)
 
634
        {
 
635
            items.push(
 
636
                {label: "CopyResponse", command: bindFixed(this.copyResponse, this, file) }
 
637
            );
 
638
        }
 
639
 
 
640
        items.push(
 
641
            "-",
 
642
            {label: "OpenInTab", command: bindFixed(openNewTab, FBL, file.href) }
 
643
        );
 
644
 
 
645
        if (!file.loaded)
 
646
        {
 
647
            items.push(
 
648
                "-",
 
649
                {label: "StopLoading", command: bindFixed(this.stopLoading, this, file) }
 
650
            );
 
651
        }
 
652
 
 
653
        if (object)
 
654
        {
 
655
            var subItems = FirebugChrome.getInspectMenuItems(object);
 
656
            if (subItems.length)
 
657
            {
 
658
                items.push("-");
 
659
                items.push.apply(items, subItems);
 
660
            }
 
661
        }
 
662
 
 
663
        return items;
 
664
    },
 
665
 
 
666
    showInfoTip: function(infoTip, target, x, y)
 
667
    {
 
668
        var row = getAncestorByClass(target, "netRow");
 
669
        if (row)
 
670
        {
 
671
            if (hasClass(row, "category-image"))
 
672
            {
 
673
                var url = row.repObject.href;
 
674
                if (url == this.infoTipURL)
 
675
                    return true;
 
676
 
 
677
                this.infoTipURL = url;
 
678
                return Firebug.InfoTip.populateImageInfoTip(infoTip, url);
 
679
            }
 
680
        }
 
681
    },
 
682
 
 
683
    search: function(text)
 
684
    {
 
685
        if (!text)
 
686
        {
 
687
            delete this.currentSearch;
 
688
            return false;
 
689
        }
 
690
 
 
691
        var row;
 
692
        if (this.currentSearch && text == this.currentSearch.text)
 
693
            row = this.currentSearch.findNext(true);
 
694
        else
 
695
        {
 
696
            function findRow(node) { return getAncestorByClass(node, "netRow"); }
 
697
            this.currentSearch = new TextSearch(this.panelNode, findRow);
 
698
            row = this.currentSearch.find(text);
 
699
        }
 
700
 
 
701
        if (row)
 
702
        {
 
703
            var sel = this.document.defaultView.getSelection();
 
704
            sel.removeAllRanges();
 
705
            sel.addRange(this.currentSearch.range);
 
706
 
 
707
            scrollIntoCenterView(row, this.panelNode);
 
708
            return true;
 
709
        }
 
710
        else
 
711
            return false;
 
712
    },
 
713
 
 
714
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
715
 
 
716
    updateFile: function(file)
 
717
    {
 
718
        if (!file.invalid)
 
719
        {
 
720
            file.invalid = true;
 
721
            this.queue.push(file);
 
722
        }
 
723
    },
 
724
 
 
725
    invalidatePhase: function(phase)
 
726
    {
 
727
        if (!phase.invalidPhase)
 
728
        {
 
729
            phase.invalidPhase = true;
 
730
            this.invalidPhases = true;
 
731
        }
 
732
    },
 
733
 
 
734
    updateLayout: function()
 
735
    {
 
736
        if (!this.queue.length)
 
737
            return;
 
738
 
 
739
        var scrolledToBottom = isScrolledToBottom(this.panelNode);
 
740
 
 
741
        this.layout();
 
742
 
 
743
        if (scrolledToBottom)
 
744
            scrollToBottom(this.panelNode);
 
745
    },
 
746
 
 
747
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
748
 
 
749
    layout: function()
 
750
    {
 
751
        if (!this.queue.length || !this.context.netProgress)
 
752
            return;
 
753
 
 
754
        if (!this.table)
 
755
        {
 
756
            this.table = this.tableTag.replace({}, this.panelNode, this);
 
757
            this.summaryRow =  this.summaryTag.insertRows({}, this.table.lastChild.lastChild)[0];
 
758
        }
 
759
 
 
760
        var rightNow = now();
 
761
        this.updateRowData(rightNow);
 
762
        this.updateTimeline(rightNow);
 
763
        this.updateSummaries(rightNow);
 
764
    },
 
765
 
 
766
    updateRowData: function(rightNow)
 
767
    {
 
768
        var queue = this.queue;
 
769
        this.queue = [];
 
770
 
 
771
        var phase;
 
772
        var newFileData = [];
 
773
 
 
774
        for (var i = 0; i < queue.length; ++i)
 
775
        {
 
776
            var file = queue[i];
 
777
 
 
778
            phase = this.calculateFileTimes(file, phase, rightNow);
 
779
            this.updateFileRow(file, newFileData);
 
780
 
 
781
            file.invalid = false;
 
782
            this.invalidatePhase(file.phase);
 
783
        }
 
784
 
 
785
        if (newFileData.length)
 
786
        {
 
787
            var tbody = this.table.firstChild;
 
788
            var lastRow = tbody.lastChild.previousSibling;
 
789
            var row = this.fileTag.insertRows({files: newFileData}, lastRow)[0];
 
790
 
 
791
            for (var i = 0; i < newFileData.length; ++i)
 
792
            {
 
793
                var file = newFileData[i].file;
 
794
                row.repObject = file;
 
795
                file.row = row;
 
796
                row = row.nextSibling;
 
797
            }
 
798
        }
 
799
    },
 
800
 
 
801
    updateFileRow: function(file, newFileData)
 
802
    {
 
803
        var row = file.row;
 
804
        if (!row)
 
805
        {
 
806
            if (file.startTime)
 
807
            {
 
808
                newFileData.push({
 
809
                        file: file,
 
810
                        offset: this.barOffset + "%",
 
811
                        width: this.barWidth + "%",
 
812
                        elapsed: file.loaded ? this.elapsed : -1
 
813
                });
 
814
            }
 
815
        }
 
816
        else if (file.invalid)
 
817
        {
 
818
            var sizeLabel = row.childNodes[2].firstChild;
 
819
            sizeLabel.firstChild.nodeValue = this.getSize(file);
 
820
 
 
821
            if (file.mimeType && !file.category)
 
822
            {
 
823
                removeClass(row, "category-undefined");
 
824
                setClass(row, "category-"+getFileCategory(file));
 
825
            }
 
826
 
 
827
            if (file.responseHeaders)
 
828
                setClass(row, "hasHeaders");
 
829
 
 
830
            if (file.fromCache)
 
831
                setClass(row, "fromCache");
 
832
            else
 
833
                removeClass(row, "fromCache");
 
834
 
 
835
            if (this.isError(file))
 
836
            {
 
837
                setClass(row, "responseError");
 
838
 
 
839
                var hrefLabel = row.firstChild.firstChild.firstChild;
 
840
                hrefLabel.nodeValue = this.getHref(file);
 
841
            }
 
842
 
 
843
            var timeLabel = row.childNodes[3].firstChild.lastChild.firstChild;
 
844
 
 
845
            if (file.loaded)
 
846
            {
 
847
                setClass(row, "loaded");
 
848
                timeLabel.innerHTML = this.formatTime(this.elapsed);
 
849
            }
 
850
            else
 
851
            {
 
852
                removeClass(row, "loaded");
 
853
                timeLabel.innerHTML = "&nbsp;";
 
854
            }
 
855
 
 
856
            if (hasClass(row, "opened"))
 
857
            {
 
858
                var netInfoBox = row.nextSibling.firstChild.firstChild;
 
859
                Firebug.NetMonitor.NetInfoBody.updateInfo(netInfoBox, file, this.context);
 
860
            }
 
861
        }
 
862
    },
 
863
 
 
864
    updateTimeline: function(rightNow)
 
865
    {
 
866
        var rootFile = this.context.netProgress.rootFile; // XXXjjb never read?
 
867
        var tbody = this.table.firstChild;
 
868
 
 
869
        // XXXjoe Don't update rows whose phase is done and layed out already
 
870
        var phase;
 
871
        for (var row = tbody.firstChild; row; row = row.nextSibling)
 
872
        {
 
873
            var file = row.repObject;
 
874
            if (!file)
 
875
                continue;
 
876
 
 
877
            phase = this.calculateFileTimes(file, phase, rightNow);
 
878
 
 
879
            var totalBar = row.childNodes[3].firstChild.childNodes[1];
 
880
            var timeBar = totalBar.nextSibling;
 
881
 
 
882
            totalBar.style.left = timeBar.style.left = this.barOffset + "%";
 
883
            timeBar.style.width = this.barWidth + "%";
 
884
 
 
885
            if (file.phase.phaseLastEnd && !file.phase.summaryRow)
 
886
            {
 
887
                var previousPhase = this.summaryRow.phase;
 
888
                if (previousPhase)
 
889
                {
 
890
                    var lastRow = previousPhase.phaseLastStart.row;
 
891
                    previousPhase.summaryRow = this.phaseTag.insertRows({}, lastRow)[0];
 
892
                    this.invalidatePhase(previousPhase);
 
893
                }
 
894
 
 
895
                this.summaryRow.phase = file.phase;
 
896
                file.phase.summaryRow = this.summaryRow;
 
897
            }
 
898
        }
 
899
    },
 
900
 
 
901
    updateSummaries: function(rightNow, updateAll)
 
902
    {
 
903
        if (!this.invalidPhases && !updateAll)
 
904
            return;
 
905
 
 
906
        this.invalidPhases = false;
 
907
 
 
908
        var phases = this.context.netProgress.phases;
 
909
        if (!phases.length)
 
910
            return;
 
911
 
 
912
        var fileCount = 0, totalSize = 0, cachedSize = 0, totalTime = 0;
 
913
        for (var i = 0; i < phases.length; ++i)
 
914
        {
 
915
            var phase = phases[i];
 
916
            phase.invalidPhase = false;
 
917
 
 
918
            var summary = this.summarizePhase(phase, rightNow);
 
919
            fileCount += summary.fileCount;
 
920
            totalSize += summary.totalSize;
 
921
            cachedSize += summary.cachedSize;
 
922
            totalTime += summary.totalTime
 
923
        }
 
924
 
 
925
        var row = this.summaryRow;
 
926
        if (!row)
 
927
            return;
 
928
 
 
929
        var countLabel = row.firstChild.firstChild;
 
930
        countLabel.firstChild.nodeValue = fileCount == 1
 
931
            ? $STR("Request")
 
932
            : $STRF("RequestCount", [fileCount]);
 
933
 
 
934
        var sizeLabel = row.childNodes[2].firstChild;
 
935
        sizeLabel.firstChild.nodeValue = this.formatSize(totalSize);
 
936
 
 
937
        var cacheSizeLabel = row.lastChild.firstChild.firstChild;
 
938
        cacheSizeLabel.setAttribute("collapsed", cachedSize == 0);
 
939
        cacheSizeLabel.childNodes[1].firstChild.nodeValue = this.formatSize(cachedSize);
 
940
 
 
941
        var timeLabel = row.lastChild.firstChild.lastChild.firstChild;
 
942
        timeLabel.innerHTML = this.formatTime(totalTime);
 
943
    },
 
944
 
 
945
    calculateFileTimes: function(file, phase, rightNow)
 
946
    {
 
947
        if (phase != file.phase)
 
948
        {
 
949
            phase = file.phase;
 
950
            this.phaseStartTime = phase.startTime;
 
951
            this.phaseEndTime = phase.phaseLastEndTime ? phase.phaseLastEndTime : rightNow;
 
952
            this.phaseElapsed = this.phaseEndTime - phase.startTime;
 
953
        }
 
954
 
 
955
        this.elapsed = file.loaded ? file.endTime - file.startTime : this.phaseEndTime - file.startTime;
 
956
        this.barWidth = Math.floor((this.elapsed/this.phaseElapsed) * 100);
 
957
        this.barOffset = Math.floor(((file.startTime-this.phaseStartTime)/this.phaseElapsed) * 100);
 
958
 
 
959
        return phase;
 
960
    }
 
961
});
 
962
 
 
963
// ************************************************************************************************
 
964
 
 
965
function NetProgress(context)
 
966
{
 
967
    this.context = context;
 
968
 
 
969
    var queue = null;
 
970
    var panel = null;
 
971
 
 
972
    this.post = function(handler, args)
 
973
    {
 
974
        if (panel)
 
975
        {
 
976
            var file = handler.apply(this, args);
 
977
            if (file)
 
978
            {
 
979
                 panel.updateFile(file);
 
980
                return file;
 
981
            }
 
982
        }
 
983
        else
 
984
        {
 
985
            if (queue.length/2 >= maxQueueRequests)
 
986
                queue.splice(0, 2);
 
987
            queue.push(handler, args);
 
988
        }
 
989
    };
 
990
 
 
991
    this.flush = function()
 
992
    {
 
993
        for (var i = 0; i < queue.length; i += 2)
 
994
        {
 
995
            var file = queue[i].apply(this, queue[i+1]);
 
996
            if (file)
 
997
                panel.updateFile(file);
 
998
        }
 
999
 
 
1000
        queue = [];
 
1001
    };
 
1002
 
 
1003
    this.activate = function(activePanel)
 
1004
    {
 
1005
        this.panel = panel = activePanel;
 
1006
        if (panel)
 
1007
            this.flush();
 
1008
    };
 
1009
 
 
1010
    this.update = function(file)
 
1011
    {
 
1012
        if (panel)
 
1013
            panel.updateFile(file);
 
1014
    };
 
1015
 
 
1016
    this.clear = function()
 
1017
    {
 
1018
        this.requests = [];
 
1019
        this.requestMap = {};
 
1020
        this.files = [];
 
1021
        this.phases = [];
 
1022
        this.documents = [];
 
1023
        this.windows = [];
 
1024
 
 
1025
        queue = [];
 
1026
    };
 
1027
 
 
1028
    this.clear();
 
1029
}
 
1030
 
 
1031
NetProgress.prototype =
 
1032
{
 
1033
    panel: null,
 
1034
 
 
1035
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1036
 
 
1037
    respondedTopWindow: function(request, time, webProgress)
 
1038
    {
 
1039
        var win = webProgress ? safeGetWindow(webProgress) : null;
 
1040
        this.requestedFile(request, time, win);
 
1041
        return this.respondedFile(request, time);
 
1042
    },
 
1043
 
 
1044
    requestedFile: function(request, time, win, category) // XXXjjb 3rd arg was webProgress, pulled safeGetWindow up
 
1045
    {
 
1046
        // XXXjjb to allow spy to pass win.  var win = webProgress ? safeGetWindow(webProgress) : null;
 
1047
        var file = this.getRequestFile(request, win);
 
1048
        if (file)
 
1049
        {
 
1050
            // For cached image files, we may never hear another peep from any observers
 
1051
            // after this point, so we have to assume that the file is cached and loaded
 
1052
            // until we get a respondedFile call later
 
1053
            file.startTime = file.endTime = time;
 
1054
            //file.fromCache = true;
 
1055
            //file.loaded = true;
 
1056
            if (category && !file.category)
 
1057
                file.category = category;
 
1058
            file.isBackground = request.loadFlags & LOAD_BACKGROUND;
 
1059
 
 
1060
            this.awaitFile(request, file);
 
1061
            this.extendPhase(file);
 
1062
 
 
1063
            return file;
 
1064
        }
 
1065
    },
 
1066
 
 
1067
    respondedFile: function(request, time)
 
1068
    {
 
1069
        var file = this.getRequestFile(request);
 
1070
        if (file)
 
1071
        {
 
1072
            var endedAlready = !!file.endTime;
 
1073
 
 
1074
            file.respondedTime = time;
 
1075
            file.endTime = time;
 
1076
 
 
1077
            if (request.contentLength > 0)
 
1078
                file.size = request.contentLength;
 
1079
 
 
1080
            if (request.responseStatus == 304)
 
1081
                file.fromCache = true;
 
1082
            else if (!file.fromCache)
 
1083
                file.fromCache = false;
 
1084
 
 
1085
            getHttpHeaders(request, file);
 
1086
 
 
1087
            // This is a strange but effective tactic for simulating the
 
1088
            // load of background images, which we can't actually track.
 
1089
            // If endTime was set before this, that means the cache request
 
1090
            // came back, which only seems to happen for background images.
 
1091
            // We thus end the load now, since we know we'll never hear
 
1092
            // from these requests again.
 
1093
            if (endedAlready)
 
1094
                this.endLoad(file);
 
1095
 
 
1096
            return file;
 
1097
        }
 
1098
    },
 
1099
 
 
1100
    progressFile: function(request, progress, expectedSize)
 
1101
    {
 
1102
        var file = this.getRequestFile(request);
 
1103
        if (file)
 
1104
        {
 
1105
            file.size = progress;
 
1106
            file.expectedSize = expectedSize;
 
1107
 
 
1108
            this.arriveFile(file, request);
 
1109
 
 
1110
            return file;
 
1111
        }
 
1112
    },
 
1113
 
 
1114
    stopFile: function(request, time, postText, responseText)
 
1115
    {
 
1116
        var file = this.getRequestFile(request);
 
1117
        if (file)
 
1118
        {
 
1119
            file.endTime = time;
 
1120
            file.postText = postText;
 
1121
            file.responseText = responseText;
 
1122
 
 
1123
            // XXXjoe Nice work, pavlov.  This crashes randomly when it access decoderObserver.
 
1124
            //file.sourceObject = getRequestElement(request);
 
1125
 
 
1126
            getHttpHeaders(request, file);
 
1127
 
 
1128
            this.arriveFile(file, request);
 
1129
            this.endLoad(file);
 
1130
 
 
1131
            getCacheEntry(file, this);
 
1132
 
 
1133
            return file;
 
1134
        }
 
1135
    },
 
1136
 
 
1137
    cacheEntryReady: function(request, file, size)
 
1138
    {
 
1139
        file.loaded = true;
 
1140
        if (size != -1)
 
1141
            file.size = size;
 
1142
 
 
1143
        getHttpHeaders(request, file);
 
1144
 
 
1145
        this.arriveFile(file, request);
 
1146
        this.endLoad(file);
 
1147
 
 
1148
        return file;
 
1149
    },
 
1150
 
 
1151
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1152
 
 
1153
    getRequestFile: function(request, win)
 
1154
    {
 
1155
        var name = safeGetName(request);
 
1156
        if (!name || reIgnore.exec(name))
 
1157
            return null;
 
1158
 
 
1159
        var index = this.requests.indexOf(request);
 
1160
        if (index == -1)
 
1161
        {
 
1162
            var file = this.requestMap[name];
 
1163
            if (file)
 
1164
                return file;
 
1165
 
 
1166
            if (!win || getRootWindow(win) != this.context.window)
 
1167
                return;
 
1168
 
 
1169
            var fileDoc = this.getRequestDocument(win);
 
1170
            var isDocument = request.loadFlags & LOAD_DOCUMENT_URI && fileDoc.parent;
 
1171
            var doc = isDocument ? fileDoc.parent : fileDoc;
 
1172
 
 
1173
            file = doc.addFile(request);
 
1174
            if (isDocument)
 
1175
            {
 
1176
                fileDoc.documentFile = file;
 
1177
                file.ownDocument = fileDoc;
 
1178
            }
 
1179
 
 
1180
            if (!this.rootFile)
 
1181
                this.rootFile = file;  // don't set file.previousFile
 
1182
            else
 
1183
                file.previousFile = this.files[this.files.length-1];
 
1184
 
 
1185
            file.request = request;
 
1186
            file.index = this.files.length;
 
1187
            this.requestMap[name] = file;
 
1188
            this.requests.push(request);
 
1189
            this.files.push(file);
 
1190
 
 
1191
            return file;
 
1192
        }
 
1193
        else
 
1194
            return this.files[index];
 
1195
    },
 
1196
 
 
1197
    getRequestDocument: function(win)
 
1198
    {
 
1199
        if (win)
 
1200
        {
 
1201
            var index = this.windows.indexOf(win);
 
1202
            if (index == -1)
 
1203
            {
 
1204
                var doc = new NetDocument(win);  // XXXjjb arg ignored
 
1205
                if (win.parent != win)
 
1206
                    doc.parent = this.getRequestDocument(win.parent);
 
1207
 
 
1208
                doc.index = this.documents.length;
 
1209
                doc.level = getFrameLevel(win);
 
1210
 
 
1211
                this.documents.push(doc);
 
1212
                this.windows.push(win);
 
1213
 
 
1214
                return doc;
 
1215
            }
 
1216
            else
 
1217
                return this.documents[index];
 
1218
        }
 
1219
        else
 
1220
            return this.documents[0];
 
1221
    },
 
1222
 
 
1223
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1224
 
 
1225
    awaitFile: function(request, file)
 
1226
    {
 
1227
        if (!this.pending)
 
1228
            this.pending = [];
 
1229
 
 
1230
        // XXXjoe Remove files after they have been checked N times
 
1231
        if (!this.pendingInterval)
 
1232
        {
 
1233
            this.pendingInterval = this.context.setInterval(bindFixed(function()
 
1234
            {
 
1235
                for (var i = 0; i < this.pending.length; ++i)
 
1236
                {
 
1237
                    var file = this.pending[i];
 
1238
                    if (file.pendingCount > maxPendingCheck)
 
1239
                    {
 
1240
                        this.post(cacheEntryReady, [request, file, 0]);
 
1241
                        this.pending.splice(i, 0);
 
1242
                        --i;
 
1243
                    }
 
1244
                    else
 
1245
                        waitForCacheCompletion(request, file, this);
 
1246
                }
 
1247
            }, this), 300);
 
1248
        }
 
1249
 
 
1250
        file.pendingIndex = this.pending.length;
 
1251
        this.pending.push(file);
 
1252
    },
 
1253
 
 
1254
    arriveFile: function(file, request)
 
1255
    {
 
1256
        delete this.requestMap[file.href];
 
1257
 
 
1258
        var index = this.pending.indexOf(file);
 
1259
        if (index != -1)
 
1260
            this.pending.splice(index, 1);
 
1261
 
 
1262
        if (!this.pending.length)
 
1263
        {
 
1264
            this.context.clearInterval(this.pendingInterval);
 
1265
            delete this.pendingInterval;
 
1266
        }
 
1267
    },
 
1268
 
 
1269
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1270
 
 
1271
    endLoad: function(file)
 
1272
    {
 
1273
        file.loaded = true;
 
1274
 
 
1275
        file.phase.phaseLastEnd = file;
 
1276
        if (!file.phase.phaseLastEndTime || file.endTime > file.phase.phaseLastEndTime)
 
1277
            file.phase.phaseLastEndTime = file.endTime;
 
1278
    },
 
1279
 
 
1280
    extendPhase: function(file)
 
1281
    {
 
1282
        if (this.currentPhase)
 
1283
        {
 
1284
            var phaseLastStart = this.currentPhase.phaseLastStart;
 
1285
 
 
1286
            if (this.loaded && file.startTime - phaseLastStart.startTime >= phaseInterval)
 
1287
                this.startPhase(file, phaseLastStart);
 
1288
            else
 
1289
                file.phase = this.currentPhase;
 
1290
        }
 
1291
        else
 
1292
            this.startPhase(file, null);
 
1293
 
 
1294
        file.phase.phaseLastStart = file;
 
1295
    },
 
1296
 
 
1297
    startPhase: function(file, phaseLastStart)
 
1298
    {
 
1299
        if (phaseLastStart)
 
1300
            phaseLastStart.endPhase = true;
 
1301
 
 
1302
        file.phase = this.currentPhase = file;
 
1303
        file.startPhase = true;
 
1304
 
 
1305
        this.phases.push(file);
 
1306
    },
 
1307
 
 
1308
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1309
    // nsISupports
 
1310
 
 
1311
    QueryInterface: function(iid)
 
1312
    {
 
1313
        if (iid.equals(nsIWebProgressListener)
 
1314
            || iid.equals(nsISupportsWeakReference)
 
1315
            || iid.equals(nsISupports))
 
1316
        {
 
1317
            return this;
 
1318
        }
 
1319
 
 
1320
        throw Components.results.NS_NOINTERFACE;
 
1321
    },
 
1322
 
 
1323
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1324
    // nsIObserver
 
1325
 
 
1326
    observe: function(request, topic, data)
 
1327
    {
 
1328
        request = QI(request, nsIHttpChannel);
 
1329
        if (topic == "http-on-modify-request")
 
1330
        {
 
1331
            var webProgress = getRequestWebProgress(request, this);
 
1332
            var category = getRequestCategory(request);
 
1333
            var win = webProgress ? safeGetWindow(webProgress) : null;
 
1334
            this.post(requestedFile, [request, now(), win, category]);
 
1335
        }
 
1336
        else
 
1337
        {
 
1338
            this.post(respondedFile, [request, now()]);
 
1339
        }
 
1340
    },
 
1341
 
 
1342
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1343
    // nsIWebProgressListener
 
1344
 
 
1345
    onStateChange: function(progress, request, flag, status)
 
1346
    {
 
1347
        if (flag & STATE_TRANSFERRING && flag & STATE_IS_DOCUMENT)
 
1348
        {
 
1349
            var win = progress.DOMWindow;
 
1350
            if (win == win.parent)
 
1351
                this.post(respondedTopWindow, [request, now(), progress]);
 
1352
        }
 
1353
        else if (flag & STATE_STOP && flag & STATE_IS_REQUEST)
 
1354
        {
 
1355
            if (this.getRequestFile(request))
 
1356
                this.post(stopFile, [request, now()]);
 
1357
        }
 
1358
    },
 
1359
 
 
1360
    onProgressChange : function(progress, request, current, max, total, maxTotal)
 
1361
    {
 
1362
        this.post(progressFile, [request, current, max]);
 
1363
    },
 
1364
 
 
1365
    stateIsRequest: false,
 
1366
    onLocationChange: function() {},
 
1367
    onStatusChange : function() {},
 
1368
    onSecurityChange : function() {},
 
1369
    onLinkIconAvailable : function() {}
 
1370
};
 
1371
 
 
1372
var requestedFile = NetProgress.prototype.requestedFile;
 
1373
var respondedTopWindow = NetProgress.prototype.respondedTopWindow;
 
1374
var respondedFile = NetProgress.prototype.respondedFile;
 
1375
var progressFile = NetProgress.prototype.progressFile;
 
1376
var stopFile = NetProgress.prototype.stopFile;
 
1377
var cacheEntryReady = NetProgress.prototype.cacheEntryReady;
 
1378
 
 
1379
// ************************************************************************************************
 
1380
 
 
1381
function NetDocument()
 
1382
{
 
1383
    this.files = [];
 
1384
}
 
1385
 
 
1386
NetDocument.prototype =
 
1387
{
 
1388
    loaded: false,
 
1389
 
 
1390
    addFile: function(request)
 
1391
    {
 
1392
        var file = new NetFile(request.name, this);
 
1393
        this.files.push(file);
 
1394
 
 
1395
        if (this.files.length == 1)
 
1396
            this.rootFile = file;
 
1397
 
 
1398
        return file;
 
1399
    }
 
1400
};
 
1401
 
 
1402
// ************************************************************************************************
 
1403
 
 
1404
function NetFile(href, document)
 
1405
{
 
1406
    this.href = href;
 
1407
    this.document = document
 
1408
}
 
1409
 
 
1410
NetFile.prototype =
 
1411
{
 
1412
    status: 0,
 
1413
    files: 0,
 
1414
    loaded: false,
 
1415
    fromCache: false,
 
1416
    size: -1,
 
1417
    expectedSize: -1,
 
1418
    endTime: null
 
1419
};
 
1420
 
 
1421
Firebug.NetFile = NetFile;
 
1422
 
 
1423
// ************************************************************************************************
 
1424
// Local Helpers
 
1425
 
 
1426
function monitorContext(context)
 
1427
{
 
1428
    if (!context.netProgress)
 
1429
    {
 
1430
        var listener = context.netProgress = new NetProgress(context);
 
1431
 
 
1432
        context.browser.addProgressListener(listener, NOTIFY_ALL);
 
1433
 
 
1434
        observerService.addObserver(listener, "http-on-modify-request", false);
 
1435
        observerService.addObserver(listener, "http-on-examine-response", false);
 
1436
    }
 
1437
}
 
1438
 
 
1439
function unmonitorContext(context)
 
1440
{
 
1441
    if (context.netProgress)
 
1442
    {
 
1443
        if (context.browser.docShell)
 
1444
            context.browser.removeProgressListener(context.netProgress, NOTIFY_ALL);
 
1445
 
 
1446
        // XXXjoe We also want to do this when the context is hidden, so that
 
1447
        // background files are only logged in the currently visible context
 
1448
        observerService.removeObserver(context.netProgress, "http-on-modify-request", false);
 
1449
        observerService.removeObserver(context.netProgress, "http-on-examine-response", false);
 
1450
 
 
1451
        delete context.netProgress;
 
1452
    }
 
1453
}
 
1454
 
 
1455
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1456
 
 
1457
function initCacheSession()
 
1458
{
 
1459
    if (!cacheSession)
 
1460
    {
 
1461
        var cacheService = CacheService.getService(nsICacheService);
 
1462
        cacheSession = cacheService.createSession("HTTP", STORE_ANYWHERE, true);
 
1463
        cacheSession.doomEntriesIfExpired = false;
 
1464
    }
 
1465
}
 
1466
 
 
1467
function waitForCacheCompletion(request, file, netProgress)
 
1468
{
 
1469
    try
 
1470
    {
 
1471
        initCacheSession();
 
1472
        var descriptor = cacheSession.openCacheEntry(file.href, ACCESS_READ, false);
 
1473
        if (descriptor)
 
1474
            netProgress.post(cacheEntryReady, [request, file, descriptor.dataSize]);
 
1475
    }
 
1476
    catch (exc)
 
1477
    {
 
1478
        if (exc.result != NS_ERROR_CACHE_WAIT_FOR_VALIDATION
 
1479
            && exc.result != NS_ERROR_CACHE_KEY_NOT_FOUND)
 
1480
        {
 
1481
            ERROR(exc);
 
1482
            netProgress.post(cacheEntryReady, [request, file, -1]);
 
1483
        }
 
1484
    }
 
1485
}
 
1486
 
 
1487
function getCacheEntry(file, netProgress)
 
1488
{
 
1489
    // Pause first because this is usually called from stopFile, at which point
 
1490
    // the file's cache entry is locked
 
1491
    setTimeout(function()
 
1492
    {
 
1493
        try
 
1494
        {
 
1495
            initCacheSession();
 
1496
            cacheSession.asyncOpenCacheEntry(file.href, ACCESS_READ, {
 
1497
                onCacheEntryAvailable: function(descriptor, accessGranted, status)
 
1498
                {
 
1499
                    if (descriptor)
 
1500
                    {
 
1501
                        if(file.size == -1)
 
1502
                        {
 
1503
                            file.size = descriptor.dataSize;
 
1504
                        }
 
1505
                        if(descriptor.lastModified && descriptor.lastFetched &&
 
1506
                            descriptor.lastModified < Math.floor(file.startTime/1000)) {
 
1507
                            file.fromCache = true;
 
1508
                        }
 
1509
                        file.cacheEntry = [
 
1510
                          { name: "Last Modified",
 
1511
                            value: getDateFromSeconds(descriptor.lastModified)
 
1512
                          },
 
1513
                          { name: "Last Fetched",
 
1514
                            value: getDateFromSeconds(descriptor.lastFetched)
 
1515
                          },
 
1516
                          { name: "Data Size",
 
1517
                            value: descriptor.dataSize
 
1518
                          },
 
1519
                          { name: "Fetch Count",
 
1520
                            value: descriptor.fetchCount
 
1521
                          },
 
1522
                          { name: "Device",
 
1523
                            value: descriptor.deviceID
 
1524
                          }
 
1525
                        ];
 
1526
                        netProgress.update(file);
 
1527
                    }
 
1528
                }
 
1529
            });
 
1530
        }
 
1531
        catch (exc)
 
1532
        {
 
1533
            ERROR(exc);
 
1534
        }
 
1535
    });
 
1536
}
 
1537
 
 
1538
function getDateFromSeconds(s)
 
1539
{
 
1540
    var d = new Date();
 
1541
    d.setTime(s*1000);
 
1542
    return d;
 
1543
}
 
1544
 
 
1545
function getHttpHeaders(request, file)
 
1546
{
 
1547
    try
 
1548
    {
 
1549
        var http = QI(request, nsIHttpChannel);
 
1550
        file.method = http.requestMethod;
 
1551
        file.status = request.responseStatus;
 
1552
        file.urlParams = parseURLParams(file.href);
 
1553
 
 
1554
        if (!file.mimeType)
 
1555
            file.mimeType = getMimeType(request);
 
1556
 
 
1557
        // Disable temporarily
 
1558
        if (!file.responseHeaders && Firebug.collectHttpHeaders)
 
1559
        {
 
1560
            var requestHeaders = [], responseHeaders = [];
 
1561
 
 
1562
            http.visitRequestHeaders({
 
1563
                visitHeader: function(name, value)
 
1564
                {
 
1565
                    requestHeaders.push({name: name, value: value});
 
1566
                }
 
1567
            });
 
1568
            http.visitResponseHeaders({
 
1569
                visitHeader: function(name, value)
 
1570
                {
 
1571
                    responseHeaders.push({name: name, value: value});
 
1572
                }
 
1573
            });
 
1574
 
 
1575
            file.requestHeaders = requestHeaders;
 
1576
            file.responseHeaders = responseHeaders;
 
1577
        }
 
1578
    }
 
1579
    catch (exc)
 
1580
    {
 
1581
    }
 
1582
}
 
1583
 
 
1584
function getRequestWebProgress(request, netProgress)
 
1585
{
 
1586
    try
 
1587
    {
 
1588
        if (request.notificationCallbacks)
 
1589
        {
 
1590
            var bypass = false;
 
1591
            if (request.notificationCallbacks instanceof XMLHttpRequest)
 
1592
            {
 
1593
                request.notificationCallbacks.channel.visitRequestHeaders(
 
1594
                {
 
1595
                    visitHeader: function(header, value)
 
1596
                    {
 
1597
                        if (header == "X-Moz" && value == "microsummary")
 
1598
                            bypass = true;
 
1599
                    }
 
1600
                });
 
1601
            }
 
1602
            // XXXjjb Joe review: code above sets bypass, so this stmt should be in if (gives exceptions otherwise)
 
1603
            // The instanceof can't be used here. Fix for #434 [Honza]
 
1604
            if (!bypass)
 
1605
                return request.notificationCallbacks.getInterface(nsIWebProgress);
 
1606
        }
 
1607
    }
 
1608
    catch (exc) {}
 
1609
 
 
1610
    try
 
1611
    {
 
1612
        if (request.loadGroup && request.loadGroup.groupObserver)
 
1613
            return QI(request.loadGroup.groupObserver, nsIWebProgress);
 
1614
    }
 
1615
    catch (exc) {}
 
1616
}
 
1617
 
 
1618
function getRequestCategory(request)
 
1619
{
 
1620
    try
 
1621
    {
 
1622
        if (request.notificationCallbacks)
 
1623
        {
 
1624
            if (request.notificationCallbacks instanceof XMLHttpRequest)
 
1625
                return "xhr";
 
1626
        }
 
1627
    }
 
1628
    catch (exc) {}
 
1629
}
 
1630
 
 
1631
function getRequestElement(request)
 
1632
{
 
1633
    if (request instanceof imgIRequest)
 
1634
    {
 
1635
        if (request.decoderObserver && request.decoderObserver instanceof Element)
 
1636
        {
 
1637
            return request.decoderObserver;
 
1638
        }
 
1639
    }
 
1640
}
 
1641
 
 
1642
function safeGetWindow(webProgress)
 
1643
{
 
1644
    try
 
1645
    {
 
1646
        return webProgress.DOMWindow;
 
1647
    }
 
1648
    catch (exc)
 
1649
    {
 
1650
        return null;
 
1651
    }
 
1652
}
 
1653
 
 
1654
function safeGetName(request)
 
1655
{
 
1656
    try
 
1657
    {
 
1658
        return request.name;
 
1659
    }
 
1660
    catch (exc)
 
1661
    {
 
1662
        return null;
 
1663
    }
 
1664
}
 
1665
 
 
1666
function getFileCategory(file)
 
1667
{
 
1668
    if (file.category)
 
1669
        return file.category;
 
1670
 
 
1671
    if (!file.mimeType)
 
1672
    {
 
1673
        var ext = getFileExtension(file.href);
 
1674
        if (ext)
 
1675
            file.mimeType = mimeExtensionMap[ext.toLowerCase()];
 
1676
    }
 
1677
 
 
1678
    return (file.category = mimeCategoryMap[file.mimeType]);
 
1679
}
 
1680
 
 
1681
function getMimeType(request)
 
1682
{
 
1683
    var mimeType = request.contentType;
 
1684
    if (!mimeType || !(mimeType in mimeCategoryMap))
 
1685
    {
 
1686
        var ext = getFileExtension(request.name);
 
1687
        if (!ext)
 
1688
            return mimeType;
 
1689
        else
 
1690
        {
 
1691
            var extMimeType = mimeExtensionMap[ext.toLowerCase()];
 
1692
            return extMimeType ? extMimeType : mimeType;
 
1693
        }
 
1694
    }
 
1695
    else
 
1696
        return mimeType;
 
1697
}
 
1698
 
 
1699
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1700
 
 
1701
function now()
 
1702
{
 
1703
    return (new Date()).getTime();
 
1704
}
 
1705
 
 
1706
function getFrameLevel(win)
 
1707
{
 
1708
    var level = 0;
 
1709
 
 
1710
    for (; win && win != win.parent; win = win.parent)
 
1711
        ++level;
 
1712
 
 
1713
    return level;
 
1714
}
 
1715
 
 
1716
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1717
 
 
1718
Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep,
 
1719
{
 
1720
    tag:
 
1721
        DIV({class: "netInfoBody", _repObject: "$file"},
 
1722
            DIV({class: "netInfoTabs"},
 
1723
                A({class: "netInfoParamsTab netInfoTab", onclick: "$onClickTab",
 
1724
                    view: "Params",
 
1725
                    $collapsed: "$file|hideParams"},
 
1726
                    $STR("URLParameters")
 
1727
                ),
 
1728
                A({class: "netInfoHeadersTab netInfoTab", onclick: "$onClickTab",
 
1729
                    view: "Headers"},
 
1730
                    $STR("Headers")
 
1731
                ),
 
1732
                A({class: "netInfoPostTab netInfoTab", onclick: "$onClickTab",
 
1733
                    view: "Post",
 
1734
                    $collapsed: "$file|hidePost"},
 
1735
                    $STR("Post")
 
1736
                ),
 
1737
                A({class: "netInfoResponseTab netInfoTab", onclick: "$onClickTab",
 
1738
                    view: "Response",
 
1739
                    $collapsed: "$file|hideResponse"},
 
1740
                    $STR("Response")
 
1741
                ),
 
1742
                A({class: "netInfoCacheTab netInfoTab", onclick: "$onClickTab",
 
1743
                   view: "Cache",
 
1744
                   $collapsed: "$file|hideCache"},
 
1745
                   "Cache" // todo: Localization
 
1746
                )
 
1747
            ),
 
1748
            TABLE({class: "netInfoParamsText netInfoText netInfoParamsTable",
 
1749
                    cellpadding: 0, cellspacing: 0}, TBODY()),
 
1750
            TABLE({class: "netInfoHeadersText netInfoText netInfoHeadersTable",
 
1751
                    cellpadding: 0, cellspacing: 0},
 
1752
                TBODY(
 
1753
                    TR({class: "netInfoResponseHeadersTitle"},
 
1754
                        TD({colspan: 2},
 
1755
                            DIV({class: "netInfoHeadersGroup"}, $STR("ResponseHeaders"))
 
1756
                        )
 
1757
                    ),
 
1758
                    TR({class: "netInfoRequestHeadersTitle"},
 
1759
                        TD({colspan: 2},
 
1760
                            DIV({class: "netInfoHeadersGroup"}, $STR("RequestHeaders"))
 
1761
                        )
 
1762
                    )
 
1763
                )
 
1764
            ),
 
1765
            DIV({class: "netInfoPostText netInfoText"},
 
1766
                TABLE({class: "netInfoPostTable", cellpadding: 0, cellspacing: 0},
 
1767
                    TBODY()
 
1768
                )
 
1769
            ),
 
1770
            DIV({class: "netInfoResponseText netInfoText"},
 
1771
                $STR("Loading")
 
1772
            ),
 
1773
            DIV({class: "netInfoCacheText netInfoText"},
 
1774
                TABLE({class: "netInfoCacheTable", cellpadding: 0, cellspacing: 0},
 
1775
                    TBODY()
 
1776
                )
 
1777
            )
 
1778
        ),
 
1779
 
 
1780
    headerDataTag:
 
1781
        FOR("param", "$headers",
 
1782
            TR(
 
1783
                TD({class: "netInfoParamName"}, "$param.name"),
 
1784
                TD({class: "netInfoParamValue"}, "$param.value")
 
1785
            )
 
1786
        ),
 
1787
 
 
1788
    hideParams: function(file)
 
1789
    {
 
1790
        return !file.urlParams || !file.urlParams.length;
 
1791
    },
 
1792
 
 
1793
    hidePost: function(file)
 
1794
    {
 
1795
        return file.method.toUpperCase() != "POST";
 
1796
    },
 
1797
 
 
1798
    hideResponse: function(file)
 
1799
    {
 
1800
        return file.category in binaryFileCategories;
 
1801
    },
 
1802
 
 
1803
    hideCache: function(file)
 
1804
    {
 
1805
        return !file.cacheEntry || file.category=="image";
 
1806
    },
 
1807
 
 
1808
    onClickTab: function(event)
 
1809
    {
 
1810
        this.selectTab(event.currentTarget);
 
1811
    },
 
1812
 
 
1813
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
1814
 
 
1815
    selectTabByName: function(netInfoBox, tabName)
 
1816
    {
 
1817
        var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab");
 
1818
        if (tab)
 
1819
            this.selectTab(tab);
 
1820
    },
 
1821
 
 
1822
    selectTab: function(tab)
 
1823
    {
 
1824
        var netInfoBox = tab.parentNode.parentNode;
 
1825
 
 
1826
        var view = tab.getAttribute("view");
 
1827
        if (netInfoBox.selectedTab)
 
1828
        {
 
1829
            netInfoBox.selectedTab.removeAttribute("selected");
 
1830
            netInfoBox.selectedText.removeAttribute("selected");
 
1831
        }
 
1832
 
 
1833
        var textBodyName = "netInfo" + view + "Text";
 
1834
 
 
1835
        netInfoBox.selectedTab = tab;
 
1836
        netInfoBox.selectedText = getChildByClass(netInfoBox, textBodyName);
 
1837
 
 
1838
        netInfoBox.selectedTab.setAttribute("selected", "true");
 
1839
        netInfoBox.selectedText.setAttribute("selected", "true");
 
1840
 
 
1841
        var file = Firebug.getRepObject(netInfoBox);
 
1842
        var context = Firebug.getElementPanel(netInfoBox).context;
 
1843
        this.updateInfo(netInfoBox, file, context);
 
1844
    },
 
1845
 
 
1846
    updateInfo: function(netInfoBox, file, context)
 
1847
    {
 
1848
        var tab = netInfoBox.selectedTab;
 
1849
        if (hasClass(tab, "netInfoParamsTab"))
 
1850
        {
 
1851
            if (file.urlParams && !netInfoBox.urlParamsPresented)
 
1852
            {
 
1853
                netInfoBox.urlParamsPresented = true;
 
1854
                this.insertHeaderRows(netInfoBox, file.urlParams, "Params");
 
1855
            }
 
1856
        }
 
1857
 
 
1858
        if (hasClass(tab, "netInfoHeadersTab"))
 
1859
        {
 
1860
            if (file.responseHeaders && !netInfoBox.responseHeadersPresented)
 
1861
            {
 
1862
                netInfoBox.responseHeadersPresented = true;
 
1863
                this.insertHeaderRows(netInfoBox, file.responseHeaders, "Headers", "ResponseHeaders");
 
1864
            }
 
1865
 
 
1866
            if (file.requestHeaders && !netInfoBox.requestHeadersPresented)
 
1867
            {
 
1868
                netInfoBox.requestHeadersPresented = true;
 
1869
                this.insertHeaderRows(netInfoBox, file.requestHeaders, "Headers", "RequestHeaders");
 
1870
            }
 
1871
        }
 
1872
 
 
1873
        if (hasClass(tab, "netInfoPostTab"))
 
1874
        {
 
1875
            var postTextBox = getChildByClass(netInfoBox, "netInfoPostText");
 
1876
            if (!netInfoBox.postPresented)
 
1877
            {
 
1878
                netInfoBox.postPresented  = true;
 
1879
 
 
1880
                var text = getPostText(file, context);
 
1881
                if (text != undefined)
 
1882
                {
 
1883
                    if (isURLEncodedFile(file, text))
 
1884
                    {
 
1885
                        var lines = text.split("\n");
 
1886
                        var params = parseURLEncodedText(lines[lines.length-1]);
 
1887
                        this.insertHeaderRows(netInfoBox, params, "Post");
 
1888
                    }
 
1889
                    else
 
1890
                    {
 
1891
                        var postText = formatPostText(text);
 
1892
                        if (postText)
 
1893
                            insertWrappedText(postText, postTextBox);
 
1894
                    }
 
1895
                }
 
1896
            }
 
1897
        }
 
1898
 
 
1899
        if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented)
 
1900
        {
 
1901
            netInfoBox.responsePresented = true;
 
1902
 
 
1903
            var responseTextBox = getChildByClass(netInfoBox, "netInfoResponseText");
 
1904
            if (file.category == "image")
 
1905
            {
 
1906
                var responseImage = netInfoBox.ownerDocument.createElement("img");
 
1907
                responseImage.src = file.href;
 
1908
                responseTextBox.replaceChild(responseImage, responseTextBox.firstChild);
 
1909
            }
 
1910
            else if (!(file.category in binaryCategoryMap))
 
1911
            {
 
1912
                var text = file.responseText
 
1913
                    ? file.responseText
 
1914
                    : context.sourceCache.loadText(file.href);
 
1915
 
 
1916
                if (text)
 
1917
                    insertWrappedText(text, responseTextBox);
 
1918
                else
 
1919
                    insertWrappedText("", responseTextBox);
 
1920
            }
 
1921
        }
 
1922
 
 
1923
        if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented)
 
1924
        {
 
1925
            netInfoBox.cachePresented = true;
 
1926
 
 
1927
            var responseTextBox = getChildByClass(netInfoBox, "netInfoCacheText");
 
1928
            if(file.cacheEntry) {
 
1929
              this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache");
 
1930
            }
 
1931
        }
 
1932
    },
 
1933
 
 
1934
    insertHeaderRows: function(netInfoBox, headers, tableName, rowName)
 
1935
    {
 
1936
        var headersTable = getElementByClass(netInfoBox, "netInfo"+tableName+"Table");
 
1937
        var tbody = headersTable.firstChild;
 
1938
        var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title");
 
1939
 
 
1940
        if (headers.length)
 
1941
        {
 
1942
            this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody);
 
1943
            removeClass(titleRow, "collapsed");
 
1944
        }
 
1945
        else
 
1946
            setClass(titleRow, "collapsed");
 
1947
    }
 
1948
});
 
1949
 
 
1950
// ************************************************************************************************
 
1951
 
 
1952
function findHeader(headers, name)
 
1953
{
 
1954
    for (var i = 0; i < headers.length; ++i)
 
1955
    {
 
1956
        if (headers[i].name == name)
 
1957
            return headers[i].value;
 
1958
    }
 
1959
}
 
1960
 
 
1961
function formatPostText(text)
 
1962
{
 
1963
    if (text instanceof XMLDocument)
 
1964
        return getElementXML(text.documentElement);
 
1965
    else
 
1966
        return text;
 
1967
}
 
1968
 
 
1969
function getPostText(file, context)
 
1970
{
 
1971
    if (!file.postText)
 
1972
        file.postText = readPostText(file.href, context);
 
1973
 
 
1974
    return file.postText;
 
1975
}
 
1976
 
 
1977
function insertWrappedText(text, textBox)
 
1978
{
 
1979
    var reNonAlphaNumeric = /[^A-Za-z_$0-9'"-]/;
 
1980
 
 
1981
    var html = [];
 
1982
    var wrapWidth = Firebug.textWrapWidth;
 
1983
 
 
1984
    var lines = splitLines(text);
 
1985
    for (var i = 0; i < lines.length; ++i)
 
1986
    {
 
1987
        var line = lines[i];
 
1988
        while (line.length > wrapWidth)
 
1989
        {
 
1990
            var m = reNonAlphaNumeric.exec(line.substr(wrapWidth, 100));
 
1991
            var wrapIndex = wrapWidth+ (m ? m.index : 0);
 
1992
            var subLine = line.substr(0, wrapIndex);
 
1993
            line = line.substr(wrapIndex);
 
1994
 
 
1995
            html.push("<pre>");
 
1996
            html.push(escapeHTML(subLine));
 
1997
            html.push("</pre>");
 
1998
        }
 
1999
 
 
2000
        html.push("<pre>");
 
2001
        html.push(escapeHTML(line));
 
2002
        html.push("</pre>");
 
2003
    }
 
2004
 
 
2005
    textBox.innerHTML = html.join("");
 
2006
}
 
2007
 
 
2008
function isURLEncodedFile(file, text)
 
2009
{
 
2010
    return (text && text.indexOf("Content-Type: application/x-www-form-urlencoded") != -1)
 
2011
        || findHeader(file.requestHeaders, "Content-Type") == "application/x-www-form-urlencoded";
 
2012
}
 
2013
 
 
2014
// ************************************************************************************************
 
2015
 
 
2016
Firebug.registerModule(Firebug.NetMonitor);
 
2017
Firebug.registerPanel(NetPanel);
 
2018
 
 
2019
// ************************************************************************************************
 
2020
 
 
2021
}});
 
2022