GET (scripted)
:instvar S
puts $S ""
:request_done
POST (scripted)
:instvar S post_data
array set "" [:get_channel_settings [:content_type]]
if {$(encoding) ne "binary"} {
set post_data [encoding convertto $(encoding) $post_data]
}
puts $S "Content-Length: [string length $post_data]"
puts $S "Content-Type: [:content_type]"
puts $S ""
fconfigure $S -translation $(translation) -encoding binary
:send_POST_datacancel (scripted)
set :status canceled
set :cancel_message $reason
:debug "--- canceled for $reason"
:close
close (scripted)
catch {close ${:S}} errMsg
:debug "--- closing socket socket?[info exists :S] => $errMsg"content_type (setter)
exists_status (scripted)
return [nsv_exists bgdelivery $key]
finish (scripted)
set :status finished
:close
:debug "--- [:host] [:port] [:path] has finished"
getLine (scripted)
:upvar $var response
:instvar S
set n [gets $S response]
if {[eof $S]} {
:debug "--premature eof"
return -2
}
if {$n == -1} {:debug "--input pending, no full line"; return -1}
return $nget_channel_settings (scripted)
set content_type [string tolower $content_type]
set trl [expr {[string match "text/*" $content_type] ? $text_translation : "binary"}]
set enc ""
if {[regexp {^text/.*$|^.*/xml.*$|^.*\+xml.*$} $content_type]} {
if {[regexp {;\s*charset\s*=([^;]*)} $content_type _ charset]} {
set enc [ns_encodingforcharset [string trim $charset]]
}
if {$enc eq "" && [regexp {^text/xml.*$|text/.*\+xml.*$} $content_type]} {
set enc [ns_encodingforcharset us-ascii]
}
if {$enc eq "" && [string match "text/*" $content_type]} {
set enc [ns_encodingforcharset iso-8859-1]
}
}
return [list encoding [expr {$enc eq ""?"binary":$enc}] translation $trl]get_status (scripted)
return [lindex [nsv_get bgdelivery $key] 0]
get_value_for_status (scripted)
return [lindex [nsv_get bgdelivery $key] 1]
header (scripted)
while {1} {
set n [:getLine response]
switch -exact -- $n {
-2 {:cancel premature-eof; return}
-1 {continue}
0 {break}
default {
if {[regexp -nocase {^content-length:(.+)$} $response _ length]} {
set :content_length [string trim $length]
} elseif {[regexp -nocase {^content-type:(.+)$} $response _ type]} {
set :content_type [string trim $type]
}
if {[regexp -nocase {^([^:]+): *(.+)$} $response _ key value]} {
lappend :meta [string tolower $key] $value
}
}
}
}
:reply_header_donehost (setter)
init (scripted)
:instvar S post_data host port protocol
:destroy_on_cleanup
set :meta [list]
set :data ""
if {![info exists :method]} {
set :method [expr {$post_data eq "" ? "GET" : "POST"}]
}
if {[info exists :url]} {
:parse_url
} else {
if {![info exists port]} {:set_default_port $protocol}
if {![info exists host]} {
error "either host or url must be specified"
}
}
if {$protocol eq "https"} {
package require tls
if {[info commands ::tls::import] eq ""} {
error "https request require the Tcl module TLS to be installed\n See e.g. http://tls.sourceforge.net/"
}
:mixin add ::xo::Tls
}
if {[catch {:open_connection} err]} {
:cancel "error during open connection via $protocol to $host $port: $err"
}method (setter)
open_connection (scripted)
:instvar host port S
set S [socket -async $host $port]
parse_url (scripted)
:instvar protocol url host port path
if {[regexp {^(http|https)://([^/]+)(/.*)?$} $url _ protocol host path]} {
if {$path eq ""} {set path /}
:set_default_port $protocol
regexp {^([^:]+):(.*)$} $host _ host port
} else {
error "unsupported or invalid url '$url'"
}path (setter)
port (setter)
post_data (setter)
protocol (setter)
reply_first_line (scripted)
:instvar S status_code
fconfigure $S -translation crlf
set n [:getLine response]
switch -exact -- $n {
-2 {:cancel premature-eof; return}
-1 {:finish; return}
}
if {[regexp {^HTTP/([0-9.]+) +([0-9]+) *} $response _ responseHttpVersion status_code]} {
:reply_first_line_done
} else {
:cancel "unexpected-response '$response'"
}reply_first_line_done (scripted)
:header
reply_header_done (scripted)
:instvar S
array set "" [:get_channel_settings [:content_type]]
fconfigure $S -translation $(translation) -encoding $(encoding)
if {[info exists :content_length]} {
set :data [read ${:S} ${:content_length}]
} else {
set :data [read ${:S}]
}
:finishrequest_done (scripted)
:instvar S
flush $S
:reply_first_line
request_header_fields (setter)
send_POST_data (scripted)
:instvar S post_data
puts -nonewline $S $post_data
:request_done
send_request (scripted)
:instvar S post_data host method
if {[catch {
puts $S "$method [:path] HTTP/1.0"
puts $S "Host: $host"
puts $S "User-Agent: [:user_agent]"
foreach {tag value} [:request_header_fields] {
puts $S "$tag: $value"
}
:$method
} err]} {
:cancel "error send $host [:port]: $err"
return
}set_default_port (scripted)
switch -- $protocol {
http {set :port 80}
https {set :port 443}
}set_status (scripted)
nsv_set bgdelivery $key [list $newStatus $value]
unset_status (scripted)
nsv_unset bgdelivery $key
url (setter)
user_agent (setter)