From f2d97af1224ae4c4e5734523fb9aa5c5cb9883fd Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Tue, 16 Apr 2024 22:31:13 +0100 Subject: [PATCH] Fixup tests. --- src/feeds/parser.rs | 37 +++++++++++++++++---------- tests/FeedReader.spec.ts | 55 ++++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/feeds/parser.rs b/src/feeds/parser.rs index 33586f9e..1c07f67a 100644 --- a/src/feeds/parser.rs +++ b/src/feeds/parser.rs @@ -200,29 +200,38 @@ pub async fn js_read_feed(url: String, options: ReadFeedOptions) -> Result { + // Pre-emptive check let content_length = res.content_length().unwrap_or(0); - if content_length > (options.maximum_feed_size_mb * 1024 * 1024) as u64 { + if content_length > max_content_size { return Err(JsError::new(Status::Unknown, "Feed exceeded maximum size")); } let res_headers = res.headers().clone(); match res.status() { StatusCode::OK => match res.text().await { - Ok(body) => match js_parse_feed(body) { - Ok(feed) => Ok(FeedResult { - feed: Some(feed), - etag: res_headers - .get("ETag") - .map(|v| v.to_str().unwrap()) - .map(|v| v.to_string()), - last_modified: res_headers - .get("Last-Modified") - .map(|v| v.to_str().unwrap()) - .map(|v| v.to_string()), - }), - Err(err) => Err(err), + Ok(body) => { + // Check if we only got the length after loading the response. + match body.len() as u64 <= max_content_size { + true => match js_parse_feed(body) { + Ok(feed) => Ok(FeedResult { + feed: Some(feed), + etag: res_headers + .get("ETag") + .map(|v| v.to_str().unwrap()) + .map(|v| v.to_string()), + last_modified: res_headers + .get("Last-Modified") + .map(|v| v.to_str().unwrap()) + .map(|v| v.to_string()), + }), + Err(err) => Err(err), + } + false => Err(JsError::new(Status::Unknown, "Feed exceeded maximum size")) + } }, Err(err) => Err(JsError::new(Status::Unknown, err)), }, diff --git a/tests/FeedReader.spec.ts b/tests/FeedReader.spec.ts index cb3a8832..30762ec7 100644 --- a/tests/FeedReader.spec.ts +++ b/tests/FeedReader.spec.ts @@ -39,12 +39,12 @@ class MockMessageQueue extends EventEmitter implements MessageQueue { } } -async function constructFeedReader(feedResponse: () => {headers: Record, data: string}, extraConfig?: Partial) { +async function constructFeedReader(feedResponse: () => {headers?: Record, data: string}, extraConfig?: Partial) { const httpServer = await new Promise(resolve => { const srv = createServer((_req, res) => { const { headers, data } = feedResponse(); - Object.entries(headers).forEach(([key,value]) => { + Object.entries(headers ?? {}).forEach(([key,value]) => { res.setHeader(key, value); }); res.writeHead(200); @@ -300,21 +300,44 @@ describe("FeedReader", () => { }); it("should fail to handle a feed which exceed the maximum size.", async () => { + // Create some data of the right length + const data = ` + + + + RSS Title + This is an example of an RSS feed + ${Array.from({length: 8000}).map((_, i) => ` + Example entry + http://www.example.com/blog/post/${i} + `).join('')} + + `; const { feedReader, feedUrl } = await constructFeedReader(() => ({ - headers: { - 'Content-Length': Math.pow(1024, 2).toString(), - }, data: ` - - - - RSS Title - This is an example of an RSS feed - - Example entry - http://www.example.com/blog/post/1 - - - ` + data, headers: { 'Content-Length': data.length.toString()} + }), { + maximumFeedSizeMB: 1 + }); + await feedReader.pollFeed(feedUrl); + expect(feedReader["feedsFailingParsing"]).to.contain(feedUrl); + }); + + it("should fail to handle a feed which exceed the maximum size which does NOT send a Content-Length.", async () => { + // Create some data of the right length + const data = ` + + + + RSS Title + This is an example of an RSS feed + ${Array.from({length: 8000}).map((_, i) => ` + Example entry + http://www.example.com/blog/post/${i} + `).join('')} + + `; + const { feedReader, feedUrl } = await constructFeedReader(() => ({ + data }), { maximumFeedSizeMB: 1 });