Jaguar-dart / jaguar

Jaguar, a server framework built for speed, simplicity and extensible. ORM, Session, Authentication & Authorization, OAuth
http://jaguar-dart.github.io
463 stars 34 forks source link

Large static file issues #126

Closed chstrong closed 5 years ago

chstrong commented 5 years ago

The static files part of Jaguar seems to have an issue with larger files or maybe unsupported content types. When I try to load a picture, it works, but with a video it will take forever and then output the binary representation of the video as text.

For testing the behaviour it should suffice to:

See also comment in this video (user that has PDF with same issue): https://www.youtube.com/watch?v=-IP-mc48n-A&index=9&list=PLS78sux6nBcRR9EyR3sBQxRXXW4jac7TR

library upload_files.server;

import 'dart:io';
import 'package:jaguar/jaguar.dart';
import 'package:path/path.dart' as p;
import 'package:jaguar_cors/jaguar_cors.dart';
import 'package:image/image.dart';

main(List<String> args) async {
  final server = Jaguar(port: 8005);

  final corsOptions = const CorsOptions(
    allowAllOrigins: true,
    allowAllHeaders: true,
    allowAllMethods: true);

  // API
  server.group('/api')
    // Upload route
    ..post('/upload', (ctx) async {
      final Map<String, FormField> formData = await ctx.bodyAsFormData();
      BinaryFileFormField media = formData['media'];
      if(media.contentType.toString().startsWith("image")) {
        if(media is BinaryFileListFormField) {
          //BinaryFileListFormField media = formData['media'];
          media.values.forEach((f) async {
            await f.writeTo(p.join('/Users/chstrong/Development/Git/Places/places_upl/bin/data/', f.filename));
            Image image = decodeImage(new File('/Users/chstrong/Development/Git/Places/places_upl/bin/data/' + f.filename).readAsBytesSync());
            Image thumbnail = copyResize(image, 300);
            new File('/Users/chstrong/Development/Git/Places/places_upl/bin/data/thumb_' + f.filename).writeAsBytesSync(encodePng(thumbnail));
          });
        } else {
          await media.writeTo(p.join('/Users/chstrong/Development/Git/Places/places_upl/bin/data/', media.filename));
          Image image = decodeImage(new File('/Users/chstrong/Development/Git/Places/places_upl/bin/data/' + media.filename).readAsBytesSync());
          Image thumbnail = copyResize(image, 300);
          new File('/Users/chstrong/Development/Git/Places/places_upl/bin/data/thumb_' + media.filename).writeAsBytesSync(encodePng(thumbnail));
        }
      } else if(media.contentType.toString().startsWith("video")) {
        if(media is BinaryFileListFormField) {
          //BinaryFileListFormField media = formData['media'];
          media.values.forEach((f) async {
            await f.writeTo(p.join('/Users/chstrong/Development/Git/Places/places_upl/bin/data/', f.filename));
          });
        } else {
          await media.writeTo(p.join('/Users/chstrong/Development/Git/Places/places_upl/bin/data/', media.filename));
        }        
      } else {
        return HttpStatus.badRequest;
      }
      return HttpStatus.ok;
    }, before: [new Cors(corsOptions)])
    ..options('/upload', (ctx) async {
      return HttpStatus.ok;
    }, before: [new Cors(corsOptions)]);

  // Serve the uploaded media
  server.staticFiles('/media/*', Directory('bin/data'));

  server.log.onRecord.listen(print);

  await server.serve(logRequests: true);
}
tejainece commented 5 years ago

@chstrong How are you sending the form? The browser or the client should send it as binary field in multipart body.

chstrong commented 5 years ago

@tejainece The form sending and upload through multipart is working.

If I want to view the video however through localhost:8005/media/video.mp4 it isn't loading, or it starts to display the binary representation of the video, instead of the content. Pictures do work though.

I mean this line, which makes Jaguar serve the static files in the directory. Images work, videos don't, and PDF's seem to have the same issue. server.staticFiles('/media/*', Directory('bin/data'));

tejainece commented 5 years ago

Ok. Got it!

tejainece commented 5 years ago

Can you do me a favor? Let me know what is the mimetype you see for the response at the client?

tejainece commented 5 years ago

I will add video mimetypes to here: https://github.com/Jaguar-dart/jaguar/blob/05398b87040c1d9322733d82fead51291dbcc7f1/jaguar/lib/http/common/mimetype.dart#L43

tejainece commented 5 years ago

This should fix it: https://github.com/Jaguar-dart/jaguar/commit/4b33d2baec4ebcf62bd9833a97d5d70c6371fbc5

chstrong commented 5 years ago

Thanks a lot, this works perfectly now. If I have some other exotic mime types, how would I add them?

Something like server.staticFiles().mimeTypes.add() would be cool, to specify a list of custom mime types for static files. Is there something similar to this built-in already?

tejainece commented 5 years ago

One could use responseProcessor.