'''`multipart/x-mixed-replace`''' is an [HTTP] header. Your server can use it to push dynamically updated content to the web browser. It works by telling the browser to keep the connection open and replace the web page or piece of media it is displaying with another when it receives a special token. The header is old and widely supported. It works in legacy browsers, even http://web.archive.org/web/19991008003359/http://www.abiglime.com/webmaster/articles/cgi/032498.htm%|%Netscape 1.1%|%. This page shows an implementation of a `multipart/x-mixed-replace` HTTP server in plain Tcl. ** Code ** ====== #! /usr/bin/env tclsh # An example of how to serve dynamic web content with # multipart/x-mixed-replace. # Copyright (c) 2021 D. Bohdan. License: MIT. package require Tcl 8.6-10 set image [join { data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAMFBM VEXy9PH+/xb/ysn/ev8A+vmhk/+XmJYA6wCBgYD/R0UArQA1ZiodCuEAMQAAAXEFCARuxRLHAA AAg0lEQVR42r3OR1UFURAE0DuFAhz0eQZIGpCAOL4EsDAWMEB2MArI6Z3TK1Z/eztULW/YYXtk 9focAAURYPKEgATQHFQHHYDl6oYdBqm28QpxDADEQQcd5s1/e7zhHCsu9Y29wXL3bBu4xgWSYr STQ6NMCMQZIBSMX0kJ8CMJYwpRAMA7X8kSzYsnKHwAAAAASUVORK5CYII= } {}] proc main {} { set server [socket -server wire 8080] vwait ::done close $server } proc wire {conn clientAddr clientPort} { # It is necessary to either disable buffering or put it in line mode or # to flush the socket every time you send the boundary delimiter. chan configure $conn \ -blocking false \ -buffering none \ -translation binary \ chan event $conn readable [list serve $conn] } proc serve conn { try { set path [process-request $conn] if {$path eq {}} return set boundary boundary-[expr rand()] send {HTTP/1.1 200 OK} send "Content-Type:\ multipart/x-mixed-replace;boundary=\"$boundary\"\r\n" send --$boundary for {set i 0} {$i < 3} {incr i} { send "Content-Type: text/plain\r\n" send {Hello, text } send --$boundary after 500 send "Content-Type: text/plain\r\n" send { plain world!} send --$boundary after 500 } send "Content-Type: image/png\r\n" set imageBin [binary decode base64 [string range $::image 22 end]] send $imageBin false send --$boundary after 1000 set s {Hello, the wonderful world of HTML!} set len [llength $s] for {set i -1} {$i <= $len} {incr i} { send "Content-Type: text/html\r\n" send "

[lrange $s 0 $i]

" if {$i == $len} { send "--$boundary--" } else { send --$boundary } after 300 } } trap {POSIX EPIPE} _ { return } finally { close $conn } } proc process-request conn { if {![regexp {GET (/[^ ]*) HTTP} [read $conn] _ path]} { send [status-phrase-response 400 {Bad Request}] close $conn return } if {$path ne {/}} { if {$path eq {/quit}} { send [status-phrase-response 202 Accepted] set ::done true } else { send [status-phrase-response 404 {Not Found}] } close $conn return } return $path } proc send {data {nl true}} { upvar 1 conn conn puts -nonewline $conn $data if {$nl} { puts -nonewline $conn \r\n } } proc status-phrase-response {code phrase} { append h "HTTP/1.1 $code $phrase\r\n" append h "Content-Type: text/plain\r\n\r\n$phrase." } main ====== ** See also ** * https://docstore.mik.ua/orelly/web2/xhtml/ch13_03.htm%|%“Server-Push Documents”%|% in ''HTML & XHTML: The Definitive Guide, 4th Edition''. <> Example | Web