Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

horse-multipart

Middleware nativo de alto desempenho para parsing e tratamento de requisições multipart/form-data (upload de arquivos e formulários) no framework Horse.

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

horse-multipart

Middleware nativo de alto desempenho para parsing e processamento de requisições multipart/form-data (upload de arquivos e campos de formulário) no framework Horse.

Ele intercepta requisições contendo fluxos de múltiplos arquivos e campos de texto comum, processa os dados diretamente na memória utilizando ponteiros binários de alta velocidade, persiste os arquivos temporariamente em disco e injeta as referências e metadados no corpo da requisição (Req.Body).


⚙️ Instalação

A instalação deve ser feita utilizando o gerenciador de pacotes boss:

bash
boss install horse-multipart

⚡️ Ciclo de Vida & Gerenciamento de Memória

  • Fase Recomendada: Registro no início das configurações das rotas (preParsing / antes do roteamento).
  • Limpeza Automática (Zero Memory Leak): Quando a requisição termina, o Horse destrói automaticamente o objeto THorseMultipart injetado no Req.Body. O destructor de THorseMultipart limpa a lista de arquivos (THorseMultipartFile), os quais excluem fisicamente os arquivos temporários do disco caso eles não tenham sido salvos ou movidos pelo desenvolvedor usando o método SaveToFile.

🛠️ Configuração Avançada

É possível customizar o diretório de upload dos arquivos temporários e o limite de tamanho individual de cada arquivo usando a classe fluida TMultipartConfig:

delphi
uses
  Horse,
  Horse.Multipart;

begin
  // Configuração customizada
  THorse.Use(Multipart(
    TMultipartConfig.New
      .UploadDir('C:\meus_uploads_temporarios') // Diretório temporário customizado
      .MaxFileSize(10 * 1024 * 1024)           // Limite de 10 MB por arquivo
  ));

  // ... suas rotas
end.

Se nenhum parâmetro for informado, o middleware usará o diretório temporário padrão do sistema operacional (ex: %TEMP% no Windows) e não limitará o tamanho dos arquivos.


📖 Exemplo Prático

Abaixo, um exemplo completo demonstrando como recuperar campos normais do formulário e salvar arquivos enviados via multipart/form-data.

Exemplo 1: Utilizando Req.Body (Método Recomendado)

delphi
uses
  System.SysUtils,
  Horse,
  Horse.Multipart;

begin
  THorse.Use(Multipart());

  THorse.Post('/upload',
    procedure(Req: THorseRequest; Res: THorseResponse)
    var
      LMultipart: THorseMultipart;
      LFile: THorseMultipartFile;
      LNomeUsuario: string;
    begin
      // Obtém o container multipart processado do Body
      LMultipart := Req.Body<THorseMultipart>;
      if not Assigned(LMultipart) then
      begin
        Res.Send('Requisição inválida ou sem dados multipart').Status(400);
        Exit;
      end;

      // 1. Obtendo campos de texto comuns do formulário
      LNomeUsuario := LMultipart.GetFieldValue('nome', 'Usuário Anônimo');

      // 2. Obtendo o arquivo pelo nome do campo (input name)
      LFile := LMultipart.GetFileByFieldName('foto');
      if Assigned(LFile) then
      begin
        // Salva o arquivo em seu destino final
        // Nota: O arquivo temporário será movido fisicamente, liberando o espaço temporário.
        LFile.SaveToFile('C:\uploads\' + LFile.FileName);
        
        Res.Send(Format('Olá %s, arquivo "%s" (%d bytes) recebido com sucesso!', [
          LNomeUsuario, LFile.FileName, LFile.Size
        ])).Status(200);
      end
      else
      begin
        Res.Send('Nenhum arquivo enviado sob o campo "foto"').Status(400);
      end;
    end);

  THorse.Listen(9000);
end.

Exemplo 2: Utilizando Injeção de Dependência (Req.Services)

Para projetos que utilizam o container de injeção de dependência (Services) do Horse, o middleware injeta dinamicamente as instâncias de THorseMultipart e do primeiro arquivo temporário recebido via RTTI:

delphi
uses
  Horse,
  Horse.Multipart;

begin
  THorse.Use(Multipart());

  THorse.Post('/upload-di',
    procedure(Req: THorseRequest; Res: THorseResponse)
    var
      LMultipart: THorseMultipart;
      LFile: THorseMultipartFile;
    begin
      // Resolve as dependências injetadas pelo middleware no request
      LMultipart := Req.Services.Resolve<THorseMultipart>;
      LFile := Req.Services.Resolve<THorseMultipartFile>;

      LFile.SaveToFile('C:\uploads\' + LFile.FileName);
      Res.Send('OK').Status(200);
    end);

  THorse.Listen(9000);
end.

🗂️ Estrutura de Métodos e Propriedades

THorseMultipart

  • Fields: TDictionary<string, string>: Dicionário bruto contendo todos os campos de texto chave/valor.
  • Files: TObjectList<THorseMultipartFile>: Lista de arquivos recebidos no upload.
  • GetFieldValue(const AFieldName: string; const ADefault: string = ''): string: Obtém o valor de um campo de texto de forma segura, retornando um valor padrão caso ele não exista.
  • GetFileByFieldName(const AFieldName: string): THorseMultipartFile: Retorna a referência do arquivo associado ao nome do campo enviado pelo formulário.

THorseMultipartFile

  • FieldName: string: Nome do campo de formulário associado (ex: foto).
  • FileName: string: Nome real do arquivo enviado pelo cliente (ex: foto_perfil.png).
  • ContentType: string: MIME type do arquivo (ex: image/png).
  • Size: Int64: Tamanho do arquivo em bytes.
  • TempFileName: string: Caminho físico completo para o arquivo temporário no disco.
  • SaveToFile(const APath: string): Move o arquivo temporário com segurança e de forma atômica para o caminho final informado, criando diretórios intermediários automaticamente caso não existam.

🚀 Arquitetura & Performance

  • Processamento Seguro de Fluxo Binário: O parser lê o stream de entrada diretamente através de buffers binários na memória (TMemoryStream.Memory), localizando delimiters de partes via varredura por ponteiros de byte (PByte).
  • Baixo Consumo de Memória: Apenas os metadados e cabeçalhos permanecem em memória. O conteúdo binário de arquivos é gravado de forma imediata em disco, evitando exaustão de memória sob uploads volumosos.
  • Totalmente Standalone: Zero dependência de bibliotecas visuais ou componentes pesados como Vcl ou FMX, tornando o middleware 100% compatível com aplicações de console e serviços Windows/Linux (via compilador Delphi e Free Pascal).

📄 Licença

Este projeto está licenciado sob a Apache License 2.0.