- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class Relations
::xotcl::THREAD create ::bgdelivery
Methods (to be applied on the object)
create_spooler (scripted)
ns_write "HTTP/1.0 200 OK\r\nContent-type: $content_type\r\n\r\n" set ch [ns_conn channel] thread::transfer [:get_tid] $ch :do ::HttpSpooler new -channel $ch -timeout $timeout
nr_running (forward, public)
bgdelivery nr_running
Interface to the background delivery thread to query the number of currently running deliveries.
- Returns:
- number of currently running background deliveries
- Testcases:
- No testcase defined.
returnfile (scripted, public)
bgdelivery returnfile [ -client_data client_data ] [ -delete delete ] \ [ -content_disposition content_disposition ] status_code mime_type \ filename
Deliver the given file to the requester in the background. This proc uses the background delivery thread to send the file in an event-driven manner without blocking a request thread. This is especially important when large files are requested over slow connections. With NaviServer, this function is mostly obsolete, at least, when writer threads are configured. The writer threads have as well the advantage, that these can be used with https, while the bgdelivery thread works directly on the socket. One remaining purpose of this function is h264 streaming delivery (when the module is in use).
- Switches:
- -client_data (optional)
- -delete (optional, defaults to
"false"
) - -content_disposition (optional)
- Parameters:
- status_code (required)
- mime_type (required)
- filename (required)
- Testcases:
- No testcase defined.
#ns_setexpires 1000000 #ns_log notice "expires-set $filename" #ns_log notice "status_code = $status_code, filename=$filename" if {![nsf::is object ::xo::cc]} { ::xo::ConnectionContext require -url [ad_conn url] } set query [::xo::cc actual_query] set secure_conn_p [security::secure_conn_p] set use_h264 [expr {[string match "video/mp4*" $mime_type] && $query ne "" && ([string match {*start=[1-9]*} $query] || [string match {*end=[1-9]*} $query]) && [info commands h264open] ne "" && !$secure_conn_p }] if {[info commands ns_driversection] ne ""} { set use_writerThread [ns_config [ns_driversection] writerthreads 0] } else { set use_writerThread 0 } if {[info exists content_disposition]} { set fn [xo::backslash_escape \" $content_disposition] ns_set put [ns_conn outputheaders] Content-Disposition "attachment;filename=\"$fn\"" } if {$secure_conn_p && !$use_writerThread} { # # The bgdelivery thread does not work over https, so fall back # to ns_returnfile. The writer thread works fine with https. # ns_returnfile $status_code $mime_type $filename return } if {$use_h264} { if {0} { # we have to obtain the size from the file; unfortunately, this # requires a duplicate open+close of the h264 stream. If the # application is performance sensitive, one might consider to use # the possibly incorrect size from the filesystem instead (works # perfectly for e.g. flowplayer) if {[catch {set handle [h264open $filename $query]} errorMsg]} { ns_log error "h264: error opening h264 channel for $filename $query: $errorMsg" return } set size [h264length $handle] h264close $handle } else { set size [ad_file size $filename] } } else { set size [ad_file size $filename] } # Make sure to set "connection close" for the requests (in other # words, don't allow keep-alive, which is does not make sense, when # we close the connections manually in the bgdelivery thread). # if {$::xo::naviserver && !$use_writerThread} { ns_conn keepalive 0 } set range [ns_set iget [ns_conn headers] range] if {[regexp {bytes=(.*)$} $range _ range]} { set ranges [list] set bytes 0 set pos 0 foreach r [split $range ,] { regexp {^(\d*)-(\d*)$} $r _ from to if {$from eq ""} { # The last $to bytes, $to must be specified; 'to' is # differently interpreted as in the case, where from is # nonempty set from [expr {$size - $to}] } else { if {$to eq ""} {set to [expr {$size-1}]} } set rangeSize [expr {1 + $to - $from}] lappend ranges [list $from $to $rangeSize] set pos [expr {$to + 1}] incr bytes $rangeSize } } else { set ranges "" set bytes $size } #ns_log notice "Range=$range bytes=$bytes // $ranges" # # For the time being, we write the headers in a simplified version # directly in the spooling thread to avoid the overhead of double # h264opens. # if {!$use_h264} { # # Add content-range header for range requests. # if {[llength $ranges] == 1 && $status_code == 200} { lassign [lindex $ranges 0] from to if {$from <= $to && $size > $to} { ns_set put [ns_conn outputheaders] Content-Range "bytes $from-$to/$size" #ns_log notice "given range <$range>, added header-field Content-Range: bytes $from-$to/$size // $ranges" set status_code 206 } else { # A byte-content-range-spec with a byte-range-resp-spec whose # last-byte-pos value is less than its first-byte-pos value, # or whose instance-length value is less than or equal to its # last-byte-pos value, is invalid. The recipient of an invalid # byte-content-range-spec MUST ignore it and any content # transferred along with it. # # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html (14.16) # ns_log notice "### ignore invalid range <$range>, pos > size-1, Content-Range: bytes $from-$to/$size // $ranges" } } elseif {[llength $ranges]>1} { ns_log warning "Multiple ranges are currently not supported, ignoring range request" } if {$::xo::naviserver && ![string match text/* $mime_type]} { :write_headers -binary -- $status_code $mime_type $bytes } else { :write_headers $status_code $mime_type $bytes } } if {$bytes == 0} { # Tcl behaves different, when one tries to send 0 bytes via # file_copy. So, we handle this special case here... # There is actually nothing to deliver.... ns_set put [ns_conn outputheaders] "Content-Length" 0 ns_return 200 $mime_type {} return } if {$use_writerThread && !$use_h264} { if {$status_code == 206} { ns_log notice "ns_writer submitfile -offset $from -size $bytes $filename" ns_writer submitfile -offset $from -size $bytes $filename } else { ns_log notice "ns_writer submitfile $filename" ns_writer submitfile $filename } return } set errorMsg "" # Get the thread id and make sure the bgdelivery thread is already # running. set tid [:get_tid] # :log "+++ lock ${:bgmutex}" ns_mutex_lock ${:mutex} # # Transfer the channel to the bgdelivery thread and report errors # in detail. # # Notice, that Tcl versions up to 8.5.4 have a bug in this area. # If one uses an earlier version of Tcl, please apply: # http://tcl.cvs.sourceforge.net/viewvc/tcl/tcl/generic/tclIO.c?r1=1.61.2.29&r2=1.61.2.30&pathrev=core-8-4-branch # catch { set ch [ns_conn channel] if {[catch {thread::transfer $tid $ch} innerError]} { set channels_in_use "??" catch {set channels_in_use [bgdelivery do file channels]} ns_log error "thread transfer failed, channel=$ch, channels_in_use=$channels_in_use" error $innerError } } errorMsg ns_mutex_unlock ${:mutex} #ns_mutex unlock ${:bgmutex} # :log "+++ unlock ${:bgmutex}" if {$errorMsg ne ""} { error ERROR=$errorMsg } if {$use_h264} { #:log "MP4 q=[::xo::cc actual_query], h=[ns_set array [ns_conn outputheaders]]" :do -async ::h264Spooler spool -delete $delete -channel $ch -filename $filename -context [list [::xo::cc requester],[::xo::cc url],$query [ns_conn start]] -query $query -client_data $client_data } else { #:log "FILE SPOOL $filename" :do -async ::fileSpooler spool -ranges $ranges -delete $delete -channel $ch -filename $filename -context [list [::xo::cc requester],[::xo::cc url],$query [ns_conn start]] -client_data $client_data } # # set the length for the access log (which is written when the # connection thread is done) ns_conn contentsentlength $size ;# maybe overly optimistic
running (forward, public)
bgdelivery running
Interface to the background delivery thread to query the currently running deliveries.
- Returns:
- list of key value pairs of all currently running background processes
- Testcases:
- No testcase defined.
send_to_subscriber (scripted)
:do -async ::Subscriber broadcast $key $msg
spooler_add_request (scripted)
:log "-- do -async $spooler add -request $request" :do -async $spooler add -request $request -post_data $post_data
spooler_release (scripted)
:do -async $spooler release
subscribe (scripted)
set ch [ns_conn channel] thread::transfer [:get_tid] $ch #:do ::Subscriber sweep $key :do ::Subscriber new -channel $ch -key $key -user_id [ad_conn user_id] -mode $mode
write_headers (forward)
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables