✓ProveIt
Examples / Report #3973201 Saved analysis

CVE-2026-86412: server-set cookie erases cookie jar

curl · 2026-08-2722.1s analysis · $0.038 in model calls

What the report claims

A remote server can set a cookie that curl writes to a Netscape cookie jar but cannot reload, causing cleanup to overwrite the jar with an empty header and delete cookies for unrelated domains.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-86412 server-set cookie erases cookie jar

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

ProveIt's finding

Code supports the claim

The code supports the reported flaw. A maintainer should review its impact and decide what to do next.

Why this finding?
  • parse_cookie_header accepts 5000-byte headers (lib/cookie.c@curl-8_21_0:604-609) but get_netscape_format emits records with no length check (lib/cookie.c:1487-1511), allowing a 4999-byte record that the loader cannot reload (lib/cookie.c:1178 + lib/curl_get_line.c:56-63 effective limit 4998 bytes).
  • cookie_load sets ci->running = TRUE unconditionally at line 1211 even after CURLE_TOO_LARGE, so cleanup calls cookie_output with an empty store.
  • cookie_output atomically replaces the jar file (lib/cookie.c:1594), deleting all cookies including unrelated domains' cookies.
  • The flaw is reachable by a remote unauthenticated server via Set-Cookie header, causes persistent DoS and cross-domain data corruption, and is not listed in the project's 'not security issues' policy.
How this analysis ran 5 claims · 19 citations verified

Checked against curl master on 2026-08-27 (b73a4f00b2a6). 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
grounded
no model · 13 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2706 tokens · $0.0003
3 · Evidence
11 code snippets
real curl source at b73a4f00b2a6 · 4 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
25779 tokens · 17.0s · $0.0374
5 · Receipts
19 of 19 citations verified
every citation must point at code the judge was shown
Review a draft reply to the reporter

Edit and verify before sending.

Thank you for the detailed report and reproduction steps. The code confirms the inconsistency: parse_cookie_header accepts 5000-byte headers, get_netscape_format can write a 4999-byte record, but Curl_get_line's 5000-byte dynbuf (including NUL) only reloads 4998 bytes of payload. The unconditional ci->running = TRUE at lib/cookie.c:1211 lets cleanup overwrite the jar with an empty store. This is a valid security issue (remote DoS and persistent state corruption). We will address both the length mismatch and the running-flag-on-error.

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

Report claims

C1flaw supported

A remote HTTP server can set a cookie that curl accepts and writes to a Netscape cookie jar but cannot reload, leading to cleanup overwriting the jar with an empty header and deleting cookies for unrelated domains.

Read the reasoning

The code confirms the inconsistency: parse_cookie_header accepts 5000-byte headers, get_netscape_format can emit a 4999-byte record (plus newline = 5000 bytes in file), but Curl_get_line's 5000-byte dynbuf (including NUL) can only reload 4998 bytes of payload plus newline. A 4999-byte record exceeds this. The unconditional ci->running = TRUE at line 1211 lets cleanup call cookie_output with an empty store, overwriting the jar.

C2location supported

The flaw occurs in the cookie handling code, specifically in `parse_cookie_header()`, `get_netscape_format()`, and `cookie_load()` functions in lib/cookie.c.

Read the reasoning

All three functions cited by the report exist in lib/cookie.c and contain the described logic.

C3trigger supported

An attacker-controlled HTTP server sets a cookie whose fully serialized Netscape record exceeds the loader's 5000-byte dynbuf limit, causing `CURLE_TOO_LARGE` before any connection is made.

Read the reasoning

Cookie loading happens in Curl_pretransfer before connecting. A record that serializes to 4999 bytes (5000 with newline) exceeds the loader's effective 4998-byte payload limit, causing CURLE_TOO_LARGE before any network I/O.

C4impact supported

The failed load causes cleanup to replace the shared cookie jar with an empty header, permanently erasing cookies belonging to unrelated domains and causing availability loss and state corruption.

Read the reasoning

The failed load leaves ci->running = TRUE with an empty cookie store. Cleanup (via cookie_output) then writes an empty jar (header only), deleting all cookies including unrelated domains' cookies.

C5reproduction supported

Steps to reproduce involve setting a victim cookie, contacting an attacker server to set a poisoned cookie that serializes to 4999 bytes, then reloading the jar as both input and output, resulting in `CURLE_TOO_LARGE` and jar overwrite.

Read the reasoning

The reproduction steps follow the code path: attacker cookie accepted by parser (≤5000 bytes), serialized to 4999 bytes, written to jar, then reload fails at 4999 bytes (exceeds 4998-byte reload limit), CURLE_TOO_LARGE returned, but running=TRUE causes cleanup to overwrite jar with empty store. The 4998-byte control works because it fits the reload limit.

Read the original report (excerpt)

Full report on HackerOne ↗

## Summary A remote HTTP server can set a cookie that curl accepts and writes to a Netscape cookie jar but cannot reload. On the next invocation using the same path for `--cookie` and `--cookie-jar`, curl fails with `CURLE_TOO_LARGE` (100) before connecting, then cleanup replaces the jar with an empty 131-byte header, deleting cookies for unrelated domains. The root cause is an inconsistency between what `get_netscape_format()` can write and what `cookie_load()` can read, combined with `cookie_load()` unconditionally marking the store as running even after a load failure, which lets cleanup overwrite the jar from an incomplete store. ## Affected versions curl 8.18.0 through 8.21.0, plus affected 8.22.0 prerelease/development versions. ## Root cause `parse_cookie_header()` accepts a `Set-Cookie` value up to `MAX_COOKIE_LINE` (5000) bytes. `get_netscape_format()` then adds the domain, path, flags, expiry, and tab delimiters via `curl_maprintf` with no length check on the serialized record. A cookie with a 4094-byte name, value `v`, and `Path=/` followed by 870 `a` characters, set by a 16-byte host (`attacker.example`), serializes to a 4999-byte jar record. `cookie_load()` initializes a dynbuf with `MAX_COOKIE_LINE` (5000). The dynbuf limit includes the NUL terminator, and `Curl_get_line()` retains or appends a newline. So the maximum reloadable payload is 4998 bytes before the newline. A 4999-byte record does not fit and `Curl_get_line()` returns `CURLE_TOO_LARGE`. After the error, `cookie_load()` still sets `ci->running = TRUE` unconditionally (`lib/cookie.c:1211`). `Curl_pretransfer()` propagates the error and never starts a connection, but cleanup sees the cookie store as running and calls `cookie_output()`, which atomically replaces the configured jar with the partially loaded (empty) store. This bypasses the incomplete-store protection added for issue #18621 because the failed loader has already set the running flag. ## Security impact A remote, unauthenticated HTTP server can: 1. Prevent all later curl transfers that load the poisoned jar (`CURLE_TOO_LARGE` before any connection is made). 2. In the documented same-file `--cookie`/`--cookie-jar` workflow, permanently erase cookies belonging to unrelated domains. The impact is availability loss and persistent-state integrity corruption across domain boundaries. There is no confidentiality loss …

Source code

lib/cookie.clines 1141–1236 · lines 1211-1211 cited by the report; definition of cookie_load
C2: cookie_load definition
C1: cookie_load initializes dynbuf with MAX_COOKIE_LINE (5000) limit
C3: dynbuf limit of 5000 bytes in cookie_load
C5: loader's dynbuf limit creates the one-byte boundary
C1: cookie_load sets ci->running = TRUE unconditionally, even after CURLE_TOO_LARGE
C4: ci->running = TRUE set unconditionally after load error
C5: running flag set even on error enables destructive cleanup
lib/curl_get_line.clines 35–67 · definition of Curl_get_line
35CURLcode Curl_get_line(struct dynbuf *buf, FILE *input, bool *eof)
36{
37 CURLcode result;
38 char buffer[128];
39 curlx_dyn_reset(buf);
40 while(1) {
41 size_t rlen;
42 const char *b = fgets(buffer, sizeof(buffer), input);
43 if(!b && ferror(input))
44 return CURLE_READ_ERROR;
45
46 *eof = feof(input);
47
48 rlen = b ? strlen(b) : 0;
49 if(rlen) {
50 result = curlx_dyn_addn(buf, b, rlen);
51 if(result)
52 /* too long line or out of memory */
53 return result;
C3: Curl_get_line returns CURLE_TOO_LARGE when line exceeds dynbuf limit
54 }
55 /* now check the full line */
56 rlen = curlx_dyn_len(buf);
C1: Curl_get_line checks line length against dynbuf limit; limit includes NUL terminator and it appends newline on EOF, so max payload is 4998 bytes
57 b = curlx_dyn_ptr(buf);
58 if(rlen && (b[rlen - 1] == '\n'))
59 /* LF at end of the line */
60 return CURLE_OK; /* all good */
61 if(*eof)
62 /* append a newline */
63 return curlx_dyn_addn(buf, "\n", 1);
64 /* otherwise get next line to append */
65 }
66 /* UNREACHABLE */
67}
lib/transfer.c@curl-8_21_0lines 446–603 · definition of Curl_pretransfer as in release curl-8_21_0; differs from master; commits that changed it since: c8df3defd9 lib: new easy option string storage | 5406d2627c urldata: drop four strings from the aptr struct | 35843dd635 progress: cleanup, less memory
446CURLcode Curl_pretransfer(struct Curl_easy *data)
447{
448 CURLcode result = CURLE_OK;
449
450 /* Reset the retry count at the start of each request.
451 * If the retry count is not reset, when the connection drops,
452 * it will not enter the retry mechanism on CONN_MAX_RETRIES + 1 attempts
453 * and will immediately throw
454 * "Connection died, tried CONN_MAX_RETRIES times before giving up".
455 * By resetting it here, we ensure each new request starts fresh. */
456 data->state.retrycount = 0;
457
458 if(!data->set.str[STRING_SET_URL] && !data->set.uh) {
459 /* we cannot do anything without URL */
460 failf(data, "No URL set");
461 return CURLE_URL_MALFORMAT;
462 }
463
464 /* CURLOPT_CURLU overrides CURLOPT_URL and the contents of the CURLU handle
465 is allowed to be changed by the user between transfers */
466 if(data->set.uh) {
467 CURLUcode uc;
468 curlx_free(data->set.str[STRING_SET_URL]);
469 uc = curl_url_get(data->set.uh,
470 CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
471 if(uc) {
472 /* clear the pointer to not point to freed memory anymore */
473 Curl_bufref_set(&data->state.url, NULL, 0, NULL);
474 failf(data, "No URL set");
475 return CURLE_URL_MALFORMAT;
476 }
477 }
478
479 Curl_bufref_set(&data->state.url, data->set.str[STRING_SET_URL], 0, NULL);
480
481 if(data->set.postfields && data->set.set_resume_from) {
482 /* we cannot */
483 failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
484 return CURLE_BAD_FUNCTION_ARGUMENT;
485 }
486
487 data->state.prefer_ascii = data->set.prefer_ascii;
488#ifdef CURL_LIST_ONLY_PROTOCOL
489 data->state.list_only = data->set.list_only;
490#endif
491 data->state.httpreq = data->set.method;
492
493 /* initial transfer request coming up, forget the initial origin
494 * from a previous perform() on this handle. */
495 Curl_peer_unlink(&data->state.initial_origin);
496 Curl_peer_unlink(&data->state.origin);
497 data->state.requests = 0;
498 data->state.followlocation = 0; /* reset the location-follow counter */
499 data->state.this_is_a_follow = FALSE; /* reset this */
500 data->state.http_ignorecustom = FALSE; /* use custom HTTP method */
501 data->state.errorbuf = FALSE; /* no error has occurred */
502#ifndef CURL_DISABLE_HTTP
503 Curl_http_neg_init(data, &data->state.http_neg);
504#endif
505 data->state.authproblem = FALSE;
506 data->state.authhost.want = data->set.httpauth;
507 data->state.authproxy.want = data->set.proxyauth;
508 curlx_safefree(data->info.wouldredirect);
509 Curl_data_priority_clear_state(data);
510 if(data->set.http_auto_referer)
511 Curl_bufref_free(&data->state.referer);
512 if(data->set.str[STRING_SET_REFERER])
513 Curl_bufref_set(&data->state.referer, data->set.str[STRING_SET_REFERER],
514 0, NULL);
515 else
516 Curl_bufref_free(&data->state.referer);
517
518 if(data->state.httpreq == HTTPREQ_PUT)
519 data->state.infilesize = data->set.filesize;
520 else if((data->state.httpreq != HTTPREQ_GET) &&
521 (data->state.httpreq != HTTPREQ_HEAD)) {
522 data->state.infilesize = data->set.postfieldsize;
523 if(data->set.postfields && (data->state.infilesize == -1))
524 data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
525 }
526 else
527 data->state.infilesize = 0;
528
529 /* If there is a list of cookie files to read, do it now! */
C3: Curl_pretransfer calls Curl_cookie_loadfiles before any connection attempt
530 result = Curl_cookie_loadfiles(data);
531 if(!result)
532 Curl_cookie_run(data); /* activate */
533
534 /* If there is a list of host pairs to deal with */
535 if(!result && data->state.resolve)
536 result = Curl_loadhostpairs(data);
537
538 if(!result)
539 /* If there is a list of hsts files to read */
540 result = Curl_hsts_loadfiles(data);
541
542 if(!result) {
543 /* Allow data->set.use_port to set which port to use. This needs to be
544 * disabled for example when we follow Location: headers to URLs using
545 * different ports! */
546 data->state.allow_port = TRUE;
547
548#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(MSG_NOSIGNAL)
549 /*************************************************************
550 * Tell signal handler to ignore SIGPIPE
551 *************************************************************/
552 if(!data->set.no_signal)
553 data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
554#endif
555
556 Curl_initinfo(data); /* reset session-specific information "variables" */
557 Curl_pgrsResetTransferSizes(data);
558 Curl_pgrsStartNow(data);
559
560 /* In case the handle is reused and an authentication method was picked
561 in the session we need to make sure we only use the one(s) we now
562 consider to be fine */
563 data->state.authhost.picked &= data->state.authhost.want;
564 data->state.authproxy.picked &= data->state.authproxy.want;
565
566#ifndef CURL_DISABLE_FTP
567 data->state.wildcardmatch = data->set.wildcard_enabled;
568 if(data->state.wildcardmatch) {
569 struct WildcardData *wc;
570 if(!data->wildcard) {
571 data->wildcard = curlx_calloc(1, sizeof(struct WildcardData));
572 if(!data->wildcard)
573 return CURLE_OUT_OF_MEMORY;
574 }
575 wc = data->wildcard;
576 if(wc->state < CURLWC_INIT) {
577 if(wc->ftpwc)
578 wc->dtor(wc->ftpwc);
579 curlx_safefree(wc->pattern);
580 curlx_safefree(wc->path);
581 Curl_wildcard_init(wc); /* init wildcard structures */
582 }
583 }
584#endif
585 result = Curl_hsts_loadcb(data, data->hsts);
586 }
587
588 /*
589 * Set user-agent. Used for HTTP, but since we can attempt to tunnel
590 * anything through an HTTP proxy we cannot limit this based on protocol.
591 */
592 if(!result && data->set.str[STRING_USERAGENT]) {
593 curlx_free(data->state.aptr.uagent);
594 data->state.aptr.uagent =
595 curl_maprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
596 if(!data->state.aptr.uagent)
597 return CURLE_OUT_OF_MEMORY;
598 }
599
600 data->req.headerbytecount = 0;
601 Curl_headers_cleanup(data);
602 return result;
603}
lib/cookie.clines 1521–1616 · definition of cookie_output
C1: cookie_output writes the store (empty after failed load) to the jar, overwriting it
C4: cookie_output writes whatever is in the store; after failed load the store is empty
C4: cookie_output atomically renames tempstore over the original jar file
lib/cookie.clines 1487–1511 · definition of get_netscape_format
C1: get_netscape_format serializes cookies with no length check on the output record
C2: get_netscape_format definition
C5: get_netscape_format can produce records up to the parser's limit
lib/cookie.c@curl-8_21_0lines 590–668 · definition of parse_cookie_header as in release curl-8_21_0; differs from master; commits that changed it since: 4f6aa41a01 cookie: improve TAB handling
C2: parse_cookie_header definition
C1: parse_cookie_header accepts lines up to MAX_COOKIE_LINE (5000) bytes
C5: parse_cookie_header accepts 5000-byte header lines
lib/transfer.clines 442–592 · definition of Curl_pretransfer
Show 151 lines (not cited by the judge)
442CURLcode Curl_pretransfer(struct Curl_easy *data)
443{
444 CURLcode result = CURLE_OK;
445
446 /* Reset the retry count at the start of each request.
447 * If the retry count is not reset, when the connection drops,
448 * it will not enter the retry mechanism on CONN_MAX_RETRIES + 1 attempts
449 * and will immediately throw
450 * "Connection died, tried CONN_MAX_RETRIES times before giving up".
451 * By resetting it here, we ensure each new request starts fresh. */
452 data->state.retrycount = 0;
453
454 if(!CURL_EASY_STR(data, STRING_SET_URL) && !data->set.uh) {
455 /* we cannot do anything without URL */
456 failf(data, "No URL set");
457 return CURLE_URL_MALFORMAT;
458 }
459
460 /* CURLOPT_CURLU overrides CURLOPT_URL and the contents of the CURLU handle
461 is allowed to be changed by the user between transfers */
462 if(data->set.uh) {
463 char *url = NULL;
464 CURLUcode uc;
465 uc = curl_url_get(data->set.uh, CURLUPART_URL, &url, 0);
466 if(uc) {
467 /* clear the pointer to not point to freed memory anymore */
468 Curl_bufref_set(&data->state.url, NULL, 0, NULL);
469 failf(data, "No URL set");
470 return CURLE_URL_MALFORMAT;
471 }
472 result = CURL_EASY_STR_SETN(data, STRING_SET_URL, url);
473 if(result)
474 return result;
475 }
476
477 Curl_bufref_set(&data->state.url, CURL_EASY_STR(data, STRING_SET_URL),
478 0, NULL);
479
480 if(data->set.postfields && data->set.set_resume_from) {
481 /* we cannot */
482 failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
483 return CURLE_BAD_FUNCTION_ARGUMENT;
484 }
485
486 data->state.prefer_ascii = data->set.prefer_ascii;
487#ifdef CURL_LIST_ONLY_PROTOCOL
488 data->state.list_only = data->set.list_only;
489#endif
490 data->state.httpreq = data->set.method;
491
492 /* initial transfer request coming up, forget the initial origin
493 * from a previous perform() on this handle. */
494 Curl_peer_unlink(&data->state.initial_origin);
495 Curl_peer_unlink(&data->state.origin);
496 data->state.requests = 0;
497 data->state.followlocation = 0; /* reset the location-follow counter */
498 data->state.this_is_a_follow = FALSE; /* reset this */
499 data->state.http_ignorecustom = FALSE; /* use custom HTTP method */
500 data->state.errorbuf = FALSE; /* no error has occurred */
501#ifndef CURL_DISABLE_HTTP
502 Curl_http_neg_init(data, &data->state.http_neg);
503#endif
504 data->state.authproblem = FALSE;
505 data->state.authhost.want = data->set.httpauth;
506 data->state.authproxy.want = data->set.proxyauth;
507 curlx_safefree(data->info.wouldredirect);
508 Curl_data_priority_clear_state(data);
509 if(data->set.http_auto_referer)
510 Curl_bufref_free(&data->state.referer);
511 if(CURL_EASY_STR(data, STRING_SET_REFERER))
512 Curl_bufref_set(&data->state.referer,
513 CURL_EASY_STR(data, STRING_SET_REFERER), 0, NULL);
514 else
515 Curl_bufref_free(&data->state.referer);
516
517 if(data->state.httpreq == HTTPREQ_PUT)
518 data->state.infilesize = data->set.filesize;
519 else if((data->state.httpreq != HTTPREQ_GET) &&
520 (data->state.httpreq != HTTPREQ_HEAD)) {
521 data->state.infilesize = data->set.postfieldsize;
522 if(data->set.postfields && (data->state.infilesize == -1))
523 data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
524 }
525 else
526 data->state.infilesize = 0;
527
528 /* If there is a list of cookie files to read, do it now! */
529 result = Curl_cookie_loadfiles(data,
530 data->set.cookiesession ?
531 COOKIE_NOSESSION : 0);
532 if(!result)
533 Curl_cookie_run(data); /* activate */
534
535 /* If there is a list of host pairs to deal with */
536 if(!result && data->state.resolve)
537 result = Curl_loadhostpairs(data);
538
539 if(!result)
540 /* If there is a list of hsts files to read */
541 result = Curl_hsts_loadfiles(data);
542
543 if(!result) {
544 /* Allow data->set.use_port to set which port to use. This needs to be
545 * disabled for example when we follow Location: headers to URLs using
546 * different ports! */
547 data->state.allow_port = TRUE;
548
549#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(MSG_NOSIGNAL)
550 /*************************************************************
551 * Tell signal handler to ignore SIGPIPE
552 *************************************************************/
553 if(!data->set.no_signal)
554 data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
555#endif
556
557 Curl_initinfo(data); /* reset session-specific information "variables" */
558 Curl_pgrsResetTransferSizes(data);
559 Curl_pgrsStart(data, NULL);
560
561 /* In case the handle is reused and an authentication method was picked
562 in the session we need to make sure we only use the one(s) we now
563 consider to be fine */
564 data->state.authhost.picked &= data->state.authhost.want;
565 data->state.authproxy.picked &= data->state.authproxy.want;
566
567#ifndef CURL_DISABLE_FTP
568 data->state.wildcardmatch = data->set.wildcard_enabled;
569 if(data->state.wildcardmatch) {
570 struct WildcardData *wc;
571 if(!data->wildcard) {
572 data->wildcard = curlx_calloc(1, sizeof(struct WildcardData));
573 if(!data->wildcard)
574 return CURLE_OUT_OF_MEMORY;
575 }
576 wc = data->wildcard;
577 if(wc->state < CURLWC_INIT) {
578 if(wc->ftpwc)
579 wc->dtor(wc->ftpwc);
580 curlx_safefree(wc->pattern);
581 curlx_safefree(wc->path);
582 Curl_wildcard_init(wc); /* init wildcard structures */
583 }
584 }
585#endif
586 result = Curl_hsts_loadcb(data, data->hsts);
587 }
588
589 data->req.headerbytecount = 0;
590 Curl_headers_cleanup(data);
591 return result;
592}
lib/cookie.hlines 81–81 · definition of MAX_COOKIE_LINE
Show 1 lines (not cited by the judge)
81#define MAX_COOKIE_LINE 5000
lib/cookie.c@curl-8_21_0lines 1129–1200 · definition of cookie_load as in release curl-8_21_0; differs from master; commits that changed it since: c04189523c cookie: refuse to load cookies set against a PSL domain
Show 72 lines (not cited by the judge)
1129static CURLcode cookie_load(struct Curl_easy *data, const char *file,
1130 struct CookieInfo *ci, bool newsession)
1131{
1132 FILE *handle = NULL;
1133 CURLcode result = CURLE_OK;
1134 FILE *fp = NULL;
1135 DEBUGASSERT(ci);
1136 DEBUGASSERT(data);
1137 DEBUGASSERT(file);
1138
1139 ci->newsession = newsession; /* new session? */
1140 ci->running = FALSE; /* this is not running, this is init */
1141
1142 if(file && *file) {
1143 if(!strcmp(file, "-"))
1144 fp = stdin;
1145 else {
1146 fp = curlx_fopen(file, "rb");
1147 if(!fp)
1148 infof(data, "WARNING: failed to open cookie file \"%s\"", file);
1149 else {
1150 curlx_struct_stat stat;
1151 if((curlx_fstat(fileno(fp), &stat) != -1) && S_ISDIR(stat.st_mode)) {
1152 curlx_fclose(fp);
1153 fp = NULL;
1154 infof(data, "WARNING: cookie filename points to a directory: \"%s\"",
1155 file);
1156 }
1157 else
1158 handle = fp;
1159 }
1160 }
1161 }
1162
1163 if(fp) {
1164 struct dynbuf buf;
1165 bool eof = FALSE;
1166 curlx_dyn_init(&buf, MAX_COOKIE_LINE);
1167 do {
1168 result = Curl_get_line(&buf, fp, &eof);
1169 if(!result) {
1170 const char *lineptr = curlx_dyn_ptr(&buf);
1171 bool headerline = FALSE;
1172 if(checkprefix("Set-Cookie:", lineptr)) {
1173 /* This is a cookie line, get it! */
1174 lineptr += 11;
1175 headerline = TRUE;
1176 curlx_str_passblanks(&lineptr);
1177 }
1178
1179 result = Curl_cookie_add(data, ci, headerline, TRUE, lineptr, NULL,
1180 NULL, TRUE);
1181 /* File reading cookie failures are not propagated back to the
1182 caller because there is no way to do that */
1183 }
1184 } while(!result && !eof);
1185 curlx_dyn_free(&buf); /* free the line buffer */
1186
1187 /*
1188 * Remove expired cookies from the hash. We must make sure to run this
1189 * after reading the file, and not on every cookie.
1190 */
1191 remove_expired(ci);
1192
1193 if(handle)
1194 curlx_fclose(handle);
1195 }
1196 data->state.cookie_engine = TRUE;
1197 ci->running = TRUE; /* now, we are running */
1198
1199 return result;
1200}
lib/mprintf.clines 1184–1192 · definition of curl_maprintf
Show 9 lines (not cited by the judge)
1184char *curl_maprintf(const char *format, ...)
1185{
1186 va_list args;
1187 char *s;
1188 va_start(args, format);
1189 s = curl_mvaprintf(format, args);
1190 va_end(args);
1191 return s;
1192}
lib/cookie.clines 587–665 · definition of parse_cookie_header
Show 79 lines (not cited by the judge)
587static CURLcode
588parse_cookie_header(struct Curl_easy *data,
589 struct Cookie *co,
590 const struct CookieInfo *ci,
591 bool *okay, /* if the cookie was fine */
592 const char *ptr, /* the header */
593 const char *domain, /* default domain */
594 /* full path used when this cookie is set */
595 const char *path,
596 bool secure_origin)
597{
598 /* This line was read off an HTTP-header */
599 time_t now = 0;
600 size_t linelength = strlen(ptr);
601 CURLcode result = CURLE_OK;
602 struct Curl_str cookie[COOKIE_PIECES];
603 *okay = FALSE;
604 if(linelength > MAX_COOKIE_LINE)
605 /* discard overly long lines at once */
606 return CURLE_OK;
607
608 /* memset instead of initializer because gcc 4.8.1 is silly */
609 memset(cookie, 0, sizeof(cookie));
610 do {
611 struct Curl_str name;
612
613 /* we have a <name>=<value> pair or a stand-alone word here */
614 if(!curlx_str_cspn(&ptr, &name, ";\r\n=")) {
615 struct Curl_str val;
616 bool sep = FALSE;
617 curlx_str_trimblanks(&name);
618
619 if(invalid_octets(curlx_str(&name), curlx_strlen(&name))) {
620 infof(data, "invalid octets in name, cookie dropped");
621 return CURLE_OK;
622 }
623
624 if(!curlx_str_single(&ptr, '=')) {
625 sep = TRUE; /* a '=' was used */
626 if(!curlx_str_cspn(&ptr, &val, ";\r\n"))
627 curlx_str_trimblanks(&val);
628
629 if(invalid_octets(curlx_str(&val), curlx_strlen(&val))) {
630 infof(data, "invalid octets in value, cookie dropped");
631 return CURLE_OK;
632 }
633 }
634 else
635 curlx_str_init(&val);
636
637 if(!curlx_strlen(&cookie[COOKIE_NAME])) {
638 if(!parse_first_pair(data, co, cookie, &name, &val, sep))
639 return CURLE_OK;
640 }
641 else if(!sep) {
642 if(!parse_flag(data, co, ci, &name, secure_origin))
643 return CURLE_OK;
644 }
645 else if(curlx_str_casecompare(&name, "path"))
646 cookie[COOKIE_PATH] = val;
647 else if(curlx_str_casecompare(&name, "domain") && curlx_strlen(&val)) {
648 if(!parse_domain(data, co, &cookie[COOKIE_DOMAIN], &val, &domain))
649 return CURLE_OK;
650 }
651 else if(curlx_str_casecompare(&name, "max-age") && curlx_strlen(&val))
652 parse_maxage(co, &val, &now);
653 else if(curlx_str_casecompare(&name, "expires") && curlx_strlen(&val))
654 parse_expires(co, &val, &now);
655 }
656 } while(!curlx_str_single(&ptr, ';'));
657
658 if(curlx_strlen(&cookie[COOKIE_NAME])) {
659 /* the header was fine, now store the data */
660 result = storecookie(co, &cookie[0], path, domain);
661 if(!result)
662 *okay = TRUE;
663 }
664 return result;
665}