Tom, I figured out the problem with the "memory bloat" when I used your 
alternative ns_getform to parse a large file upload temp file.

The problem is that if I call ns_queryget after calling your ns_getform, that 
causes aolserver to re-parse the large file upload, and to do it in the old 
memory-inefficient way.

I'm not sure if there's a way for your version of ns_getform to tell the 
aolserver internals that the parsing of the form is done, so subsequent 
ns_queryget calls don't cause a re-parse.

At any rate, there's an easy workaround, which is to read things right out the 
ns_set that your ns_getform populates.

-john


On Nov 23, 2009, at 8:47 PM, John Buckman wrote:

> Tom, there is some sort of weird interaction effect on aolserver when doing 
> tcl stuff and there is a large file as the temporary file.  Some cases cause 
> the nsd process to bloat to the size of the memory.  I wasn't able to figure 
> out why. I wasn't able to fix your ns_getform to not bloat.
> 
> However, I was able to copy Vlad's ns_parseformfile proc for use on aolserver 
> from naviserver, and it doesn't bloat.
> 
> Here is the code for handling a large file uploaded as a file, rather than in 
> memory:
> 
>       set type [ns_set iget [ns_conn headers] content-type]
>       set form [ns_set create]
>       ns_parseformfile $form $type
>       array set formdata [ns_set array $form]
>       puts "final array: [array get formdata]"
> 
> 
> proc ns_parseformfile { form contentType } {
> 
>       set fp [ns_conn contentchannel]
> 
>    if { ![regexp -nocase {boundary=(.*)$} $contentType 1 b] } {
>               puts "Warning: no MIME boundary"
>        return
>    }
> 
>    fconfigure $fp -encoding binary -translation binary
>    set boundary "--$b"
> 
>    while { ![eof $fp] } {
>       # skip past the next boundary line
>       if { ![string match $boundary* [string trim [gets $fp]]] } {
>           continue
>       }
> 
>       # fetch the disposition line and field name
>       set disposition [string trim [gets $fp]]
>       if { ![string length $disposition] } {
>           break
>       }
> 
>       set disposition [split $disposition \;]
>       set name [string trim [lindex [split [lindex $disposition 1] =] 1] \"]
> 
>       # fetch and save any field headers (usually just content-type for files)
>       
>       while { ![eof $fp] } {
>           set line [string trim [gets $fp]]
>           if { ![string length $line] } {
>               break
>           }
>           set header [split $line :]
>           set key [string tolower [string trim [lindex $header 0]]]
>           set value [string trim [lindex $header 1]]
>           
>           ns_set put $form $name.$key $value
>       }
> 
>       if { [llength $disposition] == 3 } {
>           # uploaded file -- save the original filename as the value
>           set filename [string trim [lindex [split [lindex $disposition 2] =] 
> 1] \"]
>           ns_set put $form $name $filename
> 
>           # read lines of data until another boundary is found
>           set start [tell $fp]
>           set end $start
>           
>           while { ![eof $fp] } {
>               if { [string match $boundary* [string trim [gets $fp]]] } {
>                   break
>               }
>               set end [tell $fp]
>           }
>           set length [expr $end - $start - 2]
> 
>           # create a temp file for the content, which will be deleted
>           # when the connection close.  ns_openexcl can fail, hence why 
>           # we keep spinning
> 
>           set tmp ""
>           while { $tmp == "" } {
>               set tmpfile [ns_tmpnam]
>               set tmp [ns_openexcl $tmpfile]
>           }
> 
>           catch {fconfigure $tmp -encoding binary -translation binary}
> 
>           if { $length > 0 } {
>               seek $fp $start
>               ns_cpfp $fp $tmp $length
>           }
> 
>           close $tmp
>           seek $fp $end
>           ns_set put $form $name.tmpfile $tmpfile
> 
>            if { [ns_conn isconnected] } {
>               ns_atclose "ns_unlink -nocomplain $tmpfile"
>            }
> 
>       } else {
>           # ordinary field - read lines until next boundary
>           set first 1
>           set value ""
>           set start [tell $fp]
> 
>           while { [gets $fp line] >= 0 } {
>               set line [string trimright $line \r]
>               if { [string match $boundary* $line] } {
>                   break
>               }
>               if { $first } {
>                   set first 0
>               } else {
>                   append value \n
>               }
>               append value $line
>               set start [tell $fp]
>           }
>           seek $fp $start
>           ns_set put $form $name $value
>       }
>    }
>    close $fp
> }
> 


--
AOLserver - http://www.aolserver.com/

To Remove yourself from this list, simply send an email to 
<[email protected]> with the
body of "SIGNOFF AOLSERVER" in the email message. You can leave the Subject: 
field of your email blank.

Reply via email to