PDA

Visualizza la versione completa : [CGI] c forzare download


quincy
13-05-2006, 16:02
Salve a tutti,

volevo forzare il download di un file (.txt) da parte del browser che fà richiesta tramite get con un mio CGI scritto in C.Ho trovato gli header per fare questo ma il file non mi si scarica correttamente.Provo a fare un esempio. L'utente preme su un bottone per recuperare un file .txt e questo bottone apre un get ad un mio cgi di nome example.exe e mi passa come parametro di query get il nome del file.
Io recupero il nome inviatomi e al browser mando questi header:


fprintf(cgiOut, "Content-type: %s\r\n\r\n", "application/x-download");
fprintf(cgiOut, "Content-Disposition: attachment; filename=%s;\r\n\r\n", "prova.txt");
fprintf(cgiOut, "Accept-Ranges: bytes\r\n\r\n");
fprintf(cgiOut, "Content-Length: %d\r\n\r\n",70);
if( (stream = fopen( path, "rt" )) != NULL )
{
while( !feof( stream ) )
{
//leggo tutti i BYTE in una volta solo
numByte = fread( buffer, sizeof( char ), 500, stream );
buffer[70] = '\0';
fprintf(cgiOut,buffer);
if( ferror( stream ) )
return 0;
}
}
fclose( stream );

Il cgiOut sarebbe l'invio al browser della stringa.
Il fatto è che il browser si rende conto che deve essere scaricato un file(mi pare la finestra di download file) indice che il content-type è stato letto ma il nome del file è example.exe(ossia quello del CGI) e mi restituisce gli altri header come stringa. La prova l'ho fatto con un file di 70 bytes.

Qualche idea o suggerimento?

shishii
13-05-2006, 19:58
Non conosco abbastanza il C da poterti aiutare.
Guarda se quasto codice Perl commentato ti può aiutare.



#!/usr/bin/perl

use strict; # Ormai oggi è quasi obbligatorio.
use CGI; # semplifica la lettura dell'input

my $dir = "/var/www/html"; # directory che contiene i file da scaricare

my $q = new CGI;

my $file = $q->param('file'); # raccoglie il nome file

my $size = (-s "$dir/$file"); # ne calcola la dimensione

my $buf;

# segue l'header http necessario per impedire l'apertura
# del file
print "Content-type: octet/stream\n";
print "Content-length: $size\n";
print "Content-disposition: attachment; filename=$dir/$file\n\n";

open (FILE, "<$dir/$file");
# il file viene letto e poi scritto sullo STOUT
# differenziando i file binari da quelli ASCII
if (-B "$dir/$file") {
binmode FILE;
while (read FILE, $buf, 1024) {
print $buf;
}
} else {
while (<FILE> ) {
print;
}
}
close FILE;

exit;

quincy
13-05-2006, 21:15
Grazie mille per la tua risposta!
Proverò ad adattare il tuo codice e se riesco posto il codice in C!


Ciao

Habanero
13-05-2006, 21:57
il problema è semplicemente che devi mandare il doppio invio a capo "\r\n\r\n" solo dopo l'ultima riga dell'header non ad ogni riga.... il doppio invio a capo indica la separazione tra header e contenuto...
Prova così:



fprintf(cgiOut, "Content-type: %s\r\n", "application/x-download");
fprintf(cgiOut, "Content-Disposition: attachment; filename=%s;\r\n", "prova.txt");
fprintf(cgiOut, "Accept-Ranges: bytes\r\n");
fprintf(cgiOut, "Content-Length: %d\r\n\r\n",70);
if( (stream = fopen( path, "rt" )) != NULL )
{
while( !feof( stream ) )
{
//leggo tutti i BYTE in una volta solo
numByte = fread( buffer, sizeof( char ), 500, stream );
buffer[70] = '\0';
fprintf(cgiOut,buffer);
if( ferror( stream ) )
return 0;
}
}
fclose( stream );

quincy
14-05-2006, 09:35
Grazie per la risposta!

In effetti era come scrivevi.
Ora però ho un altro problema. Il numero dei byte del file da inviare li leggo con la funzione stat, il contenuto lo leggo con fread. Il fatto è che la size del file che mi indica la stat differisce dal numero di byte letti dalla fread,ossia me ne legge di meno la fread!
Mi sapresti spiegare perchè?
Fai conto che il byte da inviare è semplicemente un documento formattato con dei numeri e dei \t o \n(insomma una tabella di dati).

Ti ringrazio per il tuo aiuto.

quincy
14-05-2006, 09:42
OK scoperto l'arcano!

Per fare il punto della cosa,gli header sono quelli scritti da Habanero. Quando però deve essere letto il file da inviare, la modalità di lettura deve essere binaria, in maniera tale che le sostituzioni dei \n\r vengono soppresse, quindi i file viene letto per intero.

Grazie ad entrambi per l'aiuto fornitomi.

Alla prossima. :ciauz: :ciauz:

Loading