PDF as response from AWS lambda returning blank document, works perfectly fine in local environment

Viewed 196

This is my setup Firebase Storage - for storing PDF files AWS lambda - backend, using express and serverless packages. FrontEnd - Flutter mobile app and web app(using flutter)

Everything works fine when testing the code in local environment. As soon as I deploy the code to production, my app is not able to read the document at all. There is no error from backend. A response with status code 200 is returned. But somehow the

My Front end code (Flutter - Dart)

  static Future<Response?> getData(String endPoint, {Function(Object)? onError}) async {
    String fromURL = baseUrl + endPoint;
    print(fromURL);
    try {
      final response = await get(Uri.parse(fromURL),
          headers: {"Access-Control-Allow-Origin": "*", "Content-Type": "application/pdf"});
      // if (response.body.isNotEmpty) {
      // final jsonData = jsonDecode(response.body);
      return response;
      // }
    } catch (e) {
      if (onError != null) {
        onError(e);
      }
    }
  }

  Future<Uint8List> _decryptPdfFile(Uint8List ecnryptedFile) async {
    // File _unecnryptedPdfFile = ecnryptedFile;
    final syn_pdf.PdfDocument document =
        syn_pdf.PdfDocument(inputBytes: ecnryptedFile, password: 'password');

    final syn_pdf.PdfSecurity security = document.security;

    security.userPassword = ''; //TODO: move the passwords to env file
    security.ownerPassword = '';

    security.algorithm = syn_pdf.PdfEncryptionAlgorithm.aesx256Bit;

    Uint8List decryptedBytes = Uint8List.fromList(document.save());

    document.dispose();
    return decryptedBytes;
  }

  Future<Uint8List> _getPdfbytes(UserFile userFile, String email) async {
    final respone = await NetworkClient.getData("/api/file?fileName=${userFile.name}&email=$email");
    _pdfFile = await _decryptPdfFile(respone!.bodyBytes);// Exception thrown on this line
    return _pdfFile;
  }

My Back-End Code

router.get("/", async (req, res) => {
  const firestore = admin.firestore();
  const firebaseStorage = admin.storage();
  const firebaseAuth = admin.auth();
  const urlParams = req.query;
  try {
    // console.log(req.headers);
    // console.log(req);
    const { email, fileName } = urlParams;

    if (!email) {
      return res.status(400).send({
        message: "failed",
        error: "unauthenticated",
      });
    }

    const reqUser = await firebaseAuth.getUserByEmail(email);
    if (!reqUser) {
      return res.status(400).send({
        message: "failed",
        error: "unauthenticated",
      });
    }

    let firebaseStorage = admin.storage();
    const bucket = await firebaseStorage.bucket();
    const file = await bucket.file(fileName);
    if (!file) {
      return res.status(400).send({
        message: "failed",
        error: "file not found",
      });
    }

    //get download url
    const urlOptions = {
      action: "read",
      expires: Date.now() + 1000 * 60 * 2, // 2 minutes
    };
    const downloadUrl = usingEmulator
      ? [await file.publicUrl()]
      : await file.getSignedUrl({
          action: "read",
          expires: Date.now() + 1000 * 60 * 4,
        });
    // const downloadedFile = await file.download();
    const respose = http.get(downloadUrl[0], (response) => {
      const { statusCode } = response;
      const contentType = response.headers["content-type"];

      let error;
      if (statusCode !== 200) {
        error = new Error("Request Failed.\n" + `Status Code: ${statusCode}`);
      }
      if (error) {
        console.error(error.message);
        response.resume();
        return res.status(400).send({
          message: "failed",
          error: error.message || error,
        });
      }

      res.setHeader("Content-Type", contentType);
      res.setHeader("Content-Disposition", `attachment; filename=${fileName}`);

      response.pipe(res);

      // response.end();

      return res.status(200);
    });
  } catch (error) {
    console.info(error.message);
    return res.status(500).send({
      message: "failed",
      error: error.message || error,
    });
  }
});

I have checked uploaded PDF manually, and it has been uploaded fine. I tried experimenting by setting various content-type in my request headers, but that doesn't work as well. I tried debugging flutter app and an Exception is thrown at the line pointed in the code. And the Exception is

ArgumentError (Invalid argument (Invalid cross reference table.): null)

I don't get any error or exception when running this code locally using Firebase emulators and running the backend locally as well. PDF gets uploaded and also read fine.

_decryptPdfFile function is removing the password which I set during PDF upload. It's hard-coded password and has never changed.
AWS lambda URL has been added to Firebase storage CORS policy.

EDIT 01: PDF file size will never go above 1mb. Max PDF size on Firebase storage is 307 KB. EDIT02: if i trigger the get URL using browse then PDF file gets downlaoded but its blank. It asks me for password and it accepts right password but PDF file is blank. SO i thought myabe firebase storage has blank file stored as well. But when i checked firebase storage manually, it has correct pdf file.

0 Answers
Related