util::http::post_payload (public)
util::http::post_payload [ -url url ] [ -files files ] [ -base64 ] \ [ -formvars formvars ] [ -formvars_list formvars_list ] \ [ -body body ] [ -max_body_size max_body_size ] \ [ -headers headers ] [ -multipart ]
Defined in packages/acs-tcl/tcl/http-client-procs.tcl
Build the payload for a POST request
- Switches:
- -url (optional)
- does not affect the payload directly, but is used to check that variables specified via the URL do not conflict with those coming from other parameters. In such case, an error is returned.
- -files (optional)
- File upload can be specified using actual files on the filesystem or binary strings of data using the '-files' parameter. '-files' must be a dict (flat list of key value pairs). Keys of '-files' parameter are: - data: binary data to be sent. If set, has precedence on 'file' key - file: path for the actual file on filesystem - filename: name the form will receive for this file - fieldname: name the field this file will be sent as - mime_type: mime_type the form will receive for this file If 'filename' is missing and an actual file is being sent, it will be set as the same name as the file. If 'mime_type' is missing, it will be guessed from 'filename'. If result is */* or an empty mime_type, 'application/octet-stream' will be used If '-base64' flag is set, files will be base64 encoded (useful for some kind of form).
- -base64 (optional, boolean)
- -formvars (optional)
- These are additional form variables already in URLencoded format, for instance, by using 'export_vars -url'. They will be translated for the proper type of form (URLencoded or multipart) depending on the presence of 'files' or the 'multipart' flag. Variables specified this way will be appended to those supplied via the 'formvars_list' parameter.
- -formvars_list (optional)
- These are additional form variables in list format. They will be translated for the proper type of form (URLencoded or multipart) depending on the presence of files or the multipart flag. The payload will be made by the sum of data coming from 'formvars', 'formvars_list' and 'files' arguments. Default behavior is to build payload as an 'application/x-www-form-urlencoded' payload if no files are specified, and 'multipart/form-data' otherwise. If '-multipart' flag is set, format will be forced to multipart.
- -body (optional)
- is the payload for the request and will be passed as is (useful for many purposes, such as webDav). A convenient way to specify form variables through this argument is passing a string obtained by 'export_vars -url'.
- -max_body_size (optional, defaults to
"25000000"
)- this value in number of characters will tell how big can the whole body payload get before we start spooling its content to a file. This is important in case of big file uploads, when keeping the entire request in memory is just not feasible. The handling of the spooling is taken care of in the API. This value takes into account also the encoding required by the content type, so its value could not reflect the exact length of body's string representation.
- -headers (optional)
- Processing the payload might set some request headers. Provide yours to either override the default behavior, or to merge your headers with those from the payload. The resulting headers will be returned in the dict.
- -multipart (optional, boolean)
- Returns:
- a dict with fields 'payload', 'payload_file' and 'headers'
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- util_http_json_encoding, postman_echo, util_http_post_vars, template_widget_file
Source code: set this_proc [lindex [info level 0] 0] # Retrieve variables sent by the URL... set parsed [ns_parseurl $url] if {[dict exists $parsed query]} { array set urlvars [ns_set array [ns_parsequery [dict get $parsed query]]] } if {[llength $formvars_list] % 2 == 1} { error "'formvars_list' must have an even number of elements" } if {$formvars ne ""} { foreach {key val} [ns_set array [ns_parsequery $formvars]] { lappend formvars_list $key $val } } # Check whether we don't have multiple variable definition in url # and payload. foreach {key value} $formvars_list { if {[info exists urlvars($key)]} { return -code error "${this_proc}: Variable '$key' already specified as url variable" } } if {$headers eq ""} { set headers [ns_set create headers] } set req_content_type [ns_set iget $headers "content-type"] set payload {} set payload_file {} set payload_file_fd {} # Request will be multipart if required by the flag, if we have # files or if set up manually by the headers if {$multipart_p || [llength $files] != 0 || [string match -nocase "*multipart/form-data*" $req_content_type]} { # delete every manually set content-type header... while {[ns_set ifind $headers "Content-type"] >= 0} { ns_set idelkey $headers "Content-type" } # ...replace it with our own... set boundary [ns_sha1 [list [clock clicks -milliseconds] [clock seconds]]] set req_content_type "multipart/form-data; boundary=$boundary" ns_set put $headers "Content-type" $req_content_type # ...and get the proper encoding for the content. set enc [util::http::get_channel_settings $req_content_type] # Transform files into binaries foreach f $files { if {![dict exists $f data]} { if {![dict exists $f file]} { return -code error "${this_proc}: No file specified" } set file [dict get $f file] if {![ad_file exists $file]} { return -code error "${this_proc}: Error reading file: $file not found" } if {![ad_file readable $file]} { return -code error "${this_proc}: Error reading file: $file permission denied" } dict set f filename [expr {[dict exists $f filename] ? [dict get $f filename] : [ad_file tail $file]}] } # Filename and fieldname must be in the file dict at this # point foreach key {filename fieldname} { if {![dict exists $f $key]} { return -code error "${this_proc}: '$key' missing for file POST" } set $key [dict get $f $key] } # Check that we don't already have this var specified in # the url if {[info exists urlvars($fieldname)]} { return -code error "${this_proc}: file field '$fieldname' already specified as url variable" } # Track form variables sent as files set filevars($fieldname) 1 if {![dict exists $f mime_type]} { set mime_type [ns_guesstype $filename] if {$mime_type in {"*/*" ""}} { set mime_type "application/octet-stream" } } else { set mime_type [dict get $f mime_type] } set transfer_encoding [expr {$base64_p ? "base64" : "binary"}] set content [list --$boundary \r\n "Content-Disposition: form-data; " "name=\"$fieldname\"; filename=\"$filename\"" \r\n "Content-Type: $mime_type" \r\n "Content-transfer-encoding: $transfer_encoding" \r\n \r\n] set app [append_to_payload -content [join $content ""] $enc $max_body_size $payload $payload_file $payload_file_fd] lassign $app payload payload_file payload_file_fd if {[dict exists $f data]} { set app [append_to_payload -content [dict get $f data] $enc $max_body_size $payload $payload_file $payload_file_fd] } else { set app [append_to_payload -file $file $enc $max_body_size $payload $payload_file $payload_file_fd] } lassign $app payload payload_file payload_file_fd set app [append_to_payload -content \r\n $enc $max_body_size $payload $payload_file $payload_file_fd] lassign $app payload payload_file payload_file_fd } # Translate urlencoded vars into multipart variables foreach {key val} $formvars_list { if {[info exists filevars($key)]} { return -code error "${this_proc}: Variable '$key' already specified as file variable" } set content [list --$boundary \r\n "Content-Disposition: form-data; name=\"$key\"" \r\n \r\n $val \r\n] set app [append_to_payload -content [join $content ""] $enc $max_body_size $payload $payload_file $payload_file_fd] lassign $app payload payload_file payload_file_fd } set content "--$boundary--\r\n" set app [append_to_payload -content $content $enc $max_body_size $payload $payload_file $payload_file_fd] lassign $app payload payload_file payload_file_fd } else { # If people specified a content type we won't overwrite it, # otherwise this will be a 'application/x-www-form-urlencoded' # payload if {$req_content_type eq ""} { set req_content_type "application/x-www-form-urlencoded" ns_set put $headers "Content-type" $req_content_type } set enc [util::http::get_channel_settings $req_content_type] set payload {} foreach {key val} $formvars_list { lappend payload [ad_urlencode_query $key]=[ad_urlencode_query $val] } set payload [join $payload &] } # Body will be appended as is to the payload set app [append_to_payload -content $body $enc $max_body_size $payload $payload_file $payload_file_fd] lassign $app payload payload_file payload_file_fd if {$payload_file_fd ne ""} { close $payload_file_fd } return [list payload $payload payload_file $payload_file headers $headers]XQL Not present: Generic, PostgreSQL, Oracle