Welcome, guest | Sign In | My Account | Store | Cart
#!/bin/sh
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$@"}

##
## httppost.tcl
##
## Post to a web page and return data
##

if {0} {
    ##
    ## EXAMPLES
    ##

    # Uploading a PTS file: (only the file as a Data elem is needed)
    httppost.tcl http://pop/~hobbs/wis/cgi-bin/pq.cgi
	    -user <valid-user> -passwd <users-passwd> \
	    -file Data <PTS_data.txt> var value var value
}

package require Tcl 8.2
package require http 2.2
#package require base64; # from tcllib - only needed for user/passwd
			 # it gets called below when necessary

proc Usage {} {
    puts stderr "[file tail $::argv0] URL \\
	    ?-proxyhost domain? \\
	    ?-proxyport port? \\
	    ?-user user? \\
	    ?-passwd passwd? \\
	    ?-output outputFile? \\
	    ?-file formElemName fileName? \\
	    formElemName value formElemName value ...

    -proxyhost and -proxyport set the proxy to use, if necessary
    -user and -passwd are required if the URL requires authentication

    files are handled specially with -file as the file has to
    be read in and then that is used as the value."
    exit
}

proc process {} {
    global argv

    if {[llength $argv] < 4} {
	Usage
    }
    set opts(URL) [lindex $argv 0]
    set argv [lrange $argv 1 end]

    set opts(FILE) [list]
    while {[string match -* [lindex $argv 0]]} {
	switch -exact -- [lindex $argv 0] {
	    -proxyhost {
		set opts(PROXYHOST) [lindex $argv 1]
		if {![info exists opts(PROXYPORT)]} {
		    set opts(PROXYPORT) 80
		}
		set argv [lrange $argv 2 end]
	    }
	    -proxyport {
		set opts(PROXYPORT) [lindex $argv 1]
		set argv [lrange $argv 2 end]
	    }
	    -user {
		set opts(USER) [lindex $argv 1]
		set argv [lrange $argv 2 end]
	    }
	    -passwd {
		set opts(PASSWD) [lindex $argv 1]
		set argv [lrange $argv 2 end]
	    }
	    -file {
		lappend opts(FILE) [lindex $argv 1] [lindex $argv 2]
		set argv [lrange $argv 3 end]
	    }
	    -output {
		set opts(OUTFILE) [lindex $argv 1]
		set argv [lrange $argv 2 end]
	    }
	    default {
		Usage
	    }
	} 
    }

    if {[info exists opts(PROXYHOST)]} {
	::http::config -proxyhost $opts(PROXYHOST) \
		-proxyport $opts(PROXYPORT)
    }

    ## Configure the output channel
    set outfd stdout
    set type "multipart/form-data"
    if {[info exists opts(OUTFILE)]} {
	set outfd [open $opts(OUTFILE) w]
    }
    fconfigure $outfd -translation binary

    set outputData {}
    set bound "-----NEXT_PART_[clock seconds].[pid]"
    foreach {elem file} $opts(FILE) {
	set fid [open $file r]
	fconfigure $fid -translation binary
	if {[catch {read $fid [file size $file]} data]} {
	    return -code error $data
	}
	close $fid
	append outputData "--$bound\nContent-Disposition: form-data;\
		name=\"$elem\"; filename=\"[file tail $file]\"\n\n$data\n"
    }
    foreach {elem data} $argv {
	append outputData "$bound\nContent-Disposition: form-data;\
		name=\"$elem\"\n\n$data\n"
    }
    if {![string length $outputData]} {
	return -code error "No data given to post"
    }
    append outputData "${bound}--"

    set request [list ::http::geturl $opts(URL) \
	    -channel $outfd \
	    -type "multipart/form-data; boundary=$bound" \
	    -query $outputData]

    if {[info exists opts(USER)] && [info exists opts(PASSWD)]} {
	package require base64
	lappend request -headers [list Authorization \
		"Basic [base64::encode $opts(USER):$opts(PASSWD)]"]
    }

    set token [eval $request]
    ::http::wait $token
    if {[string compare stdout $outfd]} {
	close $outfd
    }
}

process

History