πŸ“ HTTP Header Checker for File Preparation β€” The Case Study

When a five-person dev team at a mid-size SaaS company prepared to migrate 400GB of downloadable assets to a new CDN, they assumed the hard part would be the data transfer. It wasn't. The hard part was 11 HTTP header misconfigurations hiding in their origin server β€” each one capable of breaking downloads, corrupting file types, or poisoning the CDN cache. This is the story of how they found them all, fixed them all, and completed the migration with zero rollbacks β€” using the free HTTP Header Checker as their primary diagnostic tool.

πŸ”§ Open HTTP Header Checker β€” Free

πŸ‘₯ The Team, The Stack, The Migration

Maya is the team lead and backend engineer at CloudDesk, a SaaS company with 80,000 active users. Their platform serves downloadable assets β€” PDF reports, CSV exports, software installers (Windows .exe and macOS .dmg), product images, tutorial videos, and API documentation ZIP archives β€” from a legacy Nginx origin server to users in 40+ countries. The assets total roughly 400GB. The origin server sits in a single AWS region (us-east-1), and users in Europe, Asia, and South America report download speeds of 200-400 KB/s β€” sometimes timing out entirely for 2GB installer files.

The fix was obvious: migrate all downloadable assets behind CloudFront, AWS's CDN, with edge nodes in every region. The migration plan was straightforward: configure CloudFront distribution with the origin server as the source, update DNS to point asset URLs at the CloudFront domain, test, switch over, monitor. Estimated timeline: one week. The engineering lead signed off. Maya and her team started on Monday morning.

What they didn't know β€” what they couldn't know without auditing their HTTP response headers β€” was that 11 separate header misconfigurations had accumulated over four years on their origin server. Each one was invisible in normal operation (files still downloaded, albeit slowly). Each one would cause a different category of failure once the CDN was introduced β€” because CDNs read and respect HTTP headers with far greater rigor than direct origin-to-browser connections.

πŸ“… Monday, 9:00 AM β€” The Audit That Changed Everything

πŸ” Discovery: Maya runs the first header audit

Before touching the CloudFront configuration, Maya decided to audit the HTTP headers on a representative sample of their asset URLs. She knew from experience that CDN migrations expose header problems β€” wrong Content-Type headers, missing cache directives, incorrect Content-Disposition β€” that were "tolerated" by direct browser connections but break when a CDN intermediates. She opened the HTTP Header Checker and started pasting asset URLs.

"I figured I'd find maybe two or three minor issues β€” a missing Cache-Control on some old files, maybe a Content-Type mismatch on a legacy ZIP download. I did not expect to find eleven distinct header problems across five different file types. By the third URL, I realized we couldn't migrate anything until we fixed the origin headers."β€” Maya, Team Lead, CloudDesk

By 10:30 AM, Maya had audited 60 asset URLs β€” 10 samples from each of six file type categories. The HTTP Header Checker revealed 11 distinct header misconfigurations, grouped into five problem categories. Here is every problem, as Maya found it, and how the team fixed each one.

Problem 1–3 β€” FOUND: 9:14 AM

πŸ—‚οΈ Category 1: Wrong Content-Type Headers (3 problems)

Maya started with the PDF reports β€” the platform's most-downloaded asset type, with 12,000 downloads per month. She pasted a PDF URL into the HTTP Header Checker.

PROBLEM
URL: /reports/q4-2025-analytics.pdf
Content-Type: application/octet-stream
Expected: application/pdf

The origin server was serving every PDF with application/octet-stream β€” the generic "this is binary data" MIME type. Browsers downloading directly from the origin usually guessed the file type from the .pdf extension and opened it correctly. But CloudFront would treat application/octet-stream literally: no compression optimization, no byte-range support for partial downloads, no integration with CloudFront's PDF-specific edge features. Worse, CloudFront's cache key would be based on a generic content type, meaning all binary files β€” PDFs, ZIPs, DMGs, EXEs β€” would share cache entries, causing cache poisoning where a user requesting a PDF might receive a cached ZIP file with the same cache key.

Maya found the same problem on two more file types: SVG images served as text/plain (instead of image/svg+xml) and WebP images served as application/octet-stream (instead of image/webp). The WebP problem was particularly insidious β€” CloudFront has automatic WebP conversion for compatible clients, but it only activates when the origin correctly identifies the file as image/webp.

FIX
Updated Nginx mime.types to include correct MIME mappings for PDF (application/pdf), SVG (image/svg+xml), and WebP (image/webp). Verified all three with the HTTP Header Checker β€” each now returned the correct Content-Type.
Problem 4–5 β€” FOUND: 9:38 AM

πŸ“₯ Category 2: Missing Content-Disposition Headers (2 problems)

Next, Maya checked the software installer downloads β€” a Windows .exe and a macOS .dmg. Both downloaded correctly from the origin, but she knew CDNs handle Content-Disposition differently. She checked the headers.

PROBLEM
URL: /downloads/clouddesk-setup-3.7.2.exe
Content-Disposition: (missing entirely)
Impact: Browser may attempt to display binary files inline instead of downloading

Without a Content-Disposition: attachment; filename="clouddesk-setup-3.7.2.exe" header, browsers make their own decision about whether to display or download the file. Most browsers download .exe and .dmg files by default β€” but some corporate proxy environments and older browsers attempt to render unknown binary types inline, resulting in screens full of gibberish. The CDN wouldn't add this header on its own. Maya also found the same problem on the ZIP archives: no Content-Disposition header meant the browser might unzip and display the contents inline instead of prompting a download.

FIX
Added Nginx add_header Content-Disposition rules for .exe, .dmg, and .zip file extensions. Each rule specifies attachment and a dynamic filename extracted from the request URI. Verified all three file types now return correct Content-Disposition headers.
Problem 6–8 β€” FOUND: 10:02 AM

⚑ Category 3: Missing or Misconfigured Cache Headers (3 problems)

This was the category Maya was most worried about β€” and it proved to be the most damaging. She checked the Cache-Control headers on their highest-traffic assets: the product screenshots (PNG images loaded on the marketing site), the tutorial videos (MP4 files), and the API documentation ZIP archives.

PROBLEM
Product images (PNG): Cache-Control: no-cache
Tutorial videos (MP4): Cache-Control: (missing)
API docs (ZIP): Cache-Control: private, max-age=0

Three different cache misconfigurations, three different failure modes. The product images had no-cache β€” a leftover from a debugging session six months ago that nobody reverted. CloudFront would respect it: every image request would hit the origin, generating 40,000 unnecessary origin requests per day. The tutorial videos had no Cache-Control header at all β€” CloudFront would apply its default TTL (24 hours), which is far too short for video content that hasn't changed in two years. The API documentation ZIPs had private, max-age=0 β€” CloudFront wouldn't cache them at all, meaning every user who downloaded the 45MB ZIP file pulled it from the origin server in Virginia, even users in Tokyo and Frankfurt.

FIX
Set Cache-Control: public, max-age=31536000, immutable on all static assets (images, videos, installers). Set Cache-Control: public, max-age=86400 on ZIP archives (which update monthly). Added ETag headers (generated from file modification time) to enable conditional revalidation for ZIPs. Verified all headers with the HTTP Header Checker.
Problem 9–10 β€” FOUND: 10:17 AM

πŸ“ Category 4: Missing Content-Length and ETag Headers (2 problems)

Maya noticed that the HTTP Header Checker wasn't showing Content-Length headers on any of the large files β€” the software installers, the tutorial videos, the ZIP archives. This header tells the browser (and the CDN) exactly how many bytes to expect. Without it, the browser can't show a download progress bar, and the CDN can't verify it received the complete file from the origin.

She also noticed that ETag headers were missing on all assets β€” the origin was using chunked transfer encoding without generating entity tags. Without ETags, the CDN's conditional revalidation (If-None-Match requests) doesn't work, meaning every cache expiry triggers a full file download from the origin rather than a lightweight "has this changed?" check.

FIX
Disabled chunked transfer encoding for static file serving in Nginx (static files have known sizes at request time). Configured Nginx to generate ETags from file modification time and size. Verified both headers now appear on all asset responses using the HTTP Header Checker.
Problem 11 β€” FOUND: 10:28 AM

πŸ” Category 5: Missing Security Headers on Asset Domain (1 problem)

The final problem was subtle. Maya checked the security headers on the asset subdomain (assets.clouddesk.com) and found zero security headers β€” no Strict-Transport-Security, no X-Content-Type-Options. While these don't directly affect file downloads, their absence meant that if an attacker ever compromised the asset domain's DNS, they could serve malicious files over HTTP with no browser-level protection. The CDN migration was the right moment to add them.

FIX
Added Strict-Transport-Security: max-age=31536000; includeSubDomains and X-Content-Type-Options: nosniff to all responses on the asset subdomain. Verified with the HTTP Header Checker.

πŸ“… Tuesday–Wednesday β€” The Fix Sprint

Monday's audit took 90 minutes and revealed 11 problems. Tuesday and Wednesday were spent fixing them. Maya assigned one problem category to each team member: Content-Type fixes to Jason (the infrastructure engineer), Content-Disposition and security headers to Priya (the frontend engineer who owned the download UX), and cache + ETag headers to herself. By Wednesday afternoon, every fix was deployed to the origin server and verified with the HTTP Header Checker β€” each asset URL now returned correct, complete, CDN-ready headers.

The team also documented every fix in a shared "Asset Header Standard" document β€” a single source of truth for what headers every file type should have. This document became the reference for the CloudFront configuration and the ongoing CI/CD validation step.

πŸ“… Thursday β€” The Migration (Zero Rollbacks)

On Thursday morning, Maya configured the CloudFront distribution β€” point at the (now header-correct) origin, set cache behaviours per file type, enable automatic WebP conversion, enable byte-range requests for video, and configure the custom error responses. By 2:00 PM, DNS was updated. By 2:30 PM, traffic was flowing through CloudFront.

Maya ran the HTTP Header Checker against the CloudFront URLs to verify: Content-Type headers were correct, Cache-Control headers were propagating from the origin, CF-Cache-Status showed HIT on repeat requests, Content-Disposition headers forced downloads on installers, and Content-Length enabled progress bars. Everything checked out. The migration was complete β€” with zero rollbacks, zero broken downloads, and zero user complaints.

πŸ“Š The Outcome β€” By the Numbers

11Header problems found
and fixed pre-migration
0Migration rollbacks
or failed deployments
3.2Γ—Faster downloads
for non-US users

Time from first audit to completed migration: 4 days (vs. an estimated 7-day timeline that didn't include header fixes β€” and would have required 3+ days of rollback and debugging without the pre-migration audit). Ongoing impact: 87% reduction in origin server requests (from 68,000/day to 8,800/day). CDN cache hit ratio: 94.7%.

πŸ“‹ The File Preparation Header Checklist

Maya's team distilled their experience into this reusable checklist. Run it against any set of downloadable assets before a CDN migration, a server upgrade, or a new file hosting setup.

  1. 1Content-Type audit: Check every file type with the HTTP Header Checker. PDFs β†’ application/pdf. Images β†’ image/png, image/jpeg, image/webp, image/svg+xml. Videos β†’ video/mp4. Installers β†’ application/x-msdownload (.exe), application/x-apple-diskimage (.dmg). Archives β†’ application/zip. Never application/octet-stream for known file types.
  2. 2Content-Disposition check: Files that should download β†’ attachment; filename="...". Files that should display β†’ inline or omit the header.
  3. 3Cache-Control strategy: Immutable assets β†’ public, max-age=31536000, immutable. Changeable assets β†’ public, max-age=86400 with ETag.
  4. 4Content-Length presence: Every file should return Content-Length. Enables progress bars and CDN integrity verification.
  5. 5ETag or Last-Modified: At least one must be present for CDN conditional revalidation.
  6. 6Security baseline: HSTS and X-Content-Type-Options on the asset domain.
  7. 7CDN cache verification: After migration, check CF-Cache-Status (or equivalent) shows HIT on repeat requests.

πŸ”— Tools & Guides for File Preparation

❓ Frequently Asked Questions

What HTTP headers should I check before migrating downloadable files to a CDN?

Before migrating downloadable files to a CDN, audit five critical header categories on a representative sample of your assets: (1) Content-Type β€” every file must return the correct MIME type. PDFs must be application/pdf, not application/octet-stream. Images must be image/png or image/jpeg, not text/plain. Wrong Content-Type causes CDNs to mishandle files and browsers to render them incorrectly. (2) Content-Disposition β€” if you want files to download instead of display inline, you need Content-Disposition: attachment; filename="document.pdf". Without it, PDFs and images display in the browser tab rather than downloading. (3) Cache-Control β€” downloadable assets should use Cache-Control: public, max-age=31536000, immutable (cache for one year, never revalidate). Assets that rarely change benefit from maximum caching. (4) ETag or Last-Modified β€” enables conditional requests so CDNs can revalidate cached assets efficiently. (5) Content-Length β€” verifies the CDN received the complete file and enables download progress bars in browsers. The HTTP Header Checker shows all of these headers in one view for any asset URL. Check 20-30 representative files across different asset types before migration, and fix any header misconfigurations at the origin before they propagate through the CDN.

How do I ensure downloadable files have the correct Content-Type before pushing them to production?

Content-Type verification is the most critical pre-deployment check for downloadable files because incorrect Content-Type headers cause cascading failures: browsers render PDFs as garbled text, CDNs apply wrong compression, and download prompts fail to appear. To verify: (1) Identify every file type in your asset library β€” PDF, PNG, JPEG, GIF, SVG, WebP, MP4, ZIP, EXE, DMG, etc. (2) Look up the correct MIME type for each β€” IANA maintains the official registry. (3) Use the HTTP Header Checker to fetch headers for a sample of each file type and verify the Content-Type matches. Common problems: PDFs served as application/octet-stream (generic binary β€” browser doesn't know it's a PDF), SVG served as text/plain (renders as source code instead of graphics), WebP served as application/octet-stream (CDN won't transform or optimize it). (4) Fix incorrect Content-Types at the origin server or CDN configuration level before migration. The HTTP Header Checker makes this audit fast β€” check 30 asset URLs in under 5 minutes.

Why do my downloadable files open in the browser instead of downloading β€” and how do I fix it with headers?

Files open in the browser instead of downloading because the server is missing the Content-Disposition header or sending it with the wrong directive. When a server responds with a PDF, image, or text file and no Content-Disposition header, the browser makes its own decision β€” and most browsers default to displaying the file inline. To force a download: add Content-Disposition: attachment; filename="document.pdf" to the response headers. The 'attachment' directive tells the browser 'download this file, don't display it.' The filename parameter sets the default filename in the Save dialog. For files that should display inline (images in an tag, videos in a

What caching strategy should I use for downloadable files served through a CDN?

Downloadable files β€” PDFs, software installers, images, videos, static assets β€” should use the most aggressive caching strategy possible because they change rarely (if ever). The optimal header configuration is: Cache-Control: public, max-age=31536000, immutable. This tells every cache (browser, CDN, proxy) to store the file for one year and never revalidate it. The 'immutable' directive (supported by modern browsers and CDNs) prevents the browser from sending conditional revalidation requests even when the user clicks Refresh β€” saving a round trip on every page load that references the asset. For files that change occasionally (e.g., a monthly report PDF), use Cache-Control: public, max-age=86400 (24 hours) with an ETag or Last-Modified header for conditional revalidation. Pair aggressive caching with cache-busting filenames β€” when a file changes, change its URL (e.g., report-january-2026.pdf β†’ report-february-2026.pdf) rather than lowering the cache TTL. The HTTP Header Checker shows your current Cache-Control headers β€” verify they include 'public' and a max-age of at least 86400 for all downloadable assets.

How do I verify my CDN is correctly serving files from cache rather than hitting the origin on every request?

CDN cache verification requires checking three headers in the response: (1) The CDN's cache-status header β€” CF-Cache-Status for Cloudflare, X-Cache for Fastly and AWS CloudFront, X-Served-By for some CDNs. This header tells you whether the response was a HIT (served from CDN cache), MISS (fetched from origin), EXPIRED (cache entry existed but was stale), or BYPASS (CDN configured to bypass cache for this URL). (2) Age β€” the number of seconds the response has been cached in the CDN. A growing Age value confirms caching is working over time. (3) Cache-Control from the origin β€” the CDN respects the origin's Cache-Control directives. If your origin sends Cache-Control: no-store, the CDN won't cache regardless of CDN configuration. Use the HTTP Header Checker to fetch each asset URL and check all three headers. A CF-Cache-Status: HIT with Age > 0 and Cache-Control: public confirms the CDN is caching correctly. If you see MISS or BYPASS, investigate the origin's Cache-Control header and the CDN's caching rules.

πŸ” Audit Your File Headers Now β€” Free