<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Byte Rivet</title>
    <description>The latest articles on DEV Community by Byte Rivet (@byterivet).</description>
    <link>https://dev.to/byterivet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4047428%2Fd4c2fe9f-f8d0-429c-8b7c-f2dfeced3533.png</url>
      <title>DEV Community: Byte Rivet</title>
      <link>https://dev.to/byterivet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/byterivet"/>
    <language>en</language>
    <item>
      <title>How to generate a valid file of any exact size, in the browser</title>
      <dc:creator>Byte Rivet</dc:creator>
      <pubDate>Wed, 05 Aug 2026 01:16:47 +0000</pubDate>
      <link>https://dev.to/byterivet/how-to-generate-a-valid-file-of-any-exact-size-in-the-browser-296k</link>
      <guid>https://dev.to/byterivet/how-to-generate-a-valid-file-of-any-exact-size-in-the-browser-296k</guid>
      <description>&lt;p&gt;I needed a 10 MB PDF to test an upload limit. Not "about 10 MB" — exactly 10,485,760 bytes. Every generator I found gave me fixed sizes or made me wait for a server download.&lt;/p&gt;

&lt;p&gt;So I looked into doing it in the browser. The interesting part wasn't the size. It was keeping the file &lt;strong&gt;valid&lt;/strong&gt; while hitting an arbitrary byte count.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naive approach breaks the file
&lt;/h2&gt;

&lt;p&gt;The obvious move is: make a real file, then append junk bytes until you hit the target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;realPdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// ← corrupt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For most formats this produces a broken file. A PDF reader follows the cross-reference table to a byte offset; trailing garbage after &lt;code&gt;%%EOF&lt;/code&gt; can throw it off. A PNG decoder walks length-prefixed chunks; extra bytes at the end aren't a valid chunk.&lt;/p&gt;

&lt;p&gt;The trick is that &lt;strong&gt;every format already reserves a legal place for extra data.&lt;/strong&gt; You just have to put the padding there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Padding where the spec allows it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PNG&lt;/strong&gt; → a &lt;code&gt;tEXt&lt;/code&gt; metadata chunk. It has a length prefix and a CRC-32, so decoders read exactly its declared length and skip the rest. Perfectly valid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF&lt;/strong&gt; → an unreferenced content stream. Same mechanism PDF writers use for incremental updates — the xref table just doesn't point at it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZIP / DOCX / XLSX&lt;/strong&gt; → a stored (uncompressed) entry inside the archive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JPEG&lt;/strong&gt; → &lt;code&gt;COM&lt;/code&gt; comment segments, up to 65,533 bytes each.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For PNG, the padded chunk needs a correct CRC or the decoder rejects it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pngChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crc&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;crc32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// must be correct&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;crc&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the CRC right and the file opens everywhere — the padding is invisible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the browser part matters
&lt;/h2&gt;

&lt;p&gt;Because nothing crosses the network, size barely affects speed. Assembling a 100 MB file is a memory operation, not a download — it lands in tens of milliseconds. And the file never leaves your machine, so there's no upload, no storage, nothing to log.&lt;/p&gt;

&lt;p&gt;I verified the output against real parsers — &lt;code&gt;pypdf&lt;/code&gt; reads the PDF text, &lt;code&gt;Pillow&lt;/code&gt; decodes the PNG, &lt;code&gt;openpyxl&lt;/code&gt; opens the XLSX. They're genuinely valid files, just padded.&lt;/p&gt;

&lt;p&gt;I turned this into a free tool (&lt;a href="https://byterivet.com" rel="noopener noreferrer"&gt;ByteRivet&lt;/a&gt;) that does 19 formats at any exact size, all in-browser. But the padding-without-corruption idea is the reusable part — worth knowing whenever you need a fixture at a precise size.&lt;/p&gt;

&lt;p&gt;What's the weirdest exact-size requirement you've hit in testing?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>How to Test File Upload Limits with Exact-Size Test Files</title>
      <dc:creator>Byte Rivet</dc:creator>
      <pubDate>Sun, 26 Jul 2026 01:28:17 +0000</pubDate>
      <link>https://dev.to/byterivet/how-to-test-file-upload-limits-with-exact-size-test-files-3foh</link>
      <guid>https://dev.to/byterivet/how-to-test-file-upload-limits-with-exact-size-test-files-3foh</guid>
      <description>&lt;p&gt;File upload testing often looks simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose a file.&lt;/li&gt;
&lt;li&gt;Upload it.&lt;/li&gt;
&lt;li&gt;Confirm that it works.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But a single successful upload does not prove that the validation is reliable.&lt;/p&gt;

&lt;p&gt;If an application accepts files up to 10 MB, the most useful test cases are not random files that are “around 10 MB.” You need files that sit directly around the configured boundary.&lt;/p&gt;

&lt;p&gt;For a decimal 10 MB limit, that may mean testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;9,999,999 bytes&lt;/li&gt;
&lt;li&gt;10,000,000 bytes&lt;/li&gt;
&lt;li&gt;10,000,001 bytes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three files can reveal whether the application handles its upload limit correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why exact file size matters
&lt;/h2&gt;

&lt;p&gt;Upload limits can be enforced at several different layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser-side JavaScript&lt;/li&gt;
&lt;li&gt;Application server&lt;/li&gt;
&lt;li&gt;Reverse proxy&lt;/li&gt;
&lt;li&gt;Web server&lt;/li&gt;
&lt;li&gt;API gateway&lt;/li&gt;
&lt;li&gt;Cloud storage service&lt;/li&gt;
&lt;li&gt;Database or object storage quota&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These layers may not use the same limit or even the same measurement system.&lt;/p&gt;

&lt;p&gt;For example, one part of the application may interpret 10 MB as 10,000,000 bytes, while another may treat it as 10 MiB, which equals 10,485,760 bytes.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://byterivet.com/" rel="noopener noreferrer"&gt;ByteRivet&lt;/a&gt; to make this workflow easier.&lt;/p&gt;

&lt;p&gt;That difference is large enough to produce inconsistent behavior.&lt;/p&gt;

&lt;p&gt;A file may pass client-side validation but fail after the upload begins. It may also be accepted by the application but rejected by a proxy before reaching the server.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnf16o8cxpiezdo2bgjhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnf16o8cxpiezdo2bgjhv.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A basic boundary testing strategy
&lt;/h2&gt;

&lt;p&gt;Assume your application has a maximum upload size of 10,000,000 bytes.&lt;/p&gt;

&lt;p&gt;Create three files:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
text
Below the limit: 9,999,999 bytes
At the limit:    10,000,000 bytes
Above the limit: 10,000,001 bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>webdev</category>
      <category>qa</category>
    </item>
  </channel>
</rss>
