How to deliver a piece of HTML code as plaintext to browsers

Problem: We have HTML source code and want to deliver it to the user as plaintext. It should not be interpreted as HTML! (e.g. containing <script> tags and such).

Also it should be possible to save the link as a file, so the solution to deliver it as HTML and just escape everything is not usable. Typical use case: web forum or bugticket system where code or HTML samples can be downloaded so you don't have to copy&paste to save some sample.

The purpose of this page is to show that it can be dangerous to just deliver plaintext with untrusted content, and to show how different browsers/versions react.

Solution: There are several possibilities to influence what the browser does.



Content-Type: text/plain

is the most sensible one to tell the browser that it will receive just plain text and that it should just display it without rendering it as HTML. However, Internet Explorer works different and tries to be "clever" - if the content "looks like" a HTML page, it renders it.

Works for most browsers, but not IE < 9.

is the most sensible one to tell the browser that it will receive just plain text and that it should just display it without rendering it as HTML. However, Internet Explorer works different and tries to be "clever" - if the content "looks like" a HTML page, it renders it. Works for most browsers, but not IE < 9. Link-Suffix:

An additional possibility is to give the browser an appropriate filename, so that if the user sees the plaintext in the browser and they want to save it, the default filename will be the given one. That can be done by just changing the link, e.g. from /script.pl?bla to /script.pl/file.txt?bla . This works depending on how the link normally looks and how the Location is configured in your webserver. The script.pl will be called like before, just with /file.txt in the environment variable PATH_INFO. This solution is also nice because the link already looks like "file.txt" to the user.

Works for most browsers, but not IE < 9

An additional possibility is to give the browser an appropriate filename, so that if the user sees the plaintext in the browser and they want to save it, the default filename will be the given one. That can be done by just changing the link, e.g. from to . This works depending on how the link normally looks and how the Location is configured in your webserver. The script.pl will be called like before, just with in the environment variable PATH_INFO. This solution is also nice because the link already looks like "file.txt" to the user. Works for most browsers, but not IE < 9 Content-Disposition:

Alternatively you can set the Content-Disposition -header to Content-Disposition: inline; filename=file.txt to tell the browser to suggest file.txt as the filename.

Works for most browsers, but not IE < 9

Alternatively you can set the -header to to tell the browser to suggest file.txt as the filename. Works for most browsers, but not IE < 9 Since Internet Explorer ignores text/plain in any of these cases, the only solution left is to force the browser to do a download instead of displaying the text directly.

But setting Content-Type: application/octet-stream does not force all browsers to do a download, and you can see in the table below how different the various browsers react.

But setting does not force all browsers to do a download, and you can see in the table below how different the various browsers react. X-Content-Type-Options: nosniff

It was mentioned that IE supports X-Content-Type-Options: nosniff since version 8. So if you don't care about earlier versions, you can use this, and as long as you want to support older versions also, you could check the useragent header and decide what to do. Depends on if you want to keep things really simple or implement the most comfortable solution for each browser.

It was mentioned that IE supports since version 8. So if you don't care about earlier versions, you can use this, and as long as you want to support older versions also, you could check the useragent header and decide what to do. Depends on if you want to keep things really simple or implement the most comfortable solution for each browser. Only the combination of Content-Type: text/plain and Content-Disposition: attachment; filename=file.txt works for all tested browsers.

This forces a download instead of displaying directly, but in most browsers you can still choose to display it directly in the download dialogue, so this solution is comfortable enough for the most cases.

ok as expected maybe ok not really as expected, but at least safe wrong just wrong, possibly open to scripting attacks (XSS, CSRF)

link Content-

Type Link-

Suffix Content-

Disposition

filename Opera 10

Linux Opera 11.0

Win 7

Ult. x64 Opera 11.50

Linux FF 3.5.16

Linux FF 3.6.13

Gentoo FF 5.0

Linux Epiphany

2.30.6

Debian Safari 5.03

Win 7

Ult. x64 Chrome 8.0

Win 7

Ult. x64 IE 6

Win 7

Ult. x64 IE 7

Win 7

Ult. x64 IE 8

Win 7

Ult. x64 IE 9

Win7 Home

Premium Chromium 6

Debian ELinks 0.12pre5 Konqueror 4.4.5

KUbuntu 10 Lynx 2.6.8rel5

win32 Lynx 2.8.5rel1.1

CentOS 5.5 1.

ctttext text/plain bar - inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

HTML inline

HTML inline

HTML inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT 2.

ctttextsf text/plain bar.txt - inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

HTML inline

HTML inline

HTML inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT 3.

ctttextdispo text/plain bar.txt inline

(bar.txt) inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

HTML inline

HTML inline

HTML inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT inline

TEXT 4.

ctttextattach text/plain bar.txt attachment

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) ? download

(bar.txt) download

(bar.txt) download

(bar.txt) inline

TEXT download

(bar.txt) inline

TEXT inline

TEXT 5.

ctoctet application/

octet-stream bar - inline

HTML inline

HTML download

(bar) download

(bar) download

(bar) download

(bar) download

(bar) inline

HTML download

(bar) inline

HTML inline

HTML inline

HTML inline

HTML download

(bar) download

(bar) download

? download

? download

? 6.

ctoctetsf application/

octet-stream bar.txt - inline

TEXT inline

TEXT download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) inline

HTML download

(bar.txt) inline

HTML inline

HTML inline

HTML inline

HTML download

(bar.txt) download

(bar.txt) download

? download

? download

? 7.

ctoctetdispo application/

octet-stream bar.txt inline

(bar.txt) inline

TEXT inline

TEXT download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) inline

HTML download

(bar.txt) inline

HTML inline

HTML inline

HTML inline

HTML download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) 8.

ctoctetattach application/

octet-stream bar.txt attachment

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) ? download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) 9.

cttoctetsfdat application/

octet-stream bar.dat - inline

HTML inline

HTML download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) inline

HTML download

(bar.txt) inline

HTML inline

HTML inline

HTML inline

HTML download

(bar.dat) download

(bar.dat) download

? download

? download

? 10.

cttoctetdispodat application/

octet-stream bar.dat inline

(bar.dat) inline

HTML inline

HTML download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) inline

HTML download

(bar.dat) inline

HTML inline

HTML inline

HTML inline

HTML download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) 11.

cttoctetattachdat application/

octet-stream bar.dat attachment

(bar.dat) download

(bar.htm) download

(bar.htm) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) ? download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) download

(bar.dat) 12.

ctttextattachnosuffix text/plain bar attachment

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) download

(bar.txt) inline

TEXT 13.

nosniffplain text/plain bar.html inline

(bar.html) inline

TEXT inline

TEXT inline

TEXT 14.

nosniffhtml text/html bar.html inline

- inline

HTML inline

HTML inline

HTML

Conclusion:

The "correct" solution (this is also how I understand the specs) would be to set text/plain and give a filename by adding file.txt to the link or putting it into the Content-Disposition.

If you want to be safe and support IE you should switch to forcing a download (if possible, by checking the User-Agent for IE and only switch to download in this case).

Links:

IE content-type logic

More or less serious suggestions on this page: Create a new content-type text/plain-no-really ;-) New header X-IE-Follow-Standards: true

More or less serious suggestions on this page:

2011-02-23 - added hint about X-Content-Type-Options header, described problem more detailed

2011-08-19 - added Opera 11.50 Linux, FF 5.0 Linux and IE 9 Win7

The tests were run bei several diligent helpers (thanks to all), discussed in the (german) perl forum HTML als plaintext