Newsgroup: it.comp.lang.delphi
Titolo: [D7][Web broker] Inviare files da un form HTML ad un CGI

Salve.
ho creato un form HTML:
<form enctype="multipart/form-data" method="post" action="uploadDoc">
...
  <label>File: <input type="file" name="doc"/></label>
...
</form>
Nella action scatenata nel WebModule all'atto del post, leggendo
Request.Files.Count ottengo 0. E' normale? Se sì, c'è un'altra strada
per
prelevare i files contenuti nel messaggio post?
Grazie,
Marcello Esposito.
P.S.: non sto usando WebSnap.

 prelevare i files contenuti nel messaggio post?
Ciao,
	ti posto un pezzo di codice che un collega adatto' da qualcosa trovato 
in Internet nel 2002.
So che non e' il massimo dell'eleganza ma nel nostro caso funziona 
ancora e nessuno l'ha piu' toccata.
L'azione waDecodeBinaryContent del WebModule1 invoca la funzione 
ReadMultipartRequest().
Ciao,
baba.
-----
const
   MaxReadBlockSize = 8192;
function ReadMultipartRequest(const Boundary: string;
   ARequest: string; var AHeader: TStrings; var Data: string): string;
var
   Req, RHead: string;
   i: Integer;
begin
   Result := '';
   AHeader.Clear;
   Data := '';
   // controlla la presenza di un boundary iniziale e finale
   // e che il boundary sia ad inizio stringa
   if (Pos(Boundary, ARequest) < Pos (Boundary + '--', ARequest))
     and (Pos(Boundary, ARequest) = 1) then
   begin
     // elimina il primo boundary
     Delete(ARequest, 1, Length(Boundary) + 2);
     // isola il contenuto della singola parte di messaggio
     // es.: [Content-Disposition: form-data; name="radiobox" ON 
-----------------------------7d226f231303c0 ]
     Req := Copy(ARequest, 1, Pos(Boundary, ARequest) - 3);
     // elimina il secondo boundary (rimane: [Content-Disposition: 
form-data; name="radiobox"])
     Delete(ARequest, 1, Length(Req) + 2);
     // dalla stringa ottenuta, isola tutta la parte precedente il valore
     RHead := Copy(Req, 1, Pos(#13#10#13#10, Req)-1);
     // la elimina (rimane: [ON])
     Delete(Req, 1, Length(RHead) + 4);
     //Es Req = ON RHead = Content-Disposition: form-data; name="radiobox"
     // assegna il valore rimasto alla stringa della lista
     AHeader.Text := RHead;
     {Es AHeader.Count = 1 }
     // per il numero di elementi della lista
     for i := 0 to AHeader.Count - 1 do
       // se ci sono i due punti
       if Pos(':', AHeader.Strings[i]) > 0 then
         // modifica la stringa sostituendo i due punti con l'uguale
         AHeader.Strings[i] := Trim(Copy(AHeader.Strings[i],
                                         1,
                                         Pos(':', AHeader.Strings[i])-1)
                                         ) + '=' + 
Trim(Copy(AHeader.Strings[i],
                                                             Pos(':',
 
AHeader.Strings[i]
                                                                 )+1,
 
Length(AHeader.Strings[i]) - Pos(':', AHeader.Strings[i])
                                                             )
                                   );
     Data := Req;
     Result := ARequest;
   end
end;
procedure WebModule1.waDecodeBinaryContent(Sender: TObject;
   Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
   ByteToRead, ReadedBytes, RSize: LongInt;
   AllContent, BufferStr, Boundary, Data: string;
   Header, HList: TStrings;
   Buffer: PChar;
   OutStream: TFileStream;
   sr: TSearchRec;
begin
   if (Pos('multipart/form-data', LowerCase(Request.ContentType)) > 0) and
     (Pos('boundary', LowerCase(Request.ContentType)) > 0) then
   begin
     Header := TStringList.Create;
     try
       ExtractHeaderFields([';'], [' '], PChar(Request.ContentType), Header,
         False, False);
       Boundary := Header.Values['boundary'];
     finally
       Header.Free;
     end;
     // ------
     AllContent := Request.Content;
     // ottiene il numero di byte da leggere sottreando al valore della
     // proprieta' "Content-Length" (appartenente all' header HTTP) la 
lunghezza
     // della stringa contenuta in "AllContent"
     ByteToRead := Request.ContentLength - Length(AllContent);
     try
       // legge in un buffer locale di dimensione costante (8192 byte)
       while ByteToRead > 0 do
       begin
         RSize := MaxReadBlockSize;
         if RSize > ByteToRead then
           RSize := ByteToRead;
         // inizializza un area di memoria da riservare ad un array di 
caratteri
         GetMem(Buffer, RSize);
         try
           // scrive dentro il buffer il contenuto della proprieta' 
"Request.ReadClient"
           // leggendone RSizeByte
           ReadedBytes := Request.ReadClient(Buffer^, RSize);
           // trasferisce il contenuto del buffer dentro la variabile string
           SetString(BufferStr, Buffer, ReadedBytes);
           // incrementa la stringa AllContent concatenando il valore 
appena memorizzato
           AllContent := AllContent + BufferStr;
         finally
           FreeMem(Buffer, RSize);
         end;
         // decrementa il numero dei byte da leggere sottreando al 
valore della
         // proprieta' "Content-Length" (appartenente all' header HTTP) 
la lunghezza
         // della stringa contenuta in "AllContent"
         ByteToRead := Request.ContentLength - Length(AllContent);
        end;
        //-----
       // genera un stringa che contiene alcuni dei valori utilizzati
       Response.Content := Response.Content + Format('ContentType = 
%s<br>' +
         'ContentLength = %d<br>Readed Bytes = %d<br>Boundary = %s<hr>',
         [Request.ContentType, Request.ContentLength, Length(AllContent),
         boundary]);
       // ----------------------------
       // se tutto il buffer di dati e' stato letto
       if Request.ContentLength = Length(AllContent) then
         while Length(AllContent) > Length('--' + Boundary + '--' + 
#13#10) do
         begin
           Header := TStringList.Create;
           HList := TStringList.Create;
           try
             // invoca la funzione di lettura di un request multipart 
passando il
             // 1. delimitatore ('--' + boundary), 2. tutto il contenuto di
             // "AllContent" che ora contiene il Request.Content a cui 
sono stati
             // concatenati i bufferstring letti nel ciclo precedente, 
3. una struttura TStringList
             // per la decodifca <nome><valore>, e 4. una stringa per 
riferimento.
             AllContent := ReadMultipartRequest('--' + Boundary, AllContent,
               Header, Data);
             ExtractHeaderFields([';'], [' '],
               PChar(Header.Values['Content-Disposition']), HList, 
False, True);
             if (Header.Values['Content-Type'] <> '') and (Data <> '') then
             begin
 
OutStream:=TFileStream.Create('./uploadedFile'+ExtractFileExt(HList.Values['filename']), 
fmCreate);
               try
                 try
                   OutStream.WriteBuffer(Pointer(Data)^, Length(Data));
                   Response.Content := Response.Content +
                     Format('<p>File received<b>%s</b>.', [''+
                     ExtractFileName(HList.Values['filename'])]);
                 except
                   Response.Content := Response.Content +
                     Format('<p>Unable to save file <b>%s</b>.', [''+
                     ExtractFileName(HList.Values['filename'])]);
                 end;
               finally
                 OutStream.Free;
               end
             end
             else
               Response.Content := Response.Content + Format('<p>Field 
<b>%s</b> = %s',
                 [HList.Values['name'], Data]);
           finally
             Header.Free;
             HList.Free;
           end;
         end;
     except
       on E: Exception do
         Response.Content := Response.Content + '<p>' + E.Message;
     end;
   end
   else Response.Content := 'Content-type is not "multipart/form-data".';
end;