Not able to stream PDF, using AWS gateway/Lambda setup - amazon-web-services

Problem Statement:- Not able to stream PDF, using AWS gateway/Lambda setup.
I've following Setup:-
Gateway API -> Lambda Function(java) -> S3
Api should stream a PDF back to the client via Lambda from S3 server.
I am unable to do so.
Things tried
1) On Lambda side
Use RequestStreamHandler, write PDF on OutputStream
outputStream.write();
Tried Setting Base64 encoding using following
AWS Base64 Utility
java.util Base64 Utility
apache Base64 utility
Send Byte[] without encoding
Use non-proxy handler, write PDF as string to one of the output variable.
Tried Setting Base64 encoding using following
AWS Base64 Utility
java.util Base64 Utility
apache Base64 utility
Send Byte[] without encoding
2) On Gateway Side
Set Proxy integration
Remove Proxy integration
Tried Set Content Handling using
Passthrough
Convert to Binary
Convert to String
Set headers
Content-Type = 'application/pdf'
Content-Disposition = 'attachment; filename="nameofpdffile.pdf"'
I've tried all the permutations/combinations of these 2. However, I am not able to get it to work and documentation around this area seems poor.
When I set Base64 encoding in Lambda and on gateway side specify content handling as convert to binary, i get error, fail to conert using Base64 decode.
For other combinations, I get binary data as output when I test it using gateway Test funciton, however my client(Postman, Chrome, Safari) fail to convert it to PDF
Note:- I've a workaround in place, where I create a signedURL to S3 object, and send it as redirect. However, I am trying to make it work by streaming a binary file using Lambda.
Thanks for reading such a long post. Any pointers, links in the right direction are highly appreciated.
- Frustated AWS user :-)

I had a similar problem with trying to offer up gzipped content: Client -> API-Gateway -> S3.
I couldn't figure out why the content I pulled couldn't get recognized by the client (either browser or code) until I inspected the header(the binary header, not http).
It appears that API Gateway by default assumes a string based encoding (utf-8) so what I was seeing is data that API Gateway was transforming on the fly and adding utf-8 headers in various places.
Late last year API Gateway started to support binary payloads. I started reading this article which may help in your case. It did not in mine, but your use case is slightly different and closer to the article so it might.
https://aws.amazon.com/blogs/compute/binary-support-for-api-integrations-with-amazon-api-gateway/
As for what I ended up doing... I realized I was just using the API Gateway as a passthrough (to take advantage of the Cognito based authentication I had already setup) so I bypassed API Gateway all together and used the aws js sdk to connect directly to s3 (and set IAM policies on the bucket separately)

Related

API Gateway request blocked by CORS

I am using AWS API Gateway put method to post an image to S3 bucket. In API Gateway settings when I add / in Binary Media Types I get the following error message
Access to fetch at ‘some_invokation_request/my_s3_bucket/image.png’ from origin ‘http://localhost:3001’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.
When I remove / from Binary media types in settings I can post an image and when I check the posted image in S3 it's messed up.
I'll post the original image and S3 image
Apparently this is an open issue right now and you can find further details here
I believe you have two different errors present. One is CORS related and the other is the upload of an image getting messed up. I don't think they are necessarily related. I've hit the same issue with the image upload showing the tiny white square but faced no CORS issue.
For me, the problem turned out to be trying to combine the use of Convert to Binary (if needed) and a mapping template on the Integration Request. According to the documentation (and my experience as well), if a mapping template is defined, APIGW doesn't run the Convert to Binary passthrough functionality. What gets passed to the S3 bucket for saving is a base64 encoded string instead of actual binary, thus the messed up image.
Excerpt from the linked documentation:
"On the contentHandling property of the Integration resource, set CONVERT_TO_BINARY. Set WHEN_NO_MATCH as the passthroughBehavior property value without defining a mapping template. This enables API Gateway to invoke the passthrough template."

How to use AWS WebRTC signed url in the frontend?

The aws repo https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-js provides the backend code to generate a presigned url.
I was able to log it and it looks like this (modified by adding/removing some characters to avoid misuse):
wss://v-7bd53a347.kinesisvideo.ap-south-1.amazonaws.com/?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-ChannelARN=arn%3Aaws%3Akinesisvideo%3Aap-south-1%3A3514502525359%3Achannel%2Fwebcam-signalling-channel-4%2F1637856477339&X-Amz-ClientId=U5PAWCWS5VE&X-Amz-Credential=ASIAVDVAVN2XSBEJVNOK%2F20211207%2Fap-south-1%2Fkinesisvideo%2Faws4_request&X-Amz-Date=20211207T160335Z&X-Amz-Expires=299&X-Amz-Security-Token=IQoJb3JopZ2luX2VjEND%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCmFwLXNvdXRoLTEiRzBFAiEA50TmitWwvooci6xG3i1M4jGzt7c7lfEu36TcdzOOFm8CIBNZLLDLB%2FDiBGIkU1PymctAcnobgu4WX%2F4KptvG%2BTOjKtMECKn%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQAhoMMzUxNDUwNTI1MzU5IgzlJEvF6NfKu43Rf70qpwRckEnOpVflPcE%2FvLtSXqgUCDI5qE5F9RUSpqtVKEA0Q6qPClsXw9IJMx2PWWQdgQ5I2uuMG1Ql1EH5DbY%2Fac0%2B%2BXWUJnPeHjDvpuNRk4J52YWAO02s4692U0EayCJsyxD57z5OKuQ8y9xkfjd60juMqJ8QUX1NsRgx10OJvxEbQh8Fou2N9qJeJokSrLOD6bCIRZdJQ%2FLzg6q7HdR5oqnNTMHNv7sJ0gmcxF7UhT0wS%2FuIcEtyNBo%2FyE1NI0ytgXVic6R7Pe4wSyzIn76W2x98I3OrbPa67vq3NzyJK1h%2F%2FqhfqNFPOaBP7eFGxcVWRPqz2VOknNtMD3b8QFZV2HwwnLBUXv2Dgp3Ez%2Fl%2F06hnAwHARStNtpP3ZX1maJE%2FBK52tRP%2BAWG1mv5wNodPWNAj%2B%2B04Obn91%2BjmAUc6ntXLWbZLUUuAtS8RSYDkX41ZA%2BnKTPZusBjh5vxW8A8fa3YKl33b4T9QT5eTWqNq9EXeI51Vd6mZsWh9kgEF768MSDn3hfTTIhFienuErO6N5wPWzOVp71aUgJS95Y2LTffOocP3CL3daCaYiEvzA%2FolDXwRzTqYRK6MwlqeAGjREmIoYjb11K4kU8mtHfDAKq5c1JA4cW719WBAoiQsxRO0egcFuskkGSCiAEaMAbg94eSnHpFLmPWYJwHj61eBU4JzIUsmzhxLF5x4MADUjxf1yOTRyx3FhIiO51gutW1fbgTt7z9lPn9szDXi76NBjqFAiE7AMy1zOl4hnXhjO60JRiKgHL0YuKsHJPAV02UmAdgf7lY%2Bl14ABncq4q1HSv%2BRKA2rr1ZM9JfgjMGHD0Xw9a8qFjN0RX5N%2FMw0F5nvVV9oGC8lYmT%2BLwW7DfyinSIA30SMzfXVfIEcGhEil900hoZMQZyvOWM4q7F%2Bye%2FN4%2FzS1RqMNHQGIT%2FdgOZkSJwyho6cpH1kEZXZMfhlWjOnTBjcqQzGYd9g9GLocDq8ZivrAKCtEM6yR%2Bh%2FsLhtGinqpsVFM%2BhaxK9G929tvlIQ3ZxA4GRAuTBepucoeVhmOwWv0f%2Fk82xjET%2FD5zVYvtMEpoU76aPal7pYNis98DspPB9ugrAw%3D%3D&X-Amz-Signature=8303b836351e231e9e7850cdd565a21073eaa4cb699b06d50c9e7f7e15a933e&X-Amz-SignedHeaders=host
I am not able to understand how to use it in the frontend to view the video stream.
I have come across other comments seeking examples but there are no responses:
How to use Kinesis Video Stream WebRTC SDK in the browser without providing credentials?
Has anyone been able to use it?
In case you are still looking for an answer, the signed url can be used while creating a signalling client in the front end code and can be used for connecting with AWS WebRTC Signalling service. You may find an example at below
https://blog.learningdollars.com/2021/05/09/aws-kinesis-video-stream-with-signed-url/
I implemented the above but was unable to see request from one front-end module to the other front-end module using AWS Kinesis WebRTC.

How to prevent api gateway from converting base64 response

I have a service that returns image data as base64 encoded text in the body:e.g.
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAgAE...etc
However, when we put the service behind the api-gateway behaving as a proxy, the same request will seemingly convert the response to binary
�PNG
IHDR,,y}�u IDA... etc
and has a response header
Content-Type: application/json
The documentation explains how to convert TO binary automatically, but makes no mention on how to leave the response unmodified. I've tried changing contentHandling to CONVERT_TO_TEXT with no success, so I'm wondering if there's another way of having the api gateway not mess with my service responses.
I believe you are using the same setup as me;
API gateway
V
Proxy (no contentHandling available)
V
Lambda (returns {body: Buffer.toString('base64')})
This solved it for me: https://stackoverflow.com/a/47780921/853015.

Why is API Gateway trying to encode my binary data as a dictionary?

For some reason, API Gateway is taking my binary data that I upload and is trying to parse it as a string/convert it to a dictionary.
I just want API Gateway to leave my binary data alone from my request. None of the other answers I have seen on SO have addressed the issue.
Is there a known solution to this?
By default API Gateway messes with binary data. You have to set the binary content type for API gateway (which you can do through the console).
Be sure to double check that the Content-Type header in your requests is set to the correct value, and also the Accept header is set to the correct value.

AWS API Gateway with Lambda proxy always produces base64 string response

I'm using API Gateway Lambda proxy integration and trying to return a binary application/protobuf response. No matter what I do, the response body is always a base64 encoded string
I have application/protobuf setup as a binary media types in APIG
My client (javascript) is sending following headers in the POST:
Accept: application/protobuf
Content-Type: application/protobuf
My lambda is responing with content-type: application/protobuf, and correctly setting the IsBase64Encoded Lambda response to true
How do you get APIG to base64 decode the string? I swear I had this working a few months ago when I 1st tried this.
Note: I've also tried */* as a binary media types
Some related posts to add background:
https://github.com/twitchtv/twirp/issues/81
https://github.com/awslabs/aws-serverless-express/issues/39#issuecomment-276019222
Update:
Turns out I can only get it working if binary media type is set to */*. The client Accept header has no impact once it is set to this.
Many bad side effects of using */* because every response is attempted to get decoded (even when IsBase64Encoded is false or not set)
I thought it wasn't decoding because Chrome network inspect tools will always show binary data as base64 encoded in the Preview tab. You can see the protobuf in the Response tab.
The problem was I'm using CloudFront in front of API Gateway, and I was not passing the Accept header to the origin (APIG).
The docs on handling binary with Lambda proxy are not great, so here is a quick summary:
Your client must send an Accept header who's 1st media type matches what you have set as a binary media types in API Gateway
Your Lambda, if serving a binary media type, must set IsBase64Encoded to true AND the body must be base64 encoded
If the clients Accept header matches an entry in API Gateway's binary media types and these conditions are met, API Gateway will transform (base64 decode) before sending a response to the client.
This blog post walks you through step-by-step on how to get it working (without CloudFront).
This is a full blown aws-blueprint for getting a production grade ci/cd with CloudFront.