Error "request too large (413)" when trying to upload a PDF file to OneNote - objective-c

I'm trying to create new pages in OneNote using Microsoft Graph REST API (Objective-C). Those new pages should contain a PDF document as an attachment.
The POST operations succeed with PDF files that are under ~4MB. However, the operations for files that are over 4MB fail with the error message request too large (413) and the following response:
{
"error": {
"code": "BadRequest",
"message": "Maximum request length exceeded.",
"innerError": {
"request-id": "269c663c-9289-47cc-a833-d471b7b867f6",
"date": "2019-04-09T09:35:49"
}
}
}
The end point that is used is: https://graph.microsoft.com/v1.0/me/onenote/sections/XXX/pages
Microsoft states in the documentation for Graph and OneNote:
The total POST size limit is ~70 MB, including images, files, and other data. The actual limit is affected by downstream encoding, so there's no fixed byte-count limit. Requests that exceed the limit may produce unreliable results.
The limit for each data part is 25 MB, including the part headers. Data parts that exceed the limit are rejected by Microsoft Graph.
I could not find any limit of 4MB for POST requests in the Microsoft Graph documentation for OneNote. Is there any workaround for my current issue?

The short answer is that this documentation is incorrect. The longer answer requires a little background on Graph itself.
Graph is an API aggregator. It takes incoming requests, routes them to one or more underlying APIs, and then normalizes the responses so the end developer gets consistent results across endpoints.
In this case, the underlying API is the OneNote REST API. The limits mentioned in the docs are accurate in terms of the OneNote API but since this request is being handled by Graph, you are hitting the smaller 4 MB limit of Graph itself before that request ever gets routed to the underlying API.
More than likely the documentation error was unintentionally missed when the original docs were ported over to Graph. I've filed a documentation issue so it can be corrected.

Related

How can I ensure that ASP.NET Core's IFormFile stream doesn't read more than what's specified in the file's Content-Length?

I have an API endpoint for uploading large files, streaming then directly to DB. I use ASP.NET Core's IFormFeature to do this, calling IFormFile.OpenReadStream() to get a Stream that I pass to SqlClient for streaming.
I want to enforce a a maximum file size to avoid abuse. I know IFormFile has a Length property, but I assume that is based on Content-Length or similar and can not be trusted (please correct me if I'm wrong, but AFAIK the only way to be 100% sure about the file size is to actually read the data; the client could send an incorrect Content-Length.)
I must therefore ensure that when the stream is read, it does not read more than what is specified in IFormFile.Length (ideally it should throw if it encounters additional bytes). I have not found a way to do this. Is this possible, or is there perhaps a better way to ensure the server doesn't read enormous amounts of data from clients sending incorrect Content-Length headers?
(It should go without saying that this must not entail reading the entire file into memory.)

REST API Response body same but response size different

We have a RESTful API built using ASP.NET Web API, and it is hosted as a Azure cloud service.
Recently we had to fix the performance (response time) of an endpoint owing to which we made a few changes. The API request-response needed to remain unchanged.
Thus to test that the changes we made didn't alter the response, we benchmarked the responses by capturing it for different users. We captured the following -
Response times (Postman display)
Response size (Postman display)
Response body
Now that we are testing, oddly we see that although the response body is an exact match (done using file compare) the response sizes are order of magnitude different. For instance what was 562.37KB before is now 52.33KB. In fact we had benchmarked 30 users and all the response sizes reduced by one order. But for all the response body is exactly the same.
What could be the possible reason? Is there anything we are missing?
Size is just the response size when it will be saved inside the memory. This response size is the size of complete response and headers and cookies and everything that has been sent along with the response.
NOTE: The response size that is shown in the Postman is approximate response size and not the exact size.
For details you may refer to
https://www.toolsqa.com/postman/response-in-postman/
https://github.com/postmanlabs/postman-app-support/issues/156
Secondly, it is important to know the difference as detailed in link size and content :
Chrome Dev Tools - "Size" vs "Content"
For easy access, a snapshot of the answer is below:
"Size" is the number of bytes on the wire, and "content" is the actual size of the resource. A number of things can make them different, including:
Being served from cache (small or 0 "size")
Response headers, including cookies (larger "size" than "content")
Redirects or authentication requests
gzip compression (smaller "size" than "content", usually

HTTP status code to return by a REST API when image size exceeds limit

A POST to a specific end point allows to upload an image except if the image is too large, so I want to return the appropiate http status code response in that case.
A http status code 400 response it does not seem to fit well in this case.
400 Bad Request: "The server cannot or will not process the request due
to something that is perceived to be a client error (e.g., malformed
request syntax, invalid request message framing, or deceptive request
routing).
I think that the image being too large it does not imply that the request is malformed or syntactically incorrect.
Any suggestions?
This seems like it would be an ideal candidate for 413 Payload Too Large. From Section 6.5.11 of RFC 7231:
The 413 (Payload Too Large) status code indicates that the server is
refusing to process a request because the request payload is larger
than the server is willing or able to process.
You can use 420 or even 422, but I would avoid that until you have really good reason to have separate code for it. Usually is better to keep number of different status codes rather small. Check top 10 on that list: http://www.restapitutorial.com/httpstatuscodes.html
You should avoid using more than 10 codes, because your API will become too complex.
So my answer is: use 400 with proper error message returned to the client like: "Image too large, you can upload files up to XX MB"

How should exceptions be handled in a RESTful API for collection results?

We are designing a RESTful API to return collections of documents. Our initial implementation uses HTTP status codes to indicate if a request could not be fulfilled. This seems to be a widely accepted best practice (see for example here).
We recently ran into an issue where a user was pulling 1000 documents. One of the document retrievals failed, and thus we returned an HTTP 500 status code.
An alternative would be to return an HTTP 200 status code with the payload having the 999 documents that we were able to retrieve, and then an error collection indicating the one that failed.
Is this alternative approach a violation of RESTful principles? How should this situation be handled? Are there any options besides these two approaches?
Yes, I think it is perfectly acceptable as long as you document that the data that you are returning, can contain an "error" collection. This means that whatever semantic media-type you are using to describe this collection of documents, should have documentation that describes what the collection of documents should look like, and what the error collection should look like. The client can then decide what to do with this information.
For example, if you are returning this as JSON (just an example), you may have a media type like application/json+documents or something, which could look like this:
{ data : {
documents: [ ... ], //document objects
errors: [ ... ] //error objects
}
You would then have documentation that describes what the documents look like, and what the errors look like. In truly RESTful API's it is the media-types that are documented and not the calls, because in a truly RESTful API there is only one endpoint, and everything else is "discovered" via that initial endpoint, in conjunction with semantic media-types. So as long as you document that errors are possible, and you describe the format that the errors will be delivered, you should be alright.
This is also isn't an "exceptional" condition since it seems to be in your case that it is foreseeable that a client may not be able to retrieve all documents. Hence it is alright to inform the client of that fact.
There is a line that you sometimes have to cross in a unique situation like this: involving the user.
It's not unreasonable to notify the user that the payload is too large, and return an internal server error.

SBJson Stream Parser

I'm working in Xcode 4.3.2 + building for an app in iOS 5.
I've decided to use SBJson to parse streams of data from our server. I've verified that I'm receiving a valid JSON response from the server. My question concerns the design behind the classes SBJsonStreamParser and the SBJsonParser.
It appears that in SBJsonParser the method "objectWithData" takes the data received from the JSON response and uses the SBJsonStreamParserAccumulator to append the stream of data into a single JSON document. Once the data stream is gathered into one object, it is then parsed by the "parse" method in SBJsonStreamParser.
I've run into several issues when requesting larger JSON documents. The size of the responses seem to be reasonable (specially 9.4 KB response). It appears that the SBJsonStreamParser breaks when getting a data stream greater than a certain size. The parser succeeds when the response is small (~3KB), but fails when the response is larger (~10KB).
I used NSLog to verify that in both cases, pulling a small & large stream, the methods are successfully receiving the full json document - because it looks like [{"id": .... 123}]. I'm convinced that the issue is that the data stream is too long.
I'm wondering if I'm using SBJson incorrectly or is this simply a limitation of the parser? Is there anything that I can configure that allows SBJsonStreamParser to not throw an error for larger (but reasonable) data streams & continue to parse the full response?
Thanks in advance!
Actually you have the workings of objectWithData: backwards. SBJsonStreamParserAccumulator is used to accumulate the parsed output, not the unparsed data stream.