Skip to content

Commit bfe29f2

Browse files
authored
Merge pull request #41 from negrutiu/feature/GH-40-cookies
Feature/gh 40 cookies
2 parents c3f016b + c5be317 commit bfe29f2

File tree

5 files changed

+182
-58
lines changed

5 files changed

+182
-58
lines changed

src/nscurl/NScurl.readme.md

+8
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ Examples:
157157
> [!note]
158158
> DoH server is used for the current transfer only, it's not a global setting
159159
160+
### /COOKIEJAR
161+
```
162+
/COOKIEJAR "filepath"
163+
```
164+
Specify a custom file where libcurl stores cookies.
165+
By default `$PLUGINSDIR\cookies.txt` is used.
166+
Specifying an empty string disables cookie engine.
167+
160168
### /TIMEOUT
161169
### /CONNECTTIMEOUT
162170
```

src/nscurl/curl.c

+70-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,64 @@ CURL_GLOBALS g_Curl = {0};
2121
//x #define DEBUG_TRANSFER_SLOWDOWN 50 /// Delays during transfer
2222

2323

24+
void CurlRequestInit(_Inout_ PCURL_REQUEST pReq)
25+
{
26+
if (!pReq) return;
27+
ZeroMemory(pReq, sizeof(*pReq));
28+
pReq->Runtime.iRootCertFlags = (ULONG)-1; // Uninitialized
29+
pReq->bCastore = TRUE;
30+
{
31+
TCHAR buffer[MAX_PATH];
32+
_sntprintf(buffer, ARRAYSIZE(buffer), _T("%s\\cookies.txt"), getuservariableEx(INST_PLUGINSDIR));
33+
pReq->pszCookieFile = MyStrDup(eT2A, buffer);
34+
}
35+
}
36+
37+
void CurlRequestDestroy(_Inout_ PCURL_REQUEST pReq)
38+
{
39+
if (!pReq) return;
40+
MyFree(pReq->pszURL);
41+
MyFree(pReq->pszPath);
42+
MyFree(pReq->pszMethod);
43+
MyFree(pReq->pszProxy);
44+
MyFree(pReq->pszProxyUser);
45+
MyFree(pReq->pszProxyPass);
46+
MyFree(pReq->pszUser);
47+
MyFree(pReq->pszPass);
48+
MyFree(pReq->pszTlsUser);
49+
MyFree(pReq->pszTlsPass);
50+
curl_slist_free_all(pReq->pOutHeaders);
51+
curl_slist_free_all(pReq->pPostVars);
52+
IDataDestroy(&pReq->Data);
53+
MyFree(pReq->pszAgent);
54+
MyFree(pReq->pszReferrer);
55+
curl_slist_free_all(pReq->pCertList);
56+
curl_slist_free_all(pReq->pPemList);
57+
MyFree(pReq->pszCacert);
58+
MyFree(pReq->pszDebugFile);
59+
MyFree(pReq->pszTag);
60+
MyFree(pReq->pszDOH);
61+
MyFree(pReq->pszCookieFile);
62+
pReq->Runtime.pCurl = NULL;
63+
if (MyValidHandle(pReq->Runtime.hInFile))
64+
CloseHandle(pReq->Runtime.hInFile);
65+
if (MyValidHandle(pReq->Runtime.hOutFile))
66+
CloseHandle(pReq->Runtime.hOutFile);
67+
if (MyValidHandle(pReq->Runtime.hDebugFile))
68+
CloseHandle(pReq->Runtime.hDebugFile);
69+
VirtualMemoryDestroy(&pReq->Runtime.InHeaders);
70+
VirtualMemoryDestroy(&pReq->Runtime.OutHeaders);
71+
VirtualMemoryDestroy(&pReq->Runtime.OutData);
72+
MyFree(pReq->Runtime.pszFinalURL);
73+
MyFree(pReq->Runtime.pszServerIP);
74+
MyFree(pReq->Error.pszWin32);
75+
MyFree(pReq->Error.pszCurl);
76+
MyFree(pReq->Error.pszX509);
77+
MyFree(pReq->Error.pszHttp);
78+
ZeroMemory(pReq, sizeof(*pReq));
79+
}
80+
81+
2482
//+ CurlRequestComputeNumbers
2583
void CurlRequestComputeNumbers( _In_ PCURL_REQUEST pReq, _Out_opt_ PULONG64 piSizeTotal, _Out_opt_ PULONG64 piSizeXferred, _Out_opt_ PSHORT piPercent, _Out_opt_ PBOOL pbDown )
2684
{
@@ -548,6 +606,12 @@ ULONG CurlParseRequestParam( _In_ ULONG iParamIndex, _In_ LPTSTR pszParam, _In_
548606
if (*pszParam)
549607
pReq->pszDOH = MyStrDup( eT2A, pszParam );
550608
}
609+
} else if (lstrcmpi( pszParam, _T( "/COOKIEJAR" ) ) == 0) {
610+
if (popstring( pszParam ) == NOERROR) {
611+
MyFree( pReq->pszCookieFile );
612+
if (pszParam && pszParam[0])
613+
pReq->pszCookieFile = MyStrDup( eT2A, pszParam );
614+
}
551615
} else if (lstrcmpi( pszParam, _T( "/ENCODING" ) ) == 0 || lstrcmpi( pszParam, _T( "/accept-encoding" ) ) == 0) {
552616
pReq->bEncoding = TRUE;
553617
} else {
@@ -1126,6 +1190,11 @@ void CurlTransfer( _In_ PCURL_REQUEST pReq )
11261190
if (pReq->pszDOH)
11271191
curl_easy_setopt( curl, CURLOPT_DOH_URL, pReq->pszDOH );
11281192

1193+
if (pReq->pszCookieFile && pReq->pszCookieFile[0]) {
1194+
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, pReq->pszCookieFile); // request cookies
1195+
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, pReq->pszCookieFile); // response cookies
1196+
}
1197+
11291198
if (pReq->bEncoding && !pReq->bResume && lstrcmpi(pReq->pszPath, FILENAME_MEMORY) != 0)
11301199
curl_easy_setopt( curl, CURLOPT_ACCEPT_ENCODING, "" ); // Send Accept-Encoding header with all supported encodings
11311200

@@ -1441,8 +1510,7 @@ void CurlTransfer( _In_ PCURL_REQUEST pReq )
14411510
}
14421511

14431512
// Cleanup
1444-
curl_easy_reset( curl );
1445-
curl_easy_cleanup( curl ); // TODO: Return to cache
1513+
curl_easy_cleanup( curl );
14461514
}
14471515

14481516
curl_mime_free( form );

src/nscurl/curl.h

+4-47
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ typedef struct _CURL_REQUEST {
5858
ULONG iDependencyId; /// can be 0. This request will not be carried out until its dependency completes
5959
LPCSTR pszTag; /// can be NULL
6060
LPCSTR pszDOH; /// can be NULL. DNS-over-HTTPS server (e.g. "https://1.1.1.1/dns-query")
61+
LPCSTR pszCookieFile;
6162
struct {
6263
struct _CURL_REQUEST* pNext; /// Singly linked list
6364
ULONG iId; /// Unique ID
@@ -103,56 +104,12 @@ typedef struct _CURL_REQUEST {
103104
} Error;
104105
} CURL_REQUEST, *PCURL_REQUEST;
105106

107+
106108
//+ CurlRequestInit
107-
static void CurlRequestInit( _Inout_ PCURL_REQUEST pReq ) {
108-
if (!pReq) return;
109-
ZeroMemory( pReq, sizeof( *pReq ) );
110-
pReq->Runtime.iRootCertFlags = (ULONG)-1; // Uninitialized
111-
pReq->bCastore = TRUE;
112-
}
109+
void CurlRequestInit( _Inout_ PCURL_REQUEST pReq );
113110

114111
//+ CurlRequestDestroy
115-
static void CurlRequestDestroy( _Inout_ PCURL_REQUEST pReq ) {
116-
if (!pReq) return;
117-
MyFree( pReq->pszURL );
118-
MyFree( pReq->pszPath );
119-
MyFree( pReq->pszMethod );
120-
MyFree( pReq->pszProxy );
121-
MyFree( pReq->pszProxyUser );
122-
MyFree( pReq->pszProxyPass );
123-
MyFree( pReq->pszUser );
124-
MyFree( pReq->pszPass );
125-
MyFree( pReq->pszTlsUser );
126-
MyFree( pReq->pszTlsPass );
127-
curl_slist_free_all( pReq->pOutHeaders );
128-
curl_slist_free_all( pReq->pPostVars );
129-
IDataDestroy( &pReq->Data );
130-
MyFree( pReq->pszAgent );
131-
MyFree( pReq->pszReferrer );
132-
curl_slist_free_all( pReq->pCertList );
133-
curl_slist_free_all( pReq->pPemList );
134-
MyFree( pReq->pszCacert );
135-
MyFree( pReq->pszDebugFile );
136-
MyFree( pReq->pszTag );
137-
MyFree( pReq->pszDOH );
138-
pReq->Runtime.pCurl = NULL;
139-
if (MyValidHandle( pReq->Runtime.hInFile ))
140-
CloseHandle( pReq->Runtime.hInFile );
141-
if (MyValidHandle( pReq->Runtime.hOutFile ))
142-
CloseHandle( pReq->Runtime.hOutFile );
143-
if (MyValidHandle( pReq->Runtime.hDebugFile ))
144-
CloseHandle( pReq->Runtime.hDebugFile );
145-
VirtualMemoryDestroy( &pReq->Runtime.InHeaders );
146-
VirtualMemoryDestroy( &pReq->Runtime.OutHeaders );
147-
VirtualMemoryDestroy( &pReq->Runtime.OutData );
148-
MyFree( pReq->Runtime.pszFinalURL );
149-
MyFree( pReq->Runtime.pszServerIP );
150-
MyFree( pReq->Error.pszWin32 );
151-
MyFree( pReq->Error.pszCurl );
152-
MyFree( pReq->Error.pszX509 );
153-
MyFree( pReq->Error.pszHttp );
154-
ZeroMemory( pReq, sizeof( *pReq ) );
155-
}
112+
void CurlRequestDestroy( _Inout_ PCURL_REQUEST pReq );
156113

157114
//+ CurlRequestSetAbortFlag
158115
#define CurlRequestSetAbortFlag( pReq ) \

tests/NScurl-Debug.nsi

+36
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,42 @@ Section "httpbin.org/get"
206206
SectionEnd
207207

208208

209+
Section "httpbun.com/cookies/set"
210+
SectionIn ${INSTTYPE_MOST}
211+
DetailPrint '=====[ ${__SECTION__} ]==============================='
212+
213+
!insertmacro STACK_VERIFY_START
214+
!define /redef LINK 'https://httpbun.com/cookies/set?cookie1=value1&cookie2=value2'
215+
!define /redef FILE '$EXEDIR\_GET_httpbun_cookies_set'
216+
!define /redef JAR '$EXEDIR\_GET_httpbun_cookiejar.txt'
217+
DetailPrint 'NScurl::http "${LINK}" "${FILE}"'
218+
219+
Push "/END"
220+
221+
; Push "${FILE}.md"
222+
; Push /DEBUG
223+
224+
Push "${JAR}"
225+
Push "/COOKIEJAR"
226+
227+
Push "${FILE}"
228+
Push "${LINK}"
229+
Push "GET"
230+
CallInstDLL $DLL http
231+
Pop $0
232+
233+
${If} ${FileExists} "${JAR}"
234+
StrCpy $1 "OK (file exists)"
235+
${Else}
236+
StrCpy $1 "FAIL (not found: ${JAR})"
237+
${EndIf}
238+
239+
DetailPrint "Status: $0"
240+
DetailPrint "Cookie jar: $1"
241+
!insertmacro STACK_VERIFY_END
242+
SectionEnd
243+
244+
209245
Section "sysinternals.com/get (Page-Mode)"
210246
SectionIn ${INSTTYPE_MOST}
211247
DetailPrint '=====[ ${__SECTION__} ]==============================='

tests/NScurl-Test.nsi

+64-9
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,29 @@ Section "httpbin.org/get"
149149
SectionEnd
150150

151151

152+
Section "httpbun.com/cookies/set"
153+
SectionIn ${INSTTYPE_MOST}
154+
DetailPrint '=====[ ${__SECTION__} ]==============================='
155+
156+
!define /redef LINK 'https://httpbun.com/cookies/set?cookie1=value1&cookie2=value2'
157+
!define /redef FILE '$EXEDIR\_GET_httpbun_cookies_set'
158+
!define /redef JAR '$EXEDIR\_GET_httpbun_cookiejar.txt'
159+
DetailPrint 'NScurl::http "${LINK}" "${FILE}"'
160+
161+
NScurl::http get "${LINK}" "${FILE}" /COOKIEJAR "${JAR}" /END
162+
Pop $0
163+
164+
${If} ${FileExists} "${JAR}"
165+
StrCpy $1 "OK (file exists)"
166+
${Else}
167+
StrCpy $1 "FAIL (not found: ${JAR})"
168+
${EndIf}
169+
170+
DetailPrint "Status: $0"
171+
DetailPrint "Cookie jar: $1"
172+
SectionEnd
173+
174+
152175
Section "sysinternals.com/get (Page-Mode)"
153176
SectionIn ${INSTTYPE_MOST}
154177
DetailPrint '=====[ ${__SECTION__} ]==============================='
@@ -416,10 +439,10 @@ SectionGroup /e "Tests"
416439
; Valid to: ‎Sunday, ‎August ‎9, ‎2026 7:09:21 PM
417440
!define BADSSL_SELFSIGNED_CRT \
418441
"-----BEGIN CERTIFICATE-----$\n\
419-
MIIDeTCCAmGgAwIBAgIJAPhNZrCAQp0/MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV$\n\
442+
MIIDeTCCAmGgAwIBAgIJALfFORhDXiFeMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV$\n\
420443
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp$\n\
421444
c2NvMQ8wDQYDVQQKDAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTAeFw0y$\n\
422-
NDA4MjAxNjI0NDVaFw0yNjA4MjAxNjI0NDVaMGIxCzAJBgNVBAYTAlVTMRMwEQYD$\n\
445+
NDEyMTkyMTAzMzNaFw0yNjEyMTkyMTAzMzNaMGIxCzAJBgNVBAYTAlVTMRMwEQYD$\n\
423446
VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQK$\n\
424447
DAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEB$\n\
425448
BQADggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2$\n\
@@ -429,15 +452,15 @@ xPxTuW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqve$\n\
429452
ww9HdFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SY$\n\
430453
QCeFxxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaMyMDAwCQYDVR0T$\n\
431454
BAIwADAjBgNVHREEHDAaggwqLmJhZHNzbC5jb22CCmJhZHNzbC5jb20wDQYJKoZI$\n\
432-
hvcNAQELBQADggEBAF9F2x4tuIATEa5jZY86nEaa3Py2Rd0tjNywlryS1TKXWIqu$\n\
433-
yim+0HpNU/R6cpkN1MZ1iN7dUKTtryLJIAXgaZC1TC6sRyuOMzV/rDHShT3WY0MW$\n\
434-
+/sebaJZ4kkLUzQ1k5/FW/AmZ3su739vLQbcEEfn7UUK5cdRgcqEHA4SePhq5zQX$\n\
435-
5/FSILsStpu+9hZ6OGxVdLVWKOM5GZ8LCXw3cJCNbJvW1APCz+3bP3bGBANeCUJp$\n\
436-
gt0b83u4YBs1t66ZV/rcDQiyQzjAY6th2UfRggZxeIRDO7qbRa+M0pVW3qugMytf$\n\
437-
bPw02aMbgH96rX61u0sd1M0slJHFEeqquqbtPcU=$\n\
455+
hvcNAQELBQADggEBAITHC93SNagVrwUX41aUUJlIg6s+E8LXGZIP77HGSd48R1zS$\n\
456+
+xPQcs2OKJaFESRZTJFgZ+wyPW3VhLm/ObYKbQiqmXc7W91nne+mywOF8cxcOoNw$\n\
457+
BDkVACyN36A6Bm42zTVdf0CYQR2d4pnI1LzWsGSQVRh+oCnrapxbmmI105rgJ3q5$\n\
458+
3RRcFPuKDdycqXgCCem8Zmg+Pq4XWZlbcCk1jts1TbFjUmr9G7lBV7cUu3XurbK9$\n\
459+
6xiRwFqPA/1qwLgyEXwUlsJ63D1GwRNa9N8ynfLvtE3bhE+oGk3xPL2sQN8HMYVw$\n\
460+
NKDIcX/Eu+lJjdcg3xu8Ym/V8P/s/frahpF4Q1A=$\n\
438461
-----END CERTIFICATE-----"
439462

440-
!define BADSSL_SELFSIGNED_THUMBPRINT '8577cec7988ad89d72400f5933988221984e3009'
463+
!define BADSSL_SELFSIGNED_THUMBPRINT '6e3df5d84de941e0b4c3d5f0788b7e0bfc0d42bf'
441464

442465

443466
Var /global testCacertName
@@ -678,6 +701,38 @@ Section "Weak protocols"
678701
SectionEnd
679702

680703

704+
Section "Cookie jar"
705+
SectionIn ${INSTTYPE_MOST}
706+
DetailPrint '=====[ ${__SECTION__} ]==============================='
707+
708+
!define /redef LINK 'https://httpbun.com/cookies/set?cookie1=value1&cookie2=value2'
709+
!define /redef FILE '$EXEDIR\_test_cookiejar_body'
710+
!define /redef JAR '$EXEDIR\_test_cookiejar.txt'
711+
712+
Delete "${JAR}"
713+
714+
DetailPrint 'NScurl::http "${LINK}" /COOKIEJAR "${JAR}"'
715+
NScurl::http get "${LINK}" "${FILE}" /COOKIEJAR "${JAR}" /TAG "test" /END
716+
Pop $0
717+
718+
${If} ${FileExists} "${JAR}"
719+
StrCpy $1 "OK"
720+
${Else}
721+
StrCpy $1 "MISSING"
722+
${EndIf}
723+
724+
IntOp $g_testCount $g_testCount + 1
725+
${If} $0 == "OK"
726+
${AndIf} $1 == "OK"
727+
DetailPrint "[ OK ] status:$0, jar:$1"
728+
${Else}
729+
IntOp $g_testFails $g_testFails + 1
730+
DetailPrint "----- FAIL ----- status:$0, jar:$1"
731+
${EndIf}
732+
733+
NScurl::cancel /TAG "test" /REMOVE
734+
SectionEnd
735+
681736
SectionGroupEnd
682737

683738

0 commit comments

Comments
 (0)