Método para recebimento de arquivo de cliente

Bom dia, tenho a seguinte situação:
Um sistema desktop precisa enviar um banco de dados para um servidor web em intervalos de tempo especificos.
Atualmente estamos fazendo isso via ftp, porém sabemos que essa técnica não é segura e estamos querendo mudar.
O que precisamos agora, é um método que receba o arquivo no servidor, junto com o calculo do md5, e quando o upload terminar ele verifique esse md5 e devolva uma mensagem pro cliente dizendo se foi ou não…

A principio haviamos pensado em fazer isso via webservice mas ai fica o problema de os arquivos serem muito grande então fica inviavel fazer via webservice.

Existe algum meio de se fazer isso de um modo seguro?

Bom dia Mateus,

Eu faço um backup via dropbox, ou seja, crio uma conta e instalo o dropbox no PC origem e PC destino.
No PC origem, criei algumas tarefas agendadas que apenas da um COPY do .backup e o joga no diretório do DropBox.

Feito isso a sincronizão é automática, pelo menos evita o trabalho de ter que conectar via ftp de tempos em tempos para enviar o arquivo.

O problema disso é que teria que depender de um serviço de terceiros, e como nós já temos o servidor rodando poderiamos aproveitar esse recurso…

Por que então não fazem em FTP de novo? Primeiro enviam o arquivo e depois seu MD5?

Se for segurança como se tratando de algo a invasão de hacker, você poderia usar o SFTP.

O problema é que usando o ftp, no servidor não temos como calcular o md5 na hora do recebimento do arquivo no servidor(a idéia seria verificar por falha no upload).

Isso é verdade, depende do serviço de terceiros.

No meu caso possuo uma conta free com 5 GB de espaço, até hoje nunca ficou fora!!

[quote=mateusviccari]O problema é que usando o ftp, no servidor não temos como calcular o md5 na hora do recebimento do arquivo no servidor(a idéia seria verificar por falha no upload).
[/quote]Mas nesse caso não poderia ter uma rotina que de x em x “tempos” verificaria se chegou arquivo e se o MD5 bate?

O método mais seguro é usar sftp, que criptografa e comprime os arquivos. Se o servidor for Linux ou outro Unix, ou mesmo MacOSX, você já tem a parte server - basta habilitar isso no Linux. A parte client também está pronta no Linux e outros Unix, mas como provavelmente seu cliente é Windows, você pode usar o pscp ou psftp ( http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html ) ou então o Cygwin.

[quote=Hebert Coelho][quote=mateusviccari]O problema é que usando o ftp, no servidor não temos como calcular o md5 na hora do recebimento do arquivo no servidor(a idéia seria verificar por falha no upload).
[/quote]Mas nesse caso não poderia ter uma rotina que de x em x “tempos” verificaria se chegou arquivo e se o MD5 bate?[/quote]

Até poderia só que ai não vai ter como dar resposta pro cliente pra ele fazer o upload novamente, ou até poderia fazer isso só que ai teria que bolar um esquema pro cliente ficar olhando no servidor pra ver se o upload ja foi processado e a"autorizado"…

Estava pensando em existir a hipotese de criar uma pagina com um FileUpload e tentar adicionar esse arquivo no fileUpload via código, ai a resposta poderia vir em uma pagina que seria aberta depois desse upload ter terminar, ai seria só ler a pagina html pra obter a resposta, mas nao sei se isso é possivel

[quote=mateusviccari]Até poderia só que ai não vai ter como dar resposta pro cliente pra ele fazer o upload novamente, ou até poderia fazer isso só que ai teria que bolar um esquema pro cliente ficar olhando no servidor pra ver se o upload ja foi processado e a"autorizado"…

Estava pensando em existir a hipotese de criar uma pagina com um FileUpload e tentar adicionar esse arquivo no fileUpload via código, ai a resposta poderia vir em uma pagina que seria aberta depois desse upload ter terminar, ai seria só ler a pagina html pra obter a resposta, mas nao sei se isso é possivel[/quote]Você poderia mostrar na tela: “Estamos processando seu arquivo, em breve enviaremos uma resposta” e depois do processamento envia a resposta via email. [=

Também seria possível ter uma página para upload. Você poderia criar um servlet que receberia o arquivo e ao final faria as validações.

Além disso, se habilitar a parte de chaves públicas e privadas (que também está nesse pacote do putty) permite o login seguro. O usuário de seu sistema protege a chave privada dele com senha, e você só deixa receber arquivos assinados por esse usuário. Isso é mais fácil que parece.

[quote=mateusviccari]Bom dia, tenho a seguinte situação:
Um sistema desktop precisa enviar um banco de dados para um servidor web em intervalos de tempo especificos.
Atualmente estamos fazendo isso via ftp, porém sabemos que essa técnica não é segura e estamos querendo mudar.
O que precisamos agora, é um método que receba o arquivo no servidor, junto com o calculo do md5, e quando o upload terminar ele verifique esse md5 e devolva uma mensagem pro cliente dizendo se foi ou não…

A principio haviamos pensado em fazer isso via webservice mas ai fica o problema de os arquivos serem muito grande então fica inviavel fazer via webservice.

Existe algum meio de se fazer isso de um modo seguro?[/quote]

Via web services não necessariamente precisa ser um impeditivo, se você usar MTOM.

[]'s

Bom pesoal resolvi seguir a dica do herbert coelho usando servlet, e a principio funcionou tudo uma maravilha…
Nunca tinha pensado em usar o outputStream do servlet pra enviar informações pra uma pagina…
Consegui alocar o md5 e o arquivo no request do servlet, processar o md5 quando o servidor recebe o arquivo e devolver o retorno e capturar esse retorno no cliente.
Fiz alguns testes com arquivos relativamente grandes, de 10 a 20 MB e deu tudo certo, vamos ver como se sai em produção.

Fica o codigo aqui por curiosidade:
Método do servlet:

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            
            InputStream istream = request.getInputStream();

            // Passo a referencia ao objeto BufferedInputStream.
            BufferedInputStream bis = new BufferedInputStream(istream); 


            BufferedOutputStream bos2file = new BufferedOutputStream(new FileOutputStream("C:\\arquivo")); 

            // captura o md5
            byte[] md5bytes = new byte[32];
            bis.read(md5bytes);
            String md5Enviado=new String(md5bytes);
            
            //captura o arquivo
            byte[] buffer = new byte[4096]; 
            int size;
            size = bis.read(buffer);
            while (size != -1) {
                //bos.write(buffer, 0, size);
                bos2file.write(buffer, 0, size); 
                size = bis.read(buffer); 
            }

            bis.close();
            //bos.flush(); 
            //bos.close();
            bos2file.flush(); 
            bos2file.close();
            
            File arquivoSalvo = new File("C:\\arquivo");
            String md5Gerado = GeracaoMd5.geraHash(arquivoSalvo);
            if(md5Gerado.equals(md5Enviado)){
                out.println("Tudo certo piá véio! MD5 enviado: "+md5Enviado+" | MD5 calculado: "+md5Gerado);
            }else{
                out.println("ERRO: MD5 enviado: "+md5Enviado+" | MD5 calculado: "+md5Gerado);
                arquivoSalvo.delete();
            }
        } catch(Exception e){
            out.println(e.getLocalizedMessage());
        }finally {            
            out.close();
        }
    }

Código pra enviar o arquivo pro servlet:

    public static void main(String[] args) throws Exception {
        File file = new File("C:\\util/banco_geben.zip");
        String md5Gerado=GeracaoMd5.geraHash(file);
        //vai gravar a sequencia de 32 bytes do md5
        
        
        // URL da minha aplicação web. 
        URL url = new URL("http://localhost:8080/HelloWorld/ServletUpload");

        // Abro a conexão com a minha aplicação web.
        URLConnection con = url.openConnection();

        // Seto alguns flags importantes para nossa aplicação. O mais importante de todos é o setOutput igual a true!
        con.setDoOutput(true);
        con.setAllowUserInteraction(false);
        con.setUseCaches(false); 
        con.setDefaultUseCaches(false);

        // Seto o parametro MIME para que minha requisicao seja entendida que é um arquivo pdf. 
        con.setRequestProperty("Content-Type", "arquivo_bancoDados"); 

        // Pego a referencia ao OutputStream da propria conexao. 
        BufferedOutputStream outputToServlet = new BufferedOutputStream(con.getOutputStream()); 
        
        // Abro o stream de entrada vindo do arquivo pdf fonte.
        FileInputStream input = new FileInputStream(file); 

        // Passo a referencia ao objeto BufferedInputStream
        BufferedInputStream buf = new BufferedInputStream(input);
        
        //Grava a md5 de 32 bytes no stream
        for(int i=0; i<32; i++){
            outputToServlet.write(md5Gerado.getBytes()[i]);
        }
        
        // Grava o arquivo no stream
        int readBytes = 0; 
        while ((readBytes = buf.read()) != -1) { 
            outputToServlet.write(readBytes); 
        } 

        outputToServlet.flush();
        outputToServlet.close();

        // Aqui eu pego uma referencia a um objeto InputStream. Isso eu percebi que é necessário porque somente assim é feito a requisição a classe servlet 
        BufferedInputStream bis = new BufferedInputStream(con.getInputStream()); 
        BufferedReader br = new BufferedReader(new InputStreamReader(bis));
        String lendo;
        while((lendo=br.readLine())!=null){
            System.out.println(lendo);
        }
        bis.close();
    }

Só tome cuidado para que o servidor de produção não tenha um timeout configurado e ele mate o upload do usuário durante o processo. =D

Agora fiquei em duvida exatamente sobre esse timeout…
Se eu tirar esse timeout, e digamos que o usuario põe pra fazer o upload do arquivo e na metade do upload ele mata o processo…
O que irá acontecer no servidor?
Ele vai continuar com o arquivo pela metade na memória? O tomcat automaticamente limpa isso da memória?

[quote=mateusviccari]Agora fiquei em duvida exatamente sobre esse timeout…
Se eu tirar esse timeout, e digamos que o usuario põe pra fazer o upload do arquivo e na metade do upload ele mata o processo…
O que irá acontecer no servidor?
Ele vai continuar com o arquivo pela metade na memória? O tomcat automaticamente limpa isso da memória?[/quote]Não sei te falar ao certo. ^^

Cara, sem querer ser chato nem nada, mas o que você está realmente procurando é um serviço REST. Tudo isso que você está fazendo seria muito mais fácil e mais rápido de fazer se você usasse algo do tipo.

[]'s