Compare commits
614 Commits
curl-7_30_
...
curl-7_33_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f77e89c5d2 | ||
|
|
92cf6141ed | ||
|
|
cf12d5b62f | ||
|
|
39beaa5ffb | ||
|
|
5df04bfafd | ||
|
|
d015f4ccac | ||
|
|
143d7c13d8 | ||
|
|
9b33ecfd01 | ||
|
|
ca1b34b887 | ||
|
|
f0f95c97f7 | ||
|
|
4cd444e01a | ||
|
|
8264478490 | ||
|
|
b46491900d | ||
|
|
725288bf2f | ||
|
|
173160c0d0 | ||
|
|
3c3622b662 | ||
|
|
a22c478ed7 | ||
|
|
3d43a48781 | ||
|
|
c8b05b809e | ||
|
|
ca995010d0 | ||
|
|
25a0c96a49 | ||
|
|
a8b606b1a6 | ||
|
|
20a99a45c0 | ||
|
|
49341628b5 | ||
|
|
ab7e6afd44 | ||
|
|
4d7bf73fc3 | ||
|
|
3c34f453fa | ||
|
|
d5f687ed8f | ||
|
|
a377fab015 | ||
|
|
092f33d6bf | ||
|
|
09a13a1c01 | ||
|
|
30a09783b2 | ||
|
|
733a4419d0 | ||
|
|
77dc4ba877 | ||
|
|
14d8209adc | ||
|
|
a942d8ff5b | ||
|
|
1695c67818 | ||
|
|
f81d1e1666 | ||
|
|
b71ed1fb3d | ||
|
|
86ccfaa3fd | ||
|
|
3b69462fc0 | ||
|
|
22bccb0eda | ||
|
|
4f591b9148 | ||
|
|
52cefc8cd7 | ||
|
|
8880f84e1a | ||
|
|
9d4a8c7936 | ||
|
|
fd8dc21fd0 | ||
|
|
8ec6486d05 | ||
|
|
59c1743c78 | ||
|
|
60a2046162 | ||
|
|
6dd8bd8d2f | ||
|
|
b07709f741 | ||
|
|
9215cee4c6 | ||
|
|
34df869f99 | ||
|
|
3f04d48495 | ||
|
|
517b8e2290 | ||
|
|
af44da38d6 | ||
|
|
fcfa26a7ee | ||
|
|
18db743851 | ||
|
|
0e188e2dc3 | ||
|
|
eecb0e969f | ||
|
|
bd7d56ec71 | ||
|
|
6f78aaad6f | ||
|
|
89d320c2fd | ||
|
|
b809bafb0c | ||
|
|
3b6a1681dc | ||
|
|
9300bb826d | ||
|
|
dfe7ee1429 | ||
|
|
841103c776 | ||
|
|
8d2335ca23 | ||
|
|
04064e89c1 | ||
|
|
c873375123 | ||
|
|
62d232c131 | ||
|
|
98f7ca7e97 | ||
|
|
4cfbb201c4 | ||
|
|
dc016567ce | ||
|
|
96b68c57ce | ||
|
|
158dfe2c5c | ||
|
|
8f5336a2fa | ||
|
|
f8a9dbd391 | ||
|
|
016879d477 | ||
|
|
c03335ec68 | ||
|
|
894585784c | ||
|
|
33c1f2876b | ||
|
|
00ee5c5cf1 | ||
|
|
dadc495540 | ||
|
|
eae86ba62d | ||
|
|
e9cca79dd1 | ||
|
|
4ba3b6c05a | ||
|
|
187ac69374 | ||
|
|
84ad1569e5 | ||
|
|
45e0a661ce | ||
|
|
4d6ef6297a | ||
|
|
b68c52704b | ||
|
|
4f4dc5832d | ||
|
|
fbcefc0ce0 | ||
|
|
83f6f58834 | ||
|
|
0a691f8935 | ||
|
|
c243d45aad | ||
|
|
8a6dba520b | ||
|
|
32352ed6ad | ||
|
|
df69440d05 | ||
|
|
345955e87e | ||
|
|
6f5b46855c | ||
|
|
5f93c5d658 | ||
|
|
7fd84b14d2 | ||
|
|
f2403140f9 | ||
|
|
f3c9749a40 | ||
|
|
3f6991766f | ||
|
|
cfe5f7dbf4 | ||
|
|
5840c918d5 | ||
|
|
b0afb00000 | ||
|
|
0b5ae7c80e | ||
|
|
0d55f4e1bc | ||
|
|
86d340af27 | ||
|
|
5c14a7f068 | ||
|
|
2879ffacfa | ||
|
|
d89eb55906 | ||
|
|
4a85e60cfe | ||
|
|
bfefe2400a | ||
|
|
25c6890375 | ||
|
|
eb6314260d | ||
|
|
313c38c9de | ||
|
|
ae6096471a | ||
|
|
66ea5c415b | ||
|
|
2481ac358c | ||
|
|
c639d725a3 | ||
|
|
857f999353 | ||
|
|
6d9cddc513 | ||
|
|
e20e48cbf2 | ||
|
|
ee5e2cf6cb | ||
|
|
e8313697b6 | ||
|
|
28427b4083 | ||
|
|
131649a121 | ||
|
|
632b3d81d6 | ||
|
|
241aeadc50 | ||
|
|
669e4ca366 | ||
|
|
c9617d9f93 | ||
|
|
f8986a2b34 | ||
|
|
1b96ce04b2 | ||
|
|
f851df88fb | ||
|
|
18c595fde2 | ||
|
|
56abdd07e7 | ||
|
|
7e06c336d6 | ||
|
|
8a4069fb17 | ||
|
|
243ad539fe | ||
|
|
3d60590422 | ||
|
|
08fa4fed70 | ||
|
|
4344fa926a | ||
|
|
61672bde44 | ||
|
|
13dbb41c49 | ||
|
|
e5c2354fd5 | ||
|
|
09634f46fb | ||
|
|
0119a93b33 | ||
|
|
9fa42beddc | ||
|
|
d6cda9e8ab | ||
|
|
2a7f1425d9 | ||
|
|
900ccc26ae | ||
|
|
01d7bbbebe | ||
|
|
3dc6fc42bf | ||
|
|
d2fe616e7e | ||
|
|
316ca865e3 | ||
|
|
812d49db90 | ||
|
|
02370fff3a | ||
|
|
e9de8e78f0 | ||
|
|
2eabb7d590 | ||
|
|
d707a975f6 | ||
|
|
ac487842a1 | ||
|
|
06b6e1d0d2 | ||
|
|
b77997e6da | ||
|
|
9e8ced9890 | ||
|
|
698e3bdf82 | ||
|
|
9011fb3f0c | ||
|
|
073b03fab7 | ||
|
|
f73f052010 | ||
|
|
97ed1ac905 | ||
|
|
322f0bc2f1 | ||
|
|
af4bddf20b | ||
|
|
f19efd07e7 | ||
|
|
83f5332536 | ||
|
|
497775024c | ||
|
|
ea38a70539 | ||
|
|
5eea336d01 | ||
|
|
f3849a7b84 | ||
|
|
1ca6ed7b75 | ||
|
|
aa51d3a139 | ||
|
|
64c8909071 | ||
|
|
e848942505 | ||
|
|
7e489c42f7 | ||
|
|
75b52f9dcc | ||
|
|
221825aebf | ||
|
|
9d35ad9552 | ||
|
|
c4a7ca038e | ||
|
|
84f3b3dd44 | ||
|
|
2ef83136d4 | ||
|
|
d737aa19c8 | ||
|
|
78e6683bb0 | ||
|
|
2f9b64ac33 | ||
|
|
6a353049ac | ||
|
|
49e3d803ab | ||
|
|
b644ae68c8 | ||
|
|
4ae7b7ea69 | ||
|
|
13a2e32548 | ||
|
|
c3b513e75c | ||
|
|
a74b36af2a | ||
|
|
1b4dc10393 | ||
|
|
45b6e2dd89 | ||
|
|
6dca35c0e5 | ||
|
|
a691e04470 | ||
|
|
3d1a453d88 | ||
|
|
d7a39f8f97 | ||
|
|
3c929ff9f6 | ||
|
|
9d957294cb | ||
|
|
acf59be7f0 | ||
|
|
e7dcc454c6 | ||
|
|
84789e12fb | ||
|
|
460fb12097 | ||
|
|
63d8b3a507 | ||
|
|
90ab65c632 | ||
|
|
34122800b8 | ||
|
|
7f41eab395 | ||
|
|
0192ad65bb | ||
|
|
06c1bea72f | ||
|
|
19a05c908f | ||
|
|
bb55293313 | ||
|
|
817ceb09e0 | ||
|
|
1a911f7ec4 | ||
|
|
ea464d72e9 | ||
|
|
22adb46a32 | ||
|
|
fc99eaa5ae | ||
|
|
4bea91fc67 | ||
|
|
06d1b10cbe | ||
|
|
816b639035 | ||
|
|
8804ffd4fa | ||
|
|
19122c0768 | ||
|
|
c346c4c8f9 | ||
|
|
bc7d806e3a | ||
|
|
6cf8413e31 | ||
|
|
062e5bfd9c | ||
|
|
e4a1888bd0 | ||
|
|
2f1a0bc0bf | ||
|
|
09ddb1d61c | ||
|
|
15f76bf7bb | ||
|
|
36585b5395 | ||
|
|
11baffbff6 | ||
|
|
53333a43a1 | ||
|
|
c56f9797e7 | ||
|
|
9281be36d5 | ||
|
|
f15a88f2b2 | ||
|
|
5ca96cb844 | ||
|
|
10afe7cf10 | ||
|
|
6972335f50 | ||
|
|
d5e2d0b6bf | ||
|
|
f34b5fb4d8 | ||
|
|
f584312e81 | ||
|
|
0b4557f766 | ||
|
|
204126a5f1 | ||
|
|
2ae3d28f3d | ||
|
|
8a42c2ef8d | ||
|
|
e79535bc5e | ||
|
|
4ad8e142da | ||
|
|
e3ee73b70c | ||
|
|
70812c2f32 | ||
|
|
a64bca68c7 | ||
|
|
67633e1308 | ||
|
|
715ca7c5fe | ||
|
|
001758760b | ||
|
|
2f06265e39 | ||
|
|
432431368f | ||
|
|
4b0028f82d | ||
|
|
8c9236bb2c | ||
|
|
2af0b10c95 | ||
|
|
08adecc9a1 | ||
|
|
015556d74c | ||
|
|
4c40fe64b8 | ||
|
|
d20def2046 | ||
|
|
d2b36e466a | ||
|
|
27f8c93daf | ||
|
|
058b86e6f3 | ||
|
|
0018d6830e | ||
|
|
59224a31fd | ||
|
|
0994d737c8 | ||
|
|
96749554fd | ||
|
|
785749405f | ||
|
|
7cc00d9a83 | ||
|
|
230e16dc03 | ||
|
|
0ce410a629 | ||
|
|
5d3cbde72e | ||
|
|
8fe8fd2b17 | ||
|
|
0ddc678927 | ||
|
|
51f0b798fa | ||
|
|
6b27703b5f | ||
|
|
045ccb59a4 | ||
|
|
784336deec | ||
|
|
eb41e8eebe | ||
|
|
3cd43bbfec | ||
|
|
204e340bcd | ||
|
|
37f2ba7e57 | ||
|
|
09b9fc9009 | ||
|
|
7da3caaf95 | ||
|
|
82ab5f1b0c | ||
|
|
7ae64af368 | ||
|
|
2ad688ed7c | ||
|
|
ca786233d2 | ||
|
|
14a3139c4d | ||
|
|
5af2bfb955 | ||
|
|
1691a31cab | ||
|
|
9dedcbf9ec | ||
|
|
537ffc4c69 | ||
|
|
c3e7210548 | ||
|
|
9a5c2d8373 | ||
|
|
8693bbd8c4 | ||
|
|
251dd03b88 | ||
|
|
55ea83d622 | ||
|
|
b5478a0e03 | ||
|
|
db2deba6b4 | ||
|
|
41fb6443ce | ||
|
|
e5dfe6c282 | ||
|
|
e277e20a6d | ||
|
|
a23e56d109 | ||
|
|
ca89a0a092 | ||
|
|
50a74be125 | ||
|
|
8c1e3bb713 | ||
|
|
4fad1943a2 | ||
|
|
4d346673a2 | ||
|
|
de052ca6fc | ||
|
|
1a593191c2 | ||
|
|
2c4ef997b9 | ||
|
|
d020e2c381 | ||
|
|
48fe9226a0 | ||
|
|
a77ac42e52 | ||
|
|
5880db8abd | ||
|
|
0f4ba89ffd | ||
|
|
edeb1ae65f | ||
|
|
82232bbbaf | ||
|
|
bb2e0686ab | ||
|
|
513e587c5e | ||
|
|
6ed2bcc5f5 | ||
|
|
d529f3882b | ||
|
|
e2e92486a7 | ||
|
|
2e5b3168d6 | ||
|
|
6bcacff1a5 | ||
|
|
12d01cb6fa | ||
|
|
90695fb2c5 | ||
|
|
dd17069c9e | ||
|
|
26b0cb6ae2 | ||
|
|
6d30f8ebed | ||
|
|
11220678c4 | ||
|
|
448d55ef0a | ||
|
|
7b115cc1e1 | ||
|
|
a10d5e3851 | ||
|
|
1016637f5a | ||
|
|
2e00872c04 | ||
|
|
56ece42c81 | ||
|
|
99924f6606 | ||
|
|
0eba02fd41 | ||
|
|
464c8693d2 | ||
|
|
50af17ef24 | ||
|
|
3a24cb7bc4 | ||
|
|
e839446c2a | ||
|
|
695931cf8e | ||
|
|
964a7600b9 | ||
|
|
d4492f955d | ||
|
|
9c15325d34 | ||
|
|
d8c04909fa | ||
|
|
c0a7a98aee | ||
|
|
f5005dd8d0 | ||
|
|
d3aaa68f55 | ||
|
|
cfc907e43d | ||
|
|
2af64c6432 | ||
|
|
83f0dae129 | ||
|
|
65d53cf6ef | ||
|
|
0d9e65f79f | ||
|
|
c983aa9efc | ||
|
|
b16b7f9d3a | ||
|
|
5c6f12b9f2 | ||
|
|
2022b10e50 | ||
|
|
45339625bc | ||
|
|
20ff820ef2 | ||
|
|
39e85d99fe | ||
|
|
3a0e931fc7 | ||
|
|
fe7e3229f8 | ||
|
|
ecf042ff3c | ||
|
|
aff245b360 | ||
|
|
e01469907a | ||
|
|
b7a933154a | ||
|
|
54f18e5427 | ||
|
|
833fba265d | ||
|
|
d633052905 | ||
|
|
009d2336fe | ||
|
|
abca89aaa0 | ||
|
|
d689376cb0 | ||
|
|
98b0d66eb4 | ||
|
|
9c2853f2ae | ||
|
|
aff7562922 | ||
|
|
365c5ba395 | ||
|
|
cb1aa8b0e3 | ||
|
|
d3d5c4a40e | ||
|
|
6117d4025e | ||
|
|
d23745f7c9 | ||
|
|
ad47d8e263 | ||
|
|
8a7a277c08 | ||
|
|
0030fbd382 | ||
|
|
f3052c8a81 | ||
|
|
7d80ed64e4 | ||
|
|
a2e0ce86ba | ||
|
|
6fab0bd9f1 | ||
|
|
02964ed630 | ||
|
|
6f3e7aabdc | ||
|
|
631e3e13a9 | ||
|
|
832c195179 | ||
|
|
7877619f85 | ||
|
|
ec248b590d | ||
|
|
4846b5e9fe | ||
|
|
85c710e11e | ||
|
|
0de7249bb3 | ||
|
|
192c4f788d | ||
|
|
da0db499fd | ||
|
|
88c5c63ffc | ||
|
|
a9f5ad0e2a | ||
|
|
e305f5ec71 | ||
|
|
7ac3e9f1ba | ||
|
|
03a3dd9ee3 | ||
|
|
5fc24a5297 | ||
|
|
b1a295ac4e | ||
|
|
1826c768ab | ||
|
|
9c3e098259 | ||
|
|
0feeab7802 | ||
|
|
f24dc09d20 | ||
|
|
9e10963c20 | ||
|
|
10b6d81c64 | ||
|
|
8026bd7abd | ||
|
|
9b8df58169 | ||
|
|
529a2e9110 | ||
|
|
21091549c0 | ||
|
|
7b97f03f09 | ||
|
|
ce362e8eb9 | ||
|
|
a4decb49a6 | ||
|
|
c53fb36b0c | ||
|
|
dc19e656b5 | ||
|
|
87cf677eca | ||
|
|
5657c56f63 | ||
|
|
51b3445e84 | ||
|
|
a7452b8b8c | ||
|
|
0bf5ce77aa | ||
|
|
159d34b58e | ||
|
|
29bf0598aa | ||
|
|
239b58d34d | ||
|
|
74f1810546 | ||
|
|
f4b08b8f40 | ||
|
|
6691fdf517 | ||
|
|
7d8d2a54ba | ||
|
|
9986c6cb2b | ||
|
|
ba9a66663a | ||
|
|
ac419bf562 | ||
|
|
520833cbe1 | ||
|
|
e58d9c87f7 | ||
|
|
84f7991474 | ||
|
|
85b9dc8023 | ||
|
|
7d4d4892d8 | ||
|
|
fc4759af9d | ||
|
|
ee84c47655 | ||
|
|
ce32176db7 | ||
|
|
04f52e9b4d | ||
|
|
100a33f7ff | ||
|
|
7ed25ccf0d | ||
|
|
01eede2662 | ||
|
|
ae26ee3489 | ||
|
|
992bee504d | ||
|
|
01a2abedd7 | ||
|
|
a45e3f93e4 | ||
|
|
bdb396ef2a | ||
|
|
6add1901a1 | ||
|
|
51b0f09b5e | ||
|
|
8dac7be438 | ||
|
|
bcf1b9dec1 | ||
|
|
b045d079f8 | ||
|
|
683f2b8323 | ||
|
|
2de20dd9a1 | ||
|
|
b47cf4f688 | ||
|
|
a15b2b6c62 | ||
|
|
42e01cff9a | ||
|
|
865d4138a0 | ||
|
|
35874298e4 | ||
|
|
52d72e66c2 | ||
|
|
f3d10aa0d4 | ||
|
|
7632bc911b | ||
|
|
92ef5f19c8 | ||
|
|
99b4045183 | ||
|
|
087f9bb20a | ||
|
|
e2c7e19144 | ||
|
|
f5c3d95384 | ||
|
|
6b10f5b963 | ||
|
|
ee74b77d45 | ||
|
|
734bdb68c2 | ||
|
|
514817669e | ||
|
|
cb9c0ac7d7 | ||
|
|
1c435295b8 | ||
|
|
46d26a0e77 | ||
|
|
f4e3cae8a7 | ||
|
|
b52cf5d2cd | ||
|
|
073e83b543 | ||
|
|
c3e6d69acb | ||
|
|
b56e3d43e5 | ||
|
|
f317ffb7bb | ||
|
|
9ea5145952 | ||
|
|
1d7c38e1f0 | ||
|
|
18bfc8f2d7 | ||
|
|
945246988d | ||
|
|
a5c0e20939 | ||
|
|
128517649c | ||
|
|
219358b93d | ||
|
|
f133719f73 | ||
|
|
f4e6e201b1 | ||
|
|
790b2086d7 | ||
|
|
f9b691cdb0 | ||
|
|
4118c30261 | ||
|
|
dacbdaab94 | ||
|
|
70e30f6caa | ||
|
|
7cb6c31370 | ||
|
|
5d3a031ca7 | ||
|
|
a846fbbe2a | ||
|
|
6420672879 | ||
|
|
c4067a5678 | ||
|
|
0523152ad6 | ||
|
|
b37b5233ca | ||
|
|
c68c7e588e | ||
|
|
1498a0073e | ||
|
|
27777949a0 | ||
|
|
4dc2d965d6 | ||
|
|
70bbbccc39 | ||
|
|
0dd470fc61 | ||
|
|
89acdf50fa | ||
|
|
c0d502785f | ||
|
|
a8c92cb608 | ||
|
|
53fda844cc | ||
|
|
bbf63b0faa | ||
|
|
2af9fd4960 | ||
|
|
2c0d65785f | ||
|
|
d791179d7f | ||
|
|
c49ed0b6c0 | ||
|
|
868d8e6831 | ||
|
|
e3aca1b2ce | ||
|
|
ddac43b38e | ||
|
|
416ecc1584 | ||
|
|
455ba691a7 | ||
|
|
11332577b3 | ||
|
|
702b0dd408 | ||
|
|
e8a9f794f0 | ||
|
|
bddf3d4705 | ||
|
|
e99c81a07c | ||
|
|
fe880475ed | ||
|
|
5821d5f111 | ||
|
|
d535c4a2e1 | ||
|
|
ca8f17a303 | ||
|
|
fddb7b44a7 | ||
|
|
49184c3723 | ||
|
|
cc7f6a2ddf | ||
|
|
90fe59b829 | ||
|
|
7b074a460b | ||
|
|
993cdcd6ee | ||
|
|
8763374f0e | ||
|
|
63388fe1f3 | ||
|
|
b75a88aa72 | ||
|
|
bb20989a63 | ||
|
|
0d49e408a4 | ||
|
|
90c87f311e | ||
|
|
da06ac7f3f | ||
|
|
6d9236e805 | ||
|
|
c306d2e42f | ||
|
|
f737e3a3dd | ||
|
|
686586b0f9 | ||
|
|
e621a5f6ea | ||
|
|
8093f9541e | ||
|
|
68e7fb499d | ||
|
|
d9569720dd | ||
|
|
1c40685d32 | ||
|
|
31c6e7af6a | ||
|
|
552ba67bb1 | ||
|
|
651254dcc7 | ||
|
|
26bdafcbf9 | ||
|
|
02dc9e788f | ||
|
|
e11c6e9961 | ||
|
|
e4eaa92728 | ||
|
|
577f8e5ac6 | ||
|
|
95ba6cdd54 | ||
|
|
7ce6cb9ab4 | ||
|
|
8723cade21 | ||
|
|
d956d9db47 | ||
|
|
ecf93ac986 | ||
|
|
b3a01be2f3 | ||
|
|
00045a3009 | ||
|
|
3f7188dd94 | ||
|
|
720218fea1 | ||
|
|
73aa95592f | ||
|
|
ad3fdbc0a4 | ||
|
|
73cbd21b5e | ||
|
|
c5ba0c2f54 | ||
|
|
edddf394b8 | ||
|
|
61d259f950 | ||
|
|
c01735865f | ||
|
|
ca46c5dbe2 | ||
|
|
2da127abb5 | ||
|
|
bc33f2200d | ||
|
|
fd399cde00 | ||
|
|
00c74019f4 | ||
|
|
9d0063befa | ||
|
|
01e55ebb26 | ||
|
|
4bbad1dac7 | ||
|
|
ddbda328b3 | ||
|
|
8ffbeeda80 | ||
|
|
1d1ffaf912 | ||
|
|
e0cff02061 | ||
|
|
7fe95bb0d5 |
@@ -103,7 +103,7 @@ if test ! -z $SDK32; then
|
||||
ln -fs ${FRAMEWORK_VERSION}/Resources Resources
|
||||
ln -fs ${FRAMEWORK_VERSION}/Headers Headers
|
||||
cd Versions
|
||||
ln -fs ${FRAMEWORK_VERSION} Current
|
||||
ln -fs $(basename "${FRAMEWORK_VERSION}") Current
|
||||
|
||||
echo Testing for SDK64
|
||||
if test -d $SDK64_DIR; then
|
||||
|
||||
@@ -148,12 +148,24 @@ vc-ssl-zlib: $(VC)
|
||||
cd ..\src
|
||||
nmake /f Makefile.$(VC) cfg=release-ssl-zlib
|
||||
|
||||
vc-winssl-zlib: $(VC)
|
||||
cd lib
|
||||
nmake /f Makefile.$(VC) cfg=release-winssl-zlib
|
||||
cd ..\src
|
||||
nmake /f Makefile.$(VC) cfg=release-winssl-zlib
|
||||
|
||||
vc-x64-ssl-zlib: $(VC)
|
||||
cd lib
|
||||
nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-ssl-zlib
|
||||
cd ..\src
|
||||
nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-ssl-zlib
|
||||
|
||||
vc-x64-winssl-zlib: $(VC)
|
||||
cd lib
|
||||
nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-winssl-zlib
|
||||
cd ..\src
|
||||
nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-winssl-zlib
|
||||
|
||||
vc-ssl-dll: $(VC)
|
||||
cd lib
|
||||
nmake /f Makefile.$(VC) cfg=release-ssl-dll
|
||||
|
||||
200
RELEASE-NOTES
200
RELEASE-NOTES
@@ -1,88 +1,68 @@
|
||||
Curl and libcurl 7.30.0
|
||||
Curl and libcurl 7.33.0
|
||||
|
||||
Public curl releases: 132
|
||||
Command line options: 152
|
||||
curl_easy_setopt() options: 199
|
||||
Public curl releases: 135
|
||||
Command line options: 161
|
||||
curl_easy_setopt() options: 205
|
||||
Public functions in libcurl: 58
|
||||
Known libcurl bindings: 42
|
||||
Contributors: 1005
|
||||
|
||||
***
|
||||
krb4 support is up for removal. If you care about it at all, speak up
|
||||
on the curl-library list asap!
|
||||
***
|
||||
Contributors: 1057
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o imap: Changed response tag generation to be completely unique
|
||||
o imap: Added support for SASL-IR extension
|
||||
o imap: Added support for the list command
|
||||
o imap: Added support for the append command
|
||||
o imap: Added custom request parsing
|
||||
o imap: Added support to the fetch command for UID and SECTION properties
|
||||
o imap: Added parsing and verification of the UIDVALIDITY mailbox attribute
|
||||
o darwinssl: Make certificate errors less techy
|
||||
o imap/pop3/smtp: Added support for the STARTTLS capability
|
||||
o checksrc: ban use of sprintf, vsprintf, strcat, strncat and gets
|
||||
o curl_global_init() now accepts the CURL_GLOBAL_ACK_EINTR flag [10]
|
||||
o Added CURLMOPT_MAX_HOST_CONNECTIONS, CURLMOPT_MAX_TOTAL_CONNECTIONS for
|
||||
new multi interface connection handling
|
||||
o Added CURLMOPT_MAX_PIPELINE_LENGTH, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE,
|
||||
CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLMOPT_PIPELINING_SITE_BL and
|
||||
CURLMOPT_PIPELINING_SERVER_BL for new pipelining control [15]
|
||||
o test code for testing the event based API [3]
|
||||
o CURLM_ADDED_ALREADY: new error code
|
||||
o test TFTP server: support "writedelay" within <servercmd>
|
||||
o krb4 support has been removed
|
||||
o imap/pop3/smtp: added basic SASL XOAUTH2 support [9]
|
||||
o darwinssl: add support for PKCS#12 files for client authentication
|
||||
o darwinssl: enable BEAST workaround on iOS 7 & later
|
||||
o Pass password to OpenSSL engine by user interface [15]
|
||||
o c-ares: Add support for various DNS binding options
|
||||
o cookies: add expiration
|
||||
o curl: added --oauth2-bearer option
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o SECURITY ADVISORY: cookie tailmatching to avoid cross-domain leakage [25]
|
||||
o darwinssl: Fix build under Leopard
|
||||
o DONE: consider callback-aborted transfers premature [1]
|
||||
o ntlm: Fixed memory leaks
|
||||
o smtp: Fixed an issue when processing EHLO failure responses
|
||||
o pop3: Fixed incorrect return value from pop3_endofresp()
|
||||
o pop3: Fixed SASL authentication capability detection
|
||||
o pop3: Fixed blocking SSL connect when connecting via POP3S
|
||||
o imap: Fixed memory leak when performing multiple selects
|
||||
o nss: fix misplaced code enabling non-blocking socket mode
|
||||
o AddFormData: prevent only directories from being posted [2]
|
||||
o darwinssl: fix infinite loop if server disconnected abruptly [3]
|
||||
o metalink: fix improbable crash parsing metalink filename
|
||||
o show proper host name on failed resolve
|
||||
o MacOSX-Framework: Make script work in Xcode 4.0 and later
|
||||
o strlcat: remove function [4]
|
||||
o darwinssl: Fix send glitchiness with data > 32 or so KB [5]
|
||||
o polarssl: better 1.1.x and 1.2.x support
|
||||
o various documentation improvements
|
||||
o multi: NULL pointer reference when closing an unused multi handle [9]
|
||||
o SOCKS: fix socks proxy when noproxy matched [7]
|
||||
o install-sh: updated to support multiple source files as arguments [6]
|
||||
o PolarSSL: added human readable error strings
|
||||
o resolver_error: remove wrong error message output
|
||||
o docs: updates HTML index and general improvements
|
||||
o curlbuild.h.dist: enhance non-configure GCC ABI detection logic
|
||||
o sasl: Fixed null pointer reference when decoding empty digest challenge [8]
|
||||
o easy: do not ignore poll() failures other than EINTR
|
||||
o darwinssl: disable ECC ciphers under Mountain Lion by default
|
||||
o CONNECT: count received headers [11]
|
||||
o build: fixes for VMS
|
||||
o CONNECT: clear 'rewindaftersend' on success [12]
|
||||
o HTTP proxy: insert slash in URL if missing [13]
|
||||
o hiperfifo: updated to use current libevent API [14]
|
||||
o getinmemory.c: abort the transfer nicely if not enough memory
|
||||
o improved win32 memorytracking
|
||||
o corrected proxy header response headers count [16]
|
||||
o FTP quote operations on re-used connection [17]
|
||||
o tcpkeepalive on win32 [18]
|
||||
o tcpkeepalive on Mac OS X [23]
|
||||
o easy: acknowledge the CURLOPT_MAXCONNECTS option properly [19]
|
||||
o easy interface: restore default MAXCONNECTS to 5
|
||||
o win32: don't set SO_SNDBUF for windows vista or later versions [20]
|
||||
o HTTP: made cookie sort function more deterministic
|
||||
o winssl: Fixed memory leak if connection was not successful
|
||||
o FTP: wait on both connections during active STOR state [21]
|
||||
o connect: treat a failed local bind of an interface as a non-fatal error [22]
|
||||
o darwinssl: disable insecure ciphers by default
|
||||
o FTP: handle "rubbish" in front of directory name in 257 responses [24]
|
||||
o mk-ca-bundle: Fixed lost OpenSSL output with "-t"
|
||||
o nss: make sure that NSS is initialized
|
||||
o curl: make --no-[option] work properly for several options
|
||||
o FTP: with socket_action send better socket updates in active mode [1]
|
||||
o curl: fix the --sasl-ir in the --help output
|
||||
o tests 2032, 2033: Don't hardcode port in expected output
|
||||
o urlglob: better detect unclosed braces, empty lists and overflows [7]
|
||||
o urlglob: error out on range overflow [8]
|
||||
o imap: Fixed response check for SEARCH, EXPUNGE, LSUB, UID and NOOP commands [10]
|
||||
o handle arbitrary-length username and password [2]
|
||||
o TFTP: make the CURLOPT_LOW_SPEED* options work [4]
|
||||
o curl.h: name space pollution by "enum type" [5]
|
||||
o multi: move on from STATE_DONE faster [6]
|
||||
o FTP: 60 secs delay if aborted in the CURLOPT_HEADERFUNCTION callback [11]
|
||||
o multi_socket: improved 100-continue timeout handling
|
||||
o curl_multi_remove_handle: allow multiple removes
|
||||
o FTP: fix getsock during DO_MORE state [12]
|
||||
o -x: rephrased the --proxy section somewhat
|
||||
o acinclude: fix --without-ca-path when cross-compiling [13]
|
||||
o LDAP: fix bad free() when URL parsing failed [14]
|
||||
o --data: mention CRLF treatment when reading from file
|
||||
o curl_easy_pause: suggest one way to unpause
|
||||
o imap: Fixed calculation of transfer when partial FETCH received [16]
|
||||
o pingpong: Check SSL library buffers for already read data [16]
|
||||
o imap/pop3/smtp: Speed up SSL connection initialization
|
||||
o libcurl.3: for multi interface connections are held in the multi handle
|
||||
o curl_easy_setopt.3: mention RTMP URL quirks [17]
|
||||
o curl.1: detail how short/long options work [18]
|
||||
o curl.1: Added information about optional login options to --user option
|
||||
o curl: Added clarification to the --mail options in the --help output
|
||||
o curl_easy_setopt.3: clarify that TIMEOUT and TIMEOUT_MS set the same value
|
||||
o openssl: use correct port number in error message [19]
|
||||
o darwinssl: block TLS_RSA_WITH_NULL_SHA256 cipher
|
||||
o OpenSSL: acknowledge CURLOPT_SSL_VERIFYHOST without VERIFYPEER
|
||||
o xattr: add support for FreeBSD xattr API
|
||||
o win32: fix Visual Studio 2010 build with WINVER >= 0x600 [22]
|
||||
o configure: use icc options without space [21]
|
||||
o test1112: Increase the timeout from 7s to 16s [20]
|
||||
o SCP: upload speed on a fast connection limited to 16384 B/s
|
||||
o curl_setup_once: fix errno access for lwip on Windows [24]
|
||||
o HTTP: Output http response 304 when modified time is too old [23]
|
||||
|
||||
This release includes the following known bugs:
|
||||
|
||||
@@ -91,43 +71,41 @@ This release includes the following known bugs:
|
||||
This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
Kamil Dudka, Steve Holme, Nick Zitzmann, Patricia Muscalu, Dan Fandrich,
|
||||
Gisle Vanem, Guenter Knauf, Yang Tse, Oliver Gondža, Aki Koskinen,
|
||||
Alexander Klauer, Kim Vandry, Willem Sparreboom, Jeremy Huddleston,
|
||||
Bruno de Carvalho, Rainer Jung, Jeremy Huddleston, Kim Vandry, Jiri Hruska,
|
||||
Alexander Klauer, Saran Neti, Alessandro Ghedini, Linus Nielsen Feltzing,
|
||||
Martin Jansen, John E. Malmberg, Tom Grace, Patrick Monnerat,
|
||||
Zdenek Pavlas, Myk Taylor, Cédric Deltheil, Robert Wruck, Sam Deane,
|
||||
Clemens Gruber, Marc Hoersken, Tomas Mlcoch, Fredrik Thulin, Steven Gu,
|
||||
Andrew Kurushin, Christian Hägele, Daniel Theron, Bill Middlecamp,
|
||||
Richard Michael, Yamada Yasuharu
|
||||
Alex McLellan, Bill Doyle, Colby Ranger, Fabian Keil, Gisle Vanem,
|
||||
John E. Malmberg, Jonathan Nieder, Kamil Dudka, Shawn Landden,
|
||||
Tor Arntsen, Will Dietz, Yi Huang, Kyle L. Huff, Steve Holme, Mike Mio,
|
||||
Stefan Neis, Nick Zitzmann, Geoff Beier, John Dunn, Jiri Hruska,
|
||||
Tomas Mlcoch, Kim Vandry, Ben Greear, Gorilla Maguila, Jerry Krinock,
|
||||
Yamada Yasuharu, Gordon Marler, Dave Thompson, D. Flinkmann,
|
||||
Benoit Sigoure, Clemens Gruber, Guenter Knauf, Petr Pisar, Elmira A Semenova,
|
||||
Francois Charlier, Ishan SinghLevett, Marcel Raad, Ulf Samuelsson,
|
||||
Andrej E Baranov, Derek Higgins, Heinrich Schaefer
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
||||
References to bug reports and discussions on issues:
|
||||
|
||||
[1] = http://curl.haxx.se/bug/view.cgi?id=1184
|
||||
[2] = http://curl.haxx.se/mail/archive-2013-02/0040.html
|
||||
[3] = http://curl.haxx.se/mail/lib-2013-03/0014.html
|
||||
[4] = http://curl.haxx.se/bug/view.cgi?id=1192
|
||||
[5] = http://curl.haxx.se/mail/lib-2013-02/0145.html
|
||||
[6] = http://curl.haxx.se/bug/view.cgi?id=1195
|
||||
[7] = http://curl.haxx.se/bug/view.cgi?id=1190
|
||||
[8] = http://curl.haxx.se/bug/view.cgi?id=1193
|
||||
[9] = http://curl.haxx.se/bug/view.cgi?id=1194
|
||||
[10] = http://curl.haxx.se/bug/view.cgi?id=1168
|
||||
[11] = http://curl.haxx.se/bug/view.cgi?id=1204
|
||||
[12] = https://groups.google.com/d/msg/msysgit/B31LNftR4BI/KhRTz0iuGmUJ
|
||||
[13] = http://curl.haxx.se/bug/view.cgi?id=1206
|
||||
[14] = http://curl.haxx.se/bug/view.cgi?id=1199
|
||||
[15] = http://daniel.haxx.se/blog/2013/03/26/better-pipelining-in-libcurl-7-30-0/
|
||||
[16] = http://curl.haxx.se/bug/view.cgi?id=1204
|
||||
[17] = http://curl.haxx.se/mail/lib-2013-03/0319.html
|
||||
[18] = http://curl.haxx.se/bug/view.cgi?id=1209
|
||||
[19] = http://curl.haxx.se/bug/view.cgi?id=1212
|
||||
[20] = http://curl.haxx.se/bug/view.cgi?id=1188
|
||||
[21] = http://curl.haxx.se/bug/view.cgi?id=1183
|
||||
[22] = http://curl.haxx.se/bug/view.cgi?id=1189
|
||||
[23] = http://curl.haxx.se/bug/view.cgi?id=1214
|
||||
[24] = http://curl.haxx.se/mail/lib-2013-04/0113.html
|
||||
[25] = http://curl.haxx.se/docs/adv_20130412.html
|
||||
[1] = http://curl.haxx.se/mail/lib-2013-08/0043.html
|
||||
[2] = http://bugs.debian.org/719856
|
||||
[3] = http://daniel.haxx.se/blog/2013/08/20/testing-curl_multi_socket_action/
|
||||
[4] = http://curl.haxx.se/bug/view.cgi?id=1269
|
||||
[5] = https://github.com/bagder/curl/pull/76
|
||||
[6] = http://curl.haxx.se/mail/lib-2013-08/0211.html
|
||||
[7] = http://curl.haxx.se/bug/view.cgi?id=1264
|
||||
[8] = http://curl.haxx.se/bug/view.cgi?id=1267
|
||||
[9] = http://curl.haxx.se/mail/lib-2013-08/0234.html
|
||||
[10] = http://curl.haxx.se/mail/lib-2013-08/0136.html
|
||||
[11] = https://bugzilla.redhat.com/1005686
|
||||
[12] = http://curl.haxx.se/mail/lib-2013-08/0109.html
|
||||
[13] = http://curl.haxx.se/bug/view.cgi?id=1273
|
||||
[14] = http://curl.haxx.se/mail/lib-2013-08/0209.html
|
||||
[15] = http://curl.haxx.se/mail/lib-2013-08/0265.html
|
||||
[16] = http://curl.haxx.se/mail/lib-2013-08/0170.html
|
||||
[17] = http://curl.haxx.se/bug/view.cgi?id=1278
|
||||
[18] = http://curl.haxx.se/bug/view.cgi?id=1279
|
||||
[19] = http://curl.haxx.se/bug/view.cgi?id=1281
|
||||
[20] = http://curl.haxx.se/mail/lib-2010-02/0200.html
|
||||
[21] = http://curl.haxx.se/mail/lib-2013-09/0182.html
|
||||
[22] = http://curl.haxx.se/bug/view.cgi?id=1282
|
||||
[23] = http://curl.haxx.se/bug/view.cgi?id=1288
|
||||
[24] = http://curl.haxx.se/mail/lib-2013-10/0048.html
|
||||
|
||||
14
acinclude.m4
14
acinclude.m4
@@ -2620,15 +2620,17 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]),
|
||||
capath="$want_capath"
|
||||
ca="no"
|
||||
else
|
||||
dnl neither of --with-ca-* given
|
||||
dnl first try autodetecting a CA bundle , then a CA path
|
||||
dnl both autodetections can be skipped by --without-ca-*
|
||||
ca="no"
|
||||
capath="no"
|
||||
if test "x$cross_compiling" != "xyes"; then
|
||||
dnl NOT cross-compiling and...
|
||||
dnl neither of the --with-ca-* options are provided
|
||||
if test "x$want_ca" = "xunset"; then
|
||||
dnl the path we previously would have installed the curl ca bundle
|
||||
dnl to, and thus we now check for an already existing cert in that place
|
||||
dnl in case we find no other
|
||||
dnl to, and thus we now check for an already existing cert in that
|
||||
dnl place in case we find no other
|
||||
if test "x$prefix" != xNONE; then
|
||||
cac="${prefix}/share/curl/curl-ca-bundle.crt"
|
||||
else
|
||||
@@ -2656,9 +2658,11 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]),
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
dnl no option given and cross-compiling
|
||||
AC_MSG_WARN([skipped the ca-cert path detection when cross-compiling])
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test "x$ca" != "xno"; then
|
||||
CURL_CA_BUNDLE='"'$ca'"'
|
||||
|
||||
222
configure.ac
222
configure.ac
@@ -126,7 +126,7 @@ fi
|
||||
dnl figure out the libcurl version
|
||||
CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curlver.h`
|
||||
XC_CHECK_PROG_CC
|
||||
AM_INIT_AUTOMAKE
|
||||
XC_AUTOMAKE
|
||||
AC_MSG_CHECKING([curl version])
|
||||
AC_MSG_RESULT($CURLVERSION)
|
||||
|
||||
@@ -150,7 +150,6 @@ dnl initialize all the info variables
|
||||
curl_ssl_msg="no (--with-{ssl,gnutls,nss,polarssl,cyassl,axtls,winssl,darwinssl} )"
|
||||
curl_ssh_msg="no (--with-libssh2)"
|
||||
curl_zlib_msg="no (--with-zlib)"
|
||||
curl_krb4_msg="no (--with-krb4*)"
|
||||
curl_gss_msg="no (--with-gssapi)"
|
||||
curl_spnego_msg="no (--with-spnego)"
|
||||
curl_tls_srp_msg="no (--enable-tls-srp)"
|
||||
@@ -1134,101 +1133,6 @@ no)
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Check for the presence of Kerberos4 libraries and headers
|
||||
dnl **********************************************************************
|
||||
|
||||
AC_ARG_WITH(krb4-includes,
|
||||
AC_HELP_STRING([--with-krb4-includes=DIR],
|
||||
[Specify location of kerberos4 headers]),[
|
||||
CPPFLAGS="$CPPFLAGS -I$withval"
|
||||
KRB4INC="$withval"
|
||||
want_krb4=yes
|
||||
])
|
||||
|
||||
AC_ARG_WITH(krb4-libs,
|
||||
AC_HELP_STRING([--with-krb4-libs=DIR],[Specify location of kerberos4 libs]),[
|
||||
LDFLAGS="$LDFLAGS -L$withval"
|
||||
KRB4LIB="$withval"
|
||||
want_krb4=yes
|
||||
])
|
||||
|
||||
|
||||
OPT_KRB4=off
|
||||
AC_ARG_WITH(krb4,dnl
|
||||
AC_HELP_STRING([--with-krb4=DIR],[where to look for Kerberos4]),[
|
||||
OPT_KRB4="$withval"
|
||||
if test X"$OPT_KRB4" != Xno; then
|
||||
want_krb4="yes"
|
||||
if test X"$OPT_KRB4" != Xyes; then
|
||||
LDFLAGS="$LDFLAGS -L$OPT_KRB4/lib$libsuff"
|
||||
KRB4LIB="$OPT_KRB4/lib$libsuff"
|
||||
CPPFLAGS="$CPPFLAGS -I$OPT_KRB4/include"
|
||||
KRB4INC="$OPT_KRB4/include"
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([if Kerberos4 support is requested])
|
||||
|
||||
if test "$want_krb4" = yes
|
||||
then
|
||||
if test "$ipv6" = "yes"; then
|
||||
echo krb4 is not compatible with IPv6
|
||||
exit 1
|
||||
fi
|
||||
AC_MSG_RESULT(yes)
|
||||
|
||||
dnl Check for & handle argument to --with-krb4
|
||||
|
||||
AC_MSG_CHECKING(where to look for Kerberos4)
|
||||
if test X"$OPT_KRB4" = Xyes
|
||||
then
|
||||
AC_MSG_RESULT([defaults])
|
||||
else
|
||||
AC_MSG_RESULT([libs in $KRB4LIB, headers in $KRB4INC])
|
||||
fi
|
||||
|
||||
dnl Check for DES library
|
||||
AC_CHECK_LIB(des, des_pcbc_encrypt,
|
||||
[
|
||||
AC_CHECK_HEADERS(des.h)
|
||||
|
||||
dnl resolv lib?
|
||||
AC_CHECK_FUNC(res_search, , [AC_CHECK_LIB(resolv, res_search)])
|
||||
|
||||
dnl Check for the Kerberos4 library
|
||||
AC_CHECK_LIB(krb, krb_net_read,
|
||||
[
|
||||
dnl Check for header files
|
||||
AC_CHECK_HEADERS(krb.h)
|
||||
|
||||
dnl we found the required libraries, add to LIBS
|
||||
LIBS="-lkrb -lcom_err -ldes $LIBS"
|
||||
|
||||
dnl Check for function krb_get_our_ip_for_realm
|
||||
dnl this is needed for NAT networks
|
||||
AC_CHECK_FUNCS(krb_get_our_ip_for_realm)
|
||||
|
||||
dnl add define KRB4
|
||||
AC_DEFINE(HAVE_KRB4, 1,
|
||||
[if you have the Kerberos4 libraries (including -ldes)])
|
||||
|
||||
dnl substitute it too!
|
||||
KRB4_ENABLED=1
|
||||
AC_SUBST(KRB4_ENABLED)
|
||||
|
||||
curl_krb4_msg="enabled"
|
||||
|
||||
dnl the krb4 stuff needs a strlcpy()
|
||||
AC_CHECK_FUNCS(strlcpy)
|
||||
|
||||
])
|
||||
])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Check for FBopenssl(SPNEGO) libraries
|
||||
dnl **********************************************************************
|
||||
@@ -2808,6 +2712,92 @@ dnl http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/ \
|
||||
dnl genprogc/thread_quick_ref.htm
|
||||
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Check for nghttp2
|
||||
dnl **********************************************************************
|
||||
|
||||
AC_MSG_CHECKING([whether to build with nghttp2])
|
||||
OPT_H2="no"
|
||||
AC_ARG_WITH(nghttp2,
|
||||
AC_HELP_STRING([--with-nghttp2=PATH],[Enable nghttp2 usage])
|
||||
AC_HELP_STRING([--without-nghttp2],[Disable nghttp2 usage]),
|
||||
[OPT_H2=$withval])
|
||||
case "$OPT_H2" in
|
||||
no)
|
||||
dnl --without-nghttp2 option used
|
||||
want_idn="no"
|
||||
AC_MSG_RESULT([no])
|
||||
;;
|
||||
default)
|
||||
dnl configure option not specified
|
||||
want_h2="no"
|
||||
want_h2_path="default"
|
||||
AC_MSG_RESULT([no])
|
||||
;;
|
||||
yes)
|
||||
dnl --with-nghttp2 option used without path
|
||||
want_h2="yes"
|
||||
want_h2_path=""
|
||||
AC_MSG_RESULT([yes])
|
||||
;;
|
||||
*)
|
||||
dnl --with-nghttp2 option used with path
|
||||
want_h2="yes"
|
||||
want_h2_path="$withval"
|
||||
AC_MSG_RESULT([yes ($withval)])
|
||||
;;
|
||||
esac
|
||||
|
||||
curl_h2_msg="disabled (--with-nghttp2)"
|
||||
if test X"$OPT_H2" != Xno; then
|
||||
dnl backup the pre-librtmp variables
|
||||
CLEANLDFLAGS="$LDFLAGS"
|
||||
CLEANCPPFLAGS="$CPPFLAGS"
|
||||
CLEANLIBS="$LIBS"
|
||||
|
||||
h2pcdir=${want_h2_path}/lib/pkgconfig
|
||||
CURL_CHECK_PKGCONFIG(libnghttp2, $h2pcdir)
|
||||
|
||||
if test "$PKGCONFIG" != "no" ; then
|
||||
LIB_H2=`CURL_EXPORT_PCDIR([$h2pcdir])
|
||||
$PKGCONFIG --libs-only-l libnghttp2`
|
||||
AC_MSG_NOTICE([-l is $LIB_H2])
|
||||
|
||||
CPP_H2=`CURL_EXPORT_PCDIR([$h2pcdir]) dnl
|
||||
$PKGCONFIG --cflags-only-I libnghttp2`
|
||||
AC_MSG_NOTICE([-I is $CPP_H2])
|
||||
|
||||
LD_H2=`CURL_EXPORT_PCDIR([$h2pcdir])
|
||||
$PKGCONFIG --libs-only-L libnghttp2`
|
||||
AC_MSG_NOTICE([-L is $LD_H2])
|
||||
|
||||
else
|
||||
dnl To avoid link errors, we do not allow --libnghttp2 without
|
||||
dnl a pkgconfig file
|
||||
AC_MSG_ERROR([--with-nghttp2 was specified but could not find libnghttp2 pkg-config file.])
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS $LD_H2"
|
||||
CPPFLAGS="$CPPFLAGS $CPP_H2"
|
||||
LIBS="$LIB_H2 $LIBS"
|
||||
|
||||
AC_CHECK_LIB(nghttp2, nghttp2_session_client_new,
|
||||
[
|
||||
AC_CHECK_HEADERS(nghttp2/nghttp2.h,
|
||||
curl_h2_msg="enabled (nghttp2)"
|
||||
NGHTTP2_ENABLED=1
|
||||
AC_DEFINE(USE_NGHTTP2, 1, [if nghttp2 is in use])
|
||||
AC_SUBST(USE_NGHTTP2, [1])
|
||||
)
|
||||
],
|
||||
dnl not found, revert back to clean variables
|
||||
LDFLAGS=$CLEANLDFLAGS
|
||||
CPPFLAGS=$CLEANCPPFLAGS
|
||||
LIBS=$CLEANLIBS
|
||||
)
|
||||
|
||||
fi
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Back to "normal" configuring
|
||||
dnl **********************************************************************
|
||||
@@ -3158,14 +3148,26 @@ if test "$want_thres" = "yes"; then
|
||||
AC_CHECK_HEADER(pthread.h,
|
||||
[ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
|
||||
dnl first check for function without lib
|
||||
AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] )
|
||||
|
||||
dnl if it wasn't found without lib, search for it in pthread lib
|
||||
if test "$USE_THREADS_POSIX" != "1"
|
||||
then
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
AC_CHECK_LIB(pthread, pthread_create,
|
||||
[ AC_MSG_NOTICE([using POSIX threaded DNS lookup])
|
||||
AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup])
|
||||
USE_THREADS_POSIX=1
|
||||
curl_res_msg="threaded"
|
||||
],
|
||||
[USE_THREADS_POSIX=1],
|
||||
[ CFLAGS="$save_CFLAGS"])
|
||||
fi
|
||||
|
||||
if test "x$USE_THREADS_POSIX" = "x1"
|
||||
then
|
||||
AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup])
|
||||
curl_res_msg="POSIX threaded"
|
||||
fi
|
||||
|
||||
|
||||
])
|
||||
fi
|
||||
|
||||
@@ -3338,6 +3340,11 @@ dnl yes or no
|
||||
ENABLE_SHARED="$enable_shared"
|
||||
AC_SUBST(ENABLE_SHARED)
|
||||
|
||||
dnl to let curl-config output the static libraries correctly
|
||||
ENABLE_STATIC="$enable_static"
|
||||
AC_SUBST(ENABLE_STATIC)
|
||||
|
||||
|
||||
dnl
|
||||
dnl For keeping supported features and protocols also in pkg-config file
|
||||
dnl since it is more cross-compile friendly than curl-config
|
||||
@@ -3348,9 +3355,6 @@ if test "x$USE_SSLEAY" = "x1"; then
|
||||
elif test -n "$SSL_ENABLED"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES SSL"
|
||||
fi
|
||||
if test "@KRB4_ENABLED@" = "x1"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES KRB4"
|
||||
fi
|
||||
if test "x$IPV6_ENABLED" = "x1"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES IPv6"
|
||||
fi
|
||||
@@ -3380,6 +3384,10 @@ if test "x$USE_TLS_SRP" = "x1"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES TLS-SRP"
|
||||
fi
|
||||
|
||||
if test "x$USE_NGHTTP2" = "x1"; then
|
||||
SUPPORT_FEATURES="$SUPPORT_FEATURES HTTP2"
|
||||
fi
|
||||
|
||||
AC_SUBST(SUPPORT_FEATURES)
|
||||
|
||||
dnl For supported protocols in pkg-config file
|
||||
@@ -3514,6 +3522,8 @@ AC_OUTPUT
|
||||
|
||||
CURL_GENERATE_CONFIGUREHELP_PM
|
||||
|
||||
XC_AMEND_DISTCLEAN([lib src tests/unit tests/server tests/libtest docs/examples])
|
||||
|
||||
AC_MSG_NOTICE([Configured to build curl/libcurl:
|
||||
|
||||
curl version: ${CURLVERSION}
|
||||
@@ -3523,7 +3533,6 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
|
||||
SSL support: ${curl_ssl_msg}
|
||||
SSH support: ${curl_ssh_msg}
|
||||
zlib support: ${curl_zlib_msg}
|
||||
krb4 support: ${curl_krb4_msg}
|
||||
GSSAPI support: ${curl_gss_msg}
|
||||
SPNEGO support: ${curl_spnego_msg}
|
||||
TLS-SRP support: ${curl_tls_srp_msg}
|
||||
@@ -3542,6 +3551,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
|
||||
RTSP support: ${curl_rtsp_msg}
|
||||
RTMP support: ${curl_rtmp_msg}
|
||||
metalink support: ${curl_mtlnk_msg}
|
||||
HTTP2 support: ${curl_h2_msg}
|
||||
Protocols: ${SUPPORT_PROTOCOLS}
|
||||
])
|
||||
|
||||
|
||||
46
contributors.sh
Executable file
46
contributors.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
# are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the COPYING file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
#
|
||||
# This script shows all mentioned contributors from <hash> until HEAD. To aid
|
||||
# when writing RELEASE-NOTES and THANKS.
|
||||
#
|
||||
|
||||
start=$1
|
||||
|
||||
if test -z "$start"; then
|
||||
echo "Usage: $0 <since this tag/hash>"
|
||||
fi
|
||||
|
||||
# filter out Author:, Commit: and *by: lines
|
||||
# cut off the email parts
|
||||
# cut off spaces first and last on the line
|
||||
# only count names with a space (ie more than one word)
|
||||
# sort all unique names
|
||||
git log $start..HEAD | \
|
||||
egrep '(Author|Commit|by):' | \
|
||||
cut -d: -f2- | \
|
||||
cut '-d<' -f1 | \
|
||||
sed -e 's/^ //' -e 's/ $//g' | \
|
||||
grep ' ' | \
|
||||
sort -u
|
||||
@@ -155,7 +155,12 @@ while test $# -gt 0; do
|
||||
;;
|
||||
|
||||
--static-libs)
|
||||
if test "X@ENABLE_STATIC@" != "Xno" ; then
|
||||
echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@
|
||||
else
|
||||
echo "curl was built with static libraries disabled" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
--configure)
|
||||
|
||||
@@ -79,9 +79,9 @@
|
||||
1.3 What To Read
|
||||
|
||||
Source code, the man pages, the INTERNALS document, TODO, KNOWN_BUGS, the
|
||||
most recent CHANGES. Just lurking on the libcurl mailing list is gonna give
|
||||
you a lot of insights on what's going on right now. Asking there is a good
|
||||
idea too.
|
||||
most recent CHANGES. Just lurking on the curl-library mailing list is gonna
|
||||
give you a lot of insights on what's going on right now. Asking there is a
|
||||
good idea too.
|
||||
|
||||
2. cURL Coding Standards
|
||||
|
||||
@@ -98,12 +98,12 @@
|
||||
|
||||
2.2 Indenting
|
||||
|
||||
Please try using the same indenting levels and bracing method as all the
|
||||
other code already does. It makes the source code a lot easier to follow if
|
||||
all of it is written using the same style. We don't ask you to like it, we
|
||||
just ask you to follow the tradition! ;-) This mainly means: 2-level indents,
|
||||
using spaces only (no tabs) and having the opening brace ({) on the same line
|
||||
as the if() or while().
|
||||
Use the same indenting levels and bracing method as all the other code
|
||||
already does. It makes the source code easier to follow if all of it is
|
||||
written using the same style. We don't ask you to like it, we just ask you to
|
||||
follow the tradition! ;-) This mainly means: 2-level indents, using spaces
|
||||
only (no tabs) and having the opening brace ({) on the same line as the if()
|
||||
or while().
|
||||
|
||||
Also note that we use if() and while() with no space before the parenthesis.
|
||||
|
||||
@@ -151,6 +151,9 @@
|
||||
description exactly what they correct so that all patches can be selectively
|
||||
applied by the maintainer or other interested parties.
|
||||
|
||||
Also, separate patches enable bisecting much better when we track problems in
|
||||
the future.
|
||||
|
||||
2.9 Patch Against Recent Sources
|
||||
|
||||
Please try to get the latest available sources to make your patches
|
||||
@@ -178,6 +181,10 @@
|
||||
test case that verifies that it works as documented. If every submitter also
|
||||
posts a few test cases, it won't end up as a heavy burden on a single person!
|
||||
|
||||
If you don't have test cases or perhaps you have done something that is very
|
||||
hard to write tests for, do explain exactly how you have otherwise tested and
|
||||
verified your changes.
|
||||
|
||||
3. Pushing Out Your Changes
|
||||
|
||||
3.1 Write Access to git Repository
|
||||
|
||||
118
docs/FAQ
118
docs/FAQ
@@ -202,27 +202,25 @@ FAQ
|
||||
better. We do however believe in a few rules when it comes to the future of
|
||||
curl:
|
||||
|
||||
* Curl -- the command line tool -- is to remain a non-graphical command line
|
||||
tool. If you want GUIs or fancy scripting capabilities, you should look
|
||||
for another tool that uses libcurl.
|
||||
Curl -- the command line tool -- is to remain a non-graphical command line
|
||||
tool. If you want GUIs or fancy scripting capabilities, you should look for
|
||||
another tool that uses libcurl.
|
||||
|
||||
* We do not add things to curl that other small and available tools already
|
||||
do very fine at the side. Curl's output is fine to pipe into another
|
||||
program or redirect to another file for the next program to interpret.
|
||||
We do not add things to curl that other small and available tools already do
|
||||
very fine at the side. Curl's output is fine to pipe into another program or
|
||||
redirect to another file for the next program to interpret.
|
||||
|
||||
* We focus on protocol related issues and improvements. If you wanna do more
|
||||
magic with the supported protocols than curl currently does, chances are
|
||||
big we will agree. If you wanna add more protocols, we may very well
|
||||
agree.
|
||||
We focus on protocol related issues and improvements. If you wanna do more
|
||||
magic with the supported protocols than curl currently does, chances are big
|
||||
we will agree. If you wanna add more protocols, we may very well agree.
|
||||
|
||||
* If you want someone else to make all the work while you wait for us to
|
||||
If you want someone else to make all the work while you wait for us to
|
||||
implement it for you, that is not a very friendly attitude. We spend a
|
||||
considerable time already on maintaining and developing curl. In order to
|
||||
get more out of us, you should consider trading in some of your time and
|
||||
efforts in return.
|
||||
|
||||
* If you write the code, chances are bigger that it will get into curl
|
||||
faster.
|
||||
If you write the code, chances are bigger that it will get into curl faster.
|
||||
|
||||
1.5 Who makes curl?
|
||||
|
||||
@@ -263,7 +261,7 @@ FAQ
|
||||
|
||||
Our project name curl has been in effective use since 1998. We were not the
|
||||
first computer related project to use the name "curl" and do not claim any
|
||||
first-hand rights to the name.
|
||||
rights to the name.
|
||||
|
||||
We recognize that we will be living in parallel with curl.com and wish them
|
||||
every success.
|
||||
@@ -620,15 +618,15 @@ FAQ
|
||||
|
||||
Some workarounds usually suggested to overcome this Javascript dependency:
|
||||
|
||||
- Depending on the Javascript complexity, write up a script that
|
||||
translates it to another language and execute that.
|
||||
Depending on the Javascript complexity, write up a script that translates it
|
||||
to another language and execute that.
|
||||
|
||||
- Read the Javascript code and rewrite the same logic in another language.
|
||||
Read the Javascript code and rewrite the same logic in another language.
|
||||
|
||||
- Implement a Javascript interpreter, people have successfully used the
|
||||
Implement a Javascript interpreter, people have successfully used the
|
||||
Mozilla Javascript engine in the past.
|
||||
|
||||
- Ask your admins to stop this, for a static proxy setup or similar.
|
||||
Ask your admins to stop this, for a static proxy setup or similar.
|
||||
|
||||
3.15 Can I do recursive fetches with curl?
|
||||
|
||||
@@ -644,23 +642,27 @@ FAQ
|
||||
There are three different kinds of "certificates" to keep track of when we
|
||||
talk about using SSL-based protocols (HTTPS or FTPS) using curl or libcurl.
|
||||
|
||||
- Client certificate. The server you communicate may require that you can
|
||||
provide this in order to prove that you actually are who you claim to be.
|
||||
If the server doesn't require this, you don't need a client certificate.
|
||||
CLIENT CERTIFICATE
|
||||
|
||||
The server you communicate may require that you can provide this in order to
|
||||
prove that you actually are who you claim to be. If the server doesn't
|
||||
require this, you don't need a client certificate.
|
||||
|
||||
A client certificate is always used together with a private key, and the
|
||||
private key has a pass phrase that protects it.
|
||||
|
||||
- Server certificate. The server you communicate with has a server
|
||||
certificate. You can and should verify this certificate to make sure that
|
||||
you are truly talking to the real server and not a server impersonating
|
||||
it.
|
||||
SERVER CERTIFICATE
|
||||
|
||||
- Certificate Authority certificate ("CA cert"). You often have several CA
|
||||
certs in a CA cert bundle that can be used to verify a server certificate
|
||||
that was signed by one of the authorities in the bundle. curl does not
|
||||
come with a CA cert bundle but most curl installs provide one. You can
|
||||
also override the default.
|
||||
The server you communicate with has a server certificate. You can and should
|
||||
verify this certificate to make sure that you are truly talking to the real
|
||||
server and not a server impersonating it.
|
||||
|
||||
CERTIFICATE AUTHORITY CERTIFICATE ("CA cert")
|
||||
|
||||
You often have several CA certs in a CA cert bundle that can be used to
|
||||
verify a server certificate that was signed by one of the authorities in the
|
||||
bundle. curl does not come with a CA cert bundle but most curl installs
|
||||
provide one. You can also override the default.
|
||||
|
||||
The server certificate verification process is made by using a Certificate
|
||||
Authority certificate ("CA cert") that was used to sign the server
|
||||
@@ -669,9 +671,9 @@ FAQ
|
||||
4.12 and the SSLCERTS document
|
||||
(http://curl.haxx.se/docs/sslcerts.html). Server certificates that are
|
||||
"self-signed" or otherwise signed by a CA that you do not have a CA cert
|
||||
for, cannot be verified. If the verification during a connect fails, you
|
||||
are refused access. You then need to explicitly disable the verification
|
||||
to connect to the server.
|
||||
for, cannot be verified. If the verification during a connect fails, you are
|
||||
refused access. You then need to explicitly disable the verification to
|
||||
connect to the server.
|
||||
|
||||
3.17 How do I list the root dir of an FTP server?
|
||||
|
||||
@@ -728,7 +730,7 @@ FAQ
|
||||
When passing on a URL to curl to use, it may respond that the particular
|
||||
protocol is not supported or disabled. The particular way this error message
|
||||
is phrased is because curl doesn't make a distinction internally of whether
|
||||
a particular protocol is not supported (ie never got any code added that
|
||||
a particular protocol is not supported (i.e. never got any code added that
|
||||
knows how to speak that protocol) or if it was explicitly disabled. curl can
|
||||
be built to only support a given set of protocols, and the rest would then
|
||||
be disabled or not supported.
|
||||
@@ -794,12 +796,13 @@ FAQ
|
||||
|
||||
curl 'http://www.altavista.com/cgi-bin/query?text=yes&q=curl'
|
||||
|
||||
In Windows, the standard DOS shell treats the %-symbol specially and you
|
||||
need to use TWO %-symbols for each single one you want to use in the URL.
|
||||
In Windows, the standard DOS shell treats the percent sign specially and you
|
||||
need to use TWO percent signs for each single one you want to use in the
|
||||
URL.
|
||||
|
||||
Also note that if you want the literal %-symbol to be part of the data you
|
||||
pass in a POST using -d/--data you must encode it as '%25' (which then also
|
||||
needs the %-symbol doubled on Windows machines).
|
||||
If you want a literal percent sign to be part of the data you pass in a POST
|
||||
using -d/--data you must encode it as '%25' (which then also needs the
|
||||
percent sign doubled on Windows machines).
|
||||
|
||||
4.3 How can I use {, }, [ or ] to specify multiple URLs?
|
||||
|
||||
@@ -968,13 +971,13 @@ FAQ
|
||||
4.14 Redirects work in browser but not with curl!
|
||||
|
||||
curl supports HTTP redirects fine (see item 3.8). Browsers generally support
|
||||
at least two other ways to perform directs that curl does not:
|
||||
at least two other ways to perform redirects that curl does not:
|
||||
|
||||
- Meta tags. You can write a HTML tag that will cause the browser to
|
||||
redirect to another given URL after a certain time.
|
||||
Meta tags. You can write a HTML tag that will cause the browser to redirect
|
||||
to another given URL after a certain time.
|
||||
|
||||
- Javascript. You can write a Javascript program embedded in a HTML page
|
||||
that redirects the browser to another given URL.
|
||||
Javascript. You can write a Javascript program embedded in a HTML page that
|
||||
redirects the browser to another given URL.
|
||||
|
||||
There is no way to make curl follow these redirects. You must either
|
||||
manually figure out what the page is set to do, or you write a script that
|
||||
@@ -1055,11 +1058,11 @@ FAQ
|
||||
|
||||
4.19 Why doesn't cURL return an error when the network cable is unplugged?
|
||||
|
||||
Unplugging the cable is not an error situation. The TCP/IP protocol stack
|
||||
Unplugging a cable is not an error situation. The TCP/IP protocol stack
|
||||
was designed to be fault tolerant, so even though there may be a physical
|
||||
break somewhere the connection shouldn't be affected, just possibly
|
||||
delayed. Eventually, the physical break will be fixed or the data will be
|
||||
re-routed around the physical problem.
|
||||
re-routed around the physical problem through another path.
|
||||
|
||||
In such cases, the TCP/IP stack is responsible for detecting when the
|
||||
network connection is irrevocably lost. Since with some protocols it is
|
||||
@@ -1077,6 +1080,12 @@ FAQ
|
||||
falls too low, and --connect-timeout and --max-time can be used to put an
|
||||
overall timeout on the connection phase or the entire transfer.
|
||||
|
||||
A libcurl-using application running in a known physical environment (e.g.
|
||||
an embedded device with only a single network connection) may want to act
|
||||
immediately if its lone network connection goes down. That can be achieved
|
||||
by having the application monitor the network connection on its own using an
|
||||
OS-specific mechanism, then signalling libcurl to abort (see also item 5.13).
|
||||
|
||||
|
||||
5. libcurl Issues
|
||||
|
||||
@@ -1086,7 +1095,9 @@ FAQ
|
||||
|
||||
We have written the libcurl code specifically adjusted for multi-threaded
|
||||
programs. libcurl will use thread-safe functions instead of non-safe ones if
|
||||
your system has such.
|
||||
your system has such. Note that you must never share the same handle in
|
||||
multiple threads.
|
||||
|
||||
|
||||
If you use a OpenSSL-powered libcurl in a multi-threaded environment, you
|
||||
need to provide one or two locking functions:
|
||||
@@ -1262,17 +1273,18 @@ FAQ
|
||||
|
||||
5.12 Can I make libcurl fake or hide my real IP address?
|
||||
|
||||
No. libcurl operates on a higher level than so. Besides, faking IP address
|
||||
would imply sending IP packages with a made-up source address, and then you
|
||||
normally get a problem with intercepting the packages sent back as they
|
||||
would then not be routed to you!
|
||||
No. libcurl operates on a higher level. Besides, faking IP address would
|
||||
imply sending IP packet with a made-up source address, and then you normally
|
||||
get a problem with receiving the packet sent back as they would then not be
|
||||
routed to you!
|
||||
|
||||
If you use a proxy to access remote sites, the sites will not see your local
|
||||
IP address but instead the address of the proxy.
|
||||
|
||||
Also note that on many networks NATs or other IP-munging techniques are used
|
||||
that makes you see and use a different IP address locally than what the
|
||||
remote server will see you coming from.
|
||||
remote server will see you coming from. You may also consider using
|
||||
http://www.torproject.org .
|
||||
|
||||
5.13 How do I stop an ongoing transfer?
|
||||
|
||||
|
||||
14
docs/HISTORY
14
docs/HISTORY
@@ -7,19 +7,19 @@
|
||||
How cURL Became Like This
|
||||
|
||||
|
||||
In the second half of 1997, Daniel Stenberg came up with the idea to make
|
||||
Towards the end of 1996, Daniel Stenberg came up with the idea to make
|
||||
currency-exchange calculations available to Internet Relay Chat (IRC)
|
||||
users. All the necessary data are published on the Web; he just needed to
|
||||
automate their retrieval.
|
||||
|
||||
Daniel simply adopted an existing command-line open-source tool, httpget, that
|
||||
Brazilian Rafael Sagula had written. After a few minor adjustments, it did
|
||||
just what he needed.
|
||||
Brazilian Rafael Sagula had written and recently release version 0.1 of. After
|
||||
a few minor adjustments, it did just what he needed. HttpGet 1.0 was released
|
||||
on April 8th 1997 with brand new HTTP proxy support.
|
||||
|
||||
Soon, he found currencies on a GOPHER site, so support for that had to go in,
|
||||
and not before long FTP download support was added as well. The name of the
|
||||
project was changed to urlget to better fit what it actually did now, since
|
||||
the http-only days were already passed.
|
||||
We soon found and fixed support for getting currencies over GOPHER. Once FTP
|
||||
download support was added, the name of the project was changed and urlget 2.0
|
||||
was released in August 1997. The http-only days were already passed.
|
||||
|
||||
The project slowly grew bigger. When upload capabilities were added and the
|
||||
name once again was misleading, a second name change was made and on March 20,
|
||||
|
||||
@@ -220,7 +220,7 @@ Win32
|
||||
adjust as necessary. It is also possible to override these paths with
|
||||
environment variables, for example:
|
||||
|
||||
set ZLIB_PATH=c:\zlib-1.2.7
|
||||
set ZLIB_PATH=c:\zlib-1.2.8
|
||||
set OPENSSL_PATH=c:\openssl-0.9.8y
|
||||
set LIBSSH2_PATH=c:\libssh2-1.4.3
|
||||
|
||||
@@ -323,7 +323,7 @@ Win32
|
||||
documentation on how to compile zlib. Define the ZLIB_PATH environment
|
||||
variable to the location of zlib.h and zlib.lib, for example:
|
||||
|
||||
set ZLIB_PATH=c:\zlib-1.2.7
|
||||
set ZLIB_PATH=c:\zlib-1.2.8
|
||||
|
||||
Then run 'nmake vc-zlib' in curl's root directory.
|
||||
|
||||
@@ -1045,7 +1045,7 @@ PORTS
|
||||
- Alpha OpenVMS V7.1-1H2
|
||||
- Alpha Tru64 v5.0 5.1
|
||||
- AVR32 Linux
|
||||
- ARM Android 1.5, 2.1
|
||||
- ARM Android 1.5, 2.1, 2.3, 3.2, 4.x
|
||||
- ARM INTEGRITY
|
||||
- ARM iOS
|
||||
- Cell Linux
|
||||
@@ -1116,6 +1116,7 @@ GNU GSS http://www.gnu.org/software/gss/
|
||||
GnuTLS http://www.gnu.org/software/gnutls/
|
||||
Heimdal http://www.pdc.kth.se/heimdal/
|
||||
libidn http://www.gnu.org/software/libidn/
|
||||
libmetalink https://launchpad.net/libmetalink/
|
||||
libssh2 http://www.libssh2.org/
|
||||
MIT Kerberos http://web.mit.edu/kerberos/www/dist/
|
||||
NSS http://www.mozilla.org/projects/security/pki/nss/
|
||||
|
||||
113
docs/INTERNALS
113
docs/INTERNALS
@@ -111,6 +111,9 @@ Windows vs Unix
|
||||
Library
|
||||
=======
|
||||
|
||||
(See LIBCURL-STRUCTS for a separate document describing all major internal
|
||||
structs and their purposes.)
|
||||
|
||||
There are plenty of entry points to the library, namely each publicly defined
|
||||
function that libcurl offers to applications. All of those functions are
|
||||
rather small and easy-to-follow. All the ones prefixed with 'curl_easy' are
|
||||
@@ -135,16 +138,18 @@ Library
|
||||
options is documented in the man page. This function mainly sets things in
|
||||
the 'SessionHandle' struct.
|
||||
|
||||
curl_easy_perform() does a whole lot of things:
|
||||
curl_easy_perform() is just a wrapper function that makes use of the multi
|
||||
API. It basically curl_multi_init(), curl_multi_add_handle(),
|
||||
curl_multi_wait(), and curl_multi_perform() until the transfer is done and
|
||||
then returns.
|
||||
|
||||
It starts off in the lib/easy.c file by calling Curl_perform() and the main
|
||||
work then continues in lib/url.c. The flow continues with a call to
|
||||
Curl_connect() to connect to the remote site.
|
||||
Some of the most important key functions in url.c are called from multi.c
|
||||
when certain key steps are to be made in the transfer operation.
|
||||
|
||||
o Curl_connect()
|
||||
|
||||
... analyzes the URL, it separates the different components and connects to
|
||||
the remote host. This may involve using a proxy and/or using SSL. The
|
||||
Analyzes the URL, it separates the different components and connects to the
|
||||
remote host. This may involve using a proxy and/or using SSL. The
|
||||
Curl_resolv() function in lib/hostip.c is used for looking up host names
|
||||
(it does then use the proper underlying method, which may vary between
|
||||
platforms and builds).
|
||||
@@ -160,10 +165,7 @@ Library
|
||||
o Curl_do()
|
||||
|
||||
Curl_do() makes sure the proper protocol-specific function is called. The
|
||||
functions are named after the protocols they handle. Curl_ftp(),
|
||||
Curl_http(), Curl_dict(), etc. They all reside in their respective files
|
||||
(ftp.c, http.c and dict.c). HTTPS is handled by Curl_http() and FTPS by
|
||||
Curl_ftp().
|
||||
functions are named after the protocols they handle.
|
||||
|
||||
The protocol-specific functions of course deal with protocol-specific
|
||||
negotiations and setup. They have access to the Curl_sendf() (from
|
||||
@@ -182,10 +184,9 @@ Library
|
||||
be called with some basic info about the upcoming transfer: what socket(s)
|
||||
to read/write and the expected file transfer sizes (if known).
|
||||
|
||||
o Transfer()
|
||||
o Curl_readwrite()
|
||||
|
||||
Curl_perform() then calls Transfer() in lib/transfer.c that performs the
|
||||
entire file transfer.
|
||||
Called during the transfer of the actual protocol payload.
|
||||
|
||||
During transfer, the progress functions in lib/progress.c are called at a
|
||||
frequent interval (or at the user's choice, a specified callback might get
|
||||
@@ -207,33 +208,11 @@ Library
|
||||
used. This function is only used when we are certain that no more transfers
|
||||
is going to be made on the connection. It can be also closed by force, or
|
||||
it can be called to make sure that libcurl doesn't keep too many
|
||||
connections alive at the same time (there's a default amount of 5 but that
|
||||
can be changed with the CURLOPT_MAXCONNECTS option).
|
||||
connections alive at the same time.
|
||||
|
||||
This function cleans up all resources that are associated with a single
|
||||
connection.
|
||||
|
||||
Curl_perform() is the function that does the main "connect - do - transfer -
|
||||
done" loop. It loops if there's a Location: to follow.
|
||||
|
||||
When completed, the curl_easy_cleanup() should be called to free up used
|
||||
resources. It runs Curl_disconnect() on all open connections.
|
||||
|
||||
A quick roundup on internal function sequences (many of these call
|
||||
protocol-specific function-pointers):
|
||||
|
||||
Curl_connect - connects to a remote site and does initial connect fluff
|
||||
This also checks for an existing connection to the requested site and uses
|
||||
that one if it is possible.
|
||||
|
||||
Curl_do - starts a transfer
|
||||
Curl_handler::do_it() - transfers data
|
||||
Curl_done - ends a transfer
|
||||
|
||||
Curl_disconnect - disconnects from a remote site. This is called when the
|
||||
disconnect is really requested, which doesn't necessarily have to be
|
||||
exactly after curl_done in case we want to keep the connection open for
|
||||
a while.
|
||||
|
||||
HTTP(S)
|
||||
|
||||
@@ -316,48 +295,38 @@ Persistent Connections
|
||||
hold connection-oriented data. It is meant to hold the root data as well as
|
||||
all the options etc that the library-user may choose.
|
||||
o The 'SessionHandle' struct holds the "connection cache" (an array of
|
||||
pointers to 'connectdata' structs). There's one connectdata struct
|
||||
allocated for each connection that libcurl knows about. Note that when you
|
||||
use the multi interface, the multi handle will hold the connection cache
|
||||
and not the particular easy handle. This of course to allow all easy handles
|
||||
in a multi stack to be able to share and re-use connections.
|
||||
pointers to 'connectdata' structs).
|
||||
o This enables the 'curl handle' to be reused on subsequent transfers.
|
||||
o When we are about to perform a transfer with curl_easy_perform(), we first
|
||||
check for an already existing connection in the cache that we can use,
|
||||
otherwise we create a new one and add to the cache. If the cache is full
|
||||
already when we add a new connection, we close one of the present ones. We
|
||||
select which one to close dependent on the close policy that may have been
|
||||
previously set.
|
||||
o When the transfer operation is complete, we try to leave the connection
|
||||
open. Particular options may tell us not to, and protocols may signal
|
||||
closure on connections and then we don't keep it open of course.
|
||||
o When libcurl is told to perform a transfer, it first checks for an already
|
||||
existing connection in the cache that we can use. Otherwise it creates a
|
||||
new one and adds that the cache. If the cache is full already when a new
|
||||
conncetion is added added, it will first close the oldest unused one.
|
||||
o When the transfer operation is complete, the connection is left
|
||||
open. Particular options may tell libcurl not to, and protocols may signal
|
||||
closure on connections and then they won't be kept open of course.
|
||||
o When curl_easy_cleanup() is called, we close all still opened connections,
|
||||
unless of course the multi interface "owns" the connections.
|
||||
|
||||
You do realize that the curl handle must be re-used in order for the
|
||||
persistent connections to work.
|
||||
The curl handle must be re-used in order for the persistent connections to
|
||||
work.
|
||||
|
||||
multi interface/non-blocking
|
||||
============================
|
||||
|
||||
We make an effort to provide a non-blocking interface to the library, the
|
||||
multi interface. To make that interface work as good as possible, no
|
||||
low-level functions within libcurl must be written to work in a blocking
|
||||
manner.
|
||||
The multi interface is a non-blocking interface to the library. To make that
|
||||
interface work as good as possible, no low-level functions within libcurl
|
||||
must be written to work in a blocking manner. (There are still a few spots
|
||||
violating this rule.)
|
||||
|
||||
One of the primary reasons we introduced c-ares support was to allow the name
|
||||
resolve phase to be perfectly non-blocking as well.
|
||||
|
||||
The ultimate goal is to provide the easy interface simply by wrapping the
|
||||
multi interface functions and thus treat everything internally as the multi
|
||||
interface is the single interface we have.
|
||||
|
||||
The FTP and the SFTP/SCP protocols are thus perfect examples of how we adapt
|
||||
and adjust the code to allow non-blocking operations even on multi-stage
|
||||
protocols. They are built around state machines that return when they could
|
||||
block waiting for data. The DICT, LDAP and TELNET protocols are crappy
|
||||
examples and they are subject for rewrite in the future to better fit the
|
||||
libcurl protocol family.
|
||||
The FTP and the SFTP/SCP protocols are examples of how we adapt and adjust
|
||||
the code to allow non-blocking operations even on multi-stage command-
|
||||
response protocols. They are built around state machines that return when
|
||||
they would otherwise block waiting for data. The DICT, LDAP and TELNET
|
||||
protocols are crappy examples and they are subject for rewrite in the future
|
||||
to better fit the libcurl protocol family.
|
||||
|
||||
SSL libraries
|
||||
=============
|
||||
@@ -408,12 +377,12 @@ API/ABI
|
||||
Client
|
||||
======
|
||||
|
||||
main() resides in src/main.c together with most of the client code.
|
||||
main() resides in src/tool_main.c.
|
||||
|
||||
src/tool_hugehelp.c is automatically generated by the mkhelp.pl perl script
|
||||
to display the complete "manual" and the src/urlglob.c file holds the
|
||||
functions used for the URL-"globbing" support. Globbing in the sense that
|
||||
the {} and [] expansion stuff is there.
|
||||
to display the complete "manual" and the src/tool_urlglob.c file holds the
|
||||
functions used for the URL-"globbing" support. Globbing in the sense that the
|
||||
{} and [] expansion stuff is there.
|
||||
|
||||
The client mostly messes around to setup its 'config' struct properly, then
|
||||
it calls the curl_easy_*() functions of the library and when it gets back
|
||||
@@ -425,8 +394,8 @@ Client
|
||||
curl_easy_getinfo() function to extract useful information from the curl
|
||||
session.
|
||||
|
||||
Recent versions may loop and do all this several times if many URLs were
|
||||
specified on the command line or config file.
|
||||
It may loop and do all this several times if many URLs were specified on the
|
||||
command line or config file.
|
||||
|
||||
Memory Debugging
|
||||
================
|
||||
|
||||
@@ -3,20 +3,42 @@ join in and help us correct one or more of these! Also be sure to check the
|
||||
changelog of the current development status, as one or more of these problems
|
||||
may have been fixed since this was written!
|
||||
|
||||
84. CURLINFO_SSL_VERIFYRESULT is only implemented for the OpenSSL and NSS
|
||||
backends, so relying on this information in a generic app is flaky.
|
||||
|
||||
83. curl is unable to load non-default openssl engines, because openssl isn't
|
||||
initialized properly. This seems to require OpenSSL_config() or
|
||||
CONF_modules_load_file() to be used by libcurl but the first seems to not
|
||||
work and we've gotten not reports from tests with the latter. Possibly we
|
||||
need to discuss with OpenSSL developers how this is supposed to be done. We
|
||||
need users with actual external openssl engines for testing to work on this.
|
||||
http://curl.haxx.se/bug/view.cgi?id=1208
|
||||
|
||||
82. When building with the Windows Borland compiler, it fails because the
|
||||
"tlib" tool doesn't support hyphens (minus signs) in file names and we have
|
||||
such in the build.
|
||||
http://curl.haxx.se/bug/view.cgi?id=1222
|
||||
|
||||
81. When using -J (with -O), automaticly resumed downloading together with "-C
|
||||
-" fails. Without -J the same command line works! This happens because the
|
||||
resume logic is worked out before the target file name (and thus its
|
||||
pre-transfer size) has been figured out!
|
||||
http://curl.haxx.se/bug/view.cgi?id=1169
|
||||
|
||||
80. Curl doesn't recognize certificates in DER format in keychain, but it
|
||||
works with PEM.
|
||||
http://curl.haxx.se/bug/view.cgi?id=3439999
|
||||
http://curl.haxx.se/bug/view.cgi?id=1065
|
||||
|
||||
79. SMTP. When sending data to multiple recipients, curl will abort and return
|
||||
failure if one of the recipients indicate failure (on the "RCPT TO"
|
||||
command). Ordinary mail programs would proceed and still send to the ones
|
||||
that can receive data. This is subject for change in the future.
|
||||
http://curl.haxx.se/bug/view.cgi?id=3438362
|
||||
http://curl.haxx.se/bug/view.cgi?id=1116
|
||||
|
||||
78. curl and libcurl don't always signal the client properly when "sending"
|
||||
zero bytes files - it makes for example the command line client not creating
|
||||
any file at all. Like when using FTP.
|
||||
http://curl.haxx.se/bug/view.cgi?id=3438362
|
||||
http://curl.haxx.se/bug/view.cgi?id=1063
|
||||
|
||||
77. CURLOPT_FORBID_REUSE on a handle prevents NTLM from working since it
|
||||
"abuses" the underlying connection re-use system and if connections are
|
||||
@@ -31,7 +53,7 @@ may have been fixed since this was written!
|
||||
properly if built with UNICODE defined together with the schannel/winssl
|
||||
backend. The original problem was mentioned in:
|
||||
http://curl.haxx.se/mail/lib-2009-10/0024.html
|
||||
http://curl.haxx.se/bug/view.cgi?id=2944325
|
||||
http://curl.haxx.se/bug/view.cgi?id=896
|
||||
|
||||
The schannel version verified to work as mentioned in
|
||||
http://curl.haxx.se/mail/lib-2012-07/0073.html
|
||||
@@ -41,7 +63,7 @@ may have been fixed since this was written!
|
||||
acknowledge the connection timeout during that phase but only the "real"
|
||||
timeout - which may surprise users as it is probably considered to be the
|
||||
connect phase to most people. Brought up (and is being misunderstood) in:
|
||||
http://curl.haxx.se/bug/view.cgi?id=2844077
|
||||
http://curl.haxx.se/bug/view.cgi?id=856
|
||||
|
||||
72. "Pausing pipeline problems."
|
||||
http://curl.haxx.se/mail/lib-2009-07/0214.html
|
||||
@@ -59,7 +81,7 @@ may have been fixed since this was written!
|
||||
http://tools.ietf.org/html/draft-reschke-rfc2231-in-http-02
|
||||
|
||||
66. When using telnet, the time limitation options don't work.
|
||||
http://curl.haxx.se/bug/view.cgi?id=2818950
|
||||
http://curl.haxx.se/bug/view.cgi?id=846
|
||||
|
||||
65. When doing FTP over a socks proxy or CONNECT through HTTP proxy and the
|
||||
multi interface is used, libcurl will fail if the (passive) TCP connection
|
||||
@@ -85,19 +107,12 @@ may have been fixed since this was written!
|
||||
CURLOPT_FAILONERROR with FTP to detect if a file exists or not, but it is
|
||||
not working: http://curl.haxx.se/mail/lib-2008-07/0295.html
|
||||
|
||||
57. On VMS-Alpha: When using an http-file-upload the file is not sent to the
|
||||
Server with the correct content-length. Sending a file with 511 or less
|
||||
bytes, content-length 512 is used. Sending a file with 513 - 1023 bytes,
|
||||
content-length 1024 is used. Files with a length of a multiple of 512 Bytes
|
||||
show the correct content-length. Only these files work for upload.
|
||||
http://curl.haxx.se/bug/view.cgi?id=2057858
|
||||
|
||||
56. When libcurl sends CURLOPT_POSTQUOTE commands when connected to a SFTP
|
||||
server using the multi interface, the commands are not being sent correctly
|
||||
and instead the connection is "cancelled" (the operation is considered done)
|
||||
prematurely. There is a half-baked (busy-looping) patch provided in the bug
|
||||
report but it cannot be accepted as-is. See
|
||||
http://curl.haxx.se/bug/view.cgi?id=2006544
|
||||
http://curl.haxx.se/bug/view.cgi?id=748
|
||||
|
||||
55. libcurl fails to build with MIT Kerberos for Windows (KfW) due to KfW's
|
||||
library header files exporting symbols/macros that should be kept private
|
||||
@@ -121,12 +136,12 @@ may have been fixed since this was written!
|
||||
protocol code. This should be very rare.
|
||||
|
||||
43. There seems to be a problem when connecting to the Microsoft telnet server.
|
||||
http://curl.haxx.se/bug/view.cgi?id=1720605
|
||||
http://curl.haxx.se/bug/view.cgi?id=649
|
||||
|
||||
41. When doing an operation over FTP that requires the ACCT command (but not
|
||||
when logging in), the operation will fail since libcurl doesn't detect this
|
||||
and thus fails to issue the correct command:
|
||||
http://curl.haxx.se/bug/view.cgi?id=1693337
|
||||
http://curl.haxx.se/bug/view.cgi?id=635
|
||||
|
||||
39. Steffen Rumler's Race Condition in Curl_proxyCONNECT:
|
||||
http://curl.haxx.se/mail/lib-2007-01/0045.html
|
||||
@@ -139,7 +154,7 @@ may have been fixed since this was written!
|
||||
|
||||
34. The SOCKS4 connection codes don't properly acknowledge (connect) timeouts.
|
||||
Also see #12. According to bug #1556528, even the SOCKS5 connect code does
|
||||
not do it right: http://curl.haxx.se/bug/view.cgi?id=1556528,
|
||||
not do it right: http://curl.haxx.se/bug/view.cgi?id=604
|
||||
|
||||
31. "curl-config --libs" will include details set in LDFLAGS when configure is
|
||||
run that might be needed only for building libcurl. Further, curl-config
|
||||
@@ -154,13 +169,12 @@ may have been fixed since this was written!
|
||||
IDs in URLs to get around the problem of percent signs being
|
||||
special. According to the reporter, Firefox deals with the URL _with_ a
|
||||
percent letter (which seems like a blatant URL spec violation).
|
||||
libcurl supports zone IDs where the percent sign is URL-escaped (i.e. %25).
|
||||
|
||||
See http://curl.haxx.se/bug/view.cgi?id=1371118
|
||||
libcurl supports zone IDs where the percent sign is URL-escaped (i.e. %25):
|
||||
http://curl.haxx.se/bug/view.cgi?id=555
|
||||
|
||||
26. NTLM authentication using SSPI (on Windows) when (lib)curl is running in
|
||||
"system context" will make it use wrong(?) user name - at least when compared
|
||||
to what winhttp does. See http://curl.haxx.se/bug/view.cgi?id=1281867
|
||||
to what winhttp does. See http://curl.haxx.se/bug/view.cgi?id=535
|
||||
|
||||
23. SOCKS-related problems:
|
||||
B) libcurl doesn't support FTPS over a SOCKS proxy.
|
||||
@@ -169,12 +183,6 @@ may have been fixed since this was written!
|
||||
We probably have even more bugs and lack of features when a SOCKS proxy is
|
||||
used.
|
||||
|
||||
22. Sending files to a FTP server using curl on VMS, might lead to curl
|
||||
complaining on "unaligned file size" on completion. The problem is related
|
||||
to VMS file structures and the perceived file sizes stat() returns. A
|
||||
possible fix would involve sending a "STRU VMS" command.
|
||||
http://curl.haxx.se/bug/view.cgi?id=1156287
|
||||
|
||||
21. FTP ASCII transfers do not follow RFC959. They don't convert the data
|
||||
accordingly (not for sending nor for receiving). RFC 959 section 3.1.1.1
|
||||
clearly describes how this should be done:
|
||||
@@ -212,7 +220,7 @@ may have been fixed since this was written!
|
||||
10. To get HTTP Negotiate authentication to work fine, you need to provide a
|
||||
(fake) user name (this concerns both curl and the lib) because the code
|
||||
wrongly only considers authentication if there's a user name provided.
|
||||
http://curl.haxx.se/bug/view.cgi?id=1004841. How?
|
||||
http://curl.haxx.se/bug/view.cgi?id=440 How?
|
||||
http://curl.haxx.se/mail/lib-2004-08/0182.html
|
||||
|
||||
8. Doing resumed upload over HTTP does not work with '-C -', because curl
|
||||
|
||||
245
docs/LIBCURL-STRUCTS
Normal file
245
docs/LIBCURL-STRUCTS
Normal file
@@ -0,0 +1,245 @@
|
||||
_ _ ____ _
|
||||
___| | | | _ \| |
|
||||
/ __| | | | |_) | |
|
||||
| (__| |_| | _ <| |___
|
||||
\___|\___/|_| \_\_____|
|
||||
|
||||
Structs in libcurl
|
||||
|
||||
This document should cover 7.32.0 pretty accurately, but will make sense even
|
||||
for older and later versions as things don't change drastically that often.
|
||||
|
||||
1. The main structs in libcurl
|
||||
1.1 SessionHandle
|
||||
1.2 connectdata
|
||||
1.3 Curl_multi
|
||||
1.4 Curl_handler
|
||||
1.5 conncache
|
||||
1.6 Curl_share
|
||||
1.7 CookieInfo
|
||||
|
||||
==============================================================================
|
||||
|
||||
1. The main structs in libcurl
|
||||
|
||||
1.1 SessionHandle
|
||||
|
||||
The SessionHandle handle struct is the one returned to the outside in the
|
||||
external API as a "CURL *". This is usually known as an easy handle in API
|
||||
documentations and examples.
|
||||
|
||||
Information and state that is related to the actual connection is in the
|
||||
'connectdata' struct. When a transfer is about to be made, libcurl will
|
||||
either create a new connection or re-use an existing one. The particular
|
||||
connectdata that is used by this handle is pointed out by
|
||||
SessionHandle->easy_conn.
|
||||
|
||||
Data and information that regard this particular single transfer is put in
|
||||
the SingleRequest sub-struct.
|
||||
|
||||
When the SessionHandle struct is added to a multi handle, as it must be in
|
||||
order to do any transfer, the ->multi member will point to the Curl_multi
|
||||
struct it belongs to. The ->prev and ->next members will then be used by the
|
||||
multi code to keep a linked list of SessionHandle structs that are added to
|
||||
that same multi handle. libcurl always uses multi so ->multi *will* point to
|
||||
a Curl_multi when a transfer is in progress.
|
||||
|
||||
->mstate is the multi state of this particular SessionHandle. When
|
||||
multi_runsingle() is called, it will act on this handle according to which
|
||||
state it is in. The mstate is also what tells which sockets to return for a
|
||||
speicific SessionHandle when curl_multi_fdset() is called etc.
|
||||
|
||||
The libcurl source code generally use the name 'data' for the variable that
|
||||
points to the SessionHandle.
|
||||
|
||||
|
||||
1.2 connectdata
|
||||
|
||||
A general idea in libcurl is to keep connections around in a connection
|
||||
"cache" after they have been used in case they will be used again and then
|
||||
re-use an existing one instead of creating a new as it creates a significant
|
||||
performance boost.
|
||||
|
||||
Each 'connectdata' identifies a single physical conncetion to a server. If
|
||||
the connection can't be kept alive, the connection will be closed after use
|
||||
and then this struct can be removed from the cache and freed.
|
||||
|
||||
Thus, the same SessionHandle can be used multiple times and each time select
|
||||
another connectdata struct to use for the connection. Keep this in mind, as
|
||||
it is then important to consider if options or choices are based on the
|
||||
connection or the SessionHandle.
|
||||
|
||||
Functions in libcurl will assume that connectdata->data points to the
|
||||
SessionHandle that uses this connection.
|
||||
|
||||
As a special complexity, some protocols supported by libcurl require a
|
||||
special disconnect procedure that is more than just shutting down the
|
||||
socket. It can involve sending one or more commands to the server before
|
||||
doing so. Since connections are kept in the connection cache after use, the
|
||||
original SessionHandle may no longer be around when the time comes to shut
|
||||
down a particular connection. For this purpose, libcurl holds a special
|
||||
dummy 'closure_handle' SessionHandle in the Curl_multi struct to
|
||||
|
||||
FTP uses two TCP connections for a typical transfer but it keeps both in
|
||||
this single struct and thus can be considered a single connection for most
|
||||
internal concerns.
|
||||
|
||||
The libcurl source code generally use the name 'conn' for the variable that
|
||||
points to the connectdata.
|
||||
|
||||
|
||||
1.3 Curl_multi
|
||||
|
||||
Internally, the easy interface is implemented as a wrapper around multi
|
||||
interface functions. This makes everything multi interface.
|
||||
|
||||
Curl_multi is the multi handle struct exposed as "CURLM *" in external APIs.
|
||||
|
||||
This struct holds a list of SessionHandle structs that have been added to
|
||||
this handle with curl_multi_add_handle(). The start of the list is ->easyp
|
||||
and ->num_easy is a counter of added SessionHandles.
|
||||
|
||||
->msglist is a linked list of messages to send back when
|
||||
curl_multi_info_read() is called. Basically a node is added to that list
|
||||
when an individual SessionHandle's transfer has completed.
|
||||
|
||||
->hostcache points to the name cache. It is a hash table for looking up name
|
||||
to IP. The nodes have a limited life time in there and this cache is meant
|
||||
to reduce the time for when the same name is wanted within a short period of
|
||||
time.
|
||||
|
||||
->timetree points to a tree of SessionHandles, sorted by the remaining time
|
||||
until it should be checked - normally some sort of timeout. Each
|
||||
SessionHandle has one node in the tree.
|
||||
|
||||
->sockhash is a hash table to allow fast lookups of socket descriptor to
|
||||
which SessionHandle that uses that descriptor. This is necessary for the
|
||||
multi_socket API.
|
||||
|
||||
->conn_cache points to the connection cache. It keeps track of all
|
||||
connections that are kept after use. The cache has a maximum size.
|
||||
|
||||
->closure_handle is described in the 'connectdata' section.
|
||||
|
||||
The libcurl source code generally use the name 'multi' for the variable that
|
||||
points to the Curl_multi struct.
|
||||
|
||||
|
||||
1.4 Curl_handler
|
||||
|
||||
Each unique protocol that is supported by libcurl needs to provide at least
|
||||
one Curl_handler struct. It defines what the protocol is called and what
|
||||
functions the main code should call to deal with protocol specific issues.
|
||||
In general, there's a source file named [protocol].c in which there's a
|
||||
"struct Curl_handler Curl_handler_[protocol]" declared. In url.c there's
|
||||
then the main array with all individual Curl_handler structs pointed to from
|
||||
a single array which is scanned through when a URL is given to libcurl to
|
||||
work with.
|
||||
|
||||
->scheme is the URL scheme name, usually spelled out in uppercase. That's
|
||||
"HTTP" or "FTP" etc. SSL versions of the protcol need its own Curl_handler
|
||||
setup so HTTPS separate from HTTP.
|
||||
|
||||
->setup_connection is called to allow the protocol code to allocate protocol
|
||||
specific data that then gets associated with that SessionHandle for the rest
|
||||
of this transfer. It gets freed again at the end of the transfer. It will be
|
||||
called before the 'connectdata' for the transfer has been selected/created.
|
||||
Most protocols will allocate its private 'struct [PROTOCOL]' here and assign
|
||||
SessionHandle->req.protop to point to it.
|
||||
|
||||
->connect_it allows a protocol to do some specific actions after the TCP
|
||||
connect is done, that can still be considered part of the connection phase.
|
||||
|
||||
Some protocols will alter the connectdata->recv[] and connectdata->send[]
|
||||
function pointers in this function.
|
||||
|
||||
->connecting is similarly a function that keeps getting called as long as the
|
||||
protocol considers itself still in the connecting phase.
|
||||
|
||||
->do_it is the function called to issue the transfer request. What we call
|
||||
the DO action internally. If the DO is not enough and things need to be kept
|
||||
getting done for the entier DO sequence to complete, ->doing is then usually
|
||||
also provided. Each protocol that needs to do multiple commands or similar
|
||||
for do/doing need to implement their own state machines (see SCP, SFTP,
|
||||
FTP). Some protocols (only FTP and only due to historical reasons) has a
|
||||
separate piece of the DO state called DO_MORE.
|
||||
|
||||
->doing keeps getting called while issudeing the transfer request command(s)
|
||||
|
||||
->done gets called when the transfer is complete and DONE. That's after the
|
||||
main data has been transferred.
|
||||
|
||||
->do_more gets called doring the DO_MORE state. The FTP protocol uses this
|
||||
state when setting up the second connection.
|
||||
|
||||
->proto_getsock
|
||||
->doing_getsock
|
||||
->domore_getsock
|
||||
->perform_getsock
|
||||
Functions that return socket information. Which socket(s) to wait for which
|
||||
action(s) during the particular multi state.
|
||||
|
||||
->disconnect is called immediately before the TCP connection is shutdown.
|
||||
|
||||
->readwrite gets called during transfer to allow the protocol to do extra
|
||||
reads/writes
|
||||
|
||||
->defport is the default report TCP or UDP port this protocol uses
|
||||
|
||||
->protocol is one or more bits in the CURLPROTO_* set. The SSL versions have
|
||||
their "base" protocol set and then the SSL variation. Like "HTTP|HTTPS".
|
||||
|
||||
->flags is a bitmask with additional information about the protocol that will
|
||||
make it get treated differently by the generic engine:
|
||||
|
||||
PROTOPT_SSL - will make it connect and negotiate SSL
|
||||
|
||||
PROTOPT_DUAL - this protocol uses two connections
|
||||
|
||||
PROTOPT_CLOSEACTION - this protocol has actions to do before closing the
|
||||
connection. This flag is no longer used by code, yet still set for a bunch
|
||||
protocol handlers.
|
||||
|
||||
PROTOPT_DIRLOCK - "direction lock". The SSH protocols set this bit to
|
||||
limit which "direction" of socket actions that the main engine will
|
||||
concern itself about.
|
||||
|
||||
PROTOPT_NONETWORK - a protocol that doesn't use network (read file:)
|
||||
|
||||
PROTOPT_NEEDSPWD - this protocol needs a password and will use a default
|
||||
one unless one is provided
|
||||
|
||||
PROTOPT_NOURLQUERY - this protocol can't handle a query part on the URL
|
||||
(?foo=bar)
|
||||
|
||||
|
||||
1.5 conncache
|
||||
|
||||
Is a hash table with connections for later re-use. Each SessionHandle has
|
||||
a pointer to its connection cache. Each multi handle sets up a connection
|
||||
cache that all added SessionHandles share by default.
|
||||
|
||||
|
||||
1.6 Curl_share
|
||||
|
||||
The libcurl share API allocates a Curl_share struct, exposed to the external
|
||||
API as "CURLSH *".
|
||||
|
||||
The idea is that the struct can have a set of own versions of caches and
|
||||
pools and then by providing this struct in the CURLOPT_SHARE option, those
|
||||
specific SessionHandles will use the caches/pools that this share handle
|
||||
holds.
|
||||
|
||||
Then individual SessionHandle structs can be made to share specific things
|
||||
that they otherwise wouldn't, such as cookies.
|
||||
|
||||
The Curl_share struct can currently hold cookies, DNS cache and the SSL
|
||||
session cache.
|
||||
|
||||
|
||||
1.7 CookieInfo
|
||||
|
||||
This is the main cookie struct. It holds all known cookies and related
|
||||
information. Each SessionHandle has its own private CookieInfo even when
|
||||
they are added to a multi handle. They can be made to share cookies by using
|
||||
the share API.
|
||||
@@ -5,7 +5,7 @@
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
# Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
@@ -22,7 +22,8 @@
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign no-dependencies
|
||||
|
||||
man_MANS = curl.1 curl-config.1 mk-ca-bundle.1
|
||||
man_MANS = curl.1 curl-config.1
|
||||
noinst_man_MANS = mk-ca-bundle.1
|
||||
GENHTMLPAGES = curl.html curl-config.html mk-ca-bundle.html
|
||||
PDFPAGES = curl.pdf curl-config.pdf mk-ca-bundle.pdf
|
||||
|
||||
@@ -36,7 +37,7 @@ EXTRA_DIST = MANUAL BUGS CONTRIBUTE FAQ FEATURES INTERNALS SSLCERTS \
|
||||
README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS VERSIONS \
|
||||
KNOWN_BUGS BINDINGS $(man_MANS) $(HTMLPAGES) HISTORY INSTALL \
|
||||
$(PDFPAGES) LICENSE-MIXING README.netware DISTRO-DILEMMA INSTALL.devcpp \
|
||||
MAIL-ETIQUETTE HTTP-COOKIES
|
||||
MAIL-ETIQUETTE HTTP-COOKIES LIBCURL-STRUCTS
|
||||
|
||||
MAN2HTML= roffit < $< >$@
|
||||
|
||||
|
||||
60
docs/THANKS
60
docs/THANKS
@@ -13,14 +13,15 @@ Adam Tkac
|
||||
Adrian Schuur
|
||||
Adriano Meirelles
|
||||
Ajit Dhumale
|
||||
Aki Koskinen
|
||||
Akos Pasztory
|
||||
Alan Pinstein
|
||||
Albert Chin
|
||||
Albert Chin-A-Young
|
||||
Albert Choy
|
||||
Ale Vesely
|
||||
Alejandro Alvarez
|
||||
Aleksandar Milivojevic
|
||||
Aleksey Tulinov
|
||||
Alessandro Ghedini
|
||||
Alessandro Vesely
|
||||
Alex Bligh
|
||||
@@ -31,6 +32,7 @@ Alex Suykov
|
||||
Alex Vinnik
|
||||
Alex aka WindEagle
|
||||
Alexander Beedie
|
||||
Alexander Klauer
|
||||
Alexander Kourakos
|
||||
Alexander Krasnostavsky
|
||||
Alexander Lazic
|
||||
@@ -46,11 +48,13 @@ Amol Pattekar
|
||||
Amr Shahin
|
||||
Anatoli Tubman
|
||||
Anders Gustafsson
|
||||
Anders Havn
|
||||
Andi Jahja
|
||||
Andre Guibert de Bruet
|
||||
Andreas Damm
|
||||
Andreas Faerber
|
||||
Andreas Farber
|
||||
Andreas Malzahn
|
||||
Andreas Ntaflos
|
||||
Andreas Olsson
|
||||
Andreas Rieke
|
||||
@@ -64,9 +68,11 @@ Andrew Biggs
|
||||
Andrew Bushnell
|
||||
Andrew Francis
|
||||
Andrew Fuller
|
||||
Andrew Kurushin
|
||||
Andrew Moise
|
||||
Andrew Wansink
|
||||
Andrew de los Reyes
|
||||
Andrii Moiseiev
|
||||
Andrés García
|
||||
Andy Cedilnik
|
||||
Andy Serpa
|
||||
@@ -101,12 +107,14 @@ Ben Van Hof
|
||||
Ben Winslow
|
||||
Benbuck Nason
|
||||
Benjamin Gerard
|
||||
Benjamin Gilbert
|
||||
Benjamin Johnson
|
||||
Bernard Leak
|
||||
Bernhard Reutner-Fischer
|
||||
Bertrand Demiddelaer
|
||||
Bill Egert
|
||||
Bill Hoffman
|
||||
Bill Middlecamp
|
||||
Bjoern Sikora
|
||||
Bjorn Augustsson
|
||||
Bjorn Reese
|
||||
@@ -133,6 +141,7 @@ Bruce Mitchener
|
||||
Bruno de Carvalho
|
||||
Bryan Henderson
|
||||
Bryan Kemp
|
||||
Byrial Jensen
|
||||
Cameron Kaiser
|
||||
Camille Moncelier
|
||||
Caolan McNamara
|
||||
@@ -153,13 +162,13 @@ Chris Maltby
|
||||
Chris Mumford
|
||||
Chris Smowton
|
||||
Christian Grothoff
|
||||
Christian Hagele
|
||||
Christian Hägele
|
||||
Christian Krause
|
||||
Christian Kurz
|
||||
Christian Robottom Reis
|
||||
Christian Schmitz
|
||||
Christian Vogt
|
||||
Christian Weisgerber
|
||||
Christophe Demory
|
||||
Christophe Legry
|
||||
Christopher Conroy
|
||||
@@ -169,6 +178,7 @@ Christopher Stone
|
||||
Ciprian Badescu
|
||||
Claes Jakobsson
|
||||
Clarence Gardner
|
||||
Clemens Gruber
|
||||
Clifford Wolf
|
||||
Cody Jones
|
||||
Colin Hogben
|
||||
@@ -180,10 +190,10 @@ Craig A West
|
||||
Craig Davison
|
||||
Craig Markwardt
|
||||
Cris Bailiff
|
||||
Cristian Rodriguez
|
||||
Cristian Rodríguez
|
||||
Curt Bogmine
|
||||
Cyrill Osterwalder
|
||||
Cédric Deltheil
|
||||
Dag Ekengren
|
||||
Dagobert Michelsen
|
||||
Damien Adant
|
||||
@@ -231,6 +241,7 @@ David Odin
|
||||
David Phillips
|
||||
David Rosenstrauch
|
||||
David Shaw
|
||||
David Strauss
|
||||
David Tarendash
|
||||
David Thiel
|
||||
David Wright
|
||||
@@ -263,6 +274,7 @@ Douglas R. Horner
|
||||
Douglas Steinwand
|
||||
Dov Murik
|
||||
Duane Cathey
|
||||
Duncan
|
||||
Duncan Mac-Vicar Prett
|
||||
Dustin Boswell
|
||||
Dylan Ellicott
|
||||
@@ -271,6 +283,7 @@ Early Ehlinger
|
||||
Ebenezer Ikonne
|
||||
Edin Kadribasic
|
||||
Eduard Bloch
|
||||
Edward Rudd
|
||||
Edward Sheldrake
|
||||
Eelco Dolstra
|
||||
Eetu Ojanen
|
||||
@@ -288,15 +301,18 @@ Eric Lavigne
|
||||
Eric Melville
|
||||
Eric Mertens
|
||||
Eric Rautman
|
||||
Eric S. Raymond
|
||||
Eric Thelin
|
||||
Eric Vergnaud
|
||||
Eric Wong
|
||||
Eric Young
|
||||
Erick Nuwendam
|
||||
Erik Johansson
|
||||
Erwan Legrand
|
||||
Erwin Authried
|
||||
Eugene Kotlyarov
|
||||
Evan Jordan
|
||||
Evgeny Turnaev
|
||||
Eygene Ryabinkin
|
||||
Fabian Hiernaux
|
||||
Fabian Keil
|
||||
@@ -317,6 +333,7 @@ Fred Machado
|
||||
Fred New
|
||||
Fred Noz
|
||||
Frederic Lepied
|
||||
Fredrik Thulin
|
||||
Gabriel Kuri
|
||||
Gabriel Sjoberg
|
||||
Garrett Holmstrom
|
||||
@@ -360,6 +377,7 @@ Gwenole Beauchesne
|
||||
Götz Babin-Ebell
|
||||
Hamish Mackenzie
|
||||
Hang Kin Lau
|
||||
Hang Su
|
||||
Hanno Kranzhoff
|
||||
Hans Steegers
|
||||
Hans-Jurgen May
|
||||
@@ -394,6 +412,7 @@ Immanuel Gregoire
|
||||
Ingmar Runge
|
||||
Ingo Ralf Blum
|
||||
Ingo Wilken
|
||||
Ishan SinghLevett
|
||||
Jack Zhang
|
||||
Jacky Lam
|
||||
Jacob Meuser
|
||||
@@ -415,6 +434,7 @@ Jan Koen Annot
|
||||
Jan Kunder
|
||||
Jan Schaumann
|
||||
Jan Van Boghout
|
||||
Jared Jennings
|
||||
Jared Lundell
|
||||
Jari Sundell
|
||||
Jason Glasgow
|
||||
@@ -429,6 +449,7 @@ Jean-Claude Chauve
|
||||
Jean-Francois Bertrand
|
||||
Jean-Louis Lemaire
|
||||
Jean-Marc Ranger
|
||||
Jean-Noel Rouvignac
|
||||
Jean-Philippe Barrette-LaPierre
|
||||
Jeff Connelly
|
||||
Jeff Johnson
|
||||
@@ -438,6 +459,7 @@ Jeff Pohlmeyer
|
||||
Jeff Weber
|
||||
Jeffrey Pohlmeyer
|
||||
Jeremy Friesner
|
||||
Jeremy Huddleston
|
||||
Jerome Muffat-Meridol
|
||||
Jerome Vouillon
|
||||
Jerry Wu
|
||||
@@ -449,8 +471,8 @@ Jim Drash
|
||||
Jim Freeman
|
||||
Jim Hollinger
|
||||
Jim Meyering
|
||||
Jiri Jaburek
|
||||
Jiri Hruska
|
||||
Jiri Jaburek
|
||||
Jocelyn Jaubert
|
||||
Joe Halpin
|
||||
Joe Malicki
|
||||
@@ -465,6 +487,7 @@ John Bradshaw
|
||||
John Crow
|
||||
John Dennis
|
||||
John E. Malmberg
|
||||
John Gardiner Myers
|
||||
John Janssen
|
||||
John Joseph Bachir
|
||||
John Kelly
|
||||
@@ -506,6 +529,7 @@ Julien Royer
|
||||
Jun-ichiro itojun Hagino
|
||||
Jurij Smakov
|
||||
Justin Fletcher
|
||||
Justin Karneges
|
||||
Jörg Mueller-Tolk
|
||||
Jörn Hartroth
|
||||
Kai Engert
|
||||
@@ -534,10 +558,12 @@ Kevin Lussier
|
||||
Kevin Reed
|
||||
Kevin Roth
|
||||
Kim Rinnewitz
|
||||
Kim Vandry
|
||||
Kimmo Kinnunen
|
||||
Kjell Ericson
|
||||
Kjetil Jacobsen
|
||||
Klevtsov Vadim
|
||||
Konstantin Isakov
|
||||
Kris Kennaway
|
||||
Krishnendu Majumdar
|
||||
Krister Johansen
|
||||
@@ -550,6 +576,7 @@ Larry Fahnoe
|
||||
Lars Buitinck
|
||||
Lars Gustafsson
|
||||
Lars J. Aas
|
||||
Lars Johannesen
|
||||
Lars Nilsson
|
||||
Lars Torben Wilson
|
||||
Lau Hang Kin
|
||||
@@ -572,6 +599,7 @@ Loren Kirkby
|
||||
Luca Altea
|
||||
Luca Alteas
|
||||
Lucas Adamski
|
||||
Ludovico Cavedon
|
||||
Lukasz Czekierda
|
||||
Luke Amery
|
||||
Luke Call
|
||||
@@ -583,6 +611,7 @@ Mandy Wu
|
||||
Manfred Schwarb
|
||||
Manuel Massing
|
||||
Marc Boucher
|
||||
Marc Doughty
|
||||
Marc Hoersken
|
||||
Marc Kleine-Budde
|
||||
Marcel Raad
|
||||
@@ -614,6 +643,7 @@ Martin C. Martin
|
||||
Martin Drasar
|
||||
Martin Hager
|
||||
Martin Hedenfalk
|
||||
Martin Jansen
|
||||
Martin Lemke
|
||||
Martin Skinner
|
||||
Martin Storsjo
|
||||
@@ -661,12 +691,14 @@ Michal Gorny
|
||||
Michal Kowalczyk
|
||||
Michal Marek
|
||||
Michele Bini
|
||||
Miguel Angel
|
||||
Mihai Ionescu
|
||||
Mikael Johansson
|
||||
Mikael Sennerholm
|
||||
Mike Bytnar
|
||||
Mike Crowe
|
||||
Mike Dobbs
|
||||
Mike Giancola
|
||||
Mike Hommey
|
||||
Mike Power
|
||||
Mike Protts
|
||||
@@ -676,6 +708,8 @@ Mitz Wark
|
||||
Mohamed Lrhazi
|
||||
Mohun Biswas
|
||||
Moonesamy
|
||||
Myk Taylor
|
||||
Nach M. S.
|
||||
Nathan Coulter
|
||||
Nathan O'Sullivan
|
||||
Nathanael Nerode
|
||||
@@ -709,6 +743,7 @@ Ofer
|
||||
Olaf Flebbe
|
||||
Olaf Stueben
|
||||
Olaf Stüben
|
||||
Oliver Gondža
|
||||
Olivier Berger
|
||||
Oren Tirosh
|
||||
Ori Avtalion
|
||||
@@ -720,6 +755,7 @@ Pascal Terjan
|
||||
Pasha Kuznetsov
|
||||
Pat Ray
|
||||
Patrice Guerin
|
||||
Patricia Muscalu
|
||||
Patrick Bihan-Faou
|
||||
Patrick Monnerat
|
||||
Patrick Scott
|
||||
@@ -742,6 +778,7 @@ Pedro Neves
|
||||
Pete Su
|
||||
Peter Bray
|
||||
Peter Forret
|
||||
Peter Gal
|
||||
Peter Heuchert
|
||||
Peter Hjalmarsson
|
||||
Peter Korsgaard
|
||||
@@ -779,6 +816,7 @@ Quinn Slack
|
||||
Rafa Muyo
|
||||
Rafael Sagula
|
||||
Rainer Canavan
|
||||
Rainer Jung
|
||||
Rainer Koenig
|
||||
Rajesh Naganathan
|
||||
Ralf S. Engelschall
|
||||
@@ -793,6 +831,7 @@ Reinout van Schouwen
|
||||
Renato Botelho
|
||||
Renaud Chaillat
|
||||
Renaud Duhaut
|
||||
Renaud Guillard
|
||||
Rene Bernhardt
|
||||
Rene Rebe
|
||||
Reuven Wachtfogel
|
||||
@@ -806,6 +845,7 @@ Richard Bramante
|
||||
Richard Clayton
|
||||
Richard Cooper
|
||||
Richard Gorton
|
||||
Richard Michael
|
||||
Richard Prescott
|
||||
Richard Silverman
|
||||
Rick Jones
|
||||
@@ -822,6 +862,7 @@ Robert Iakobashvili
|
||||
Robert Olson
|
||||
Robert Schumann
|
||||
Robert Weaver
|
||||
Robert Wruck
|
||||
Robin Cornelius
|
||||
Robin Johnson
|
||||
Robin Kay
|
||||
@@ -846,6 +887,7 @@ Ryan Schmidt
|
||||
S. Moonesamy
|
||||
Salvador Dávila
|
||||
Salvatore Sorrentino
|
||||
Sam Deane
|
||||
Sam Listopad
|
||||
Sampo Kellomaki
|
||||
Samuel Díaz García
|
||||
@@ -856,6 +898,7 @@ Sandor Feldi
|
||||
Santhana Todatry
|
||||
Saqib Ali
|
||||
Sara Golemon
|
||||
Saran Neti
|
||||
Saul good
|
||||
Scott Bailey
|
||||
Scott Barrett
|
||||
@@ -888,6 +931,7 @@ Stan van de Burgt
|
||||
Stanislav Ivochkin
|
||||
Stefan Esser
|
||||
Stefan Krause
|
||||
Stefan Neis
|
||||
Stefan Teleman
|
||||
Stefan Tomanek
|
||||
Stefan Ulrich
|
||||
@@ -906,6 +950,7 @@ Steve Oliphant
|
||||
Steve Roskowski
|
||||
Steven Bazyl
|
||||
Steven G. Johnson
|
||||
Steven Gu
|
||||
Steven M. Schweda
|
||||
Steven Parkes
|
||||
Stoned Elipot
|
||||
@@ -934,6 +979,7 @@ Tim Harder
|
||||
Tim Heckman
|
||||
Tim Newsome
|
||||
Tim Sneddon
|
||||
Timo Sirainen
|
||||
Tinus van den Berg
|
||||
Tobias Rundström
|
||||
Toby Peterson
|
||||
@@ -943,6 +989,7 @@ Todd Ouska
|
||||
Todd Vierling
|
||||
Tom Benoist
|
||||
Tom Donovan
|
||||
Tom Grace
|
||||
Tom Lee
|
||||
Tom Mattison
|
||||
Tom Moers
|
||||
@@ -994,9 +1041,12 @@ Wesley Laxton
|
||||
Wesley Miaw
|
||||
Wez Furlong
|
||||
Wilfredo Sanchez
|
||||
Willem Sparreboom
|
||||
Wojciech Zwiefka
|
||||
Wouter Van Rooy
|
||||
Wu Yongzheng
|
||||
Xavier Bouchoux
|
||||
Yamada Yasuharu
|
||||
Yang Tse
|
||||
Yarram Sunil
|
||||
Yehoshua Hershberg
|
||||
@@ -1004,6 +1054,8 @@ Yukihiro Kawada
|
||||
Yuriy Sosov
|
||||
Yves Arrouye
|
||||
Yves Lejeune
|
||||
Zdenek Pavlas
|
||||
Zekun Ni
|
||||
Zmey Petroff
|
||||
Zvi Har'El
|
||||
nk
|
||||
|
||||
133
docs/TODO
133
docs/TODO
@@ -16,8 +16,8 @@
|
||||
1.3 struct lifreq
|
||||
1.4 signal-based resolver timeouts
|
||||
1.5 get rid of PATH_MAX
|
||||
1.6 progress callback without doubles
|
||||
1.7 Happy Eyeball dual stack connect
|
||||
1.6 Happy Eyeball dual stack connect
|
||||
1.7 Modified buffer size approach
|
||||
|
||||
2. libcurl - multi interface
|
||||
2.1 More non-blocking
|
||||
@@ -38,6 +38,7 @@
|
||||
5.1 Better persistency for HTTP 1.0
|
||||
5.2 support FF3 sqlite cookie files
|
||||
5.3 Rearrange request header order
|
||||
5.4 HTTP2/SPDY
|
||||
|
||||
6. TELNET
|
||||
6.1 ditch stdin
|
||||
@@ -46,19 +47,18 @@
|
||||
6.4 send data in chunks
|
||||
|
||||
7. SMTP
|
||||
7.1 Specify the preferred authentication mechanism
|
||||
7.2 Initial response
|
||||
7.3 Pipelining
|
||||
7.4 Graceful base64 decoding failure
|
||||
7.1 Pipelining
|
||||
7.2 Graceful base64 decoding failure
|
||||
7.3 Enhanced capability support
|
||||
|
||||
8. POP3
|
||||
8.1 auth= in URLs
|
||||
8.2 Initial response
|
||||
8.3 Graceful base64 decoding failure
|
||||
8.1 Pipelining
|
||||
8.2 Graceful base64 decoding failure
|
||||
8.3 Enhanced capability support
|
||||
|
||||
9. IMAP
|
||||
9.1 auth= in URLs
|
||||
9.2 Graceful base64 decoding failure
|
||||
9.1 Graceful base64 decoding failure
|
||||
9.2 Enhanced capability support
|
||||
|
||||
10. LDAP
|
||||
10.1 SASL based authentication mechanisms
|
||||
@@ -157,16 +157,7 @@
|
||||
we need libssh2 to properly tell us when we pass in a too small buffer and
|
||||
its current API (as of libssh2 1.2.7) doesn't.
|
||||
|
||||
1.6 progress callback without doubles
|
||||
|
||||
The progress callback was introduced way back in the days and the choice to
|
||||
use doubles in the arguments was possibly good at the time. Today the doubles
|
||||
only confuse users and make the amounts less precise. We should introduce
|
||||
another progress callback option that take precedence over the old one and
|
||||
have both co-exist for a forseeable time until we can remove the double-using
|
||||
one.
|
||||
|
||||
1.7 Happy Eyeball dual stack connect
|
||||
1.6 Happy Eyeball dual stack connect
|
||||
|
||||
In order to make alternative technologies not suffer when transitioning, like
|
||||
when introducing IPv6 as an alternative to IPv4 and there are more than one
|
||||
@@ -178,6 +169,28 @@
|
||||
|
||||
http://tools.ietf.org/html/rfc6555
|
||||
|
||||
1.7 Modified buffer size approach
|
||||
|
||||
Current libcurl allocates a fixed 16K size buffer for download and an
|
||||
additional 16K for upload. They are always unconditionally part of the easy
|
||||
handle. If CRLF translations are requested, an additional 32K "scratch
|
||||
buffer" is allocated. A total of 64K transfer buffers in the worst case.
|
||||
|
||||
First, while the handles are not actually in use these buffers could be freed
|
||||
so that lingering handles just kept in queues or whatever waste less memory.
|
||||
|
||||
Secondly, SFTP is a protocol that needs to handle many ~30K blocks at once
|
||||
since each need to be individually acked and therefore libssh2 must be
|
||||
allowed to send (or receive) many separate ones in parallel to achieve high
|
||||
transfer speeds. A current libcurl build with a 16K buffer makes that
|
||||
impossible, but one with a 512K buffer will reach MUCH faster transfers. But
|
||||
allocating 512K unconditionally for all buffers just in case they would like
|
||||
to do fast SFTP transfers at some point is not a good solution either.
|
||||
|
||||
Dynamically allocate buffer size depending on protocol in use in combination
|
||||
with freeing it after each individual transfer? Other suggestions?
|
||||
|
||||
|
||||
2. libcurl - multi interface
|
||||
|
||||
2.1 More non-blocking
|
||||
@@ -269,6 +282,25 @@
|
||||
headers use a default value so only headers that need to be moved have to be
|
||||
specified.
|
||||
|
||||
5.4 HTTP2/SPDY
|
||||
|
||||
The first drafts for HTTP2 have been published
|
||||
(http://tools.ietf.org/html/draft-ietf-httpbis-http2-03) and is so far based
|
||||
on SPDY (http://www.chromium.org/spdy) designs and experiences. Chances are
|
||||
it will end up in that style. Chrome and Firefox already support SPDY and
|
||||
lots of web services do.
|
||||
|
||||
It would make sense to implement SPDY support now and later transition into
|
||||
or add HTTP2 support as well.
|
||||
|
||||
We should base or HTTP2/SPDY work on a 3rd party library for the protocol
|
||||
fiddling. The Spindy library (http://spindly.haxx.se/) was an attempt to make
|
||||
such a library with an API suitable for use by libcurl but that effort has
|
||||
more or less stalled. spdylay (https://github.com/tatsuhiro-t/spdylay) may
|
||||
be a better option, either used directly or wrapped with a more spindly-like
|
||||
API.
|
||||
|
||||
|
||||
6. TELNET
|
||||
|
||||
6.1 ditch stdin
|
||||
@@ -295,65 +327,54 @@ to provide the data to send.
|
||||
|
||||
7. SMTP
|
||||
|
||||
7.1 Specify the preferred authentication mechanism
|
||||
|
||||
Add the ability to specify the preferred authentication mechanism or a list
|
||||
of mechanisms that should be used. Not only that, but the order that is
|
||||
returned by the server during the EHLO response should be honored by curl.
|
||||
|
||||
7.2 Initial response
|
||||
|
||||
Add the ability for the user to specify whether the initial response is
|
||||
included in the AUTH command. Some email servers, such as Microsoft
|
||||
Exchange, can work with either whilst others need to have the initial
|
||||
response sent separately:
|
||||
|
||||
http://curl.haxx.se/mail/lib-2012-03/0114.html
|
||||
|
||||
7.3 Pipelining
|
||||
7.1 Pipelining
|
||||
|
||||
Add support for pipelining emails.
|
||||
|
||||
7.4 Graceful base64 decoding failure
|
||||
7.2 Graceful base64 decoding failure
|
||||
|
||||
Rather than shutting down the session and returning an error when the
|
||||
decoding of a base64 encoded authentication response fails, we should
|
||||
gracefully shutdown the authentication process by sending a * response to the
|
||||
server as per RFC4954.
|
||||
|
||||
7.3 Enhanced capability support
|
||||
|
||||
Add the ability, for an application that uses libcurl, to obtain the list of
|
||||
capabilities returned from the EHLO command.
|
||||
|
||||
8. POP3
|
||||
|
||||
8.1 auth= in URLs
|
||||
8.1 Pipelining
|
||||
|
||||
Being able to specify the preferred authentication mechanism in the URL as
|
||||
per RFC2384.
|
||||
Add support for pipelining commands.
|
||||
|
||||
8.2 Initial response
|
||||
|
||||
Add the ability for the user to specify whether the initial response is
|
||||
included in the AUTH command as per RFC5034.
|
||||
|
||||
8.3 Graceful base64 decoding failure
|
||||
8.2 Graceful base64 decoding failure
|
||||
|
||||
Rather than shutting down the session and returning an error when the
|
||||
decoding of a base64 encoded authentication response fails, we should
|
||||
gracefully shutdown the authentication process by sending a * response to the
|
||||
server as per RFC5034.
|
||||
|
||||
8.3 Enhanced capability support
|
||||
|
||||
Add the ability, for an application that uses libcurl, to obtain the list of
|
||||
capabilities returned from the CAPA command.
|
||||
|
||||
9. IMAP
|
||||
|
||||
9.1 auth= in URLs
|
||||
|
||||
Being able to specify the preferred authentication mechanism in the URL as
|
||||
per RFC5092.
|
||||
|
||||
9.2 Graceful base64 decoding failure
|
||||
9.1 Graceful base64 decoding failure
|
||||
|
||||
Rather than shutting down the session and returning an error when the
|
||||
decoding of a base64 encoded authentication response fails, we should
|
||||
gracefully shutdown the authentication process by sending a * response to the
|
||||
server as per RFC3501.
|
||||
|
||||
9.2 Enhanced capability support
|
||||
|
||||
Add the ability, for an application that uses libcurl, to obtain the list of
|
||||
capabilities returned from the CAPABILITY command.
|
||||
|
||||
10. LDAP
|
||||
|
||||
10.1 SASL based authentication mechanisms
|
||||
@@ -429,6 +450,12 @@ to provide the data to send.
|
||||
keys and certs over DNS using DNSSEC as an alternative to the CA model.
|
||||
http://www.rfc-editor.org/rfc/rfc6698.txt
|
||||
|
||||
An initial patch was posted by Suresh Krishnaswamy on March 7th 2013
|
||||
(http://curl.haxx.se/mail/lib-2013-03/0075.html) but it was a too simple
|
||||
approach. See Daniel's comments:
|
||||
http://curl.haxx.se/mail/lib-2013-03/0103.html . libunbound may be the
|
||||
correct library to base this development on.
|
||||
|
||||
13. GnuTLS
|
||||
|
||||
13.1 SSL engine stuff
|
||||
|
||||
152
docs/curl.1
152
docs/curl.1
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -103,6 +103,18 @@ any response data to the terminal.
|
||||
If you prefer a progress "bar" instead of the regular meter, \fI-#\fP is your
|
||||
friend.
|
||||
.SH OPTIONS
|
||||
Options start with one or two dashes. Many of the options require an addition
|
||||
value next to it.
|
||||
|
||||
The short "single-dash" form of the options, -d for example, may be used with
|
||||
or without a space between it and its value, although a space is a recommended
|
||||
separator. The long "double-dash" form, --data for example, requires a space
|
||||
between it and its value.
|
||||
|
||||
Short version options that don't need any additional values can be used
|
||||
immediately next to each other, like for example you can specify all the
|
||||
options -O, -L and -v at once as -OLv.
|
||||
|
||||
In general, all boolean options are enabled with --\fBoption\fP and yet again
|
||||
disabled with --\fBno-\fPoption. That is, you use the exact same option name
|
||||
but prefix it with "no-". However, in this list we mostly only list and show
|
||||
@@ -113,8 +125,14 @@ same command line option.)
|
||||
Make curl display progress as a simple progress bar instead of the standard,
|
||||
more informational, meter.
|
||||
.IP "-0, --http1.0"
|
||||
(HTTP) Forces curl to issue its requests using HTTP 1.0 instead of using its
|
||||
internally preferred: HTTP 1.1.
|
||||
(HTTP) Tells curl to use HTTP version 1.0 instead of using its internally
|
||||
preferred: HTTP 1.1.
|
||||
.IP "--http1.1"
|
||||
(HTTP) Tells curl to use HTTP version 1.1. This is the internal default
|
||||
version. (Added in 7.33.0)
|
||||
.IP "--http2.0"
|
||||
(HTTP) Tells curl to issue its requests using HTTP 2.0. This requires that the
|
||||
underlying libcurl was built to support it. (Added in 7.33.0)
|
||||
.IP "-1, --tlsv1"
|
||||
(SSL)
|
||||
Forces curl to use TLS version 1 when negotiating with a remote TLS server.
|
||||
@@ -230,7 +248,9 @@ server sends an unsupported encoding, curl will report an error.
|
||||
.IP "--connect-timeout <seconds>"
|
||||
Maximum time in seconds that you allow the connection to the server to take.
|
||||
This only limits the connection phase, once curl has connected this option is
|
||||
of no more use. See also the \fI-m, --max-time\fP option.
|
||||
of no more use. Since 7.32.0, this option accepts decimal values, but the
|
||||
actual timeout will decrease in accuracy as the specified timeout increases in
|
||||
decimal precision. See also the \fI-m, --max-time\fP option.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "--create-dirs"
|
||||
@@ -270,7 +290,8 @@ If you start the data with the letter @, the rest should be a file name to
|
||||
read the data from, or - if you want curl to read the data from stdin. The
|
||||
contents of the file must already be URL-encoded. Multiple files can also be
|
||||
specified. Posting data from a file named 'foobar' would thus be done with
|
||||
\fI--data @foobar\fP.
|
||||
\fI--data\fP @foobar. When --data is told to read from a file like that,
|
||||
carriage returns and newlines will be stripped out.
|
||||
.IP "-D, --dump-header <file>"
|
||||
Write the protocol headers to the specified file.
|
||||
|
||||
@@ -292,7 +313,7 @@ whatsoever.
|
||||
|
||||
If you start the data with the letter @, the rest should be a filename. Data
|
||||
is posted in a similar manner as \fI--data-ascii\fP does, except that newlines
|
||||
are preserved and conversions are never done.
|
||||
and carriage returns are preserved and conversions are never done.
|
||||
|
||||
If this option is used several times, the ones following the first will append
|
||||
data as described in \fI-d, --data\fP.
|
||||
@@ -367,6 +388,39 @@ is an alias for \fB--disable-epsv\fP.
|
||||
|
||||
Disabling EPSV only changes the passive behavior. If you want to switch to
|
||||
active mode you need to use \fI-P, --ftp-port\fP.
|
||||
.IP "--dns-interface <interface>"
|
||||
Tell curl to send outgoing DNS requests through <interface>. This option
|
||||
is a counterpart to \fI--interface\fP (which does not affect DNS). The
|
||||
supplied string must be an interface name (not an address).
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one. (Added in
|
||||
7.33.0)
|
||||
.IP "--dns-ipv4-addr <ip-address>"
|
||||
Tell curl to bind to <ip-address> when making IPv4 DNS requests, so that
|
||||
the DNS requests originate from this address. The argument should be a
|
||||
single IPv4 address.
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one. (Added in
|
||||
7.33.0)
|
||||
.IP "--dns-ipv6-addr <ip-address>"
|
||||
Tell curl to bind to <ip-address> when making IPv6 DNS requests, so that
|
||||
the DNS requests originate from this address. The argument should be a
|
||||
single IPv6 address.
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one. (Added in
|
||||
7.33.0)
|
||||
.IP "--dns-servers <ip-address,ip-address>"
|
||||
Set the list of DNS servers to be used instead of the system default.
|
||||
The list of IP addresses should be separated with commas. Port numbers
|
||||
may also optionally be given as \fI:<port-number>\fP after each IP
|
||||
address.
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one. (Added in
|
||||
7.33.0)
|
||||
.IP "-e, --referer <URL>"
|
||||
(HTTP) Sends the "Referer Page" information to the HTTP server. This can also
|
||||
be set with the \fI-H, --header\fP flag of course. When used with
|
||||
@@ -378,7 +432,8 @@ If this option is used several times, the last one will be used.
|
||||
.IP "-E, --cert <certificate[:password]>"
|
||||
(SSL) Tells curl to use the specified client certificate file when getting a
|
||||
file with HTTPS, FTPS or another SSL-based protocol. The certificate must be
|
||||
in PEM format. If the optional password isn't specified, it will be queried
|
||||
in PKCS#12 format if using Secure Transport, or PEM format if using any other
|
||||
engine. If the optional password isn't specified, it will be queried
|
||||
for on the terminal. Note that this option assumes a \&"certificate" file that
|
||||
is the private key and the private certificate concatenated! See \fI--cert\fP
|
||||
and \fI--key\fP to specify them independently.
|
||||
@@ -388,7 +443,16 @@ curl the nickname of the certificate to use within the NSS database defined
|
||||
by the environment variable SSL_DIR (or by default /etc/pki/nssdb). If the
|
||||
NSS PEM PKCS#11 module (libnsspem.so) is available then PEM files may be
|
||||
loaded. If you want to use a file from the current directory, please precede
|
||||
it with "./" prefix, in order to avoid confusion with a nickname.
|
||||
it with "./" prefix, in order to avoid confusion with a nickname. If the
|
||||
nickname contains ":", it needs to be preceded by "\\" so that it is not
|
||||
recognized as password delimiter. If the nickname contains "\\", it needs to
|
||||
be escaped as "\\\\" so that it is not recognized as an escape character.
|
||||
|
||||
(iOS and Mac OS X only) If curl is built against Secure Transport, then the
|
||||
certificate string can either be the name of a certificate/private key in the
|
||||
system or user keychain, or the path to a PKCS#12-encoded certificate and
|
||||
private key. If you want to use a file from the current directory, please
|
||||
precede it with "./" prefix, in order to avoid confusion with a nickname.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "--engine <name>"
|
||||
@@ -805,7 +869,10 @@ Basic authentication).
|
||||
.IP "-m, --max-time <seconds>"
|
||||
Maximum time in seconds that you allow the whole operation to take. This is
|
||||
useful for preventing your batch jobs from hanging for hours due to slow
|
||||
networks or links going down. See also the \fI--connect-timeout\fP option.
|
||||
networks or links going down. Since 7.32.0, this option accepts decimal
|
||||
values, but the actual timeout will decrease in accuracy as the specified
|
||||
timeout increases in decimal precision. See also the \fI--connect-timeout\fP
|
||||
option.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "--mail-auth <address>"
|
||||
@@ -987,6 +1054,14 @@ you want the file saved in a different directory, make sure you change current
|
||||
working directory before you invoke curl with the \fB-O, --remote-name\fP flag!
|
||||
|
||||
You may use this option as many times as the number of URLs you have.
|
||||
.IP "--oauth2-bearer"
|
||||
(IMAP/POP3/SMTP) Specify the Bearer Token for OAUTH 2.0 server authentication.
|
||||
The Bearer Token is used in conjuction with the user name which can be
|
||||
specified as part of the \fI--url\fP or \fI-u, --user\fP options.
|
||||
|
||||
The Bearer Token and user name are formatted according to RFC 6750.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-p, --proxytunnel"
|
||||
When an HTTP proxy is used (\fI-x, --proxy\fP), this option will cause non-HTTP
|
||||
protocols to attempt to tunnel through the proxy instead of merely using it to
|
||||
@@ -1038,6 +1113,13 @@ ubiquitous in web browsers, so curl does the conversion by default to maintain
|
||||
consistency. However, a server may require a POST to remain a POST after such
|
||||
a redirection. This option is meaningful only when using \fI-L, --location\fP
|
||||
(Added in 7.19.1)
|
||||
.IP "--post303"
|
||||
(HTTP) Tells curl to respect RFC 2616/10.3.2 and not convert POST requests
|
||||
into GET requests when following a 303 redirection. The non-RFC behaviour is
|
||||
ubiquitous in web browsers, so curl does the conversion by default to maintain
|
||||
consistency. However, a server may require a POST to remain a POST after such
|
||||
a redirection. This option is meaningful only when using \fI-L, --location\fP
|
||||
(Added in 7.26.0)
|
||||
.IP "--proto <protocols>"
|
||||
Tells curl to use the listed protocols for its initial retrieval. Protocols
|
||||
are evaluated left to right, are comma separated, and are each a protocol
|
||||
@@ -1272,8 +1354,12 @@ Set this option to zero to not timeout retries. (Added in 7.12.3)
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-s, --silent"
|
||||
Silent or quiet mode. Don't show progress meter or error messages. Makes
|
||||
Curl mute.
|
||||
Silent or quiet mode. Don't show progress meter or error messages. Makes Curl
|
||||
mute. It will still output the data you ask for, potentially even to the
|
||||
terminal/stdout unless you redirect it.
|
||||
.IP "--sasl-ir"
|
||||
Enable initial response in SASL authentication.
|
||||
(Added in 7.31.0)
|
||||
.IP "-S, --show-error"
|
||||
When used with \fI-s\fP it makes curl show an error message if it fails.
|
||||
.IP "--ssl"
|
||||
@@ -1449,16 +1535,23 @@ If this option is used several times, the last one will be used.
|
||||
.IP "--trace-time"
|
||||
Prepends a time stamp to each trace or verbose line that curl displays.
|
||||
(Added in 7.14.0)
|
||||
.IP "-u, --user <user:password>"
|
||||
Specify the user name and password to use for server authentication. Overrides
|
||||
\fI-n, --netrc\fP and \fI--netrc-optional\fP.
|
||||
.IP "-u, --user <user:password;options>"
|
||||
Specify the user name, password and optional login options to use for server
|
||||
authentication. Overrides \fI-n, --netrc\fP and \fI--netrc-optional\fP.
|
||||
|
||||
If you just give the user name (without entering a colon) curl will prompt for
|
||||
a password.
|
||||
If you simply specify the user name, with or without the login options, curl
|
||||
will prompt for a password.
|
||||
|
||||
If you use an SSPI-enabled curl binary and do NTLM authentication, you can
|
||||
force curl to pick up the user name and password from your environment by
|
||||
simply specifying a single colon with this option: "-u :".
|
||||
If you use an SSPI-enabled curl binary and perform NTLM authentication, you
|
||||
can force curl to select the user name and password from your environment by
|
||||
simply specifying a single colon with this option: "-u :" or by specfying the
|
||||
login options on their own, for example "-u ;auth=NTLM".
|
||||
|
||||
You can use the optional login options part to specify protocol specific
|
||||
options that may be used during authentication. At present only IMAP, POP3 and
|
||||
SMTP support login options as part of the user login information. For more
|
||||
information about the login options please see RFC 2384, RFC 5092 and IETF
|
||||
draft draft-earhart-url-smtp-00.txt (Added in 7.31.0).
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-U, --proxy-user <user:password>"
|
||||
@@ -1619,8 +1712,16 @@ to follow location: headers.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-x, --proxy <[protocol://][user:password@]proxyhost[:port]>"
|
||||
Use the specified HTTP proxy. If the port number is not specified, it is
|
||||
assumed at port 1080.
|
||||
Use the specified proxy.
|
||||
|
||||
The proxy string can be specified with a protocol:// prefix to specify
|
||||
alternative proxy protocols. Use socks4://, socks4a://, socks5:// or
|
||||
socks5h:// to request the specific SOCKS version to be used. No protocol
|
||||
specified, http:// and all others will be treated as HTTP proxies. (The
|
||||
protocol support was added in curl 7.21.7)
|
||||
|
||||
If the port number is not specified in the proxy string, it is assumed to be
|
||||
1080.
|
||||
|
||||
This option overrides existing environment variables that set the proxy to
|
||||
use. If there's an environment variable setting a proxy, you can set proxy to
|
||||
@@ -1639,11 +1740,6 @@ The proxy host can be specified the exact same way as the proxy environment
|
||||
variables, including the protocol prefix (http://) and the embedded user +
|
||||
password.
|
||||
|
||||
From 7.21.7, the proxy string may be specified with a protocol:// prefix to
|
||||
specify alternative proxy protocols. Use socks4://, socks4a://, socks5:// or
|
||||
socks5h:// to request the specific SOCKS version to be used. No protocol
|
||||
specified, http:// and all others will be treated as HTTP proxies.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-X, --request <command>"
|
||||
(HTTP) Specifies a custom request method to use when communicating with the
|
||||
@@ -1669,7 +1765,7 @@ If this option is used several times, the last one will be used.
|
||||
|
||||
.IP "--xattr"
|
||||
When saving output to a file, this option tells curl to store certain file
|
||||
metadata in extened file attributes. Currently, the URL is stored in the
|
||||
metadata in extended file attributes. Currently, the URL is stored in the
|
||||
xdg.origin.url attribute and, for HTTP, the content type is stored in
|
||||
the mime_type attribute. If the file system does not support extended
|
||||
attributes, a warning is issued.
|
||||
@@ -1689,7 +1785,7 @@ speed-time seconds it gets aborted. speed-time is set with \fI-y\fP and is 30
|
||||
if not set.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "-z/--time-cond <date expression>|<file>"
|
||||
.IP "-z, --time-cond <date expression>|<file>"
|
||||
(HTTP/FTP) Request a file that has been modified later than the given time and
|
||||
date, or one that has been modified before that time. The <date expression>
|
||||
can be all sorts of date strings or if it doesn't match any internal ones, it
|
||||
|
||||
2
docs/examples/.gitignore
vendored
2
docs/examples/.gitignore
vendored
@@ -43,3 +43,5 @@ simplessl
|
||||
smtp-multi
|
||||
smtp-tls
|
||||
url2file
|
||||
usercertinmem
|
||||
xmlstream
|
||||
|
||||
@@ -5,7 +5,7 @@ check_PROGRAMS = 10-at-a-time anyauthput cookie_interface debug fileupload \
|
||||
persistant post-callback postit2 sepheaders simple simplepost simplessl \
|
||||
sendrecv httpcustomheader certinfo chkspeed ftpgetinfo ftp-wildcard \
|
||||
smtp-multi simplesmtp smtp-tls rtsp externalsocket resolve \
|
||||
progressfunc pop3s pop3slist imap url2file sftpget ftpsget
|
||||
progressfunc pop3s pop3slist imap url2file sftpget ftpsget postinmemory
|
||||
|
||||
# These examples require external dependencies that may not be commonly
|
||||
# available on POSIX systems, so don't bother attempting to compile them here.
|
||||
@@ -13,4 +13,4 @@ COMPLICATED_EXAMPLES = curlgtk.c curlx.c htmltitle.cpp cacertinmem.c \
|
||||
ftpuploadresume.c ghiper.c hiperfifo.c htmltidy.c multithread.c \
|
||||
opensslthreadlock.c sampleconv.c synctime.c threaded-ssl.c evhiperfifo.c \
|
||||
smooth-gtk-thread.c version-check.pl href_extractor.c asiohiper.cpp \
|
||||
multi-uv.c
|
||||
multi-uv.c xmlstream.c usercertinmem.c
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn
|
||||
##
|
||||
## Hint: you can also set environment vars to control the build, f.e.:
|
||||
## set ZLIB_PATH=c:/zlib-1.2.7
|
||||
## set ZLIB_PATH=c:/zlib-1.2.8
|
||||
## set ZLIB=1
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../../zlib-1.2.8
|
||||
endif
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
|
||||
@@ -14,7 +14,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../../zlib-1.2.8
|
||||
endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
||||
@@ -78,4 +78,5 @@ simplepost.c - HTTP POST
|
||||
simplessl.c - HTTPS example with certificates many options set
|
||||
synctime.c - Sync local time by extracting date from remote HTTP servers
|
||||
url2file.c - download a document and store it in a file
|
||||
xmlstream.c - Stream-parse a document using the streaming Expat parser
|
||||
10-at-a-time.c - Download many files simultaneously, 10 at a time.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -98,10 +98,6 @@ int main(void)
|
||||
* bytes big and contains the remote file.
|
||||
*
|
||||
* Do something nice with it!
|
||||
*
|
||||
* You should be aware of the fact that at this point we might have an
|
||||
* allocated data block, and nothing has yet deallocated that data. So when
|
||||
* you're done with it, you should free() it as a nice application.
|
||||
*/
|
||||
|
||||
printf("%lu bytes retrieved\n", (long)chunk.size);
|
||||
|
||||
111
docs/examples/postinmemory.c
Normal file
111
docs/examples/postinmemory.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t
|
||||
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
|
||||
|
||||
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
||||
if(mem->memory == NULL) {
|
||||
/* out of memory! */
|
||||
printf("not enough memory (realloc returned NULL)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct MemoryStruct chunk;
|
||||
static const char *postthis="Field=1&Field=2&Field=3";
|
||||
|
||||
chunk.memory = malloc(1); /* will be grown as needed by realloc above */
|
||||
chunk.size = 0; /* no data at this point */
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "http://www.example.org/");
|
||||
|
||||
/* send all data to this function */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
|
||||
/* we pass our 'chunk' struct to the callback function */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
|
||||
|
||||
/* some servers don't like requests that are made without a user-agent
|
||||
field, so we provide one */
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis);
|
||||
|
||||
/* if we don't provide POSTFIELDSIZE, libcurl will strlen() by
|
||||
itself */
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis));
|
||||
|
||||
/* Perform the request, res will get the return code */
|
||||
res = curl_easy_perform(curl);
|
||||
/* Check for errors */
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||
curl_easy_strerror(res));
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Now, our chunk.memory points to a memory block that is chunk.size
|
||||
* bytes big and contains the remote file.
|
||||
*
|
||||
* Do something nice with it!
|
||||
*/
|
||||
printf("%s\n",chunk.memory);
|
||||
}
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if(chunk.memory)
|
||||
free(chunk.memory);
|
||||
|
||||
/* we're done with libcurl, so clean it up */
|
||||
curl_global_cleanup();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -30,9 +30,10 @@ struct myprogress {
|
||||
CURL *curl;
|
||||
};
|
||||
|
||||
static int progress(void *p,
|
||||
double dltotal, double dlnow,
|
||||
double ultotal, double ulnow)
|
||||
/* this is how the CURLOPT_XFERINFOFUNCTION callback works */
|
||||
static int xferinfo(void *p,
|
||||
curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
struct myprogress *myp = (struct myprogress *)p;
|
||||
CURL *curl = myp->curl;
|
||||
@@ -48,7 +49,9 @@ static int progress(void *p,
|
||||
fprintf(stderr, "TOTAL TIME: %f \r\n", curtime);
|
||||
}
|
||||
|
||||
fprintf(stderr, "UP: %g of %g DOWN: %g of %g\r\n",
|
||||
fprintf(stderr, "UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
|
||||
" DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
|
||||
"\r\n",
|
||||
ulnow, ultotal, dlnow, dltotal);
|
||||
|
||||
if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES)
|
||||
@@ -56,6 +59,19 @@ static int progress(void *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */
|
||||
static int older_progress(void *p,
|
||||
double dltotal, double dlnow,
|
||||
double ultotal, double ulnow)
|
||||
{
|
||||
return xferinfo(p,
|
||||
(curl_off_t)dltotal,
|
||||
(curl_off_t)dlnow,
|
||||
(curl_off_t)ultotal,
|
||||
(curl_off_t)ulnow);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl;
|
||||
@@ -68,9 +84,28 @@ int main(void)
|
||||
prog.curl = curl;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/");
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress);
|
||||
/* pass the struct pointer into the progress function */
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog);
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x072000
|
||||
/* xferinfo was introduced in 7.32.0, no earlier libcurl versions will
|
||||
compile as they won't have the symbols around.
|
||||
|
||||
If built with a newer libcurl, but running with an older libcurl:
|
||||
curl_easy_setopt() will fail in run-time trying to set the new
|
||||
callback, making the older callback get used.
|
||||
|
||||
New libcurls will prefer the new callback and instead use that one even
|
||||
if both callbacks are set. */
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
|
||||
/* pass the struct pointer into the xferinfo function, note that this is
|
||||
an alias to CURLOPT_PROGRESSDATA */
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);
|
||||
#endif
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
|
||||
@@ -54,23 +54,22 @@ int main(void)
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||
|
||||
/* open the files */
|
||||
headerfile = fopen(headerfilename,"w");
|
||||
headerfile = fopen(headerfilename,"wb");
|
||||
if (headerfile == NULL) {
|
||||
curl_easy_cleanup(curl_handle);
|
||||
return -1;
|
||||
}
|
||||
bodyfile = fopen(bodyfilename,"w");
|
||||
bodyfile = fopen(bodyfilename,"wb");
|
||||
if (bodyfile == NULL) {
|
||||
curl_easy_cleanup(curl_handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we want the headers to this file handle */
|
||||
/* we want the headers be written to this file handle */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, headerfile);
|
||||
|
||||
/*
|
||||
* Notice here that if you want the actual data sent anywhere else but
|
||||
* stdout, you should consider using the CURLOPT_WRITEDATA option. */
|
||||
/* we want the body be written to this file handle instead of stdout */
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile);
|
||||
|
||||
/* get it! */
|
||||
curl_easy_perform(curl_handle);
|
||||
@@ -78,6 +77,9 @@ int main(void)
|
||||
/* close the header file */
|
||||
fclose(headerfile);
|
||||
|
||||
/* close the body file */
|
||||
fclose(bodyfile);
|
||||
|
||||
/* cleanup curl stuff */
|
||||
curl_easy_cleanup(curl_handle);
|
||||
|
||||
|
||||
211
docs/examples/usercertinmem.c
Normal file
211
docs/examples/usercertinmem.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
/* Example using an in memory PEM user certificate and RSA key to retrieve an
|
||||
* https page.
|
||||
* Written by Ishan SinghLevett, based on Theo Borm's cacertinmem.c.
|
||||
* Note this example does not use a CA certificate, however one should be used
|
||||
* if you want a properly secure connection
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <curl/curl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
fwrite(ptr,size,nmemb,stream);
|
||||
return(nmemb*size);
|
||||
}
|
||||
|
||||
static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
BIO *bio = NULL;
|
||||
BIO *kbio = NULL;
|
||||
RSA *rsa = NULL;
|
||||
int ret;
|
||||
|
||||
const char *mypem = /* www.cacert.org */
|
||||
"-----BEGIN CERTIFICATE-----\n"\
|
||||
"MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"\
|
||||
"IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"\
|
||||
"IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"\
|
||||
"Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"\
|
||||
"BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi\n"\
|
||||
"MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ\n"\
|
||||
"ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n"\
|
||||
"CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ\n"\
|
||||
"8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6\n"\
|
||||
"zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y\n"\
|
||||
"fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7\n"\
|
||||
"w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc\n"\
|
||||
"G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k\n"\
|
||||
"epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q\n"\
|
||||
"laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ\n"\
|
||||
"QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU\n"\
|
||||
"fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826\n"\
|
||||
"YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w\n"\
|
||||
"ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY\n"\
|
||||
"gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe\n"\
|
||||
"MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0\n"\
|
||||
"IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy\n"\
|
||||
"dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw\n"\
|
||||
"czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0\n"\
|
||||
"dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl\n"\
|
||||
"aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC\n"\
|
||||
"AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg\n"\
|
||||
"b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB\n"\
|
||||
"ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc\n"\
|
||||
"nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg\n"\
|
||||
"18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c\n"\
|
||||
"gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl\n"\
|
||||
"Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY\n"\
|
||||
"sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T\n"\
|
||||
"SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF\n"\
|
||||
"CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum\n"\
|
||||
"GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"\
|
||||
"zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"\
|
||||
"omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"\
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
/*replace the XXX with the actual RSA key*/
|
||||
const char *mykey =
|
||||
"-----BEGIN RSA PRIVATE KEY-----\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
|
||||
(void)curl; /* avoid warnings */
|
||||
(void)parm; /* avoid warnings */
|
||||
|
||||
/* get a BIO */
|
||||
bio = BIO_new_mem_buf((char *)mypem, -1);
|
||||
|
||||
if (bio == NULL) {
|
||||
printf("BIO_new_mem_buf failed\n");
|
||||
}
|
||||
|
||||
/* use it to read the PEM formatted certificate from memory into an X509
|
||||
* structure that SSL can use
|
||||
*/
|
||||
cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||
if (cert == NULL) {
|
||||
printf("PEM_read_bio_X509 failed...\n");
|
||||
}
|
||||
|
||||
/*tell SSL to use the X509 certificate*/
|
||||
ret = SSL_CTX_use_certificate((SSL_CTX*)sslctx, cert);
|
||||
if (ret != 1) {
|
||||
printf("Use certificate failed\n");
|
||||
}
|
||||
|
||||
/*create a bio for the RSA key*/
|
||||
kbio = BIO_new_mem_buf((char *)mykey, -1);
|
||||
if (kbio == NULL) {
|
||||
printf("BIO_new_mem_buf failed\n");
|
||||
}
|
||||
|
||||
/*read the key bio into an RSA object*/
|
||||
rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
|
||||
if (rsa == NULL) {
|
||||
printf("Failed to create key bio\n");
|
||||
}
|
||||
|
||||
/*tell SSL to use the RSA key from memory*/
|
||||
ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa);
|
||||
if (ret != 1) {
|
||||
printf("Use Key failed\n");
|
||||
}
|
||||
|
||||
|
||||
/* all set to go */
|
||||
return CURLE_OK ;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *ch;
|
||||
CURLcode rv;
|
||||
|
||||
rv = curl_global_init(CURL_GLOBAL_ALL);
|
||||
ch = curl_easy_init();
|
||||
rv = curl_easy_setopt(ch,CURLOPT_VERBOSE, 0L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_HEADER, 0L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_NOPROGRESS, 1L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_NOSIGNAL, 1L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_WRITEFUNCTION, *writefunction);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_WRITEDATA, stdout);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_HEADERFUNCTION, *writefunction);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_WRITEHEADER, stderr);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSLCERTTYPE,"PEM");
|
||||
|
||||
/* both VERIFYPEER and VERIFYHOST are set to 0 in this case because there is
|
||||
no CA certificate*/
|
||||
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
rv = curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/");
|
||||
rv = curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM");
|
||||
|
||||
/* first try: retrieve page without user certificate and key -> will fail
|
||||
*/
|
||||
rv = curl_easy_perform(ch);
|
||||
if (rv==CURLE_OK) {
|
||||
printf("*** transfer succeeded ***\n");
|
||||
}
|
||||
else {
|
||||
printf("*** transfer failed ***\n");
|
||||
}
|
||||
|
||||
/* second try: retrieve page using user certificate and key -> will succeed
|
||||
* load the certificate and key by installing a function doing the necessary
|
||||
* "modifications" to the SSL CONTEXT just before link init
|
||||
*/
|
||||
rv = curl_easy_setopt(ch,CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
|
||||
rv = curl_easy_perform(ch);
|
||||
if (rv==CURLE_OK) {
|
||||
printf("*** transfer succeeded ***\n");
|
||||
}
|
||||
else {
|
||||
printf("*** transfer failed ***\n");
|
||||
}
|
||||
|
||||
curl_easy_cleanup(ch);
|
||||
curl_global_cleanup();
|
||||
return rv;
|
||||
}
|
||||
158
docs/examples/xmlstream.c
Normal file
158
docs/examples/xmlstream.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
/* Stream-parse a document using the streaming Expat parser.
|
||||
* Written by David Strauss
|
||||
*
|
||||
* Expat => http://www.libexpat.org/
|
||||
*
|
||||
* gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <expat.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct ParserStruct {
|
||||
int ok;
|
||||
size_t tags;
|
||||
size_t depth;
|
||||
struct MemoryStruct characters;
|
||||
};
|
||||
|
||||
static void startElement(void *userData, const XML_Char *name, const XML_Char **atts)
|
||||
{
|
||||
struct ParserStruct *state = (struct ParserStruct *) userData;
|
||||
state->tags++;
|
||||
state->depth++;
|
||||
|
||||
/* Get a clean slate for reading in character data. */
|
||||
free(state->characters.memory);
|
||||
state->characters.memory = NULL;
|
||||
state->characters.size = 0;
|
||||
}
|
||||
|
||||
static void characterDataHandler(void *userData, const XML_Char *s, int len)
|
||||
{
|
||||
struct ParserStruct *state = (struct ParserStruct *) userData;
|
||||
struct MemoryStruct *mem = &state->characters;
|
||||
|
||||
mem->memory = realloc(mem->memory, mem->size + len + 1);
|
||||
if(mem->memory == NULL) {
|
||||
/* Out of memory. */
|
||||
fprintf(stderr, "Not enough memory (realloc returned NULL).\n");
|
||||
state->ok = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&(mem->memory[mem->size]), s, len);
|
||||
mem->size += len;
|
||||
mem->memory[mem->size] = 0;
|
||||
}
|
||||
|
||||
static void endElement(void *userData, const XML_Char *name)
|
||||
{
|
||||
struct ParserStruct *state = (struct ParserStruct *) userData;
|
||||
state->depth--;
|
||||
|
||||
printf("%5lu %10lu %s\n", state->depth, state->characters.size, name);
|
||||
}
|
||||
|
||||
static size_t parseStreamCallback(void *contents, size_t length, size_t nmemb, void *userp)
|
||||
{
|
||||
XML_Parser parser = (XML_Parser) userp;
|
||||
size_t real_size = length * nmemb;
|
||||
struct ParserStruct *state = (struct ParserStruct *) XML_GetUserData(parser);
|
||||
|
||||
/* Only parse if we're not already in a failure state. */
|
||||
if (state->ok && XML_Parse(parser, contents, real_size, 0) == 0) {
|
||||
int error_code = XML_GetErrorCode(parser);
|
||||
fprintf(stderr, "Parsing response buffer of length %lu failed with error code %d (%s).\n",
|
||||
real_size, error_code, XML_ErrorString(error_code));
|
||||
state->ok = 0;
|
||||
}
|
||||
|
||||
return real_size;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl_handle;
|
||||
CURLcode res;
|
||||
XML_Parser parser;
|
||||
struct ParserStruct state;
|
||||
|
||||
/* Initialize the state structure for parsing. */
|
||||
memset(&state, 0, sizeof(struct ParserStruct));
|
||||
state.ok = 1;
|
||||
|
||||
/* Initialize a namespace-aware parser. */
|
||||
parser = XML_ParserCreateNS(NULL, '\0');
|
||||
XML_SetUserData(parser, &state);
|
||||
XML_SetElementHandler(parser, startElement, endElement);
|
||||
XML_SetCharacterDataHandler(parser, characterDataHandler);
|
||||
|
||||
/* Initalize a libcurl handle. */
|
||||
curl_global_init(CURL_GLOBAL_ALL ^ CURL_GLOBAL_SSL);
|
||||
curl_handle = curl_easy_init();
|
||||
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.w3schools.com/xml/simple.xml");
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback);
|
||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser);
|
||||
|
||||
printf("Depth Characters Closing Tag\n");
|
||||
|
||||
/* Perform the request and any follow-up parsing. */
|
||||
res = curl_easy_perform(curl_handle);
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||
curl_easy_strerror(res));
|
||||
}
|
||||
else if (state.ok) {
|
||||
/* Expat requires one final call to finalize parsing. */
|
||||
if (XML_Parse(parser, NULL, 0, 1) == 0) {
|
||||
int error_code = XML_GetErrorCode(parser);
|
||||
fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n",
|
||||
error_code, XML_ErrorString(error_code));
|
||||
}
|
||||
else {
|
||||
printf(" --------------\n");
|
||||
printf(" %lu tags total\n", state.tags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
free(state.characters.memory);
|
||||
XML_ParserFree(parser);
|
||||
curl_easy_cleanup(curl_handle);
|
||||
curl_global_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -232,7 +232,7 @@ Pass a pointer to a char pointer to receive a pointer to a string holding the
|
||||
most recent RTSP Session ID.
|
||||
|
||||
Applications wishing to resume an RTSP session on another connection should
|
||||
retreive this info before closing the active connection.
|
||||
retrieve this info before closing the active connection.
|
||||
.IP CURLINFO_RTSP_CLIENT_CSEQ
|
||||
Pass a pointer to a long to receive the next CSeq that will be used by the
|
||||
application.
|
||||
@@ -244,7 +244,7 @@ by the application.
|
||||
unimplemented).\fP
|
||||
|
||||
Applications wishing to resume an RTSP session on another connection should
|
||||
retreive this info before closing the active connection.
|
||||
retrieve this info before closing the active connection.
|
||||
.IP CURLINFO_RTSP_CSEQ_RECV
|
||||
Pass a pointer to a long to receive the most recently received CSeq from the
|
||||
server. If your application encounters a \fICURLE_RTSP_CSEQ_ERROR\fP then you
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -38,8 +38,11 @@ that returns pause signals to the library that it couldn't take care of any
|
||||
data at all, and that data will then be delivered again to the callback when
|
||||
the writing is later unpaused.
|
||||
|
||||
NOTE: while it may feel tempting, take care and notice that you cannot call
|
||||
this function from another thread.
|
||||
While it may feel tempting, take care and notice that you cannot call this
|
||||
function from another thread. To unpause, you may for example call it from the
|
||||
progress callback (see \fIcurl_easy_setopt(3)\fP's
|
||||
\fICURLOPT_PROGRESSFUNCTION\fP), which gets called at least once per second,
|
||||
even if the connection is paused.
|
||||
|
||||
When this function is called to unpause reading, the chance is high that you
|
||||
will get your write callback called before this function returns.
|
||||
@@ -68,6 +71,18 @@ code means something wrong occurred after the new state was set. See the
|
||||
.SH AVAILABILITY
|
||||
This function was added in libcurl 7.18.0. Before this version, there was no
|
||||
explicit support for pausing transfers.
|
||||
.SH "USAGE WITH THE MULTI-SOCKET INTERFACE"
|
||||
Before libcurl 7.32.0, when a specific handle was unpaused with this function,
|
||||
there was no particular forced rechecking or similar of the socket's state,
|
||||
which made the continuation of the transfer get delayed until next
|
||||
multi-socket call invoke or even longer. Alternatively, the user could
|
||||
forcibly call for example curl_multi_socket_all(3) - with a rather hefty
|
||||
performance penalty.
|
||||
|
||||
Starting in libcurl 7.32.0, unpausing a transfer will schedule a timeout
|
||||
trigger for that handle 1 millisecond into the future, so that a
|
||||
curl_multi_socket_action( ... CURL_SOCKET_TIMEOUT) can be used immediately
|
||||
afterwards to get the transfer going again as desired.
|
||||
.SH "MEMORY USE"
|
||||
When pausing a read by returning the magic return code from a write callback,
|
||||
the read data is already in libcurl's internal buffers so it'll have to keep
|
||||
|
||||
@@ -260,9 +260,9 @@ used to fast forward a file in a resumed upload (instead of reading all
|
||||
uploaded bytes with the normal read function/callback). It is also called to
|
||||
rewind a stream when doing a HTTP PUT or POST with a multi-pass authentication
|
||||
method. The function shall work like "fseek" or "lseek" and accepted SEEK_SET,
|
||||
SEEK_CUR and SEEK_END as argument for origin, although (in 7.18.0) libcurl
|
||||
only passes SEEK_SET. The callback must return 0 (CURL_SEEKFUNC_OK) on
|
||||
success, 1 (CURL_SEEKFUNC_FAIL) to cause the upload operation to fail or 2
|
||||
SEEK_CUR and SEEK_END as argument for origin, although libcurl currently only
|
||||
passes SEEK_SET. The callback must return 0 (CURL_SEEKFUNC_OK) on success, 1
|
||||
(CURL_SEEKFUNC_FAIL) to cause the upload operation to fail or 2
|
||||
(CURL_SEEKFUNC_CANTSEEK) to indicate that while the seek failed, libcurl is
|
||||
free to work around the problem if possible. The latter can sometimes be done
|
||||
by instead reading from the input or similar.
|
||||
@@ -342,15 +342,34 @@ argument in the closesocket callback set with
|
||||
The default value of this parameter is unspecified.
|
||||
(Option added in 7.21.7)
|
||||
.IP CURLOPT_PROGRESSFUNCTION
|
||||
Pass a pointer to a function that matches the following prototype: \fBint
|
||||
function(void *clientp, double dltotal, double dlnow, double ultotal, double
|
||||
ulnow); \fP. This function gets called by libcurl instead of its internal
|
||||
equivalent with a frequent interval during operation (roughly once per second
|
||||
or sooner) no matter if data is being transferred or not. Unknown/unused
|
||||
argument values passed to the callback will be set to zero (like if you only
|
||||
download data, the upload size will remain 0). Returning a non-zero value from
|
||||
this callback will cause libcurl to abort the transfer and return
|
||||
\fICURLE_ABORTED_BY_CALLBACK\fP.
|
||||
Pass a pointer to a function that matches the following prototype:
|
||||
|
||||
\fBint function(void *clientp, double dltotal, double dlnow, double ultotal,
|
||||
double ulnow);\fP
|
||||
|
||||
This function gets called by libcurl instead of its internal equivalent with a
|
||||
frequent interval. While data is being transferred it will be called very
|
||||
frequently, and during slow periods like when nothing is being transferred it
|
||||
can slow down to about one call per second.
|
||||
|
||||
\fIclientp\fP is the pointer set with \fICURLOPT_PROGRESSDATA\fP, it is not
|
||||
actually used by libcurl but is only passed along from the application to the
|
||||
callback.
|
||||
|
||||
The callback gets told how much data libcurl will transfer and has
|
||||
transferred, in number of bytes. \fIdltotal\fP is the total number of bytes
|
||||
libcurl expects to download in this transfer. \fIdlnow\fP is the number of
|
||||
bytes downloaded so far. \fIultotal\fP is the total number of bytes libcurl
|
||||
expects to upload in this transfer. \fIulnow\fP is the number of bytes
|
||||
uploaded so far.
|
||||
|
||||
Unknown/unused argument values passed to the callback will be set to zero
|
||||
(like if you only download data, the upload size will remain 0). Many times
|
||||
the callback will be called one or more times first, before it knows the data
|
||||
sizes so a program must be made to handle that.
|
||||
|
||||
Returning a non-zero value from this callback will cause libcurl to abort the
|
||||
transfer and return \fICURLE_ABORTED_BY_CALLBACK\fP.
|
||||
|
||||
If you transfer data with the multi interface, this function will not be
|
||||
called during periods of idleness unless you call the appropriate libcurl
|
||||
@@ -358,10 +377,54 @@ function that performs transfers.
|
||||
|
||||
\fICURLOPT_NOPROGRESS\fP must be set to 0 to make this function actually
|
||||
get called.
|
||||
.IP CURLOPT_XFERINFOFUNCTION
|
||||
Pass a pointer to a function that matches the following prototype:
|
||||
|
||||
.nf
|
||||
\fBint function(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow);\fP
|
||||
.fi
|
||||
|
||||
This function gets called by libcurl instead of its internal equivalent with a
|
||||
frequent interval. While data is being transferred it will be called very
|
||||
frequently, and during slow periods like when nothing is being transferred it
|
||||
can slow down to about one call per second.
|
||||
|
||||
\fIclientp\fP is the pointer set with \fICURLOPT_XFERINFODATA\fP, it is only
|
||||
passed along from the application to the callback.
|
||||
|
||||
The callback gets told how much data libcurl will transfer and has
|
||||
transferred, in number of bytes. \fIdltotal\fP is the total number of bytes
|
||||
libcurl expects to download in this transfer. \fIdlnow\fP is the number of
|
||||
bytes downloaded so far. \fIultotal\fP is the total number of bytes libcurl
|
||||
expects to upload in this transfer. \fIulnow\fP is the number of bytes
|
||||
uploaded so far.
|
||||
|
||||
Unknown/unused argument values passed to the callback will be set to zero
|
||||
(like if you only download data, the upload size will remain 0). Many times
|
||||
the callback will be called one or more times first, before it knows the data
|
||||
sizes so a program must be made to handle that.
|
||||
|
||||
Returning a non-zero value from this callback will cause libcurl to abort the
|
||||
transfer and return \fICURLE_ABORTED_BY_CALLBACK\fP.
|
||||
|
||||
If you transfer data with the multi interface, this function will not be
|
||||
called during periods of idleness unless you call the appropriate libcurl
|
||||
function that performs transfers.
|
||||
|
||||
\fICURLOPT_NOPROGRESS\fP must be set to 0 to make this function actually
|
||||
get called.
|
||||
|
||||
(Added in 7.32.0)
|
||||
.IP CURLOPT_PROGRESSDATA
|
||||
Pass a pointer that will be untouched by libcurl and passed as the first
|
||||
argument in the progress callback set with \fICURLOPT_PROGRESSFUNCTION\fP.
|
||||
The default value of this parameter is unspecified.
|
||||
.IP CURLOPT_XFERINFODATA
|
||||
Pass a pointer that will be untouched by libcurl and passed as the first
|
||||
argument in the progress callback set with \fICURLOPT_XFERINFOFUNCTION\fP.
|
||||
The default value of this parameter is unspecified. This option is an alias
|
||||
for CURLOPT_PROGRESSDATA. (Added in 7.32.0)
|
||||
.IP CURLOPT_HEADERFUNCTION
|
||||
Pass a pointer to a function that matches the following prototype:
|
||||
\fBsize_t function( void *ptr, size_t size, size_t nmemb, void
|
||||
@@ -620,12 +683,20 @@ scheme://host:port/path
|
||||
|
||||
For a greater explanation of the format please see RFC3986.
|
||||
|
||||
If the given URL lacks the scheme, or protocol, part ("http://" or "ftp://"
|
||||
etc), libcurl will attempt to resolve which protocol to use based on the
|
||||
given host mame. If the protocol is not supported, libcurl will return
|
||||
(\fICURLE_UNSUPPORTED_PROTOCOL\fP) when you call \fIcurl_easy_perform(3)\fP
|
||||
or \fIcurl_multi_perform(3)\fP. Use \fIcurl_version_info(3)\fP for detailed
|
||||
information on which protocols are supported.
|
||||
If the given URL lacks the scheme (such as "http://" or "ftp://" etc) then
|
||||
libcurl will attempt to resolve the protocol based on one of the following
|
||||
given host names:
|
||||
|
||||
HTTP, FTP, DICT, LDAP, IMAP, POP3 or SMTP
|
||||
|
||||
(POP3 and SMTP added in 7.31.0)
|
||||
|
||||
Should the protocol, either that specified by the scheme or deduced by libcurl
|
||||
from the host name, not be supported by libcurl then
|
||||
(\fICURLE_UNSUPPORTED_PROTOCOL\fP) will be returned from either the
|
||||
\fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP functions when you
|
||||
call them. Use \fIcurl_version_info(3)\fP for detailed information of which
|
||||
protocols are supported by the build of libcurl you are using.
|
||||
|
||||
The host part of the URL contains the address of the server that you want to
|
||||
connect to. This can be the fully qualified domain name of the server, the
|
||||
@@ -640,17 +711,23 @@ http://192.168.0.1/
|
||||
|
||||
http://[2001:1890:1112:1::20]/
|
||||
|
||||
It is also possible to specify the user name and password as part of the
|
||||
host, for some protocols, when connecting to servers that require
|
||||
authentication.
|
||||
|
||||
For example the following types of authentication support this:
|
||||
It is also possible to specify the user name, password and any supported login
|
||||
options as part of the host, for the following protocols, when connecting to
|
||||
servers that require authentication:
|
||||
|
||||
http://user:password@www.example.com
|
||||
|
||||
ftp://user:password@ftp.example.com
|
||||
|
||||
pop3://user:password@mail.example.com
|
||||
imap://user:password;options@mail.example.com
|
||||
|
||||
pop3://user:password;options@mail.example.com
|
||||
|
||||
smtp://user:password;options@mail.example.com
|
||||
|
||||
At present only IMAP, POP3 and SMTP support login options as part of the host.
|
||||
For more information about the login options in URL syntax please see RFC2384,
|
||||
RFC5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0).
|
||||
|
||||
The port is optional and when not specified libcurl will use the default port
|
||||
based on the determined or specified protocol: 80 for HTTP, 21 for FTP and 25
|
||||
@@ -814,6 +891,19 @@ Active Directory server.
|
||||
For more information about the individual components of a LDAP URL please
|
||||
see RFC4516.
|
||||
|
||||
.B RTMP
|
||||
|
||||
There's no official URL spec for RTMP so libcurl uses the URL syntax supported
|
||||
by the underlying librtmp library. It has a syntax where it wants a
|
||||
traditional URL, followed by a space and a series of space-separated
|
||||
name=value pairs.
|
||||
|
||||
While space is not typically a "legal" letter, libcurl accepts them. When a
|
||||
user wants to pass in a '#' (hash) character it will be treated as a fragment
|
||||
and get cut off by libcurl if provided literally. You will instead have to
|
||||
escape it by providing it as backslash and its ASCII value in hexadecimal:
|
||||
"\\23".
|
||||
|
||||
.B NOTES
|
||||
|
||||
Starting with version 7.20.0, the fragment part of the URI will not be sent as
|
||||
@@ -1040,8 +1130,8 @@ the full path name to the file you want libcurl to use as .netrc file. If this
|
||||
option is omitted, and \fICURLOPT_NETRC\fP is set, libcurl will attempt to
|
||||
find a .netrc file in the current user's home directory. (Added in 7.10.9)
|
||||
.IP CURLOPT_USERPWD
|
||||
Pass a char * as parameter, which should be [user name]:[password] to use for
|
||||
the connection. Use \fICURLOPT_HTTPAUTH\fP to decide the authentication method.
|
||||
Pass a char * as parameter, pointing to a zero terminated login details string
|
||||
for the connection. The format of which is: [user name]:[password];[options].
|
||||
|
||||
When using NTLM, you can set the domain by prepending it to the user name and
|
||||
separating the domain and name with a forward (/) or backward slash (\\). Like
|
||||
@@ -1054,10 +1144,18 @@ and password information to hosts using the initial host name (unless
|
||||
\fICURLOPT_UNRESTRICTED_AUTH\fP is set), so if libcurl follows locations to
|
||||
other hosts it will not send the user and password to those. This is enforced
|
||||
to prevent accidental information leakage.
|
||||
|
||||
At present only IMAP, POP3 and SMTP support login options as part of the
|
||||
details string. For more information about the login options please see
|
||||
RFC2384, RFC5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0).
|
||||
|
||||
Use \fICURLOPT_HTTPAUTH\fP to specify the authentication method for HTTP based
|
||||
connections.
|
||||
.IP CURLOPT_PROXYUSERPWD
|
||||
Pass a char * as parameter, which should be [user name]:[password] to use for
|
||||
the connection to the HTTP proxy. Use \fICURLOPT_PROXYAUTH\fP to decide
|
||||
the authentication method.
|
||||
the connection to the HTTP proxy.
|
||||
|
||||
Use \fICURLOPT_PROXYAUTH\fP to specify the authentication method.
|
||||
.IP CURLOPT_USERNAME
|
||||
Pass a char * as parameter, which should be pointing to the zero terminated
|
||||
user name to use for the transfer.
|
||||
@@ -1134,7 +1232,7 @@ Microsoft. It uses a challenge-response and hash concept similar to Digest, to
|
||||
prevent the password from being eavesdropped.
|
||||
|
||||
You need to build libcurl with either OpenSSL, GnuTLS or NSS support for this
|
||||
option to work, or build libcurl on Windows.
|
||||
option to work, or build libcurl on Windows with SSPI support.
|
||||
.IP CURLAUTH_NTLM_WB
|
||||
NTLM delegating to winbind helper. Authentication is performed by a separate
|
||||
binary application that is executed when needed. The name of the application
|
||||
@@ -1195,6 +1293,22 @@ actual name and password with the \fICURLOPT_PROXYUSERPWD\fP option. The
|
||||
bitmask can be constructed by or'ing together the bits listed above for the
|
||||
\fICURLOPT_HTTPAUTH\fP option. As of this writing, only Basic, Digest and NTLM
|
||||
work. (Added in 7.10.7)
|
||||
.IP CURLOPT_SASL_IR
|
||||
Pass a long. If the value is 1, curl will send the initial response to the
|
||||
server in the first authentication packet in order to reduce the number of
|
||||
ping pong requests. Only applicable to supporting SASL authentication
|
||||
mechanisms and to the IMAP, POP3 and SMTP protocols. (Added in 7.31.0)
|
||||
|
||||
Note: Whilst IMAP supports this option there is no need to explicitly set it,
|
||||
as libcurl can determine the feature itself when the server supports the
|
||||
SASL-IR CAPABILITY.
|
||||
.IP CURLOPT_BEARER
|
||||
Pass a char * as parameter, which should point to the zero terminated OAUTH
|
||||
2.0 Bearer Access Token for use with IMAP. POP3 and SMTP servers that support
|
||||
the OAUTH 2.0 Authorization Framework. (Added in 7.33.0)
|
||||
|
||||
Note: The user name used to generate the Bearer Token should be supplied via
|
||||
the \fICURLOPT_USERNAME\fP option.
|
||||
.SH HTTP OPTIONS
|
||||
.IP CURLOPT_AUTOREFERER
|
||||
Pass a parameter set to 1 to enable this. When enabled, libcurl will
|
||||
@@ -1392,10 +1506,12 @@ internally, your added one will be used instead. If you add a header with no
|
||||
content as in 'Accept:' (no data on the right side of the colon), the
|
||||
internally used header will get disabled. Thus, using this option you can add
|
||||
new headers, replace internal headers and remove internal headers. To add a
|
||||
header with no content, make the content be two quotes: \&"". The headers
|
||||
included in the linked list must not be CRLF-terminated, because curl adds
|
||||
CRLF after each header item. Failure to comply with this will result in
|
||||
strange bugs because the server will most likely ignore part of the headers
|
||||
header with no content (nothing to the right side of the colon), use the
|
||||
form 'MyHeader;' (note the ending semicolon).
|
||||
|
||||
The headers included in the linked list must not be CRLF-terminated, because
|
||||
curl adds CRLF after each header item. Failure to comply with this will result
|
||||
in strange bugs because the server will most likely ignore part of the headers
|
||||
you specified.
|
||||
|
||||
The first line in a request (containing the method, usually a GET or POST) is
|
||||
@@ -2046,10 +2162,14 @@ In unix-like systems, this might cause signals to be used unless
|
||||
|
||||
Default timeout is 0 (zero) which means it never times out.
|
||||
.IP CURLOPT_TIMEOUT_MS
|
||||
Like \fICURLOPT_TIMEOUT\fP but takes number of milliseconds instead. If
|
||||
libcurl is built to use the standard system name resolver, that portion
|
||||
of the transfer will still use full-second resolution for timeouts with
|
||||
a minimum timeout allowed of one second.
|
||||
An alternative to \fICURLOPT_TIMEOUT\fP but takes number of milliseconds
|
||||
instead. If libcurl is built to use the standard system name resolver, that
|
||||
portion of the transfer will still use full-second resolution for timeouts
|
||||
with a minimum timeout allowed of one second.
|
||||
|
||||
If both \fICURLOPT_TIMEOUT\fP and \fICURLOPT_TIMEOUT_MS\fP are set, the value
|
||||
set last will be used.
|
||||
|
||||
(Added in 7.16.2)
|
||||
.IP CURLOPT_LOW_SPEED_LIMIT
|
||||
Pass a long as parameter. It contains the transfer speed in bytes per second
|
||||
@@ -2195,6 +2315,36 @@ This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one.
|
||||
|
||||
(Added in 7.24.0)
|
||||
.IP CURLOPT_DNS_INTERFACE
|
||||
Pass a char * as parameter. Set the name of the network interface that
|
||||
the DNS resolver should bind to. This must be an interface name (not an
|
||||
address). Set this option to NULL to use the default setting (don't
|
||||
bind to a specific interface).
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one.
|
||||
|
||||
(Added in 7.33.0)
|
||||
.IP CURLOPT_DNS_LOCAL_IP4
|
||||
Set the local IPv4 address that the resolver should bind to. The argument
|
||||
should be of type char * and contain a single IPv4 address as a string.
|
||||
Set this option to NULL to use the default setting (don't
|
||||
bind to a specific IP address).
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one.
|
||||
|
||||
(Added in 7.33.0)
|
||||
.IP CURLOPT_DNS_LOCAL_IP6
|
||||
Set the local IPv6 address that the resolver should bind to. The argument
|
||||
should be of type char * and contain a single IPv6 address as a string.
|
||||
Set this option to NULL to use the default setting (don't
|
||||
bind to a specific IP address).
|
||||
|
||||
This option requires that libcurl was built with a resolver backend that
|
||||
supports this operation. The c-ares backend is the only such one.
|
||||
|
||||
(Added in 7.33.0)
|
||||
.IP CURLOPT_ACCEPTTIMEOUT_MS
|
||||
Pass a long telling libcurl the maximum number of milliseconds to wait for a
|
||||
server to connect back to libcurl when an active FTP connection is used. If no
|
||||
@@ -2202,20 +2352,28 @@ timeout is set, the internal default of 60000 will be used. (Added in 7.24.0)
|
||||
.SH SSL and SECURITY OPTIONS
|
||||
.IP CURLOPT_SSLCERT
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the file name of your certificate. The default format is "PEM" and can be
|
||||
changed with \fICURLOPT_SSLCERTTYPE\fP.
|
||||
the file name of your certificate. The default format is "P12" on Secure
|
||||
Transport and "PEM" on other engines, and can be changed with
|
||||
\fICURLOPT_SSLCERTTYPE\fP.
|
||||
|
||||
With NSS this can also be the nickname of the certificate you wish to
|
||||
authenticate with. If you want to use a file from the current directory, please
|
||||
precede it with "./" prefix, in order to avoid confusion with a nickname.
|
||||
With NSS or Secure Transport, this can also be the nickname of the certificate
|
||||
you wish to authenticate with as it is named in the security database. If you
|
||||
want to use a file from the current directory, please precede it with "./"
|
||||
prefix, in order to avoid confusion with a nickname.
|
||||
.IP CURLOPT_SSLCERTTYPE
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your certificate. Supported formats are "PEM" and "DER". (Added
|
||||
in 7.9.3)
|
||||
the format of your certificate. Supported formats are "PEM" and "DER", except
|
||||
with Secure Transport. OpenSSL (versions 0.9.3 and later) and Secure Transport
|
||||
(on iOS 5 or later, or OS X 10.6 or later) also support "P12" for
|
||||
PKCS#12-encoded files. (Added in 7.9.3)
|
||||
.IP CURLOPT_SSLKEY
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the file name of your private key. The default format is "PEM" and can be
|
||||
changed with \fICURLOPT_SSLKEYTYPE\fP.
|
||||
|
||||
(iOS and Mac OS X only) This option is ignored if curl was built against Secure
|
||||
Transport. Secure Transport expects the private key to be already present in
|
||||
the keychain or PKCS#12 file containing the certificate.
|
||||
.IP CURLOPT_SSLKEYTYPE
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your private key. Supported formats are "PEM", "DER" and "ENG".
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -42,7 +42,7 @@ After the \fIlastitem\fP pointer follow the real arguments.
|
||||
The pointers \fIfirstitem\fP and \fIlastitem\fP should both be pointing to
|
||||
NULL in the first call to this function. All list-data will be allocated by
|
||||
the function itself. You must call \fIcurl_formfree(3)\fP on the
|
||||
\fIfirstitem\P after the form post has been done to free the resources.
|
||||
\fIfirstitem\fP after the form post has been done to free the resources.
|
||||
|
||||
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header.
|
||||
You can disable this header with \fICURLOPT_HTTPHEADER\fP as usual.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -29,9 +29,9 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle);
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
Adds a standard easy handle to the multi stack. This function call will make
|
||||
this \fImulti_handle\fP control the specified \fIeasy_handle\fP.
|
||||
Furthermore, libcurl now initiates the connection associated with the
|
||||
specified \fIeasy_handle\fP.
|
||||
this \fImulti_handle\fP control the specified \fIeasy_handle\fP. Furthermore,
|
||||
libcurl now initiates the connection associated with the specified
|
||||
\fIeasy_handle\fP.
|
||||
|
||||
When an easy handle has been added to a multi stack, you can not and you must
|
||||
not use \fIcurl_easy_perform(3)\fP on that handle!
|
||||
@@ -41,6 +41,12 @@ cache (CURLOPT_DNS_USE_GLOBAL_CACHE), it will be made to use the DNS cache
|
||||
that is shared between all easy handles within the multi handle when
|
||||
\fIcurl_multi_add_handle(3)\fP is called.
|
||||
|
||||
If you have CURLMOPT_TIMERFUNCTION set in the multi handle (and you really
|
||||
should if you're working event-based with \fIcurl_multi_socket_action(3)\fP
|
||||
and friends), that callback will be called from within this function to ask
|
||||
for an updated timer so that your main event loop will get the activity on
|
||||
this handle to get started.
|
||||
|
||||
The easy handle will remain added until you remove it again with
|
||||
\fIcurl_multi_remove_handle(3)\fP. You should remove the easy handle from the
|
||||
multi stack before you terminate first the easy handle and then the multi
|
||||
|
||||
@@ -74,9 +74,9 @@ The socket \fBcallback\fP function uses a prototype like this
|
||||
int action, /* see values below */
|
||||
void *userp, /* private callback pointer */
|
||||
void *socketp); /* private socket pointer,
|
||||
\fBNULL\fI if not
|
||||
\fBNULL\fP if not
|
||||
previously assigned with
|
||||
\fIcurl_multi_assign(3)\fP */
|
||||
\fBcurl_multi_assign(3)\fP */
|
||||
|
||||
.fi
|
||||
The callback MUST return 0.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -36,12 +36,17 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
|
||||
This function polls on all file descriptors used by the curl easy handles
|
||||
contained in the given multi handle set. It will block until activity is
|
||||
detected on at least one of the handles or \fItimeout_ms\fP has passed.
|
||||
Alternatively, if the multi handle has a pending internal timeout that has a
|
||||
shorter expiry time than \fItimeout_ms\fP, that shorter time will be used
|
||||
instead to make sure timeout accuracy is reasonably kept.
|
||||
|
||||
The calling application may pass additional curl_waitfd structures which are
|
||||
similar to \fIpoll(2)\fP's pollfd structure to be waited on in the same call.
|
||||
|
||||
On completion, if \fInumfds\fP is supplied, it will be populated with the
|
||||
number of file descriptors on which interesting events occured.
|
||||
total number of file descriptors on which interesting events occured. This
|
||||
number can include both libcurl internal descriptors as well as descriptors
|
||||
provided in \fIextra_fds\fP.
|
||||
|
||||
If no extra file descriptors are provided and libcurl has no file descriptor
|
||||
to offer to wait for, this function will return immediately.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -273,6 +273,9 @@ The passed-in socket is not a valid one that libcurl already knows about.
|
||||
.IP "CURLM_UNKNOWN_OPTION (6)"
|
||||
curl_multi_setopt() with unsupported option
|
||||
(Added in 7.15.4)
|
||||
.IP "CURLM_ADDED_ALREADY (7)"
|
||||
An easy handle already added to a multi handle was attempted to get added a
|
||||
second time. (Added in 7.32.1)
|
||||
.SH "CURLSHcode"
|
||||
The "share" interface will return a CURLSHcode to indicate when an error has
|
||||
occurred. Also consider \fIcurl_share_strerror(3)\fP.
|
||||
|
||||
@@ -34,8 +34,10 @@ The share interface was added to enable sharing of data between curl
|
||||
\&"handles".
|
||||
.SH "ONE SET OF DATA - MANY TRANSFERS"
|
||||
You can have multiple easy handles share data between them. Have them update
|
||||
and use the \fBsame\fP cookie database or DNS cache! This way, each single
|
||||
transfer will take advantage from data updates made by the other transfer(s).
|
||||
and use the \fBsame\fP cookie database, DNS cache, TLS session cache! This
|
||||
way, each single transfer will take advantage from data updates made by the
|
||||
other transfer(s). The sharing interface, however, does not share active or
|
||||
persistent connections between different easy handles.
|
||||
.SH "SHARE OBJECT"
|
||||
You create a shared object with \fIcurl_share_init(3)\fP. It returns a handle
|
||||
for a newly created one.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -1157,13 +1157,13 @@ and install a CURLOPT_OPENSOCKETFUNCTION callback function in which addresses
|
||||
are sanitized before use.
|
||||
|
||||
.IP "Private Resources"
|
||||
A user who can control the DNS server of a domain being passed in within
|
||||
a URL can change the address of the host to a local, private address
|
||||
which the libcurl application will then use. e.g. The innocuous URL
|
||||
http://fuzzybunnies.example.com/ could actually resolve to the IP address
|
||||
of a server behind a firewall, such as 127.0.0.1 or 10.1.2.3
|
||||
Apps can mitigate against this by setting a CURLOPT_OPENSOCKETFUNCTION
|
||||
and checking the address before a connection.
|
||||
A user who can control the DNS server of a domain being passed in within a URL
|
||||
can change the address of the host to a local, private address which a
|
||||
server-side libcurl-using application could then use. e.g. the innocuous URL
|
||||
http://fuzzybunnies.example.com/ could actually resolve to the IP address of a
|
||||
server behind a firewall, such as 127.0.0.1 or 10.1.2.3. Apps can mitigate
|
||||
against this by setting a CURLOPT_OPENSOCKETFUNCTION and checking the address
|
||||
before a connection.
|
||||
|
||||
All the malicious scenarios regarding redirected URLs apply just as well
|
||||
to non-redirected URLs, if the user is allowed to specify an arbitrary URL
|
||||
@@ -1178,6 +1178,19 @@ IP address and port number for a server local to the app running libcurl
|
||||
but behind a firewall. Apps can mitigate against this by using the
|
||||
CURLOPT_FTP_SKIP_PASV_IP option or CURLOPT_FTPPORT.
|
||||
|
||||
.IP "IPv6 Addresses"
|
||||
libcurl will normally handle IPv6 addresses transparently and just as easily
|
||||
as IPv4 addresses. That means that a sanitizing function that filters out
|
||||
addressses like 127.0.0.1 isn't sufficient--the equivalent IPv6 addresses ::1,
|
||||
::, 0:00::0:1, ::127.0.0.1 and ::ffff:7f00:1 supplied somehow by an attacker
|
||||
would all bypass a naive filter and could allow access to undesired local
|
||||
resources. IPv6 also has special address blocks like link-local and site-local
|
||||
that generally shouldn't be accessed by a server-side libcurl-using
|
||||
application. A poorly-configured firewall installed in a data center,
|
||||
organization or server may also be configured to limit IPv4 connections but
|
||||
leave IPv6 connections wide open. In some cases, the CURL_IPRESOLVE_V4 option
|
||||
can be used to limit resolved addresses to IPv4 only and bypass these issues.
|
||||
|
||||
.IP Uploads
|
||||
When uploading, a redirect can cause a local (or remote) file to be
|
||||
overwritten. Apps must not allow any unsanitized URL to be passed in
|
||||
@@ -1250,7 +1263,7 @@ using the Content-disposition: header to generate a file name. An application
|
||||
could also use CURLINFO_EFFECTIVE_URL to generate a file name from a
|
||||
server-supplied redirect URL. Special care must be taken to sanitize such
|
||||
names to avoid the possibility of a malicious server supplying one like
|
||||
"/etc/passwd", "\autoexec.bat" or even ".bashrc".
|
||||
"/etc/passwd", "\\autoexec.bat", "prn:" or even ".bashrc".
|
||||
|
||||
.IP "Server Certificates"
|
||||
A secure application should never use the CURLOPT_SSL_VERIFYPEER option to
|
||||
@@ -1263,10 +1276,15 @@ validated certificates is potentially as insecure as a plain HTTP connection.
|
||||
On a related issue, be aware that even in situations like when you have
|
||||
problems with libcurl and ask someone for help, everything you reveal in order
|
||||
to get best possible help might also impose certain security related
|
||||
risks. Host names, user names, paths, operating system specifics, etc (not to
|
||||
risks. Host names, user names, paths, operating system specifics, etc. (not to
|
||||
mention passwords of course) may in fact be used by intruders to gain
|
||||
additional information of a potential target.
|
||||
|
||||
Be sure to limit access to application logs if they could hold private or
|
||||
security-related data. Besides the obvious candidates like user names and
|
||||
passwords, things like URLs, cookies or even file names could also hold
|
||||
sensitive data.
|
||||
|
||||
To avoid this problem, you must of course use your common sense. Often, you
|
||||
can just edit out the sensitive data or just search/replace your true
|
||||
information with faked data.
|
||||
@@ -1347,10 +1365,10 @@ automatically share a lot of the data that otherwise would be kept on a
|
||||
per-easy handle basis when the easy interface is used.
|
||||
|
||||
The DNS cache is shared between handles within a multi handle, making
|
||||
subsequent name resolvings faster and the connection pool that is kept to
|
||||
better allow persistent connections and connection re-use is shared. If you're
|
||||
using the easy interface, you can still share these between specific easy
|
||||
handles by using the share interface, see \fIlibcurl-share(3)\fP.
|
||||
subsequent name resolving faster, and the connection pool that is kept to
|
||||
better allow persistent connections and connection re-use is also shared. If
|
||||
you're using the easy interface, you can still share these between specific
|
||||
easy handles by using the share interface, see \fIlibcurl-share(3)\fP.
|
||||
|
||||
Some things are never shared automatically, not within multi handles, like for
|
||||
example cookies so the only way to share that is with the share interface.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.\" * | (__| |_| | _ <| |___
|
||||
.\" * \___|\___/|_| \_\_____|
|
||||
.\" *
|
||||
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
.\" *
|
||||
.\" * This software is licensed as described in the file COPYING, which
|
||||
.\" * you should have received as part of this distribution. The terms
|
||||
@@ -39,8 +39,15 @@ maintain while using libcurl. This essentially means you call
|
||||
for details.
|
||||
|
||||
To transfer files, you always set up an "easy handle" using
|
||||
\fIcurl_easy_init(3)\fP, but when you want the file(s) transferred you have
|
||||
the option of using the "easy" interface, or the "multi" interface.
|
||||
\fIcurl_easy_init(3)\fP for a single specific transfer (in either
|
||||
direction). You then set your desired set of options in that handle with
|
||||
\fIcurk_easy_setopt(3)\fP. Options you set with \fIcurl_easy_setopt(3)\fP will
|
||||
be used on every repeated use of this handle until you either call the
|
||||
function again and change the option, or you reset them all with
|
||||
\fIcurl_easy_reset(3)\fP.
|
||||
|
||||
To actually transfer data you have the option of using the "easy" interface,
|
||||
or the "multi" interface.
|
||||
|
||||
The easy interface is a synchronous interface with which you call
|
||||
\fIcurl_easy_perform(3)\fP and let it perform the transfer. When it is
|
||||
@@ -51,7 +58,8 @@ The multi interface on the other hand is an asynchronous interface, that you
|
||||
call and that performs only a little piece of the transfer on each invoke. It
|
||||
is perfect if you want to do things while the transfer is in progress, or
|
||||
similar. The multi interface allows you to select() on libcurl action, and
|
||||
even to easily download multiple files simultaneously using a single thread. See further details in the \fIlibcurl-multi(3)\fP man page.
|
||||
even to easily download multiple files simultaneously using a single
|
||||
thread. See further details in the \fIlibcurl-multi(3)\fP man page.
|
||||
|
||||
You can have multiple easy handles share certain data, even if they are used
|
||||
in different threads. This magic is setup using the share interface, as
|
||||
@@ -115,19 +123,21 @@ Persistent connections means that libcurl can re-use the same connection for
|
||||
several transfers, if the conditions are right.
|
||||
|
||||
libcurl will \fBalways\fP attempt to use persistent connections. Whenever you
|
||||
use \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP, libcurl will
|
||||
attempt to use an existing connection to do the transfer, and if none exists
|
||||
it'll open a new one that will be subject for re-use on a possible following
|
||||
call to \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP.
|
||||
use \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP etc, libcurl
|
||||
will attempt to use an existing connection to do the transfer, and if none
|
||||
exists it'll open a new one that will be subject for re-use on a possible
|
||||
following call to \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP.
|
||||
|
||||
To allow libcurl to take full advantage of persistent connections, you should
|
||||
do as many of your file transfers as possible using the same curl handle. When
|
||||
you call \fIcurl_easy_cleanup(3)\fP, all the possibly open connections held by
|
||||
libcurl will be closed and forgotten.
|
||||
do as many of your file transfers as possible using the same handle.
|
||||
|
||||
Note that the options set with \fIcurl_easy_setopt(3)\fP will be used on
|
||||
every repeated \fIcurl_easy_perform(3)\fP call.
|
||||
If you use the easy interface, and you call \fIcurl_easy_cleanup(3)\fP, all
|
||||
the possibly open connections held by libcurl will be closed and forgotten.
|
||||
|
||||
When you've created a multi handle and are using the multi interface, the
|
||||
connection pool is instead kept in the multi handle so closing and creating
|
||||
new easy handles to do transfers will not affect them. Instead all added easy
|
||||
handles can take advantage of the single shared pool.
|
||||
.SH "GLOBAL CONSTANTS"
|
||||
There are a variety of constants that libcurl uses, mainly through its
|
||||
internal use of other libraries, which are too complicated for the
|
||||
|
||||
@@ -85,8 +85,8 @@ CURLE_LDAP_SEARCH_FAILED 7.1
|
||||
CURLE_LIBRARY_NOT_FOUND 7.1 7.17.0
|
||||
CURLE_LOGIN_DENIED 7.13.1
|
||||
CURLE_MALFORMAT_USER 7.1 7.17.0
|
||||
CURLE_NO_CONNECTION_AVAILABLE 7.30.0
|
||||
CURLE_NOT_BUILT_IN 7.21.5
|
||||
CURLE_NO_CONNECTION_AVAILABLE 7.30.0
|
||||
CURLE_OK 7.1
|
||||
CURLE_OPERATION_TIMEDOUT 7.10.2
|
||||
CURLE_OPERATION_TIMEOUTED 7.1 7.17.0
|
||||
@@ -270,10 +270,10 @@ CURLKHTYPE_RSA1 7.19.6
|
||||
CURLKHTYPE_UNKNOWN 7.19.6
|
||||
CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 7.30.0
|
||||
CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 7.30.0
|
||||
CURLMOPT_MAXCONNECTS 7.16.3
|
||||
CURLMOPT_MAX_HOST_CONNECTIONS 7.30.0
|
||||
CURLMOPT_MAX_PIPELINE_LENGTH 7.30.0
|
||||
CURLMOPT_MAX_TOTAL_CONNECTIONS 7.30.0
|
||||
CURLMOPT_MAXCONNECTS 7.16.3
|
||||
CURLMOPT_PIPELINING 7.16.0
|
||||
CURLMOPT_PIPELINING_SERVER_BL 7.30.0
|
||||
CURLMOPT_PIPELINING_SITE_BL 7.30.0
|
||||
@@ -283,6 +283,7 @@ CURLMOPT_TIMERDATA 7.16.0
|
||||
CURLMOPT_TIMERFUNCTION 7.16.0
|
||||
CURLMSG_DONE 7.9.6
|
||||
CURLMSG_NONE 7.9.6
|
||||
CURLM_ADDED_ALREADY 7.32.1
|
||||
CURLM_BAD_EASY_HANDLE 7.9.6
|
||||
CURLM_BAD_HANDLE 7.9.6
|
||||
CURLM_BAD_SOCKET 7.15.4
|
||||
@@ -331,6 +332,9 @@ CURLOPT_DEBUGDATA 7.9.6
|
||||
CURLOPT_DEBUGFUNCTION 7.9.6
|
||||
CURLOPT_DIRLISTONLY 7.17.0
|
||||
CURLOPT_DNS_CACHE_TIMEOUT 7.9.3
|
||||
CURLOPT_DNS_INTERFACE 7.33.0
|
||||
CURLOPT_DNS_LOCAL_IP4 7.33.0
|
||||
CURLOPT_DNS_LOCAL_IP6 7.33.0
|
||||
CURLOPT_DNS_SERVERS 7.24.0
|
||||
CURLOPT_DNS_USE_GLOBAL_CACHE 7.9.3 7.11.1
|
||||
CURLOPT_EGDSOCKET 7.7
|
||||
@@ -428,7 +432,7 @@ CURLOPT_POSTREDIR 7.19.1
|
||||
CURLOPT_PREQUOTE 7.9.5
|
||||
CURLOPT_PRIVATE 7.10.3
|
||||
CURLOPT_PROGRESSDATA 7.1
|
||||
CURLOPT_PROGRESSFUNCTION 7.1
|
||||
CURLOPT_PROGRESSFUNCTION 7.1 7.32.0
|
||||
CURLOPT_PROTOCOLS 7.19.4
|
||||
CURLOPT_PROXY 7.1
|
||||
CURLOPT_PROXYAUTH 7.10.7
|
||||
@@ -456,6 +460,7 @@ CURLOPT_RTSP_SERVER_CSEQ 7.20.0
|
||||
CURLOPT_RTSP_SESSION_ID 7.20.0
|
||||
CURLOPT_RTSP_STREAM_URI 7.20.0
|
||||
CURLOPT_RTSP_TRANSPORT 7.20.0
|
||||
CURLOPT_SASL_IR 7.31.0
|
||||
CURLOPT_SEEKDATA 7.18.0
|
||||
CURLOPT_SEEKFUNCTION 7.18.0
|
||||
CURLOPT_SERVER_RESPONSE_TIMEOUT 7.20.0
|
||||
@@ -524,6 +529,9 @@ CURLOPT_WRITEDATA 7.9.7
|
||||
CURLOPT_WRITEFUNCTION 7.1
|
||||
CURLOPT_WRITEHEADER 7.1
|
||||
CURLOPT_WRITEINFO 7.1
|
||||
CURLOPT_XFERINFODATA 7.32.0
|
||||
CURLOPT_XFERINFOFUNCTION 7.32.0
|
||||
CURLOPT_XOAUTH2_BEARER 7.33.0
|
||||
CURLPAUSE_ALL 7.18.0
|
||||
CURLPAUSE_CONT 7.18.0
|
||||
CURLPAUSE_RECV 7.18.0
|
||||
@@ -617,14 +625,15 @@ CURL_FORMADD_NULL 7.9.8
|
||||
CURL_FORMADD_OK 7.9.8
|
||||
CURL_FORMADD_OPTION_TWICE 7.9.8
|
||||
CURL_FORMADD_UNKNOWN_OPTION 7.9.8
|
||||
CURL_GLOBAL_ACK_EINTR 7.30.0
|
||||
CURL_GLOBAL_ALL 7.8
|
||||
CURL_GLOBAL_DEFAULT 7.8
|
||||
CURL_GLOBAL_NOTHING 7.8
|
||||
CURL_GLOBAL_SSL 7.8
|
||||
CURL_GLOBAL_WIN32 7.8.1
|
||||
CURL_GLOBAL_ACK_EINTR 7.30.0
|
||||
CURL_HTTP_VERSION_1_0 7.9.1
|
||||
CURL_HTTP_VERSION_1_1 7.9.1
|
||||
CURL_HTTP_VERSION_2_0 7.33.0
|
||||
CURL_HTTP_VERSION_NONE 7.9.1
|
||||
CURL_IPRESOLVE_V4 7.10.8
|
||||
CURL_IPRESOLVE_V6 7.10.8
|
||||
@@ -697,6 +706,7 @@ CURL_VERSION_CONV 7.15.4
|
||||
CURL_VERSION_CURLDEBUG 7.19.6
|
||||
CURL_VERSION_DEBUG 7.10.6
|
||||
CURL_VERSION_GSSNEGOTIATE 7.10.6
|
||||
CURL_VERSION_HTTP2 7.33.0
|
||||
CURL_VERSION_IDN 7.12.0
|
||||
CURL_VERSION_IPV6 7.10
|
||||
CURL_VERSION_KERBEROS4 7.10
|
||||
|
||||
@@ -60,11 +60,16 @@ unlink (remove) certdata.txt after processing
|
||||
be verbose and print out processed CAs
|
||||
.SH EXIT STATUS
|
||||
Returns 0 on success. Returns 1 if it fails to download data.
|
||||
.SH CERTDATA FORMAT
|
||||
The file format used by Mozilla for this trust information seems to be documented here:
|
||||
.nf
|
||||
http://p11-glue.freedesktop.org/doc/storing-trust-policy/storing-trust-existing.html
|
||||
.fi
|
||||
.SH SEE ALSO
|
||||
.BR curl (1)
|
||||
.SH HISTORY
|
||||
\fBmk-ca-bundle\fP is a command line tool that is shipped as part of every
|
||||
curl and libcurl release (see http://curl.haxx.se/). It was originally based
|
||||
on the parse-certs script written by Roland Krikava and was later much
|
||||
improved by Guenter Knauf. This manual page was written by Jan Schaumann
|
||||
\&<jschauma@netmeister.org>.
|
||||
improved by Guenter Knauf. This manual page was initially written by Jan
|
||||
Schaumann \&<jschauma@netmeister.org>.
|
||||
|
||||
@@ -156,12 +156,22 @@ struct curl_httppost {
|
||||
HTTPPOST_CALLBACK posts */
|
||||
};
|
||||
|
||||
/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered
|
||||
deprecated but was the only choice up until 7.31.0 */
|
||||
typedef int (*curl_progress_callback)(void *clientp,
|
||||
double dltotal,
|
||||
double dlnow,
|
||||
double ultotal,
|
||||
double ulnow);
|
||||
|
||||
/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in
|
||||
7.32.0, it avoids floating point and provides more detailed information. */
|
||||
typedef int (*curl_xferinfo_callback)(void *clientp,
|
||||
curl_off_t dltotal,
|
||||
curl_off_t dlnow,
|
||||
curl_off_t ultotal,
|
||||
curl_off_t ulnow);
|
||||
|
||||
#ifndef CURL_MAX_WRITE_SIZE
|
||||
/* Tests have proven that 20K is a very bad buffer size for uploads on
|
||||
Windows, while 16K for some odd reason performed a lot better.
|
||||
@@ -635,16 +645,18 @@ typedef enum {
|
||||
|
||||
#define CURL_ERROR_SIZE 256
|
||||
|
||||
struct curl_khkey {
|
||||
const char *key; /* points to a zero-terminated string encoded with base64
|
||||
if len is zero, otherwise to the "raw" data */
|
||||
size_t len;
|
||||
enum type {
|
||||
enum curl_khtype {
|
||||
CURLKHTYPE_UNKNOWN,
|
||||
CURLKHTYPE_RSA1,
|
||||
CURLKHTYPE_RSA,
|
||||
CURLKHTYPE_DSS
|
||||
} keytype;
|
||||
};
|
||||
|
||||
struct curl_khkey {
|
||||
const char *key; /* points to a zero-terminated string encoded with base64
|
||||
if len is zero, otherwise to the "raw" data */
|
||||
size_t len;
|
||||
enum curl_khtype keytype;
|
||||
};
|
||||
|
||||
/* this is the set of return values expected from the curl_sshkeycallback
|
||||
@@ -968,13 +980,16 @@ typedef enum {
|
||||
|
||||
/* 55 = OBSOLETE */
|
||||
|
||||
/* Function that will be called instead of the internal progress display
|
||||
/* DEPRECATED
|
||||
* Function that will be called instead of the internal progress display
|
||||
* function. This function should be defined as the curl_progress_callback
|
||||
* prototype defines. */
|
||||
CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
|
||||
|
||||
/* Data passed to the progress callback */
|
||||
/* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
|
||||
callbacks */
|
||||
CINIT(PROGRESSDATA, OBJECTPOINT, 57),
|
||||
#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA
|
||||
|
||||
/* We want the referrer field set automatically when following locations */
|
||||
CINIT(AUTOREFERER, LONG, 58),
|
||||
@@ -1527,9 +1542,33 @@ typedef enum {
|
||||
/* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
|
||||
CINIT(SSL_OPTIONS, LONG, 216),
|
||||
|
||||
/* set the SMTP auth originator */
|
||||
/* Set the SMTP auth originator */
|
||||
CINIT(MAIL_AUTH, OBJECTPOINT, 217),
|
||||
|
||||
/* Enable/disable SASL initial response */
|
||||
CINIT(SASL_IR, LONG, 218),
|
||||
|
||||
/* Function that will be called instead of the internal progress display
|
||||
* function. This function should be defined as the curl_xferinfo_callback
|
||||
* prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
|
||||
CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219),
|
||||
|
||||
/* The XOAUTH2 bearer token */
|
||||
CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220),
|
||||
|
||||
/* Set the interface string to use as outgoing network
|
||||
* interface for DNS requests.
|
||||
* Only supported by the c-ares DNS backend */
|
||||
CINIT(DNS_INTERFACE, OBJECTPOINT, 221),
|
||||
|
||||
/* Set the local IPv4 address to use for outgoing DNS requests.
|
||||
* Only supported by the c-ares DNS backend */
|
||||
CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222),
|
||||
|
||||
/* Set the local IPv4 address to use for outgoing DNS requests.
|
||||
* Only supported by the c-ares DNS backend */
|
||||
CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
@@ -1582,6 +1621,7 @@ enum {
|
||||
for us! */
|
||||
CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
|
||||
CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
|
||||
CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */
|
||||
|
||||
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
|
||||
};
|
||||
@@ -2145,6 +2185,7 @@ typedef struct {
|
||||
#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */
|
||||
#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
|
||||
#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */
|
||||
#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */
|
||||
|
||||
/*
|
||||
* NAME curl_version_info()
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
file origins: */
|
||||
#define LIBCURL_VERSION "7.30.0-DEV"
|
||||
#define LIBCURL_VERSION "7.33.0-DEV"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 30
|
||||
#define LIBCURL_VERSION_MINOR 33
|
||||
#define LIBCURL_VERSION_PATCH 0
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
@@ -53,7 +53,7 @@
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBCURL_VERSION_NUM 0x071e00
|
||||
#define LIBCURL_VERSION_NUM 0x072100
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -64,6 +64,8 @@ typedef enum {
|
||||
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
|
||||
CURLM_BAD_SOCKET, /* the passed in socket argument did not match */
|
||||
CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
|
||||
CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was
|
||||
attempted to get added - again */
|
||||
CURLM_LAST
|
||||
} CURLMcode;
|
||||
|
||||
|
||||
@@ -264,6 +264,11 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
|
||||
(option) == CURLOPT_RTSP_SESSION_ID || \
|
||||
(option) == CURLOPT_RTSP_STREAM_URI || \
|
||||
(option) == CURLOPT_RTSP_TRANSPORT || \
|
||||
(option) == CURLOPT_XOAUTH2_BEARER || \
|
||||
(option) == CURLOPT_DNS_SERVERS || \
|
||||
(option) == CURLOPT_DNS_INTERFACE || \
|
||||
(option) == CURLOPT_DNS_LOCAL_IP4 || \
|
||||
(option) == CURLOPT_DNS_LOCAL_IP6 || \
|
||||
0)
|
||||
|
||||
/* evaluates to true if option takes a curl_write_callback argument */
|
||||
|
||||
@@ -94,6 +94,10 @@ add_library(
|
||||
${HHEADERS} ${CSOURCES}
|
||||
)
|
||||
|
||||
if(MSVC AND CURL_STATICLIB)
|
||||
set_target_properties(${LIB_NAME} PROPERTIES STATIC_LIBRARY_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${LIB_NAME} ${CURL_LIBS})
|
||||
|
||||
if(WIN32)
|
||||
@@ -108,14 +112,6 @@ setup_curl_dependencies(${LIB_NAME})
|
||||
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
|
||||
set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "")
|
||||
|
||||
if(MSVC)
|
||||
if(NOT BUILD_RELEASE_DEBUG_DIRS)
|
||||
# Ugly workaround to remove the "/debug" or "/release" in each output
|
||||
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "../")
|
||||
set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "../")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(NOT CURL_STATICLIB)
|
||||
# Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"
|
||||
|
||||
@@ -83,7 +83,7 @@ CFLAGS += -dWANT_IDN_PROTOTYPES
|
||||
!ifdef %zlib_root
|
||||
ZLIB_ROOT = $(%zlib_root)
|
||||
!else
|
||||
ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.7
|
||||
ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.8
|
||||
!endif
|
||||
|
||||
!ifdef %libssh2_root
|
||||
|
||||
@@ -141,7 +141,7 @@ libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING)
|
||||
endif
|
||||
|
||||
libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA)
|
||||
libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LIBCURL_LIBS)
|
||||
libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS)
|
||||
libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA)
|
||||
|
||||
libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS
|
||||
|
||||
@@ -22,7 +22,7 @@ BCCDIR = $(MAKEDIR)\..
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
!ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ..\..\zlib-1.2.7
|
||||
ZLIB_PATH = ..\..\zlib-1.2.8
|
||||
!endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
@@ -52,7 +52,7 @@ LDFLAGS = -q -lq -laa -tWD
|
||||
SRCDIR = .
|
||||
OBJDIR = .\BCC_objs
|
||||
INCDIRS = -I.;..\include
|
||||
LINKLIB = $(BCCDIR)\lib\cw32mt.lib
|
||||
LINKLIB = $(BCCDIR)\lib\cw32mt.lib $(BCCDIR)\lib\ws2_32.lib
|
||||
DEFINES = -DNDEBUG -DWIN32 -DBUILDING_LIBCURL
|
||||
|
||||
# By default SSPI support is enabled for BCC
|
||||
@@ -88,8 +88,24 @@ LINKLIB = $(LINKLIB) $(OPENSSL_PATH)\out32\ssleay32.lib $(OPENSSL_PATH)\out32\l
|
||||
# Makefile.inc provides the CSOURCES and HHEADERS defines
|
||||
!include Makefile.inc
|
||||
|
||||
OBJECTS = $(CSOURCES:.c=.obj)
|
||||
PREPROCESSED = $(CSOURCES:.c=.int)
|
||||
# Borland's command line librarian program TLIB version 4.5 is not capable
|
||||
# of building a library when any of its objects contains an hypen in its
|
||||
# name, due to a command line parsing bug. In order to workaround this, we
|
||||
# build source files with hyphens in their name as objects with underscores
|
||||
# using explicit compilation build rules instead of implicit ones.
|
||||
|
||||
NOHYPHEN = $(CSOURCES:-=_)
|
||||
|
||||
OBJECTS = $(NOHYPHEN:.c=.obj)
|
||||
PREPROCESSED = $(NOHYPHEN:.c=.int)
|
||||
|
||||
# Borland's command line compiler (BCC32) version 5.5.1 integrated
|
||||
# preprocessor has a bug which results in silently generating wrong
|
||||
# definitions for libcurl macros such as CURL_OFF_T_C, on the other
|
||||
# hand Borland's command line preprocessor (CPP32) version 5.5.1 does
|
||||
# not have the bug and achieves proper results. In order to avoid the
|
||||
# silent bug we first preprocess source files and later compile the
|
||||
# preprocessed result.
|
||||
|
||||
.c.obj:
|
||||
@-$(RM) $(@R).int
|
||||
@@ -98,6 +114,21 @@ PREPROCESSED = $(CSOURCES:.c=.int)
|
||||
|
||||
all: $(OBJDIR) $(LIBCURL_LIB) $(LIBCURL_DLL)
|
||||
|
||||
asyn_ares.obj: asyn-ares.c
|
||||
@-$(RM) $(@R).int
|
||||
$(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?)
|
||||
$(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int
|
||||
|
||||
asyn_thread.obj: asyn-thread.c
|
||||
@-$(RM) $(@R).int
|
||||
$(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?)
|
||||
$(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int
|
||||
|
||||
non_ascii.obj: non-ascii.c
|
||||
@-$(RM) $(@R).int
|
||||
$(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?)
|
||||
$(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int
|
||||
|
||||
clean:
|
||||
cd $(OBJDIR)
|
||||
@-$(RM) $(OBJECTS)
|
||||
@@ -122,7 +153,10 @@ $(LIBCURL_LIB): $(OBJECTS)
|
||||
$(LIBCURL_DLL) $(LIBCURL_IMPLIB): $(OBJECTS) $(LINKLIB)
|
||||
@-$(RM) $(LIBCURL_DLL)
|
||||
@-$(RM) $(LIBCURL_IMPLIB)
|
||||
$(LD) $(LDFLAGS) -e$(LIBCURL_DLL) $**
|
||||
$(LD) $(LDFLAGS) -e$(LIBCURL_DLL) @&&!
|
||||
$(**: = ^
|
||||
)
|
||||
!
|
||||
$(IMPLIB) $(LIBCURL_IMPLIB) $(LIBCURL_DLL)
|
||||
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
|
||||
ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \
|
||||
netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \
|
||||
netrc.c getinfo.c transfer.c strequal.c easy.c security.c \
|
||||
curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c krb5.c \
|
||||
memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \
|
||||
content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \
|
||||
content_encoding.c share.c http_digest.c md4.c md5.c \
|
||||
http_negotiate.c inet_pton.c strtoofft.c strerror.c amigaos.c \
|
||||
hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c \
|
||||
select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c \
|
||||
@@ -25,12 +25,13 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||
http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \
|
||||
curl_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_ntlm_msgs.c \
|
||||
curl_sasl.c curl_schannel.c curl_multibyte.c curl_darwinssl.c \
|
||||
hostcheck.c bundles.c conncache.c pipeline.c
|
||||
hostcheck.c bundles.c conncache.c pipeline.c dotdot.c x509asn1.c \
|
||||
gskit.c http2.c
|
||||
|
||||
HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
|
||||
progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \
|
||||
if2ip.h speedcheck.h urldata.h curl_ldap.h ssluse.h escape.h telnet.h \
|
||||
getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h \
|
||||
getinfo.h strequal.h curl_sec.h memdebug.h http_chunks.h \
|
||||
curl_fnmatch.h wildcard.h fileinfo.h ftplistparser.h strtok.h \
|
||||
connect.h llist.h hash.h content_encoding.h share.h curl_md4.h \
|
||||
curl_md5.h http_digest.h http_negotiate.h inet_pton.h amigaos.h \
|
||||
@@ -44,4 +45,5 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
|
||||
asyn.h curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \
|
||||
curl_ntlm_msgs.h curl_sasl.h curl_schannel.h curl_multibyte.h \
|
||||
curl_darwinssl.h hostcheck.h bundles.h conncache.h curl_setup_once.h \
|
||||
multihandle.h setup-vms.h pipeline.h
|
||||
multihandle.h setup-vms.h pipeline.h dotdot.h x509asn1.h gskit.h \
|
||||
http2.h
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn
|
||||
##
|
||||
## Hint: you can also set environment vars to control the build, f.e.:
|
||||
## set ZLIB_PATH=c:/zlib-1.2.7
|
||||
## set ZLIB_PATH=c:/zlib-1.2.8
|
||||
## set ZLIB=1
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
endif
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
|
||||
@@ -14,7 +14,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your Zlib sources.
|
||||
ifndef ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
|
||||
@@ -73,7 +73,7 @@ LIBSSH2_PATH = ../../libssh2-1.4.3
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF ZLIB_PATH
|
||||
ZLIB_PATH = ../../zlib-1.2.7
|
||||
ZLIB_PATH = ../../zlib-1.2.8
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF MACHINE
|
||||
@@ -106,6 +106,7 @@ WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK"
|
||||
CCNODBG = cl.exe /O2 /DNDEBUG
|
||||
CCDEBUG = cl.exe /Od /Gm /Zi /D_DEBUG /GZ
|
||||
CFLAGSSSL = /DUSE_SSLEAY /DUSE_OPENSSL /I "$(OPENSSL_PATH)/inc32" /I "$(OPENSSL_PATH)/inc32/openssl"
|
||||
CFLAGSWINSSL = /DUSE_SCHANNEL
|
||||
CFLAGSSSH2 = /DUSE_LIBSSH2 /DCURL_DISABLE_LDAP /DHAVE_LIBSSH2 /DHAVE_LIBSSH2_H /DLIBSSH2_WIN32 /DLIBSSH2_LIBRARY /I "$(LIBSSH2_PATH)/include"
|
||||
CFLAGSZLIB = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ /I "$(ZLIB_PATH)"
|
||||
CFLAGS = /I. /I../include /nologo /W3 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL /D_BIND_TO_CURRENT_VCLIBS_VERSION=1
|
||||
@@ -189,6 +190,18 @@ CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSZLIB) $(CFLAGSLIB)
|
||||
CFGSET = TRUE
|
||||
!ENDIF
|
||||
|
||||
######################
|
||||
# release-winssl-zlib
|
||||
|
||||
!IF "$(CFG)" == "release-winssl-zlib"
|
||||
TARGET = $(LIBCURL_STA_LIB_REL)
|
||||
DIROBJ = $(CFG)
|
||||
LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)"
|
||||
LNK = $(LNKLIB) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET)
|
||||
CC = $(CCNODBG) $(RTLIB) $(CFLAGSWINSSL) $(CFLAGSZLIB) $(CFLAGSLIB)
|
||||
CFGSET = TRUE
|
||||
!ENDIF
|
||||
|
||||
######################
|
||||
# release-ssl-ssh2-zlib
|
||||
|
||||
@@ -515,7 +528,6 @@ X_OBJS= \
|
||||
$(DIROBJ)\curl_ntlm_core.obj \
|
||||
$(DIROBJ)\curl_ntlm_msgs.obj \
|
||||
$(DIROBJ)\curl_ntlm_wb.obj \
|
||||
$(DIROBJ)\curl_rand.obj \
|
||||
$(DIROBJ)\curl_rtmp.obj \
|
||||
$(DIROBJ)\curl_sasl.obj \
|
||||
$(DIROBJ)\curl_schannel.obj \
|
||||
@@ -523,6 +535,7 @@ X_OBJS= \
|
||||
$(DIROBJ)\curl_threads.obj \
|
||||
$(DIROBJ)\cyassl.obj \
|
||||
$(DIROBJ)\dict.obj \
|
||||
$(DIROBJ)\dotdot.obj \
|
||||
$(DIROBJ)\easy.obj \
|
||||
$(DIROBJ)\escape.obj \
|
||||
$(DIROBJ)\file.obj \
|
||||
@@ -553,7 +566,6 @@ X_OBJS= \
|
||||
$(DIROBJ)\imap.obj \
|
||||
$(DIROBJ)\inet_ntop.obj \
|
||||
$(DIROBJ)\inet_pton.obj \
|
||||
$(DIROBJ)\krb4.obj \
|
||||
$(DIROBJ)\krb5.obj \
|
||||
$(DIROBJ)\ldap.obj \
|
||||
$(DIROBJ)\llist.obj \
|
||||
|
||||
@@ -35,8 +35,8 @@ USER_CFLAGS:=
|
||||
# directories where to seek for includes and libraries
|
||||
OPENSSL_INC := D:/libraries/openssl/openssl-0.9.8y-vxWorks6.3/include
|
||||
OPENSSL_LIB := D:/libraries/openssl/openssl-0.9.8y-vxWorks6.3
|
||||
ZLIB_INC := D:/libraries/zlib/zlib-1.2.7-VxWorks6.3/zlib-1.2.7
|
||||
ZLIB_LIB := D:/libraries/zlib/zlib-1.2.7-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib
|
||||
ZLIB_INC := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/zlib-1.2.8
|
||||
ZLIB_LIB := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib
|
||||
ARES_INC :=
|
||||
ARES_LIB :=
|
||||
|
||||
|
||||
31
lib/README.http2
Normal file
31
lib/README.http2
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
HTTP2 with libcurl
|
||||
|
||||
Spec: http://tools.ietf.org/html/draft-ietf-httpbis-http2-06
|
||||
|
||||
nghttp2 (https://github.com/tatsuhiro-t/nghttp2)
|
||||
|
||||
We're depending on this 3rd party library for the actual low level protocol
|
||||
handling parts. The reason for this is that HTTP2 is much more complex at
|
||||
that layer than HTTP1.1 (which we implement on our own) and that nghttp2 is
|
||||
an already existing and well functional library.
|
||||
|
||||
Over an http:// URL
|
||||
|
||||
If CURLOPT_HTTP_VERSION is set to CURL_HTTP_VERSION_2, libcurl will include
|
||||
an upgrade header in the initial request to the host to allow upgrading to
|
||||
http2. Possibly introduce an option that will cause libcurl to fail if not
|
||||
possible to upgrade. Possibly introduce an option that makes libcurl use
|
||||
http2 at once over http://
|
||||
|
||||
Over an https:// URL
|
||||
|
||||
If CURLOPT_HTTP_VERSION is set to CURL_HTTP_VERSION_2, libcurl will use ALPN
|
||||
(or NPN) to negotiate which protocol to continue with. Possibly introduce an
|
||||
option that will cause libcurl to fail if not possible to use http2.
|
||||
|
||||
To consider:
|
||||
|
||||
- How to tell libcurl when using the multi interface that all or some of the
|
||||
handles are allowed to re-use the same physical connection. Can we just
|
||||
re-use existing pipelining logic?
|
||||
131
lib/asyn-ares.c
131
lib/asyn-ares.c
@@ -315,6 +315,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct ResolverResults *res = (struct ResolverResults *)
|
||||
conn->async.os_specific;
|
||||
CURLcode rc = CURLE_OK;
|
||||
|
||||
*dns = NULL;
|
||||
|
||||
@@ -325,19 +326,19 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
|
||||
/* temp_ai ownership is moved to the connection, so we need not free-up
|
||||
them */
|
||||
res->temp_ai = NULL;
|
||||
destroy_async_data(&conn->async);
|
||||
if(!conn->async.dns) {
|
||||
failf(data, "Could not resolve %s: %s (%s)",
|
||||
conn->bits.proxy?"proxy":"host",
|
||||
conn->host.dispname,
|
||||
ares_strerror(conn->async.status));
|
||||
return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
|
||||
failf(data, "Could not resolve: %s (%s)",
|
||||
conn->async.hostname, ares_strerror(conn->async.status));
|
||||
rc = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
|
||||
CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
else
|
||||
*dns = conn->async.dns;
|
||||
|
||||
destroy_async_data(&conn->async);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -415,37 +416,12 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
|
||||
if(entry)
|
||||
*entry = conn->async.dns;
|
||||
|
||||
if(!conn->async.dns) {
|
||||
/* a name was not resolved */
|
||||
if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
|
||||
if(conn->bits.proxy) {
|
||||
failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname);
|
||||
rc = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
}
|
||||
else {
|
||||
failf(data, "Resolving host timed out: %s", conn->host.dispname);
|
||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
}
|
||||
else if(conn->async.done) {
|
||||
if(conn->bits.proxy) {
|
||||
failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname,
|
||||
ares_strerror(conn->async.status));
|
||||
rc = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
}
|
||||
else {
|
||||
failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
|
||||
ares_strerror(conn->async.status));
|
||||
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
}
|
||||
else
|
||||
rc = CURLE_OPERATION_TIMEDOUT;
|
||||
|
||||
if(rc)
|
||||
/* close the connection, since we can't return failure here without
|
||||
cleaning up this connection properly */
|
||||
cleaning up this connection properly.
|
||||
TODO: remove this action from here, it is not a name resolver decision.
|
||||
*/
|
||||
conn->bits.close = TRUE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -614,8 +590,19 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
|
||||
char *servers)
|
||||
{
|
||||
CURLcode result = CURLE_NOT_BUILT_IN;
|
||||
int ares_result;
|
||||
|
||||
/* If server is NULL or empty, this would purge all DNS servers
|
||||
* from ares library, which will cause any and all queries to fail.
|
||||
* So, just return OK if none are configured and don't actually make
|
||||
* any changes to c-ares. This lets c-ares use it's defaults, which
|
||||
* it gets from the OS (for instance from /etc/resolv.conf on Linux).
|
||||
*/
|
||||
if(!(servers && servers[0]))
|
||||
return CURLE_OK;
|
||||
|
||||
#if (ARES_VERSION >= 0x010704)
|
||||
int ares_result = ares_set_servers_csv(data->state.resolver, servers);
|
||||
ares_result = ares_set_servers_csv(data->state.resolver, servers);
|
||||
switch(ares_result) {
|
||||
case ARES_SUCCESS:
|
||||
result = CURLE_OK;
|
||||
@@ -632,8 +619,76 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
|
||||
}
|
||||
#else /* too old c-ares version! */
|
||||
(void)data;
|
||||
(void)servers;
|
||||
(void)(ares_result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_set_dns_interface(struct SessionHandle *data,
|
||||
const char *interf)
|
||||
{
|
||||
#if (ARES_VERSION >= 0x010704)
|
||||
if(!interf)
|
||||
interf = "";
|
||||
|
||||
ares_set_local_dev((ares_channel)data->state.resolver, interf);
|
||||
|
||||
return CURLE_OK;
|
||||
#else /* c-ares version too old! */
|
||||
(void)data;
|
||||
(void)interf;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
|
||||
const char *local_ip4)
|
||||
{
|
||||
#if (ARES_VERSION >= 0x010704)
|
||||
uint32_t a4;
|
||||
|
||||
if((!local_ip4) || (local_ip4[0] == 0)) {
|
||||
a4 = 0; /* disabled: do not bind to a specific address */
|
||||
}
|
||||
else {
|
||||
if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4));
|
||||
|
||||
return CURLE_OK;
|
||||
#else /* c-ares version too old! */
|
||||
(void)data;
|
||||
(void)local_ip4;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
|
||||
const char *local_ip6)
|
||||
{
|
||||
#if (ARES_VERSION >= 0x010704)
|
||||
unsigned char a6[INET6_ADDRSTRLEN];
|
||||
|
||||
if((!local_ip6) || (local_ip6[0] == 0)) {
|
||||
/* disabled: do not bind to a specific address */
|
||||
memset(a6, 0, sizeof(a6));
|
||||
}
|
||||
else {
|
||||
if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
ares_set_local_ip6((ares_channel)data->state.resolver, a6);
|
||||
|
||||
return CURLE_OK;
|
||||
#else /* c-ares version too old! */
|
||||
(void)data;
|
||||
(void)local_ip6;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
#endif /* CURLRES_ARES */
|
||||
|
||||
@@ -265,7 +265,7 @@ static int getaddrinfo_complete(struct connectdata *conn)
|
||||
static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
|
||||
{
|
||||
struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
|
||||
char service [NI_MAXSERV];
|
||||
char service[12];
|
||||
int rc;
|
||||
|
||||
snprintf(service, sizeof(service), "%d", tsd->port);
|
||||
@@ -559,7 +559,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
|
||||
struct in_addr in;
|
||||
Curl_addrinfo *res;
|
||||
int error;
|
||||
char sbuf[NI_MAXSERV];
|
||||
char sbuf[12];
|
||||
int pf = PF_INET;
|
||||
#ifdef CURLRES_IPV6
|
||||
struct in6_addr in6;
|
||||
@@ -635,4 +635,28 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
|
||||
|
||||
}
|
||||
|
||||
CURLcode Curl_set_dns_interface(struct SessionHandle *data,
|
||||
const char *interf)
|
||||
{
|
||||
(void)data;
|
||||
(void)interf;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
|
||||
const char *local_ip4)
|
||||
{
|
||||
(void)data;
|
||||
(void)local_ip4;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
|
||||
const char *local_ip6)
|
||||
{
|
||||
(void)data;
|
||||
(void)local_ip6;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
#endif /* CURLRES_THREADED */
|
||||
|
||||
254
lib/axtls.c
254
lib/axtls.c
@@ -41,26 +41,12 @@
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
#include "curl_memory.h"
|
||||
#include <unistd.h>
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
#include "hostcheck.h"
|
||||
|
||||
|
||||
/* SSL_read is opied from axTLS compat layer */
|
||||
static int SSL_read(SSL *ssl, void *buf, int num)
|
||||
{
|
||||
uint8_t *read_buf;
|
||||
int ret;
|
||||
|
||||
while((ret = ssl_read(ssl, &read_buf)) == SSL_OK);
|
||||
|
||||
if(ret > SSL_OK) {
|
||||
memcpy(buf, read_buf, ret > num ? num : ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Global axTLS init, called from Curl_ssl_init() */
|
||||
int Curl_axtls_init(void)
|
||||
{
|
||||
@@ -131,31 +117,40 @@ static CURLcode map_error_to_curl(int axtls_err)
|
||||
static Curl_recv axtls_recv;
|
||||
static Curl_send axtls_send;
|
||||
|
||||
/*
|
||||
* This function is called after the TCP connect has completed. Setup the TLS
|
||||
* layer and do all necessary magic.
|
||||
*/
|
||||
CURLcode
|
||||
Curl_axtls_connect(struct connectdata *conn,
|
||||
int sockindex)
|
||||
static void free_ssl_structs(struct ssl_connect_data *connssl)
|
||||
{
|
||||
if(connssl->ssl) {
|
||||
ssl_free (connssl->ssl);
|
||||
connssl->ssl = NULL;
|
||||
}
|
||||
if(connssl->ssl_ctx) {
|
||||
ssl_ctx_free(connssl->ssl_ctx);
|
||||
connssl->ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For both blocking and non-blocking connects, this function sets up the
|
||||
* ssl context and state. This function is called after the TCP connect
|
||||
* has completed.
|
||||
*/
|
||||
static CURLcode connect_prep(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
SSL *ssl = NULL;
|
||||
int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
|
||||
int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
|
||||
int i, ssl_fcn_return;
|
||||
const uint8_t *ssl_sessionid;
|
||||
size_t ssl_idsize;
|
||||
const char *peer_CN;
|
||||
uint32_t dns_altname_index;
|
||||
const char *dns_altname;
|
||||
int8_t found_subject_alt_names = 0;
|
||||
int8_t found_subject_alt_name_matching_conn = 0;
|
||||
|
||||
/* Assuming users will not compile in custom key/cert to axTLS */
|
||||
uint32_t client_option = SSL_NO_DEFAULT_KEY|SSL_SERVER_VERIFY_LATER;
|
||||
/* Assuming users will not compile in custom key/cert to axTLS.
|
||||
* Also, even for blocking connects, use axTLS non-blocking feature.
|
||||
*/
|
||||
uint32_t client_option = SSL_NO_DEFAULT_KEY |
|
||||
SSL_SERVER_VERIFY_LATER |
|
||||
SSL_CONNECT_IN_PARTS;
|
||||
|
||||
if(conn->ssl[sockindex].state == ssl_connection_complete)
|
||||
/* to make us tolerant against being called more than once for the
|
||||
@@ -184,6 +179,9 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
conn->ssl[sockindex].ssl_ctx = ssl_ctx;
|
||||
conn->ssl[sockindex].ssl = NULL;
|
||||
|
||||
/* Load the trusted CA cert bundle file */
|
||||
if(data->set.ssl.CAfile) {
|
||||
if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL)
|
||||
@@ -191,7 +189,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
infof(data, "error reading ca cert file %s \n",
|
||||
data->set.ssl.CAfile);
|
||||
if(data->set.ssl.verifypeer) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +222,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
if(cert_types[i] == 0) {
|
||||
failf(data, "%s is not x509 or pkcs12 format",
|
||||
data->set.str[STRING_CERT]);
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +246,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
if(key_types[i] == 0) {
|
||||
failf(data, "Failure: %s is not a supported key file",
|
||||
data->set.str[STRING_KEY]);
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -271,14 +266,25 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
else
|
||||
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
|
||||
|
||||
/* Check to make sure handshake was ok. */
|
||||
ssl_fcn_return = ssl_handshake_status(ssl);
|
||||
if(ssl_fcn_return != SSL_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
|
||||
return map_error_to_curl(ssl_fcn_return);
|
||||
conn->ssl[sockindex].ssl = ssl;
|
||||
return CURLE_OK;
|
||||
}
|
||||
infof (data, "handshake completed successfully\n");
|
||||
|
||||
/*
|
||||
* For both blocking and non-blocking connects, this function finalizes the
|
||||
* SSL connection.
|
||||
*/
|
||||
static CURLcode connect_finish(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
SSL *ssl = conn->ssl[sockindex].ssl;
|
||||
const uint8_t *ssl_sessionid;
|
||||
size_t ssl_idsize;
|
||||
const char *peer_CN;
|
||||
uint32_t dns_altname_index;
|
||||
const char *dns_altname;
|
||||
int8_t found_subject_alt_names = 0;
|
||||
int8_t found_subject_alt_name_matching_conn = 0;
|
||||
|
||||
/* Here, gtls.c gets the peer certificates and fails out depending on
|
||||
* settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
|
||||
@@ -289,7 +295,7 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
if(ssl_verify_cert(ssl) != SSL_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "server cert verify failed");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -306,7 +312,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
* this, but a couple fields are available.
|
||||
*/
|
||||
|
||||
|
||||
/* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
|
||||
risk of an inifite loop */
|
||||
for(dns_altname_index = 0; ; dns_altname_index++) {
|
||||
@@ -326,21 +331,30 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
|
||||
/* RFC2818 checks */
|
||||
if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
|
||||
if(data->set.ssl.verifyhost) {
|
||||
/* Break connection ! */
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "\tsubjectAltName(s) do not match %s\n", conn->host.dispname);
|
||||
failf(data, "\tsubjectAltName(s) do not match %s\n",
|
||||
conn->host.dispname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else
|
||||
infof(data, "\tsubjectAltName(s) do not match %s\n",
|
||||
conn->host.dispname);
|
||||
}
|
||||
else if(found_subject_alt_names == 0) {
|
||||
/* Per RFC2818, when no Subject Alt Names were available, examine the peer
|
||||
CN as a legacy fallback */
|
||||
peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
|
||||
if(peer_CN == NULL) {
|
||||
/* Similar behaviour to the OpenSSL interface */
|
||||
if(data->set.ssl.verifyhost) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
failf(data, "unable to obtain common name from peer certificate");
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else
|
||||
infof(data, "unable to obtain common name from peer certificate");
|
||||
}
|
||||
else {
|
||||
if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
|
||||
if(data->set.ssl.verifyhost) {
|
||||
@@ -359,8 +373,6 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
|
||||
/* General housekeeping */
|
||||
conn->ssl[sockindex].state = ssl_connection_complete;
|
||||
conn->ssl[sockindex].ssl = ssl;
|
||||
conn->ssl[sockindex].ssl_ctx = ssl_ctx;
|
||||
conn->recv[sockindex] = axtls_recv;
|
||||
conn->send[sockindex] = axtls_send;
|
||||
|
||||
@@ -374,6 +386,107 @@ Curl_axtls_connect(struct connectdata *conn,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use axTLS's non-blocking connection feature to open an SSL connection.
|
||||
* This is called after a TCP connection is already established.
|
||||
*/
|
||||
CURLcode Curl_axtls_connect_nonblocking(
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
bool *done)
|
||||
{
|
||||
CURLcode conn_step;
|
||||
int ssl_fcn_return;
|
||||
|
||||
*done = FALSE;
|
||||
/* connectdata is calloc'd and connecting_state is only changed in this
|
||||
function, so this is safe, as the state is effectively initialized. */
|
||||
if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
|
||||
conn_step = connect_prep(conn, sockindex);
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_2;
|
||||
}
|
||||
|
||||
if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
|
||||
/* Check to make sure handshake was ok. */
|
||||
if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
|
||||
ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
|
||||
if(ssl_fcn_return < 0) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
|
||||
return map_error_to_curl(ssl_fcn_return);
|
||||
}
|
||||
else {
|
||||
return CURLE_OK; /* Return control to caller for retries */
|
||||
}
|
||||
}
|
||||
infof (conn->data, "handshake completed successfully\n");
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_3;
|
||||
}
|
||||
|
||||
if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
|
||||
conn_step = connect_finish(conn, sockindex);
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
|
||||
/* Reset connect state */
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_1;
|
||||
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Unrecognized state. Things are very bad. */
|
||||
conn->ssl[sockindex].state = ssl_connection_none;
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_1;
|
||||
/* Return value perhaps not strictly correct, but distinguishes the issue.*/
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after the TCP connect has completed. Setup the TLS
|
||||
* layer and do all necessary magic for a blocking connect.
|
||||
*/
|
||||
CURLcode
|
||||
Curl_axtls_connect(struct connectdata *conn,
|
||||
int sockindex)
|
||||
|
||||
{
|
||||
CURLcode conn_step = connect_prep(conn, sockindex);
|
||||
int ssl_fcn_return;
|
||||
SSL *ssl = conn->ssl[sockindex].ssl;
|
||||
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
|
||||
/* Check to make sure handshake was ok. */
|
||||
while(ssl_handshake_status(ssl) != SSL_OK) {
|
||||
ssl_fcn_return = ssl_read(ssl, NULL);
|
||||
if(ssl_fcn_return < 0) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
|
||||
return map_error_to_curl(ssl_fcn_return);
|
||||
}
|
||||
usleep(10000);
|
||||
}
|
||||
infof (conn->data, "handshake completed successfully\n");
|
||||
|
||||
conn_step = connect_finish(conn, sockindex);
|
||||
if(conn_step != CURLE_OK) {
|
||||
Curl_axtls_close(conn, sockindex);
|
||||
return conn_step;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* return number of sent (non-SSL) bytes */
|
||||
static ssize_t axtls_send(struct connectdata *conn,
|
||||
@@ -407,7 +520,7 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex)
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
|
||||
infof(conn->data, " Curl_axtls_close\n");
|
||||
if(connssl->ssl) {
|
||||
|
||||
/* line from ssluse.c: (void)SSL_shutdown(connssl->ssl);
|
||||
axTLS compat layer does nothing for SSL_shutdown */
|
||||
|
||||
@@ -415,13 +528,7 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex)
|
||||
equivalent. ssl_free and ssl_ctx_free close things.
|
||||
SSL_set_connect_state(connssl->handle); */
|
||||
|
||||
ssl_free (connssl->ssl);
|
||||
connssl->ssl = NULL;
|
||||
}
|
||||
if(connssl->ssl_ctx) {
|
||||
ssl_ctx_free (connssl->ssl_ctx);
|
||||
connssl->ssl_ctx = NULL;
|
||||
}
|
||||
free_ssl_structs(connssl);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -436,8 +543,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
|
||||
int retval = 0;
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
struct SessionHandle *data = conn->data;
|
||||
char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
|
||||
to be at least 120 bytes long. */
|
||||
uint8_t *buf;
|
||||
ssize_t nread;
|
||||
|
||||
infof(conn->data, " Curl_axtls_shutdown\n");
|
||||
@@ -457,9 +563,10 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
|
||||
CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
|
||||
if(what > 0) {
|
||||
/* Something to read, let's do it and hope that it is the close
|
||||
notify alert from the server */
|
||||
nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf,
|
||||
sizeof(buf));
|
||||
notify alert from the server. buf is managed internally by
|
||||
axTLS and will be released upon calling ssl_free via
|
||||
free_ssl_structs. */
|
||||
nread = (ssize_t)ssl_read(connssl->ssl, &buf);
|
||||
|
||||
if(nread < SSL_OK) {
|
||||
failf(data, "close notify alert not received during shutdown");
|
||||
@@ -476,8 +583,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
ssl_free (connssl->ssl);
|
||||
connssl->ssl = NULL;
|
||||
free_ssl_structs(connssl);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -490,26 +596,36 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
|
||||
{
|
||||
struct ssl_connect_data *connssl = &conn->ssl[num];
|
||||
ssize_t ret = 0;
|
||||
uint8_t *read_buf;
|
||||
|
||||
infof(conn->data, " axtls_recv\n");
|
||||
|
||||
*err = CURLE_OK;
|
||||
if(connssl) {
|
||||
ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize);
|
||||
|
||||
/* axTLS isn't terribly generous about error reporting */
|
||||
ret = ssl_read(connssl->ssl, &read_buf);
|
||||
if(ret > SSL_OK) {
|
||||
/* ssl_read returns SSL_OK if there is more data to read, so if it is
|
||||
larger, then all data has been read already. */
|
||||
memcpy(buf, read_buf,
|
||||
(size_t)ret > buffersize ? buffersize : (size_t)ret);
|
||||
}
|
||||
else if(ret == SSL_OK) {
|
||||
/* more data to be read, signal caller to call again */
|
||||
*err = CURLE_AGAIN;
|
||||
ret = -1;
|
||||
}
|
||||
else if(ret == -3) {
|
||||
/* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
|
||||
team approves proposed fix. */
|
||||
if(ret == -3 ) {
|
||||
Curl_axtls_close(conn, num);
|
||||
}
|
||||
else if(ret < 0) {
|
||||
failf(conn->data, "axTLS recv error (%d)", (int)ret);
|
||||
else {
|
||||
failf(conn->data, "axTLS recv error (%d)", ret);
|
||||
*err = map_error_to_curl(ret);
|
||||
return -1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
*err = CURLE_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
int Curl_axtls_init(void);
|
||||
int Curl_axtls_cleanup(void);
|
||||
CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex);
|
||||
CURLcode Curl_axtls_connect_nonblocking(
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
bool *done);
|
||||
|
||||
/* tell axTLS to close down all open information regarding connections (and
|
||||
thus session ID caching etc) */
|
||||
@@ -47,6 +51,7 @@ int Curl_axtls_check_cxn(struct connectdata *conn);
|
||||
#define curlssl_init Curl_axtls_init
|
||||
#define curlssl_cleanup Curl_axtls_cleanup
|
||||
#define curlssl_connect Curl_axtls_connect
|
||||
#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking
|
||||
#define curlssl_session_free(x) Curl_axtls_session_free(x)
|
||||
#define curlssl_close_all Curl_axtls_close_all
|
||||
#define curlssl_close Curl_axtls_close
|
||||
|
||||
@@ -277,21 +277,27 @@
|
||||
/* Define if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H
|
||||
|
||||
|
||||
/* The following define is needed on OS400 to enable strcmpi(), stricmp() and
|
||||
strdup(). */
|
||||
#define __cplusplus__strings__
|
||||
|
||||
/* Define if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define if you have the `strcmpi' function. */
|
||||
#undef HAVE_STRCMPI
|
||||
#define HAVE_STRCMPI
|
||||
|
||||
/* Define if you have the `stricmp' function. */
|
||||
#define HAVE_STRICMP
|
||||
|
||||
/* Define if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
#define HAVE_STRDUP
|
||||
|
||||
|
||||
/* Define if you have the `strftime' function. */
|
||||
#define HAVE_STRFTIME
|
||||
|
||||
/* Define if you have the `stricmp' function. */
|
||||
#undef HAVE_STRICMP
|
||||
|
||||
/* Define if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H
|
||||
|
||||
@@ -525,6 +531,9 @@
|
||||
/* Define to use the QsoSSL package. */
|
||||
#define USE_QSOSSL
|
||||
|
||||
/* Define to use the GSKit package. */
|
||||
#undef USE_GSKIT
|
||||
|
||||
/* Use the system keyring as the default CA bundle. */
|
||||
#define CURL_CA_BUNDLE "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB"
|
||||
|
||||
|
||||
@@ -390,21 +390,6 @@
|
||||
# define SIZEOF_SIZE_T 4
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* STRUCT RELATED */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have struct sockaddr_storage. */
|
||||
#if !defined(__SALFORDC__) && !defined(__BORLANDC__)
|
||||
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
|
||||
#endif
|
||||
|
||||
/* Define if you have struct timeval. */
|
||||
#define HAVE_STRUCT_TIMEVAL 1
|
||||
|
||||
/* Define if struct sockaddr_in6 has the sin6_scope_id member. */
|
||||
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* BSD-style lwIP TCP/IP stack SPECIFIC */
|
||||
/* ---------------------------------------------------------------- */
|
||||
@@ -572,6 +557,25 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* STRUCT RELATED */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Define if you have struct sockaddr_storage. */
|
||||
#if !defined(__SALFORDC__) && !defined(__BORLANDC__)
|
||||
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
|
||||
#endif
|
||||
|
||||
/* Define if you have struct timeval. */
|
||||
#define HAVE_STRUCT_TIMEVAL 1
|
||||
|
||||
/* Define if struct sockaddr_in6 has the sin6_scope_id member. */
|
||||
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
#if HAVE_WINSOCK2_H && defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
#define HAVE_STRUCT_POLLFD 1
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* LARGE FILE SUPPORT */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
@@ -38,8 +38,6 @@
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#define CONNECTION_HASH_SIZE 97
|
||||
|
||||
static void free_bundle_hash_entry(void *freethis)
|
||||
{
|
||||
struct connectbundle *b = (struct connectbundle *) freethis;
|
||||
@@ -47,7 +45,7 @@ static void free_bundle_hash_entry(void *freethis)
|
||||
Curl_bundle_destroy(b);
|
||||
}
|
||||
|
||||
struct conncache *Curl_conncache_init(void)
|
||||
struct conncache *Curl_conncache_init(int size)
|
||||
{
|
||||
struct conncache *connc;
|
||||
|
||||
@@ -55,7 +53,7 @@ struct conncache *Curl_conncache_init(void)
|
||||
if(!connc)
|
||||
return NULL;
|
||||
|
||||
connc->hash = Curl_hash_alloc(CONNECTION_HASH_SIZE, Curl_hash_str,
|
||||
connc->hash = Curl_hash_alloc(size, Curl_hash_str,
|
||||
Curl_str_key_compare, free_bundle_hash_entry);
|
||||
|
||||
if(!connc->hash) {
|
||||
|
||||
@@ -27,7 +27,7 @@ struct conncache {
|
||||
size_t num_connections;
|
||||
};
|
||||
|
||||
struct conncache *Curl_conncache_init(void);
|
||||
struct conncache *Curl_conncache_init(int size);
|
||||
|
||||
void Curl_conncache_destroy(struct conncache *connc);
|
||||
|
||||
|
||||
@@ -413,22 +413,21 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
if(af == AF_INET6) {
|
||||
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
char *scope_ptr = strchr(myhost, '%');
|
||||
|
||||
if(scope_ptr) *(scope_ptr++) = 0;
|
||||
if(scope_ptr)
|
||||
*(scope_ptr++) = 0;
|
||||
#endif
|
||||
if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
|
||||
si6->sin6_family = AF_INET6;
|
||||
si6->sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
if(scope_ptr) {
|
||||
/* The "myhost" string either comes from Curl_if2ip or
|
||||
from Curl_printable_address. The latter returns only
|
||||
numeric scope IDs and the former returns none at all.
|
||||
So the scope ID, if present, is known to be numeric */
|
||||
if(scope_ptr)
|
||||
/* The "myhost" string either comes from Curl_if2ip or from
|
||||
Curl_printable_address. The latter returns only numeric scope
|
||||
IDs and the former returns none at all. So the scope ID, if
|
||||
present, is known to be numeric */
|
||||
si6->sin6_scope_id = atoi(scope_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sizeof_sa = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else
|
||||
@@ -1145,7 +1144,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
|
||||
if(sockfd == CURL_SOCKET_BAD) {
|
||||
/* no good connect was made */
|
||||
failf(data, "couldn't connect to %s at %s:%d",
|
||||
failf(data, "couldn't connect to %s at %s:%ld",
|
||||
conn->bits.proxy?"proxy":"host",
|
||||
conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port);
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
@@ -1252,7 +1251,13 @@ int Curl_closesocket(struct connectdata *conn,
|
||||
else
|
||||
return conn->fclosesocket(conn->closesocket_client, sock);
|
||||
}
|
||||
return sclose(sock);
|
||||
sclose(sock);
|
||||
|
||||
if(conn)
|
||||
/* tell the multi-socket code about this */
|
||||
Curl_multi_closed(conn, sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
231
lib/cookie.c
231
lib/cookie.c
@@ -89,6 +89,7 @@ Example set of cookies:
|
||||
#include "strequal.h"
|
||||
#include "strtok.h"
|
||||
#include "sendf.h"
|
||||
#include "slist.h"
|
||||
#include "curl_memory.h"
|
||||
#include "share.h"
|
||||
#include "strtoofft.h"
|
||||
@@ -106,6 +107,8 @@ static void freecookie(struct Cookie *co)
|
||||
free(co->domain);
|
||||
if(co->path)
|
||||
free(co->path);
|
||||
if(co->spath)
|
||||
free(co->spath);
|
||||
if(co->name)
|
||||
free(co->name);
|
||||
if(co->value)
|
||||
@@ -143,6 +146,116 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* matching cookie path and url path
|
||||
* RFC6265 5.1.4 Paths and Path-Match
|
||||
*/
|
||||
static bool pathmatch(const char* cookie_path, const char* request_uri)
|
||||
{
|
||||
size_t cookie_path_len;
|
||||
size_t uri_path_len;
|
||||
char* uri_path = NULL;
|
||||
char* pos;
|
||||
bool ret = FALSE;
|
||||
|
||||
/* cookie_path must not have last '/' separator. ex: /sample */
|
||||
cookie_path_len = strlen(cookie_path);
|
||||
if(1 == cookie_path_len) {
|
||||
/* cookie_path must be '/' */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uri_path = strdup(request_uri);
|
||||
if(!uri_path)
|
||||
return FALSE;
|
||||
pos = strchr(uri_path, '?');
|
||||
if(pos)
|
||||
*pos = 0x0;
|
||||
|
||||
/* #-fragments are already cut off! */
|
||||
if(0 == strlen(uri_path) || uri_path[0] != '/') {
|
||||
free(uri_path);
|
||||
uri_path = strdup("/");
|
||||
if(!uri_path)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* here, RFC6265 5.1.4 says
|
||||
4. Output the characters of the uri-path from the first character up
|
||||
to, but not including, the right-most %x2F ("/").
|
||||
but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
|
||||
without redirect.
|
||||
Ignore this algorithm because /hoge is uri path for this case
|
||||
(uri path is not /).
|
||||
*/
|
||||
|
||||
uri_path_len = strlen(uri_path);
|
||||
|
||||
if(uri_path_len < cookie_path_len) {
|
||||
ret = FALSE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* not using checkprefix() because matching should be case-sensitive */
|
||||
if(strncmp(cookie_path, uri_path, cookie_path_len)) {
|
||||
ret = FALSE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* The cookie-path and the uri-path are identical. */
|
||||
if(cookie_path_len == uri_path_len) {
|
||||
ret = TRUE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
/* here, cookie_path_len < url_path_len */
|
||||
if(uri_path[cookie_path_len] == '/') {
|
||||
ret = TRUE;
|
||||
goto pathmatched;
|
||||
}
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
pathmatched:
|
||||
free(uri_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* cookie path sanitize
|
||||
*/
|
||||
static char *sanitize_cookie_path(const char *cookie_path)
|
||||
{
|
||||
size_t len;
|
||||
char *new_path = strdup(cookie_path);
|
||||
if(!new_path)
|
||||
return NULL;
|
||||
|
||||
/* some stupid site sends path attribute with '"'. */
|
||||
if(new_path[0] == '\"') {
|
||||
memmove((void *)new_path, (const void *)(new_path + 1), strlen(new_path));
|
||||
}
|
||||
if(new_path[strlen(new_path) - 1] == '\"') {
|
||||
new_path[strlen(new_path) - 1] = 0x0;
|
||||
}
|
||||
|
||||
/* RFC6265 5.2.4 The Path Attribute */
|
||||
if(new_path[0] != '/') {
|
||||
/* Let cookie-path be the default-path. */
|
||||
free(new_path);
|
||||
new_path = strdup("/");
|
||||
return new_path;
|
||||
}
|
||||
|
||||
/* convert /hoge/ to /hoge */
|
||||
len = strlen(new_path);
|
||||
if(1 < len && new_path[len - 1] == '/') {
|
||||
new_path[len - 1] = 0x0;
|
||||
}
|
||||
|
||||
return new_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
|
||||
*/
|
||||
@@ -177,6 +290,34 @@ static void strstore(char **str, const char *newstr)
|
||||
*str = strdup(newstr);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove_expired() removes expired cookies.
|
||||
*/
|
||||
static void remove_expired(struct CookieInfo *cookies)
|
||||
{
|
||||
struct Cookie *co, *nx, *pv;
|
||||
curl_off_t now = (curl_off_t)time(NULL);
|
||||
|
||||
co = cookies->cookies;
|
||||
pv = NULL;
|
||||
while(co) {
|
||||
nx = co->next;
|
||||
if((co->expirestr || co->maxage) && co->expires < now) {
|
||||
if(co == cookies->cookies) {
|
||||
cookies->cookies = co->next;
|
||||
}
|
||||
else {
|
||||
pv->next = co->next;
|
||||
}
|
||||
cookies->numcookies--;
|
||||
freecookie(co);
|
||||
}
|
||||
else {
|
||||
pv = co;
|
||||
}
|
||||
co = nx;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
@@ -184,6 +325,9 @@ static void strstore(char **str, const char *newstr)
|
||||
*
|
||||
* Add a single cookie line to the cookie keeping object.
|
||||
*
|
||||
* Be aware that sometimes we get an IP-only host name, and that might also be
|
||||
* a numerical IPv6 address.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
struct Cookie *
|
||||
@@ -288,45 +432,13 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
break;
|
||||
}
|
||||
co->spath = sanitize_cookie_path(co->path);
|
||||
if(!co->spath) {
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(Curl_raw_equal("domain", name)) {
|
||||
/* note that this name may or may not have a preceding dot, but
|
||||
we don't care about that, we treat the names the same anyway */
|
||||
|
||||
const char *domptr=whatptr;
|
||||
const char *nextptr;
|
||||
int dotcount=1;
|
||||
|
||||
/* Count the dots, we need to make sure that there are enough
|
||||
of them. */
|
||||
|
||||
if('.' == whatptr[0])
|
||||
/* don't count the initial dot, assume it */
|
||||
domptr++;
|
||||
|
||||
do {
|
||||
nextptr = strchr(domptr, '.');
|
||||
if(nextptr) {
|
||||
if(domptr != nextptr)
|
||||
dotcount++;
|
||||
domptr = nextptr+1;
|
||||
}
|
||||
} while(nextptr);
|
||||
|
||||
/* The original Netscape cookie spec defined that this domain name
|
||||
MUST have three dots (or two if one of the seven holy TLDs),
|
||||
but it seems that these kinds of cookies are in use "out there"
|
||||
so we cannot be that strict. I've therefore lowered the check
|
||||
to not allow less than two dots. */
|
||||
|
||||
if(dotcount < 2) {
|
||||
/* Received and skipped a cookie with a domain using too few
|
||||
dots. */
|
||||
badcookie=TRUE; /* mark this as a bad cookie */
|
||||
infof(data, "skipped cookie with illegal dotcount domain: %s\n",
|
||||
whatptr);
|
||||
}
|
||||
else {
|
||||
/* Now, we make sure that our host is within the given domain,
|
||||
or the given domain is not valid and thus cannot be set. */
|
||||
|
||||
@@ -355,7 +467,6 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
whatptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(Curl_raw_equal("version", name)) {
|
||||
strstore(&co->version, whatptr);
|
||||
if(!co->version) {
|
||||
@@ -461,6 +572,9 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
if(co->path) {
|
||||
memcpy(co->path, path, pathlen);
|
||||
co->path[pathlen]=0; /* zero terminate */
|
||||
co->spath = sanitize_cookie_path(co->path);
|
||||
if(!co->spath)
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
}
|
||||
else
|
||||
badcookie = TRUE;
|
||||
@@ -512,12 +626,6 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
|
||||
firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
|
||||
|
||||
/* Here's a quick check to eliminate normal HTTP-headers from this */
|
||||
if(!firstptr || strchr(firstptr, ':')) {
|
||||
free(co);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now loop through the fields and init the struct we already have
|
||||
allocated */
|
||||
for(ptr=firstptr, fields=0; ptr && !badcookie;
|
||||
@@ -552,12 +660,21 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
co->path = strdup(ptr);
|
||||
if(!co->path)
|
||||
badcookie = TRUE;
|
||||
else {
|
||||
co->spath = sanitize_cookie_path(co->path);
|
||||
if(!co->spath) {
|
||||
badcookie = TRUE; /* out of memory bad */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* this doesn't look like a path, make one up! */
|
||||
co->path = strdup("/");
|
||||
if(!co->path)
|
||||
badcookie = TRUE;
|
||||
co->spath = strdup("/");
|
||||
if(!co->spath)
|
||||
badcookie = TRUE;
|
||||
fields++; /* add a field and fall down to secure */
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
@@ -611,6 +728,9 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
superceeds an already existing cookie, which it may if the previous have
|
||||
the same domain and path as this */
|
||||
|
||||
/* at first, remove expired cookies */
|
||||
remove_expired(c);
|
||||
|
||||
clist = c->cookies;
|
||||
replace_old = FALSE;
|
||||
while(clist) {
|
||||
@@ -628,14 +748,14 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
if(replace_old) {
|
||||
/* the domains were identical */
|
||||
|
||||
if(clist->path && co->path) {
|
||||
if(Curl_raw_equal(clist->path, co->path)) {
|
||||
if(clist->spath && co->spath) {
|
||||
if(Curl_raw_equal(clist->spath, co->spath)) {
|
||||
replace_old = TRUE;
|
||||
}
|
||||
else
|
||||
replace_old = FALSE;
|
||||
}
|
||||
else if(!clist->path && !co->path)
|
||||
else if(!clist->spath && !co->spath)
|
||||
replace_old = TRUE;
|
||||
else
|
||||
replace_old = FALSE;
|
||||
@@ -664,6 +784,8 @@ Curl_cookie_add(struct SessionHandle *data,
|
||||
free(clist->domain);
|
||||
if(clist->path)
|
||||
free(clist->path);
|
||||
if(clist->spath)
|
||||
free(clist->spath);
|
||||
if(clist->expirestr)
|
||||
free(clist->expirestr);
|
||||
|
||||
@@ -840,6 +962,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
if(!c || !c->cookies)
|
||||
return NULL; /* no cookie struct or no cookies in the struct */
|
||||
|
||||
/* at first, remove expired cookies */
|
||||
remove_expired(c);
|
||||
|
||||
co = c->cookies;
|
||||
|
||||
while(co) {
|
||||
@@ -858,10 +983,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
|
||||
/* now check the left part of the path with the cookies path
|
||||
requirement */
|
||||
if(!co->path ||
|
||||
/* not using checkprefix() because matching should be
|
||||
case-sensitive */
|
||||
!strncmp(co->path, path, strlen(co->path)) ) {
|
||||
if(!co->spath || pathmatch(co->spath, path) ) {
|
||||
|
||||
/* and now, we know this is a match and we should create an
|
||||
entry for the return-linked-list */
|
||||
@@ -1085,6 +1207,9 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
|
||||
destination file */
|
||||
return 0;
|
||||
|
||||
/* at first, remove expired cookies */
|
||||
remove_expired(c);
|
||||
|
||||
if(strequal("-", dumphere)) {
|
||||
/* use stdout */
|
||||
out = stdout;
|
||||
@@ -1145,9 +1270,9 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
|
||||
curl_slist_free_all(list);
|
||||
return NULL;
|
||||
}
|
||||
beg = curl_slist_append(list, line);
|
||||
free(line);
|
||||
beg = Curl_slist_append_nodup(list, line);
|
||||
if(!beg) {
|
||||
free(line);
|
||||
curl_slist_free_all(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ struct Cookie {
|
||||
struct Cookie *next; /* next in the chain */
|
||||
char *name; /* <this> = value */
|
||||
char *value; /* name = <this> */
|
||||
char *path; /* path = <this> */
|
||||
char *path; /* path = <this> which is in Set-Cookie: */
|
||||
char *spath; /* sanitized cookie path */
|
||||
char *domain; /* domain = <this> */
|
||||
curl_off_t expires; /* expires = <this> */
|
||||
char *expirestr; /* the plain text version */
|
||||
|
||||
@@ -38,9 +38,58 @@
|
||||
#include <Security/SecureTransport.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
|
||||
/* The Security framework has changed greatly between iOS and different OS X
|
||||
versions, and we will try to support as many of them as we can (back to
|
||||
Leopard and iOS 5) by using macros and weak-linking.
|
||||
|
||||
IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then
|
||||
you must build this project against the 10.8 SDK or later. */
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
|
||||
#error "The darwinssl back-end requires Leopard or later."
|
||||
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
|
||||
|
||||
#define CURL_BUILD_IOS 0
|
||||
#define CURL_BUILD_IOS_7 0
|
||||
#define CURL_BUILD_MAC 1
|
||||
/* This is the maximum API level we are allowed to use when building: */
|
||||
#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
|
||||
#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
|
||||
#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
|
||||
#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
|
||||
/* These macros mean "the following code is present to allow runtime backward
|
||||
compatibility with at least this cat or earlier":
|
||||
(You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET
|
||||
environmental variable.) */
|
||||
#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
|
||||
#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
|
||||
#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
|
||||
#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
|
||||
#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
|
||||
|
||||
#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
|
||||
#define CURL_BUILD_IOS 1
|
||||
#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
||||
#define CURL_BUILD_MAC 0
|
||||
#define CURL_BUILD_MAC_10_5 0
|
||||
#define CURL_BUILD_MAC_10_6 0
|
||||
#define CURL_BUILD_MAC_10_7 0
|
||||
#define CURL_BUILD_MAC_10_8 0
|
||||
#define CURL_SUPPORT_MAC_10_5 0
|
||||
#define CURL_SUPPORT_MAC_10_6 0
|
||||
#define CURL_SUPPORT_MAC_10_7 0
|
||||
#define CURL_SUPPORT_MAC_10_8 0
|
||||
|
||||
#else
|
||||
#error "The darwinssl back-end requires iOS or OS X."
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
|
||||
#if CURL_BUILD_MAC
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#endif /* CURL_BUILD_MAC */
|
||||
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
@@ -61,16 +110,6 @@
|
||||
#define ioErr -36
|
||||
#define paramErr -50
|
||||
|
||||
/* In Mountain Lion and iOS 5, Apple made some changes to the API. They
|
||||
added TLS 1.1 and 1.2 support, and deprecated and replaced some
|
||||
functions. You need to build against the Mountain Lion or iOS 5 SDK
|
||||
or later to get TLS 1.1 or 1.2 support working in cURL. We'll weak-link
|
||||
to the newer functions and use them if present in the user's OS.
|
||||
|
||||
Builders: If you want TLS 1.1 and 1.2 but still want to retain support
|
||||
for older cats, don't forget to set the MACOSX_DEPLOYMENT_TARGET
|
||||
environmental variable prior to building cURL. */
|
||||
|
||||
/* The following two functions were ripped from Apple sample code,
|
||||
* with some modifications: */
|
||||
static OSStatus SocketRead(SSLConnectionRef connection,
|
||||
@@ -361,7 +400,7 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
|
||||
case TLS_DH_anon_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
|
||||
break;
|
||||
#if defined(__MAC_10_6) || defined(__IPHONE_5_0)
|
||||
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
|
||||
/* TLS 1.0 with ECDSA (RFC 4492) */
|
||||
case TLS_ECDH_ECDSA_WITH_NULL_SHA:
|
||||
return "TLS_ECDH_ECDSA_WITH_NULL_SHA";
|
||||
@@ -438,8 +477,8 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
|
||||
case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
|
||||
break;
|
||||
#endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */
|
||||
#if defined(__MAC_10_8) || defined(__IPHONE_5_0)
|
||||
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
|
||||
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
|
||||
/* TLS 1.2 (RFC 5246) */
|
||||
case TLS_RSA_WITH_NULL_MD5:
|
||||
return "TLS_RSA_WITH_NULL_MD5";
|
||||
@@ -624,12 +663,116 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
|
||||
case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
|
||||
return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
|
||||
break;
|
||||
#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */
|
||||
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
|
||||
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
|
||||
/* TLS PSK (RFC 4279): */
|
||||
case TLS_PSK_WITH_RC4_128_SHA:
|
||||
return "TLS_PSK_WITH_RC4_128_SHA";
|
||||
break;
|
||||
case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
return "TLS_PSK_WITH_3DES_EDE_CBC_SHA";
|
||||
break;
|
||||
case TLS_PSK_WITH_AES_128_CBC_SHA:
|
||||
return "TLS_PSK_WITH_AES_128_CBC_SHA";
|
||||
break;
|
||||
case TLS_PSK_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_PSK_WITH_AES_256_CBC_SHA";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_RC4_128_SHA:
|
||||
return "TLS_DHE_PSK_WITH_RC4_128_SHA";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
|
||||
return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_RC4_128_SHA:
|
||||
return "TLS_RSA_PSK_WITH_RC4_128_SHA";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
|
||||
return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
|
||||
return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA";
|
||||
break;
|
||||
/* More TLS PSK (RFC 4785): */
|
||||
case TLS_PSK_WITH_NULL_SHA:
|
||||
return "TLS_PSK_WITH_NULL_SHA";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_NULL_SHA:
|
||||
return "TLS_DHE_PSK_WITH_NULL_SHA";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_NULL_SHA:
|
||||
return "TLS_RSA_PSK_WITH_NULL_SHA";
|
||||
break;
|
||||
/* Even more TLS PSK (RFC 5487): */
|
||||
case TLS_PSK_WITH_AES_128_GCM_SHA256:
|
||||
return "TLS_PSK_WITH_AES_128_GCM_SHA256";
|
||||
break;
|
||||
case TLS_PSK_WITH_AES_256_GCM_SHA384:
|
||||
return "TLS_PSK_WITH_AES_256_GCM_SHA384";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
|
||||
return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
|
||||
return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
|
||||
return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
|
||||
return "TLS_PSK_WITH_AES_256_GCM_SHA384";
|
||||
break;
|
||||
case TLS_PSK_WITH_AES_128_CBC_SHA256:
|
||||
return "TLS_PSK_WITH_AES_128_CBC_SHA256";
|
||||
break;
|
||||
case TLS_PSK_WITH_AES_256_CBC_SHA384:
|
||||
return "TLS_PSK_WITH_AES_256_CBC_SHA384";
|
||||
break;
|
||||
case TLS_PSK_WITH_NULL_SHA256:
|
||||
return "TLS_PSK_WITH_NULL_SHA256";
|
||||
break;
|
||||
case TLS_PSK_WITH_NULL_SHA384:
|
||||
return "TLS_PSK_WITH_NULL_SHA384";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
|
||||
return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
|
||||
return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_NULL_SHA256:
|
||||
return "TLS_DHE_PSK_WITH_NULL_SHA256";
|
||||
break;
|
||||
case TLS_DHE_PSK_WITH_NULL_SHA384:
|
||||
return "TLS_RSA_PSK_WITH_NULL_SHA384";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
|
||||
return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
|
||||
return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_NULL_SHA256:
|
||||
return "TLS_RSA_PSK_WITH_NULL_SHA256";
|
||||
break;
|
||||
case TLS_RSA_PSK_WITH_NULL_SHA384:
|
||||
return "TLS_RSA_PSK_WITH_NULL_SHA384";
|
||||
break;
|
||||
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
|
||||
}
|
||||
return "TLS_NULL_WITH_NULL_NULL";
|
||||
}
|
||||
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_BUILD_MAC
|
||||
CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
|
||||
{
|
||||
int mib[2];
|
||||
@@ -658,7 +801,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
|
||||
*minor = atoi(os_version_minor);
|
||||
free(os_version);
|
||||
}
|
||||
#endif
|
||||
#endif /* CURL_BUILD_MAC */
|
||||
|
||||
/* Apple provides a myriad of ways of getting information about a certificate
|
||||
into a string. Some aren't available under iOS or newer cats. So here's
|
||||
@@ -668,29 +811,184 @@ CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
|
||||
{
|
||||
CFStringRef server_cert_summary = CFSTR("(null)");
|
||||
|
||||
#if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
|
||||
#if CURL_BUILD_IOS
|
||||
/* iOS: There's only one way to do this. */
|
||||
server_cert_summary = SecCertificateCopySubjectSummary(cert);
|
||||
#else
|
||||
#if defined(__MAC_10_7)
|
||||
#if CURL_BUILD_MAC_10_7
|
||||
/* Lion & later: Get the long description if we can. */
|
||||
if(SecCertificateCopyLongDescription != NULL)
|
||||
server_cert_summary =
|
||||
SecCertificateCopyLongDescription(NULL, cert, NULL);
|
||||
else
|
||||
#endif /* defined(__MAC_10_7) */
|
||||
#if defined(__MAC_10_6)
|
||||
#endif /* CURL_BUILD_MAC_10_7 */
|
||||
#if CURL_BUILD_MAC_10_6
|
||||
/* Snow Leopard: Get the certificate summary. */
|
||||
if(SecCertificateCopySubjectSummary != NULL)
|
||||
server_cert_summary = SecCertificateCopySubjectSummary(cert);
|
||||
else
|
||||
#endif /* defined(__MAC_10_6) */
|
||||
#endif /* CURL_BUILD_MAC_10_6 */
|
||||
/* Leopard is as far back as we go... */
|
||||
(void)SecCertificateCopyCommonName(cert, &server_cert_summary);
|
||||
#endif /* (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) */
|
||||
#endif /* CURL_BUILD_IOS */
|
||||
return server_cert_summary;
|
||||
}
|
||||
|
||||
#if CURL_SUPPORT_MAC_10_7
|
||||
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
|
||||
deprecation warnings, so let's not compile this unless it's necessary: */
|
||||
static OSStatus CopyIdentityWithLabelOldSchool(char *label,
|
||||
SecIdentityRef *out_c_a_k)
|
||||
{
|
||||
OSStatus status = errSecItemNotFound;
|
||||
SecKeychainAttributeList attr_list;
|
||||
SecKeychainAttribute attr;
|
||||
SecKeychainSearchRef search = NULL;
|
||||
SecCertificateRef cert = NULL;
|
||||
|
||||
/* Set up the attribute list: */
|
||||
attr_list.count = 1L;
|
||||
attr_list.attr = &attr;
|
||||
|
||||
/* Set up our lone search criterion: */
|
||||
attr.tag = kSecLabelItemAttr;
|
||||
attr.data = label;
|
||||
attr.length = (UInt32)strlen(label);
|
||||
|
||||
/* Start searching: */
|
||||
status = SecKeychainSearchCreateFromAttributes(NULL,
|
||||
kSecCertificateItemClass,
|
||||
&attr_list,
|
||||
&search);
|
||||
if(status == noErr) {
|
||||
status = SecKeychainSearchCopyNext(search,
|
||||
(SecKeychainItemRef *)&cert);
|
||||
if(status == noErr && cert) {
|
||||
/* If we found a certificate, does it have a private key? */
|
||||
status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
|
||||
CFRelease(cert);
|
||||
}
|
||||
}
|
||||
|
||||
if(search)
|
||||
CFRelease(search);
|
||||
return status;
|
||||
}
|
||||
#endif /* CURL_SUPPORT_MAC_10_7 */
|
||||
|
||||
static OSStatus CopyIdentityWithLabel(char *label,
|
||||
SecIdentityRef *out_cert_and_key)
|
||||
{
|
||||
OSStatus status = errSecItemNotFound;
|
||||
|
||||
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
|
||||
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
|
||||
kSecClassIdentity was introduced in Lion. If both exist, let's use them
|
||||
to find the certificate. */
|
||||
if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
|
||||
CFTypeRef keys[4];
|
||||
CFTypeRef values[4];
|
||||
CFDictionaryRef query_dict;
|
||||
CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
|
||||
kCFStringEncodingUTF8);
|
||||
|
||||
/* Set up our search criteria and expected results: */
|
||||
values[0] = kSecClassIdentity; /* we want a certificate and a key */
|
||||
keys[0] = kSecClass;
|
||||
values[1] = kCFBooleanTrue; /* we want a reference */
|
||||
keys[1] = kSecReturnRef;
|
||||
values[2] = kSecMatchLimitOne; /* one is enough, thanks */
|
||||
keys[2] = kSecMatchLimit;
|
||||
/* identity searches need a SecPolicyRef in order to work */
|
||||
values[3] = SecPolicyCreateSSL(false, label_cf);
|
||||
keys[3] = kSecMatchPolicy;
|
||||
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
|
||||
(const void **)values, 4L,
|
||||
&kCFCopyStringDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(values[3]);
|
||||
CFRelease(label_cf);
|
||||
|
||||
/* Do we have a match? */
|
||||
status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
|
||||
CFRelease(query_dict);
|
||||
}
|
||||
else {
|
||||
#if CURL_SUPPORT_MAC_10_7
|
||||
/* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */
|
||||
status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
|
||||
#endif /* CURL_SUPPORT_MAC_10_7 */
|
||||
}
|
||||
#elif CURL_SUPPORT_MAC_10_7
|
||||
/* For developers building on older cats, we have no choice but to fall back
|
||||
to SecKeychainSearch. */
|
||||
status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
|
||||
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
|
||||
return status;
|
||||
}
|
||||
|
||||
static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
|
||||
const char *cPassword,
|
||||
SecIdentityRef *out_cert_and_key)
|
||||
{
|
||||
OSStatus status = errSecItemNotFound;
|
||||
CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
|
||||
(const UInt8 *)cPath, strlen(cPath), false);
|
||||
CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
|
||||
cPassword, kCFStringEncodingUTF8) : NULL;
|
||||
CFDataRef pkcs_data = NULL;
|
||||
|
||||
/* We can import P12 files on iOS or OS X 10.6 or later: */
|
||||
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
|
||||
if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
|
||||
NULL, NULL, &status)) {
|
||||
const void *cKeys[] = {kSecImportExportPassphrase};
|
||||
const void *cValues[] = {password};
|
||||
CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
|
||||
password ? 1L : 0L, NULL, NULL);
|
||||
CFArrayRef items = NULL;
|
||||
|
||||
/* Here we go: */
|
||||
status = SecPKCS12Import(pkcs_data, options, &items);
|
||||
if(status == noErr) {
|
||||
CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L);
|
||||
const void *temp_identity = CFDictionaryGetValue(identity_and_trust,
|
||||
kSecImportItemIdentity);
|
||||
|
||||
/* Retain the identity; we don't care about any other data... */
|
||||
CFRetain(temp_identity);
|
||||
*out_cert_and_key = (SecIdentityRef)temp_identity;
|
||||
CFRelease(items);
|
||||
}
|
||||
CFRelease(options);
|
||||
CFRelease(pkcs_data);
|
||||
}
|
||||
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
|
||||
if(password)
|
||||
CFRelease(password);
|
||||
CFRelease(pkcs_url);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* This code was borrowed from nss.c, with some modifications:
|
||||
* Determine whether the nickname passed in is a filename that needs to
|
||||
* be loaded as a PEM or a regular NSS nickname.
|
||||
*
|
||||
* returns 1 for a file
|
||||
* returns 0 for not a file
|
||||
*/
|
||||
CF_INLINE bool is_file(const char *filename)
|
||||
{
|
||||
struct_stat st;
|
||||
|
||||
if(filename == NULL)
|
||||
return false;
|
||||
|
||||
if(stat(filename, &st) == 0)
|
||||
return S_ISREG(st.st_mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
@@ -701,17 +999,19 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
#endif /* ENABLE_IPV6 */
|
||||
size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
|
||||
SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
|
||||
char *ssl_sessionid;
|
||||
size_t ssl_sessionid_len;
|
||||
OSStatus err = noErr;
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_BUILD_MAC
|
||||
int darwinver_maj = 0, darwinver_min = 0;
|
||||
|
||||
GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
|
||||
#endif
|
||||
#endif /* CURL_BUILD_MAC */
|
||||
|
||||
#if defined(__MAC_10_8) || defined(__IPHONE_5_0)
|
||||
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
|
||||
if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
|
||||
if(connssl->ssl_ctx)
|
||||
CFRelease(connssl->ssl_ctx);
|
||||
@@ -723,7 +1023,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
}
|
||||
else {
|
||||
/* The old ST API does not exist under iOS, so don't compile it: */
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_SUPPORT_MAC_10_8
|
||||
if(connssl->ssl_ctx)
|
||||
(void)SSLDisposeContext(connssl->ssl_ctx);
|
||||
err = SSLNewContext(false, &(connssl->ssl_ctx));
|
||||
@@ -731,7 +1031,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
failf(data, "SSL: couldn't create a context: OSStatus %d", err);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
#endif /* CURL_SUPPORT_MAC_10_8 */
|
||||
}
|
||||
#else
|
||||
if(connssl->ssl_ctx)
|
||||
@@ -741,11 +1041,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
failf(data, "SSL: couldn't create a context: OSStatus %d", err);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */
|
||||
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
|
||||
connssl->ssl_write_buffered_length = 0UL; /* reset buffered write length */
|
||||
|
||||
/* check to see if we've been told to use an explicit SSL/TLS version */
|
||||
#if defined(__MAC_10_8) || defined(__IPHONE_5_0)
|
||||
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
|
||||
if(SSLSetProtocolVersionMax != NULL) {
|
||||
switch(data->set.ssl.version) {
|
||||
case CURL_SSLVERSION_DEFAULT: default:
|
||||
@@ -761,12 +1061,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
|
||||
break;
|
||||
case CURL_SSLVERSION_SSLv2:
|
||||
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
|
||||
err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
|
||||
if(err != noErr) {
|
||||
failf(data, "Your version of the OS does not support SSLv2");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_SUPPORT_MAC_10_8
|
||||
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
|
||||
kSSLProtocolAll,
|
||||
false);
|
||||
@@ -802,12 +1106,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
true);
|
||||
break;
|
||||
case CURL_SSLVERSION_SSLv2:
|
||||
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
|
||||
err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
|
||||
kSSLProtocol2,
|
||||
true);
|
||||
if(err != noErr) {
|
||||
failf(data, "Your version of the OS does not support SSLv2");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
#endif /* CURL_SUPPORT_MAC_10_8 */
|
||||
}
|
||||
#else
|
||||
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
|
||||
@@ -827,9 +1135,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
true);
|
||||
break;
|
||||
case CURL_SSLVERSION_SSLv2:
|
||||
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
|
||||
err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
|
||||
kSSLProtocol2,
|
||||
true);
|
||||
if(err != noErr) {
|
||||
failf(data, "Your version of the OS does not support SSLv2");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
break;
|
||||
case CURL_SSLVERSION_SSLv3:
|
||||
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
|
||||
@@ -837,16 +1149,104 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
true);
|
||||
break;
|
||||
}
|
||||
#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */
|
||||
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
|
||||
|
||||
/* No need to load certificates here. SecureTransport uses the Keychain
|
||||
* (which is also part of the Security framework) to evaluate trust. */
|
||||
if(data->set.str[STRING_KEY]) {
|
||||
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
|
||||
"Transport. The private key must be in the Keychain.\n");
|
||||
}
|
||||
|
||||
if(data->set.str[STRING_CERT]) {
|
||||
SecIdentityRef cert_and_key = NULL;
|
||||
bool is_cert_file = is_file(data->set.str[STRING_CERT]);
|
||||
|
||||
/* User wants to authenticate with a client cert. Look for it:
|
||||
If we detect that this is a file on disk, then let's load it.
|
||||
Otherwise, assume that the user wants to use an identity loaded
|
||||
from the Keychain. */
|
||||
if(is_cert_file) {
|
||||
if(!data->set.str[STRING_CERT_TYPE])
|
||||
infof(data, "WARNING: SSL: Certificate type not set, assuming "
|
||||
"PKCS#12 format.\n");
|
||||
else if(strncmp(data->set.str[STRING_CERT_TYPE], "P12",
|
||||
strlen(data->set.str[STRING_CERT_TYPE])) != 0)
|
||||
infof(data, "WARNING: SSL: The Security framework only supports "
|
||||
"loading identities that are in PKCS#12 format.\n");
|
||||
|
||||
err = CopyIdentityFromPKCS12File(data->set.str[STRING_CERT],
|
||||
data->set.str[STRING_KEY_PASSWD], &cert_and_key);
|
||||
}
|
||||
else
|
||||
err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key);
|
||||
|
||||
if(err == noErr) {
|
||||
SecCertificateRef cert = NULL;
|
||||
CFTypeRef certs_c[1];
|
||||
CFArrayRef certs;
|
||||
|
||||
/* If we found one, print it out: */
|
||||
err = SecIdentityCopyCertificate(cert_and_key, &cert);
|
||||
if(err == noErr) {
|
||||
CFStringRef cert_summary = CopyCertSubject(cert);
|
||||
char cert_summary_c[128];
|
||||
|
||||
if(cert_summary) {
|
||||
memset(cert_summary_c, 0, 128);
|
||||
if(CFStringGetCString(cert_summary,
|
||||
cert_summary_c,
|
||||
128,
|
||||
kCFStringEncodingUTF8)) {
|
||||
infof(data, "Client certificate: %s\n", cert_summary_c);
|
||||
}
|
||||
CFRelease(cert_summary);
|
||||
CFRelease(cert);
|
||||
}
|
||||
}
|
||||
certs_c[0] = cert_and_key;
|
||||
certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
|
||||
&kCFTypeArrayCallBacks);
|
||||
err = SSLSetCertificate(connssl->ssl_ctx, certs);
|
||||
if(certs)
|
||||
CFRelease(certs);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
CFRelease(cert_and_key);
|
||||
}
|
||||
else {
|
||||
switch(err) {
|
||||
case errSecPkcs12VerifyFailure: case errSecAuthFailed:
|
||||
failf(data, "SSL: Incorrect password for the certificate \"%s\" "
|
||||
"and its private key.", data->set.str[STRING_CERT]);
|
||||
break;
|
||||
case errSecDecode: case errSecUnknownFormat:
|
||||
failf(data, "SSL: Couldn't make sense of the data in the "
|
||||
"certificate \"%s\" and its private key.",
|
||||
data->set.str[STRING_CERT]);
|
||||
break;
|
||||
case errSecPassphraseRequired:
|
||||
failf(data, "SSL The certificate \"%s\" requires a password.",
|
||||
data->set.str[STRING_CERT]);
|
||||
break;
|
||||
case errSecItemNotFound:
|
||||
failf(data, "SSL: Can't find the certificate \"%s\" and its private "
|
||||
"key in the Keychain.", data->set.str[STRING_CERT]);
|
||||
break;
|
||||
default:
|
||||
failf(data, "SSL: Can't load the certificate \"%s\" and its private "
|
||||
"key: OSStatus %d", data->set.str[STRING_CERT], err);
|
||||
break;
|
||||
}
|
||||
return CURLE_SSL_CERTPROBLEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* SSL always tries to verify the peer, this only says whether it should
|
||||
* fail to connect if the verification fails, or if it should continue
|
||||
* anyway. In the latter case the result of the verification is checked with
|
||||
* SSL_get_verify_result() below. */
|
||||
#if defined(__MAC_10_6) || defined(__IPHONE_5_0)
|
||||
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
|
||||
/* Snow Leopard introduced the SSLSetSessionOption() function, but due to
|
||||
a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
|
||||
works, it doesn't work as expected under Snow Leopard or Lion.
|
||||
@@ -855,11 +1255,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
(SecureTransport will always validate the certificate chain by
|
||||
default.) */
|
||||
/* (Note: Darwin 12.x.x is Mountain Lion.) */
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_BUILD_MAC
|
||||
if(SSLSetSessionOption != NULL && darwinver_maj >= 12) {
|
||||
#else
|
||||
if(SSLSetSessionOption != NULL) {
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
#endif /* CURL_BUILD_MAC */
|
||||
err = SSLSetSessionOption(connssl->ssl_ctx,
|
||||
kSSLSessionOptionBreakOnServerAuth,
|
||||
data->set.ssl.verifypeer?false:true);
|
||||
@@ -869,14 +1269,14 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_SUPPORT_MAC_10_8
|
||||
err = SSLSetEnableCertVerify(connssl->ssl_ctx,
|
||||
data->set.ssl.verifypeer?true:false);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
#endif /* CURL_SUPPORT_MAC_10_8 */
|
||||
}
|
||||
#else
|
||||
err = SSLSetEnableCertVerify(connssl->ssl_ctx,
|
||||
@@ -885,7 +1285,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
#endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */
|
||||
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
|
||||
|
||||
/* If this is a domain name and not an IP address, then configure SNI.
|
||||
* Also: the verifyhost setting influences SNI usage */
|
||||
@@ -898,7 +1298,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name,
|
||||
strlen(conn->host.name));
|
||||
if(err != noErr) {
|
||||
infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d",
|
||||
infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
|
||||
err);
|
||||
}
|
||||
}
|
||||
@@ -915,7 +1315,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers,
|
||||
&all_ciphers_count) == noErr) {
|
||||
for(i = 0UL ; i < all_ciphers_count ; i++) {
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_BUILD_MAC
|
||||
/* There's a known bug in early versions of Mountain Lion where ST's ECC
|
||||
ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
|
||||
Work around the problem here by disabling those ciphers if we are
|
||||
@@ -924,17 +1324,27 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#endif /* CURL_BUILD_MAC */
|
||||
switch(all_ciphers[i]) {
|
||||
/* Disable NULL ciphersuites: */
|
||||
case SSL_NULL_WITH_NULL_NULL:
|
||||
case SSL_RSA_WITH_NULL_MD5:
|
||||
case SSL_RSA_WITH_NULL_SHA:
|
||||
case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */
|
||||
case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
|
||||
case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
|
||||
case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
|
||||
case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */
|
||||
case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */
|
||||
case 0x002C: /* TLS_PSK_WITH_NULL_SHA */
|
||||
case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */
|
||||
case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */
|
||||
case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */
|
||||
case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */
|
||||
case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */
|
||||
case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */
|
||||
case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */
|
||||
case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */
|
||||
/* Disable anonymous ciphersuites: */
|
||||
case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
|
||||
case SSL_DH_anon_WITH_RC4_128_MD5:
|
||||
@@ -990,6 +1400,45 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
Curl_safefree(all_ciphers);
|
||||
Curl_safefree(allowed_ciphers);
|
||||
|
||||
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
|
||||
/* We want to enable 1/n-1 when using a CBC cipher unless the user
|
||||
specifically doesn't want us doing that: */
|
||||
SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
|
||||
!data->set.ssl_enable_beast);
|
||||
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
|
||||
|
||||
/* Check if there's a cached ID we can/should use here! */
|
||||
if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
|
||||
&ssl_sessionid_len)) {
|
||||
/* we got a session id, use it! */
|
||||
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
/* Informational message */
|
||||
infof(data, "SSL re-using session ID\n");
|
||||
}
|
||||
/* If there isn't one, then let's make one up! This has to be done prior
|
||||
to starting the handshake. */
|
||||
else {
|
||||
CURLcode retcode;
|
||||
|
||||
ssl_sessionid = malloc(256*sizeof(char));
|
||||
ssl_sessionid_len = snprintf(ssl_sessionid, 256, "curl:%s:%hu",
|
||||
conn->host.name, conn->remote_port);
|
||||
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
retcode = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
|
||||
if(retcode!= CURLE_OK) {
|
||||
failf(data, "failed to store ssl session");
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
|
||||
err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite);
|
||||
if(err != noErr) {
|
||||
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
|
||||
@@ -1059,6 +1508,20 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
|
||||
"certificate format");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
/* These are all certificate problems with the client: */
|
||||
case errSecAuthFailed:
|
||||
failf(data, "SSL authentication failed");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
case errSSLPeerHandshakeFail:
|
||||
failf(data, "SSL peer handshake failed, the server most likely "
|
||||
"requires a client certificate to connect");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
case errSSLPeerUnknownCA:
|
||||
failf(data, "SSL server rejected the client certificate due to "
|
||||
"the certificate being signed by an unknown certificate "
|
||||
"authority");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
/* This error is raised if the server's cert didn't match the server's
|
||||
host name: */
|
||||
case errSSLHostNameMismatch:
|
||||
@@ -1111,7 +1574,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
|
||||
infof(data, "TLS 1.0 connection using %s\n",
|
||||
TLSCipherNameForNumber(cipher));
|
||||
break;
|
||||
#if defined(__MAC_10_8) || defined(__IPHONE_5_0)
|
||||
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
|
||||
case kTLSProtocol11:
|
||||
infof(data, "TLS 1.1 connection using %s\n",
|
||||
TLSCipherNameForNumber(cipher));
|
||||
@@ -1138,20 +1601,22 @@ darwinssl_connect_step3(struct connectdata *conn,
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
CFStringRef server_cert_summary;
|
||||
char server_cert_summary_c[128];
|
||||
CFArrayRef server_certs;
|
||||
CFArrayRef server_certs = NULL;
|
||||
SecCertificateRef server_cert;
|
||||
OSStatus err;
|
||||
CFIndex i, count;
|
||||
SecTrustRef trust;
|
||||
SecTrustRef trust = NULL;
|
||||
|
||||
/* There is no step 3!
|
||||
* Well, okay, if verbose mode is on, let's print the details of the
|
||||
* server certificates. */
|
||||
#if defined(__MAC_10_7) || defined(__IPHONE_5_0)
|
||||
#if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
|
||||
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
|
||||
#if CURL_BUILD_IOS
|
||||
#pragma unused(server_certs)
|
||||
err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
|
||||
if(err == noErr) {
|
||||
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
|
||||
a null trust, so be on guard for that: */
|
||||
if(err == noErr && trust) {
|
||||
count = SecTrustGetCertificateCount(trust);
|
||||
for(i = 0L ; i < count ; i++) {
|
||||
server_cert = SecTrustGetCertificateAtIndex(trust, i);
|
||||
@@ -1177,7 +1642,9 @@ darwinssl_connect_step3(struct connectdata *conn,
|
||||
if(SecTrustEvaluateAsync != NULL) {
|
||||
#pragma unused(server_certs)
|
||||
err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
|
||||
if(err == noErr) {
|
||||
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
|
||||
a null trust, so be on guard for that: */
|
||||
if(err == noErr && trust) {
|
||||
count = SecTrustGetCertificateCount(trust);
|
||||
for(i = 0L ; i < count ; i++) {
|
||||
server_cert = SecTrustGetCertificateAtIndex(trust, i);
|
||||
@@ -1195,8 +1662,10 @@ darwinssl_connect_step3(struct connectdata *conn,
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if CURL_SUPPORT_MAC_10_8
|
||||
err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
|
||||
if(err == noErr) {
|
||||
/* Just in case SSLCopyPeerCertificates() returns null too... */
|
||||
if(err == noErr && server_certs) {
|
||||
count = CFArrayGetCount(server_certs);
|
||||
for(i = 0L ; i < count ; i++) {
|
||||
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
|
||||
@@ -1214,8 +1683,9 @@ darwinssl_connect_step3(struct connectdata *conn,
|
||||
}
|
||||
CFRelease(server_certs);
|
||||
}
|
||||
#endif /* CURL_SUPPORT_MAC_10_8 */
|
||||
}
|
||||
#endif /* (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) */
|
||||
#endif /* CURL_BUILD_IOS */
|
||||
#else
|
||||
#pragma unused(trust)
|
||||
err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
|
||||
@@ -1235,7 +1705,7 @@ darwinssl_connect_step3(struct connectdata *conn,
|
||||
}
|
||||
CFRelease(server_certs);
|
||||
}
|
||||
#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */
|
||||
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
|
||||
|
||||
connssl->connecting_state = ssl_connect_done;
|
||||
return CURLE_OK;
|
||||
@@ -1387,16 +1857,16 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
|
||||
|
||||
if(connssl->ssl_ctx) {
|
||||
(void)SSLClose(connssl->ssl_ctx);
|
||||
#if defined(__MAC_10_8) || defined(__IPHONE_5_0)
|
||||
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
|
||||
if(SSLCreateContext != NULL)
|
||||
CFRelease(connssl->ssl_ctx);
|
||||
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
|
||||
#if CURL_SUPPORT_MAC_10_8
|
||||
else
|
||||
(void)SSLDisposeContext(connssl->ssl_ctx);
|
||||
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
|
||||
#endif /* CURL_SUPPORT_MAC_10_8 */
|
||||
#else
|
||||
(void)SSLDisposeContext(connssl->ssl_ctx);
|
||||
#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */
|
||||
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
|
||||
connssl->ssl_ctx = NULL;
|
||||
}
|
||||
connssl->ssl_sockfd = 0;
|
||||
@@ -1462,6 +1932,17 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Curl_darwinssl_session_free(void *ptr)
|
||||
{
|
||||
/* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
|
||||
cached session ID inside the Security framework. There is a private
|
||||
function that does this, but I don't want to have to explain to you why I
|
||||
got your application rejected from the App Store due to the use of a
|
||||
private API, so the best we can do is free up our own char array that we
|
||||
created way back in darwinssl_connect_step1... */
|
||||
Curl_safefree(ptr);
|
||||
}
|
||||
|
||||
size_t Curl_darwinssl_version(char *buffer, size_t size)
|
||||
{
|
||||
return snprintf(buffer, size, "SecureTransport");
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2012, Nick Zitzmann, <nickzman@gmail.com>.
|
||||
* Copyright (C) 2012 - 2013, Nick Zitzmann, <nickzman@gmail.com>.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -37,6 +37,7 @@ void Curl_darwinssl_close_all(struct SessionHandle *data);
|
||||
/* close a SSL connection */
|
||||
void Curl_darwinssl_close(struct connectdata *conn, int sockindex);
|
||||
|
||||
void Curl_darwinssl_session_free(void *ptr);
|
||||
size_t Curl_darwinssl_version(char *buffer, size_t size);
|
||||
int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex);
|
||||
int Curl_darwinssl_check_cxn(struct connectdata *conn);
|
||||
@@ -51,12 +52,16 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
|
||||
unsigned char *md5sum, /* output */
|
||||
size_t md5len);
|
||||
|
||||
/* this backend provides these functions: */
|
||||
#define have_curlssl_random 1
|
||||
#define have_curlssl_md5sum 1
|
||||
|
||||
/* API setup for SecureTransport */
|
||||
#define curlssl_init() (1)
|
||||
#define curlssl_cleanup() Curl_nop_stmt
|
||||
#define curlssl_connect Curl_darwinssl_connect
|
||||
#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking
|
||||
#define curlssl_session_free(x) Curl_nop_stmt
|
||||
#define curlssl_session_free(x) Curl_darwinssl_session_free(x)
|
||||
#define curlssl_close_all Curl_darwinssl_close_all
|
||||
#define curlssl_close Curl_darwinssl_close
|
||||
#define curlssl_shutdown(x,y) 0
|
||||
|
||||
@@ -87,7 +87,7 @@ extern curl_free_callback Curl_cfree;
|
||||
extern curl_realloc_callback Curl_crealloc;
|
||||
extern curl_strdup_callback Curl_cstrdup;
|
||||
extern curl_calloc_callback Curl_ccalloc;
|
||||
#ifdef WIN32
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
extern curl_wcsdup_callback Curl_cwcsdup;
|
||||
#endif
|
||||
|
||||
@@ -114,14 +114,15 @@ extern curl_wcsdup_callback Curl_cwcsdup;
|
||||
#define free(ptr) Curl_cfree(ptr)
|
||||
|
||||
#ifdef WIN32
|
||||
# ifdef UNICODE
|
||||
# undef wcsdup
|
||||
# define wcsdup(ptr) Curl_cwcsdup(ptr)
|
||||
# undef _wcsdup
|
||||
# define _wcsdup(ptr) Curl_cwcsdup(ptr)
|
||||
# undef _tcsdup
|
||||
# ifdef UNICODE
|
||||
# define _tcsdup(ptr) Curl_cwcsdup(ptr)
|
||||
# else
|
||||
# undef _tcsdup
|
||||
# define _tcsdup(ptr) Curl_cstrdup(ptr)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* RFC2831 DIGEST-MD5 authentication
|
||||
* RFC4422 Simple Authentication and Security Layer (SASL)
|
||||
* RFC4616 PLAIN authentication
|
||||
* RFC6749 OAuth 2.0 Authorization Framework
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
@@ -32,7 +33,7 @@
|
||||
|
||||
#include "curl_base64.h"
|
||||
#include "curl_md5.h"
|
||||
#include "curl_rand.h"
|
||||
#include "sslgen.h"
|
||||
#include "curl_hmac.h"
|
||||
#include "curl_ntlm_msgs.h"
|
||||
#include "curl_sasl.h"
|
||||
@@ -94,18 +95,18 @@ CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data,
|
||||
const char *passwdp,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH];
|
||||
CURLcode result;
|
||||
char *plainauth;
|
||||
size_t ulen;
|
||||
size_t plen;
|
||||
|
||||
ulen = strlen(userp);
|
||||
plen = strlen(passwdp);
|
||||
|
||||
if(2 * ulen + plen + 2 > sizeof(plainauth)) {
|
||||
plainauth = malloc(2 * ulen + plen + 2);
|
||||
if(!plainauth) {
|
||||
*outlen = 0;
|
||||
*outptr = NULL;
|
||||
|
||||
/* Plainauth too small */
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@@ -117,8 +118,10 @@ CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data,
|
||||
memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
|
||||
|
||||
/* Base64 encode the reply */
|
||||
return Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
|
||||
result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
|
||||
outlen);
|
||||
Curl_safefree(plainauth);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -190,7 +193,7 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
|
||||
size_t chlglen = 0;
|
||||
HMAC_context *ctxt;
|
||||
unsigned char digest[MD5_DIGEST_LEN];
|
||||
char response[MAX_CURL_USER_LENGTH + 2 * MD5_DIGEST_LEN + 1];
|
||||
char *response;
|
||||
|
||||
/* Decode the challenge if necessary */
|
||||
if(chlg64len && *chlg64 != '=') {
|
||||
@@ -220,14 +223,19 @@ CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
|
||||
Curl_HMAC_final(ctxt, digest);
|
||||
|
||||
/* Prepare the response */
|
||||
snprintf(response, sizeof(response),
|
||||
response = aprintf(
|
||||
"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
userp, digest[0], digest[1], digest[2], digest[3], digest[4],
|
||||
digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
|
||||
digest[11], digest[12], digest[13], digest[14], digest[15]);
|
||||
if(!response)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Base64 encode the reply */
|
||||
return Curl_base64_encode(data, response, 0, outptr, outlen);
|
||||
result = Curl_base64_encode(data, response, 0, outptr, outlen);
|
||||
|
||||
Curl_safefree(response);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -314,7 +322,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
|
||||
|
||||
/* Generate 64 bits of random data */
|
||||
for(i = 0; i < 8; i++)
|
||||
cnonce[i] = table16[Curl_rand()%16];
|
||||
cnonce[i] = table16[Curl_rand(data)%16];
|
||||
|
||||
/* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
|
||||
ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
|
||||
@@ -470,6 +478,40 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
|
||||
}
|
||||
#endif /* USE_NTLM */
|
||||
|
||||
/*
|
||||
* Curl_sasl_create_xoauth2_message()
|
||||
*
|
||||
* This is used to generate an already encoded XOAUTH2 message ready
|
||||
* for sending to the recipient.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* data [in] - The session handle.
|
||||
* user [in] - The user name.
|
||||
* bearer [in] - The XOAUTH Bearer token.
|
||||
* outptr [in/out] - The address where a pointer to newly allocated memory
|
||||
* holding the result will be stored upon completion.
|
||||
* outlen [out] - The length of the output message.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*/
|
||||
CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
|
||||
const char *user,
|
||||
const char *bearer,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
char *xoauth;
|
||||
|
||||
xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
|
||||
|
||||
if(!xoauth)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Base64 encode the reply */
|
||||
return Curl_base64_encode(data, xoauth, strlen(xoauth), outptr,
|
||||
outlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_sasl_cleanup()
|
||||
*
|
||||
|
||||
@@ -24,14 +24,34 @@
|
||||
|
||||
#include "pingpong.h"
|
||||
|
||||
/* Authentication mechanism values */
|
||||
#define SASL_AUTH_NONE 0
|
||||
#define SASL_AUTH_ANY ~0U
|
||||
|
||||
/* Authentication mechanism flags */
|
||||
#define SASL_MECH_LOGIN 0x0001
|
||||
#define SASL_MECH_PLAIN 0x0002
|
||||
#define SASL_MECH_CRAM_MD5 0x0004
|
||||
#define SASL_MECH_DIGEST_MD5 0x0008
|
||||
#define SASL_MECH_GSSAPI 0x0010
|
||||
#define SASL_MECH_EXTERNAL 0x0020
|
||||
#define SASL_MECH_NTLM 0x0040
|
||||
#define SASL_MECH_LOGIN (1 << 0)
|
||||
#define SASL_MECH_PLAIN (1 << 1)
|
||||
#define SASL_MECH_CRAM_MD5 (1 << 2)
|
||||
#define SASL_MECH_DIGEST_MD5 (1 << 3)
|
||||
#define SASL_MECH_GSSAPI (1 << 4)
|
||||
#define SASL_MECH_EXTERNAL (1 << 5)
|
||||
#define SASL_MECH_NTLM (1 << 6)
|
||||
#define SASL_MECH_XOAUTH2 (1 << 7)
|
||||
|
||||
/* Authentication mechanism strings */
|
||||
#define SASL_MECH_STRING_LOGIN "LOGIN"
|
||||
#define SASL_MECH_STRING_PLAIN "PLAIN"
|
||||
#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
|
||||
#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
|
||||
#define SASL_MECH_STRING_GSSAPI "GSSAPI"
|
||||
#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
|
||||
#define SASL_MECH_STRING_NTLM "NTLM"
|
||||
#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
|
||||
|
||||
/* This is used to test whether the line starts with the given mechanism */
|
||||
#define sasl_mech_equal(line, wordlen, mech) \
|
||||
(wordlen == (sizeof(mech) - 1) / sizeof(char) && \
|
||||
!memcmp(line, mech, wordlen))
|
||||
|
||||
/* This is used to generate a base64 encoded PLAIN authentication message */
|
||||
CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data,
|
||||
@@ -81,6 +101,13 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
|
||||
|
||||
#endif /* USE_NTLM */
|
||||
|
||||
/* This is used to generate a base64 encoded XOAUTH2 authentication message
|
||||
containing the user name and bearer token */
|
||||
CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
|
||||
const char *user,
|
||||
const char *bearer,
|
||||
char **outptr, size_t *outlen);
|
||||
|
||||
/* This is used to cleanup any libraries or curl modules used by the sasl
|
||||
functions */
|
||||
void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
|
||||
|
||||
@@ -534,6 +534,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
|
||||
return retcode;
|
||||
}
|
||||
else {
|
||||
connssl->cred->cached = TRUE;
|
||||
infof(data, "schannel: stored credential handle in session cache\n");
|
||||
}
|
||||
}
|
||||
@@ -1063,7 +1064,6 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
|
||||
*/
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
struct curl_schannel_cred *cached_cred = NULL;
|
||||
|
||||
infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
|
||||
conn->host.name, conn->remote_port);
|
||||
@@ -1141,20 +1141,14 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
|
||||
connssl->cred->refcount);
|
||||
}
|
||||
|
||||
/* if the handle refcount is zero, check if we have not cached it */
|
||||
if(connssl->cred->refcount == 0) {
|
||||
if(Curl_ssl_getsessionid(conn, (void**)&cached_cred, NULL)) {
|
||||
cached_cred = NULL;
|
||||
}
|
||||
/* if the handle was not cached, it is stale to be freed */
|
||||
if(connssl->cred != cached_cred) {
|
||||
/* if the handle was not cached and the refcount is zero */
|
||||
if(!connssl->cred->cached && connssl->cred->refcount == 0) {
|
||||
infof(data, "schannel: clear credential handle\n");
|
||||
s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle);
|
||||
Curl_safefree(connssl->cred);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free internal buffer for received encrypted data */
|
||||
if(connssl->encdata_buffer != NULL) {
|
||||
@@ -1177,7 +1171,7 @@ void Curl_schannel_session_free(void *ptr)
|
||||
{
|
||||
struct curl_schannel_cred *cred = ptr;
|
||||
|
||||
if(cred && cred->refcount == 0) {
|
||||
if(cred && cred->cached && cred->refcount == 0) {
|
||||
s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
|
||||
Curl_safefree(cred);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef HEADER_CURL_KRB4_H
|
||||
#define HEADER_CURL_KRB4_H
|
||||
#ifndef HEADER_CURL_SECURITY_H
|
||||
#define HEADER_CURL_SECURITY_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -34,24 +34,18 @@ struct Curl_sec_client_mech {
|
||||
int (*decode)(void *, void*, int, int, struct connectdata *);
|
||||
};
|
||||
|
||||
|
||||
#define AUTH_OK 0
|
||||
#define AUTH_CONTINUE 1
|
||||
#define AUTH_ERROR 2
|
||||
|
||||
#ifdef HAVE_KRB4
|
||||
extern struct Curl_sec_client_mech Curl_krb4_client_mech;
|
||||
#endif
|
||||
#ifdef HAVE_GSSAPI
|
||||
extern struct Curl_sec_client_mech Curl_krb5_client_mech;
|
||||
#endif
|
||||
|
||||
CURLcode Curl_krb_kauth(struct connectdata *conn);
|
||||
int Curl_sec_read_msg (struct connectdata *conn, char *,
|
||||
enum protection_level);
|
||||
void Curl_sec_end (struct connectdata *);
|
||||
CURLcode Curl_sec_login (struct connectdata *);
|
||||
int Curl_sec_request_prot (struct connectdata *conn, const char *level);
|
||||
|
||||
#endif /* HEADER_CURL_KRB4_H */
|
||||
extern struct Curl_sec_client_mech Curl_krb5_client_mech;
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_SECURITY_H */
|
||||
@@ -270,8 +270,10 @@
|
||||
# endif
|
||||
# endif
|
||||
# include <tchar.h>
|
||||
# ifdef UNICODE
|
||||
typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
|
||||
@@ -369,7 +371,9 @@
|
||||
# include <sys/stat.h>
|
||||
# undef lseek
|
||||
# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
|
||||
# undef fstat
|
||||
# define fstat(fdes,stp) _fstati64(fdes, stp)
|
||||
# undef stat
|
||||
# define stat(fname,stp) _stati64(fname, stp)
|
||||
# define struct_stat struct _stati64
|
||||
# define LSEEK_ERROR (__int64)-1
|
||||
@@ -616,7 +620,7 @@ int netware_init(void);
|
||||
#if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \
|
||||
defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \
|
||||
defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
|
||||
defined(USE_DARWINSSL)
|
||||
defined(USE_DARWINSSL) || defined(USE_GSKIT)
|
||||
#define USE_SSL /* SSL support has been enabled */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -440,7 +440,7 @@ typedef int sig_atomic_t;
|
||||
* (or equivalent) on this platform to hide platform details to code using it.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#if defined(WIN32) && !defined(USE_LWIPSOCK)
|
||||
#define ERRNO ((int)GetLastError())
|
||||
#define SET_ERRNO(x) (SetLastError((DWORD)(x)))
|
||||
#else
|
||||
|
||||
170
lib/dotdot.c
Normal file
170
lib/dotdot.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#include "dotdot.h"
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
* "Remove Dot Segments"
|
||||
* http://tools.ietf.org/html/rfc3986#section-5.2.4
|
||||
*/
|
||||
|
||||
/*
|
||||
* Curl_dedotdotify()
|
||||
*
|
||||
* This function gets a zero-terminated path with dot and dotdot sequences
|
||||
* passed in and strips them off according to the rules in RFC 3986 section
|
||||
* 5.2.4.
|
||||
*
|
||||
* The function handles a query part ('?' + stuff) appended but it expects
|
||||
* that fragments ('#' + stuff) have already been cut off.
|
||||
*
|
||||
* RETURNS
|
||||
*
|
||||
* an allocated dedotdotified output string
|
||||
*/
|
||||
char *Curl_dedotdotify(char *input)
|
||||
{
|
||||
size_t inlen = strlen(input);
|
||||
char *clone;
|
||||
size_t clen = inlen; /* the length of the cloned input */
|
||||
char *out = malloc(inlen+1);
|
||||
char *outptr;
|
||||
char *orgclone;
|
||||
char *queryp;
|
||||
if(!out)
|
||||
return NULL; /* out of memory */
|
||||
|
||||
/* get a cloned copy of the input */
|
||||
clone = strdup(input);
|
||||
if(!clone) {
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
orgclone = clone;
|
||||
outptr = out;
|
||||
|
||||
/*
|
||||
* To handle query-parts properly, we must find it and remove it during the
|
||||
* dotdot-operation and then append it again at the end to the output
|
||||
* string.
|
||||
*/
|
||||
queryp = strchr(clone, '?');
|
||||
if(queryp)
|
||||
*queryp = 0;
|
||||
|
||||
do {
|
||||
|
||||
/* A. If the input buffer begins with a prefix of "../" or "./", then
|
||||
remove that prefix from the input buffer; otherwise, */
|
||||
|
||||
if(!strncmp("./", clone, 2)) {
|
||||
clone+=2;
|
||||
clen-=2;
|
||||
}
|
||||
else if(!strncmp("../", clone, 3)) {
|
||||
clone+=3;
|
||||
clen-=3;
|
||||
}
|
||||
|
||||
/* B. if the input buffer begins with a prefix of "/./" or "/.", where
|
||||
"." is a complete path segment, then replace that prefix with "/" in
|
||||
the input buffer; otherwise, */
|
||||
else if(!strncmp("/./", clone, 3)) {
|
||||
clone+=2;
|
||||
clen-=2;
|
||||
}
|
||||
else if(!strcmp("/.", clone)) {
|
||||
clone[1]='/';
|
||||
clone++;
|
||||
clen-=1;
|
||||
}
|
||||
|
||||
/* C. if the input buffer begins with a prefix of "/../" or "/..", where
|
||||
".." is a complete path segment, then replace that prefix with "/" in
|
||||
the input buffer and remove the last segment and its preceding "/" (if
|
||||
any) from the output buffer; otherwise, */
|
||||
|
||||
else if(!strncmp("/../", clone, 4)) {
|
||||
clone+=3;
|
||||
clen-=3;
|
||||
/* remove the last segment from the output buffer */
|
||||
while(outptr > out) {
|
||||
outptr--;
|
||||
if(*outptr == '/')
|
||||
break;
|
||||
}
|
||||
*outptr = 0; /* zero-terminate where it stops */
|
||||
}
|
||||
else if(!strcmp("/..", clone)) {
|
||||
clone[2]='/';
|
||||
clone+=2;
|
||||
clen-=2;
|
||||
/* remove the last segment from the output buffer */
|
||||
while(outptr > out) {
|
||||
outptr--;
|
||||
if(*outptr == '/')
|
||||
break;
|
||||
}
|
||||
*outptr = 0; /* zero-terminate where it stops */
|
||||
}
|
||||
|
||||
/* D. if the input buffer consists only of "." or "..", then remove
|
||||
that from the input buffer; otherwise, */
|
||||
|
||||
else if(!strcmp(".", clone) || !strcmp("..", clone)) {
|
||||
*clone=0;
|
||||
}
|
||||
|
||||
else {
|
||||
/* E. move the first path segment in the input buffer to the end of
|
||||
the output buffer, including the initial "/" character (if any) and
|
||||
any subsequent characters up to, but not including, the next "/"
|
||||
character or the end of the input buffer. */
|
||||
|
||||
do {
|
||||
*outptr++ = *clone++;
|
||||
clen--;
|
||||
} while(*clone && (*clone != '/'));
|
||||
*outptr = 0;
|
||||
}
|
||||
|
||||
} while(*clone);
|
||||
|
||||
if(queryp) {
|
||||
size_t qlen;
|
||||
/* There was a query part, append that to the output. The 'clone' string
|
||||
may now have been altered so we copy from the original input string
|
||||
from the correct index. */
|
||||
size_t oindex = queryp - orgclone;
|
||||
qlen = strlen(&input[oindex]);
|
||||
memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */
|
||||
}
|
||||
|
||||
free(orgclone);
|
||||
return out;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef HEADER_CURL_RAND_H
|
||||
#define HEADER_CURL_RAND_H
|
||||
#ifndef HEADER_CURL_DOTDOT_H
|
||||
#define HEADER_CURL_DOTDOT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -21,9 +21,5 @@
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
void Curl_srand(void);
|
||||
|
||||
unsigned int Curl_rand(void);
|
||||
|
||||
#endif /* HEADER_CURL_RAND_H */
|
||||
char *Curl_dedotdotify(char *input);
|
||||
#endif
|
||||
505
lib/easy.c
505
lib/easy.c
@@ -50,6 +50,11 @@
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL)
|
||||
#define SIGPIPE_IGNORE 1
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "strequal.h"
|
||||
#include "urldata.h"
|
||||
#include <curl/curl.h>
|
||||
@@ -69,10 +74,10 @@
|
||||
#include "connect.h" /* for Curl_getconnectinfo */
|
||||
#include "slist.h"
|
||||
#include "amigaos.h"
|
||||
#include "curl_rand.h"
|
||||
#include "non-ascii.h"
|
||||
#include "warnless.h"
|
||||
#include "conncache.h"
|
||||
#include "multiif.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
@@ -80,6 +85,56 @@
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef SIGPIPE_IGNORE
|
||||
struct sigpipe_ignore {
|
||||
struct sigaction old_pipe_act;
|
||||
bool no_signal;
|
||||
};
|
||||
|
||||
#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x
|
||||
|
||||
/*
|
||||
* sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl
|
||||
* internals, and then sigpipe_restore() will restore the situation when we
|
||||
* return from libcurl again.
|
||||
*/
|
||||
static void sigpipe_ignore(struct SessionHandle *data,
|
||||
struct sigpipe_ignore *ig)
|
||||
{
|
||||
/* get a local copy of no_signal because the SessionHandle might not be
|
||||
around when we restore */
|
||||
ig->no_signal = data->set.no_signal;
|
||||
if(!data->set.no_signal) {
|
||||
struct sigaction action;
|
||||
/* first, extract the existing situation */
|
||||
memset(&ig->old_pipe_act, 0, sizeof(struct sigaction));
|
||||
sigaction(SIGPIPE, NULL, &ig->old_pipe_act);
|
||||
action = ig->old_pipe_act;
|
||||
/* ignore this signal */
|
||||
action.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &action, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* sigpipe_restore() puts back the outside world's opinion of signal handler
|
||||
* and SIGPIPE handling. It MUST only be called after a corresponding
|
||||
* sigpipe_ignore() was used.
|
||||
*/
|
||||
static void sigpipe_restore(struct sigpipe_ignore *ig)
|
||||
{
|
||||
if(!ig->no_signal)
|
||||
/* restore the outside state */
|
||||
sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
/* for systems without sigaction */
|
||||
#define sigpipe_ignore(x,y) Curl_nop_stmt
|
||||
#define sigpipe_restore(x) Curl_nop_stmt
|
||||
#define SIGPIPE_VARIABLE(x)
|
||||
#endif
|
||||
|
||||
/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
|
||||
of win32_init() */
|
||||
static void win32_cleanup(void)
|
||||
@@ -197,8 +252,8 @@ curl_free_callback Curl_cfree = (curl_free_callback)free;
|
||||
curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
|
||||
curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
|
||||
curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
|
||||
#ifdef WIN32
|
||||
curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)wcsdup;
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
|
||||
#endif
|
||||
#else
|
||||
/*
|
||||
@@ -231,8 +286,8 @@ CURLcode curl_global_init(long flags)
|
||||
Curl_crealloc = (curl_realloc_callback)realloc;
|
||||
Curl_cstrdup = (curl_strdup_callback)system_strdup;
|
||||
Curl_ccalloc = (curl_calloc_callback)calloc;
|
||||
#ifdef WIN32
|
||||
Curl_cwcsdup = (curl_wcsdup_callback)wcsdup;
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
|
||||
#endif
|
||||
|
||||
if(flags & CURL_GLOBAL_SSL)
|
||||
@@ -281,10 +336,6 @@ CURLcode curl_global_init(long flags)
|
||||
|
||||
init_flags = flags;
|
||||
|
||||
/* Preset pseudo-random number sequence. */
|
||||
|
||||
Curl_srand();
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -402,8 +453,328 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CURLDEBUG
|
||||
|
||||
struct socketmonitor {
|
||||
struct socketmonitor *next; /* the next node in the list or NULL */
|
||||
struct pollfd socket; /* socket info of what to monitor */
|
||||
};
|
||||
|
||||
struct events {
|
||||
long ms; /* timeout, run the timeout function when reached */
|
||||
bool msbump; /* set TRUE when timeout is set by callback */
|
||||
int num_sockets; /* number of nodes in the monitor list */
|
||||
struct socketmonitor *list; /* list of sockets to monitor */
|
||||
int running_handles; /* store the returned number */
|
||||
};
|
||||
|
||||
/* events_timer
|
||||
*
|
||||
* Callback that gets called with a new value when the timeout should be
|
||||
* updated.
|
||||
*/
|
||||
|
||||
static int events_timer(CURLM *multi, /* multi handle */
|
||||
long timeout_ms, /* see above */
|
||||
void *userp) /* private callback pointer */
|
||||
{
|
||||
struct events *ev = userp;
|
||||
(void)multi;
|
||||
if(timeout_ms == -1)
|
||||
/* timeout removed */
|
||||
timeout_ms = 0;
|
||||
else if(timeout_ms == 0)
|
||||
/* timeout is already reached! */
|
||||
timeout_ms = 1; /* trigger asap */
|
||||
|
||||
ev->ms = timeout_ms;
|
||||
ev->msbump = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* poll2cselect
|
||||
*
|
||||
* convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
|
||||
*/
|
||||
static int poll2cselect(int pollmask)
|
||||
{
|
||||
int omask=0;
|
||||
if(pollmask & POLLIN)
|
||||
omask |= CURL_CSELECT_IN;
|
||||
if(pollmask & POLLOUT)
|
||||
omask |= CURL_CSELECT_OUT;
|
||||
if(pollmask & POLLERR)
|
||||
omask |= CURL_CSELECT_ERR;
|
||||
return omask;
|
||||
}
|
||||
|
||||
|
||||
/* socketcb2poll
|
||||
*
|
||||
* convert from libcurl' CURL_POLL_* bit definitions to poll()'s
|
||||
*/
|
||||
static short socketcb2poll(int pollmask)
|
||||
{
|
||||
short omask=0;
|
||||
if(pollmask & CURL_POLL_IN)
|
||||
omask |= POLLIN;
|
||||
if(pollmask & CURL_POLL_OUT)
|
||||
omask |= POLLOUT;
|
||||
return omask;
|
||||
}
|
||||
|
||||
/* events_socket
|
||||
*
|
||||
* Callback that gets called with information about socket activity to
|
||||
* monitor.
|
||||
*/
|
||||
static int events_socket(CURL *easy, /* easy handle */
|
||||
curl_socket_t s, /* socket */
|
||||
int what, /* see above */
|
||||
void *userp, /* private callback
|
||||
pointer */
|
||||
void *socketp) /* private socket
|
||||
pointer */
|
||||
{
|
||||
struct events *ev = userp;
|
||||
struct socketmonitor *m;
|
||||
struct socketmonitor *prev=NULL;
|
||||
(void)socketp;
|
||||
|
||||
m = ev->list;
|
||||
while(m) {
|
||||
if(m->socket.fd == s) {
|
||||
|
||||
if(what == CURL_POLL_REMOVE) {
|
||||
struct socketmonitor *nxt = m->next;
|
||||
/* remove this node from the list of monitored sockets */
|
||||
if(prev)
|
||||
prev->next = nxt;
|
||||
else
|
||||
ev->list = nxt;
|
||||
free(m);
|
||||
m = nxt;
|
||||
infof(easy, "socket cb: socket %d REMOVED\n", s);
|
||||
}
|
||||
else {
|
||||
/* The socket 's' is already being monitored, update the activity
|
||||
mask. Convert from libcurl bitmask to the poll one. */
|
||||
m->socket.events = socketcb2poll(what);
|
||||
infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
|
||||
what&CURL_POLL_IN?"IN":"",
|
||||
what&CURL_POLL_OUT?"OUT":"");
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = m;
|
||||
m = m->next; /* move to next node */
|
||||
}
|
||||
if(!m) {
|
||||
if(what == CURL_POLL_REMOVE) {
|
||||
/* this happens a bit too often, libcurl fix perhaps? */
|
||||
/* fprintf(stderr,
|
||||
"%s: socket %d asked to be REMOVED but not present!\n",
|
||||
__func__, s); */
|
||||
}
|
||||
else {
|
||||
m = malloc(sizeof(struct socketmonitor));
|
||||
m->next = ev->list;
|
||||
m->socket.fd = s;
|
||||
m->socket.events = socketcb2poll(what);
|
||||
m->socket.revents = 0;
|
||||
ev->list = m;
|
||||
infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
|
||||
what&CURL_POLL_IN?"IN":"",
|
||||
what&CURL_POLL_OUT?"OUT":"");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* curl_easy_perform() is the external interface that performs a blocking
|
||||
* events_setup()
|
||||
*
|
||||
* Do the multi handle setups that only event-based transfers need.
|
||||
*/
|
||||
static void events_setup(CURLM *multi, struct events *ev)
|
||||
{
|
||||
/* timer callback */
|
||||
curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
|
||||
curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
|
||||
|
||||
/* socket callback */
|
||||
curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
|
||||
curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
|
||||
}
|
||||
|
||||
|
||||
/* wait_or_timeout()
|
||||
*
|
||||
* waits for activity on any of the given sockets, or the timeout to trigger.
|
||||
*/
|
||||
|
||||
static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
|
||||
{
|
||||
bool done = FALSE;
|
||||
CURLMcode mcode;
|
||||
CURLcode rc = CURLE_OK;
|
||||
|
||||
while(!done) {
|
||||
CURLMsg *msg;
|
||||
struct socketmonitor *m;
|
||||
struct pollfd *f;
|
||||
struct pollfd fds[4];
|
||||
int numfds=0;
|
||||
int pollrc;
|
||||
int i;
|
||||
struct timeval before;
|
||||
struct timeval after;
|
||||
|
||||
/* populate the fds[] array */
|
||||
for(m = ev->list, f=&fds[0]; m; m = m->next) {
|
||||
f->fd = m->socket.fd;
|
||||
f->events = m->socket.events;
|
||||
f->revents = 0;
|
||||
/* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
|
||||
f++;
|
||||
numfds++;
|
||||
}
|
||||
|
||||
/* get the time stamp to use to figure out how long poll takes */
|
||||
before = curlx_tvnow();
|
||||
|
||||
/* wait for activity or timeout */
|
||||
pollrc = Curl_poll(fds, numfds, (int)ev->ms);
|
||||
|
||||
after = curlx_tvnow();
|
||||
|
||||
ev->msbump = FALSE; /* reset here */
|
||||
|
||||
if(0 == pollrc) {
|
||||
/* timeout! */
|
||||
ev->ms = 0;
|
||||
/* fprintf(stderr, "call curl_multi_socket_action( TIMEOUT )\n"); */
|
||||
mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
|
||||
&ev->running_handles);
|
||||
}
|
||||
else if(pollrc > 0) {
|
||||
/* loop over the monitored sockets to see which ones had activity */
|
||||
for(i = 0; i< numfds; i++) {
|
||||
if(fds[i].revents) {
|
||||
/* socket activity, tell libcurl */
|
||||
int act = poll2cselect(fds[i].revents); /* convert */
|
||||
infof(multi->easyp, "call curl_multi_socket_action( socket %d )\n",
|
||||
fds[i].fd);
|
||||
mcode = curl_multi_socket_action(multi, fds[i].fd, act,
|
||||
&ev->running_handles);
|
||||
}
|
||||
}
|
||||
|
||||
if(!ev->msbump)
|
||||
/* If nothing updated the timeout, we decrease it by the spent time.
|
||||
* If it was updated, it has the new timeout time stored already.
|
||||
*/
|
||||
ev->ms += curlx_tvdiff(after, before);
|
||||
|
||||
}
|
||||
if(mcode)
|
||||
return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */
|
||||
|
||||
/* we don't really care about the "msgs_in_queue" value returned in the
|
||||
second argument */
|
||||
msg = curl_multi_info_read(multi, &pollrc);
|
||||
if(msg) {
|
||||
rc = msg->data.result;
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* easy_events()
|
||||
*
|
||||
* Runs a transfer in a blocking manner using the events-based API
|
||||
*/
|
||||
static CURLcode easy_events(CURLM *multi)
|
||||
{
|
||||
struct events evs= {2, FALSE, 0, NULL, 0};
|
||||
|
||||
/* if running event-based, do some further multi inits */
|
||||
events_setup(multi, &evs);
|
||||
|
||||
return wait_or_timeout(multi, &evs);
|
||||
}
|
||||
#else /* CURLDEBUG */
|
||||
/* when not built with debug, this function doesn't exist */
|
||||
#define easy_events(x) CURLE_NOT_BUILT_IN
|
||||
#endif
|
||||
|
||||
static CURLcode easy_transfer(CURLM *multi)
|
||||
{
|
||||
bool done = FALSE;
|
||||
CURLMcode mcode = CURLM_OK;
|
||||
CURLcode code = CURLE_OK;
|
||||
struct timeval before;
|
||||
int without_fds = 0; /* count number of consecutive returns from
|
||||
curl_multi_wait() without any filedescriptors */
|
||||
|
||||
while(!done && !mcode) {
|
||||
int still_running;
|
||||
int ret;
|
||||
|
||||
before = curlx_tvnow();
|
||||
mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret);
|
||||
|
||||
if(mcode == CURLM_OK) {
|
||||
if(ret == -1) {
|
||||
/* poll() failed not on EINTR, indicate a network problem */
|
||||
code = CURLE_RECV_ERROR;
|
||||
break;
|
||||
}
|
||||
else if(ret == 0) {
|
||||
struct timeval after = curlx_tvnow();
|
||||
/* If it returns without any filedescriptor instantly, we need to
|
||||
avoid busy-looping during periods where it has nothing particular
|
||||
to wait for */
|
||||
if(curlx_tvdiff(after, before) <= 10) {
|
||||
without_fds++;
|
||||
if(without_fds > 2) {
|
||||
int sleep_ms = without_fds < 10 ? (1 << (without_fds-1)): 1000;
|
||||
Curl_wait_ms(sleep_ms);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* it wasn't "instant", restart counter */
|
||||
without_fds = 0;
|
||||
}
|
||||
else
|
||||
/* got file descriptor, restart counter */
|
||||
without_fds = 0;
|
||||
|
||||
mcode = curl_multi_perform(multi, &still_running);
|
||||
}
|
||||
|
||||
/* only read 'still_running' if curl_multi_perform() return OK */
|
||||
if((mcode == CURLM_OK) && !still_running) {
|
||||
int rc;
|
||||
CURLMsg *msg = curl_multi_info_read(multi, &rc);
|
||||
if(msg) {
|
||||
code = msg->data.result;
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* easy_perform() is the external interface that performs a blocking
|
||||
* transfer as previously setup.
|
||||
*
|
||||
* CONCEPT: This function creates a multi handle, adds the easy handle to it,
|
||||
@@ -415,18 +786,18 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
|
||||
* needs to keep it around since if this easy handle is used again by this
|
||||
* function, the same multi handle must be re-used so that the same pools and
|
||||
* caches can be used.
|
||||
*
|
||||
* DEBUG: if 'events' is set TRUE, this function will use a replacement engine
|
||||
* instead of curl_multi_perform() and use curl_multi_socket_action().
|
||||
*/
|
||||
CURLcode curl_easy_perform(CURL *easy)
|
||||
static CURLcode easy_perform(struct SessionHandle *data, bool events)
|
||||
{
|
||||
CURLM *multi;
|
||||
CURLMcode mcode;
|
||||
CURLcode code = CURLE_OK;
|
||||
CURLMsg *msg;
|
||||
bool done = FALSE;
|
||||
int rc;
|
||||
struct SessionHandle *data = easy;
|
||||
SIGPIPE_VARIABLE(pipe_st);
|
||||
|
||||
if(!easy)
|
||||
if(!data)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
if(data->multi) {
|
||||
@@ -437,7 +808,9 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
if(data->multi_easy)
|
||||
multi = data->multi_easy;
|
||||
else {
|
||||
multi = curl_multi_init();
|
||||
/* this multi handle will only ever have a single easy handled attached
|
||||
to it, so make it use minimal hashes */
|
||||
multi = Curl_multi_handle(1, 3);
|
||||
if(!multi)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
data->multi_easy = multi;
|
||||
@@ -446,7 +819,7 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
/* Copy the MAXCONNECTS option to the multi handle */
|
||||
curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
|
||||
|
||||
mcode = curl_multi_add_handle(multi, easy);
|
||||
mcode = curl_multi_add_handle(multi, data);
|
||||
if(mcode) {
|
||||
curl_multi_cleanup(multi);
|
||||
if(mcode == CURLM_OUT_OF_MEMORY)
|
||||
@@ -455,44 +828,47 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
sigpipe_ignore(data, &pipe_st);
|
||||
|
||||
/* assign this after curl_multi_add_handle() since that function checks for
|
||||
it and rejects this handle otherwise */
|
||||
data->multi = multi;
|
||||
|
||||
while(!done && !mcode) {
|
||||
int still_running;
|
||||
int ret;
|
||||
|
||||
mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret);
|
||||
|
||||
if(mcode == CURLM_OK) {
|
||||
if(ret == -1) {
|
||||
/* poll() failed not on EINTR, indicate a network problem */
|
||||
code = CURLE_RECV_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mcode = curl_multi_perform(multi, &still_running);
|
||||
}
|
||||
|
||||
/* only read 'still_running' if curl_multi_perform() return OK */
|
||||
if((mcode == CURLM_OK) && !still_running) {
|
||||
msg = curl_multi_info_read(multi, &rc);
|
||||
if(msg) {
|
||||
code = msg->data.result;
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* run the transfer */
|
||||
code = events ? easy_events(multi) : easy_transfer(multi);
|
||||
|
||||
/* ignoring the return code isn't nice, but atm we can't really handle
|
||||
a failure here, room for future improvement! */
|
||||
(void)curl_multi_remove_handle(multi, easy);
|
||||
(void)curl_multi_remove_handle(multi, data);
|
||||
|
||||
sigpipe_restore(&pipe_st);
|
||||
|
||||
/* The multi handle is kept alive, owned by the easy handle */
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* curl_easy_perform() is the external interface that performs a blocking
|
||||
* transfer as previously setup.
|
||||
*/
|
||||
CURLcode curl_easy_perform(CURL *easy)
|
||||
{
|
||||
return easy_perform(easy, FALSE);
|
||||
}
|
||||
|
||||
#ifdef CURLDEBUG
|
||||
/*
|
||||
* curl_easy_perform_ev() is the external interface that performs a blocking
|
||||
* transfer using the event-based API internally.
|
||||
*/
|
||||
CURLcode curl_easy_perform_ev(CURL *easy)
|
||||
{
|
||||
return easy_perform(easy, TRUE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* curl_easy_cleanup() is the external interface to cleaning/freeing the given
|
||||
* easy handle.
|
||||
@@ -500,27 +876,14 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
void curl_easy_cleanup(CURL *curl)
|
||||
{
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
SIGPIPE_VARIABLE(pipe_st);
|
||||
|
||||
if(!data)
|
||||
return;
|
||||
|
||||
sigpipe_ignore(data, &pipe_st);
|
||||
Curl_close(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a pointed to the multi handle within the easy handle's data struct.
|
||||
*/
|
||||
void Curl_easy_addmulti(struct SessionHandle *data,
|
||||
void *multi)
|
||||
{
|
||||
data->multi = multi;
|
||||
}
|
||||
|
||||
void Curl_easy_initHandleData(struct SessionHandle *data)
|
||||
{
|
||||
memset(&data->req, 0, sizeof(struct SingleRequest));
|
||||
|
||||
data->req.maxdownload = -1;
|
||||
sigpipe_restore(&pipe_st);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -532,12 +895,16 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
|
||||
{
|
||||
va_list arg;
|
||||
void *paramp;
|
||||
CURLcode ret;
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
|
||||
va_start(arg, info);
|
||||
paramp = va_arg(arg, void *);
|
||||
|
||||
return Curl_getinfo(data, info, paramp);
|
||||
ret = Curl_getinfo(data, info, paramp);
|
||||
|
||||
va_end(arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -615,8 +982,6 @@ CURL *curl_easy_duphandle(CURL *incurl)
|
||||
|
||||
Curl_convert_setup(outcurl);
|
||||
|
||||
Curl_easy_initHandleData(outcurl);
|
||||
|
||||
outcurl->magic = CURLEASY_MAGIC_NUMBER;
|
||||
|
||||
/* we reach this point and thus we are OK */
|
||||
@@ -650,7 +1015,7 @@ void curl_easy_reset(CURL *curl)
|
||||
|
||||
data->state.path = NULL;
|
||||
|
||||
Curl_safefree(data->state.proto.generic);
|
||||
Curl_free_request_state(data);
|
||||
|
||||
/* zero out UserDefined data: */
|
||||
Curl_freeset(data);
|
||||
@@ -660,9 +1025,6 @@ void curl_easy_reset(CURL *curl)
|
||||
/* zero out Progress data: */
|
||||
memset(&data->progress, 0, sizeof(struct Progress));
|
||||
|
||||
/* init Handle data */
|
||||
Curl_easy_initHandleData(data);
|
||||
|
||||
data->progress.flags |= PGRS_HIDE;
|
||||
data->state.current_speed = -1; /* init to negative == impossible */
|
||||
}
|
||||
@@ -724,7 +1086,7 @@ CURLcode curl_easy_pause(CURL *curl, int action)
|
||||
do {
|
||||
chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
|
||||
|
||||
result = Curl_client_write(data->state.current_conn,
|
||||
result = Curl_client_write(data->easy_conn,
|
||||
temptype, tempwrite, chunklen);
|
||||
if(result)
|
||||
/* failures abort the loop at once */
|
||||
@@ -766,6 +1128,13 @@ CURLcode curl_easy_pause(CURL *curl, int action)
|
||||
free(freewrite); /* this is unconditionally no longer used */
|
||||
}
|
||||
|
||||
/* if there's no error and we're not pausing both directions, we want
|
||||
to have this handle checked soon */
|
||||
if(!result &&
|
||||
((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
|
||||
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) )
|
||||
Curl_expire(data, 1); /* get this handle going again */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -25,9 +25,9 @@
|
||||
/*
|
||||
* Prototypes for library-wide functions provided by easy.c
|
||||
*/
|
||||
void Curl_easy_addmulti(struct SessionHandle *data, void *multi);
|
||||
|
||||
void Curl_easy_initHandleData(struct SessionHandle *data);
|
||||
#ifdef CURLDEBUG
|
||||
CURL_EXTERN CURLcode curl_easy_perform_ev(CURL *easy);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_EASYIF_H */
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -159,7 +159,8 @@ CURLcode Curl_urldecode(struct SessionHandle *data,
|
||||
|
||||
while(--alloc > 0) {
|
||||
in = *string;
|
||||
if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
|
||||
if(('%' == in) && (alloc > 2) &&
|
||||
ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
|
||||
/* this is two hexadecimal digits following a '%' */
|
||||
char hexstr[3];
|
||||
char *ptr;
|
||||
|
||||
51
lib/file.c
51
lib/file.c
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -90,7 +90,7 @@ static CURLcode file_done(struct connectdata *conn,
|
||||
static CURLcode file_connect(struct connectdata *conn, bool *done);
|
||||
static CURLcode file_disconnect(struct connectdata *conn,
|
||||
bool dead_connection);
|
||||
|
||||
static CURLcode file_setup_connection(struct connectdata *conn);
|
||||
|
||||
/*
|
||||
* FILE scheme handler.
|
||||
@@ -98,7 +98,7 @@ static CURLcode file_disconnect(struct connectdata *conn,
|
||||
|
||||
const struct Curl_handler Curl_handler_file = {
|
||||
"FILE", /* scheme */
|
||||
ZERO_NULL, /* setup_connection */
|
||||
file_setup_connection, /* setup_connection */
|
||||
file_do, /* do_it */
|
||||
file_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
@@ -117,6 +117,16 @@ const struct Curl_handler Curl_handler_file = {
|
||||
};
|
||||
|
||||
|
||||
static CURLcode file_setup_connection(struct connectdata *conn)
|
||||
{
|
||||
/* allocate the FILE specific struct */
|
||||
conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO));
|
||||
if(!conn->data->req.protop)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if this is a range download, and if so, set the internal variables
|
||||
properly. This code is copied from the FTP implementation and might as
|
||||
@@ -179,39 +189,17 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
char *real_path;
|
||||
struct FILEPROTO *file;
|
||||
struct FILEPROTO *file = data->req.protop;
|
||||
int fd;
|
||||
#ifdef DOS_FILESYSTEM
|
||||
int i;
|
||||
char *actual_path;
|
||||
#endif
|
||||
|
||||
/* If there already is a protocol-specific struct allocated for this
|
||||
sessionhandle, deal with it */
|
||||
Curl_reset_reqproto(conn);
|
||||
|
||||
real_path = curl_easy_unescape(data, data->state.path, 0, NULL);
|
||||
if(!real_path)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(!data->state.proto.file) {
|
||||
file = calloc(1, sizeof(struct FILEPROTO));
|
||||
if(!file) {
|
||||
free(real_path);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
data->state.proto.file = file;
|
||||
}
|
||||
else {
|
||||
/* file is not a protocol that can deal with "persistancy" */
|
||||
file = data->state.proto.file;
|
||||
Curl_safefree(file->freepath);
|
||||
file->path = NULL;
|
||||
if(file->fd != -1)
|
||||
close(file->fd);
|
||||
file->fd = -1;
|
||||
}
|
||||
|
||||
#ifdef DOS_FILESYSTEM
|
||||
/* If the first character is a slash, and there's
|
||||
something that looks like a drive at the beginning of
|
||||
@@ -262,7 +250,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
|
||||
static CURLcode file_done(struct connectdata *conn,
|
||||
CURLcode status, bool premature)
|
||||
{
|
||||
struct FILEPROTO *file = conn->data->state.proto.file;
|
||||
struct FILEPROTO *file = conn->data->req.protop;
|
||||
(void)status; /* not used */
|
||||
(void)premature; /* not used */
|
||||
|
||||
@@ -280,7 +268,7 @@ static CURLcode file_done(struct connectdata *conn,
|
||||
static CURLcode file_disconnect(struct connectdata *conn,
|
||||
bool dead_connection)
|
||||
{
|
||||
struct FILEPROTO *file = conn->data->state.proto.file;
|
||||
struct FILEPROTO *file = conn->data->req.protop;
|
||||
(void)dead_connection; /* not used */
|
||||
|
||||
if(file) {
|
||||
@@ -302,7 +290,7 @@ static CURLcode file_disconnect(struct connectdata *conn,
|
||||
|
||||
static CURLcode file_upload(struct connectdata *conn)
|
||||
{
|
||||
struct FILEPROTO *file = conn->data->state.proto.file;
|
||||
struct FILEPROTO *file = conn->data->req.protop;
|
||||
const char *dir = strchr(file->path, DIRSEP);
|
||||
int fd;
|
||||
int mode;
|
||||
@@ -440,6 +428,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
|
||||
curl_off_t bytecount = 0;
|
||||
int fd;
|
||||
struct timeval now = Curl_tvnow();
|
||||
struct FILEPROTO *file;
|
||||
|
||||
*done = TRUE; /* unconditionally */
|
||||
|
||||
@@ -449,8 +438,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
|
||||
if(data->set.upload)
|
||||
return file_upload(conn);
|
||||
|
||||
file = conn->data->req.protop;
|
||||
|
||||
/* get the fd from the connection phase */
|
||||
fd = conn->data->state.proto.file->fd;
|
||||
fd = file->fd;
|
||||
|
||||
/* VMS: This only works reliable for STREAMLF files */
|
||||
if(-1 != fstat(fd, &statbuf)) {
|
||||
|
||||
143
lib/formdata.c
143
lib/formdata.c
@@ -24,9 +24,6 @@
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
/* Length of the random boundary string. */
|
||||
#define BOUNDARY_LENGTH 40
|
||||
|
||||
#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
|
||||
|
||||
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
|
||||
@@ -35,7 +32,7 @@
|
||||
|
||||
#include "urldata.h" /* for struct SessionHandle */
|
||||
#include "formdata.h"
|
||||
#include "curl_rand.h"
|
||||
#include "sslgen.h"
|
||||
#include "strequal.h"
|
||||
#include "curl_memory.h"
|
||||
#include "sendf.h"
|
||||
@@ -56,7 +53,7 @@ static char *Curl_basename(char *path);
|
||||
#endif
|
||||
|
||||
static size_t readfromfile(struct Form *form, char *buffer, size_t size);
|
||||
static char *formboundary(void);
|
||||
static char *formboundary(struct SessionHandle *data);
|
||||
|
||||
/* What kind of Content-Type to use on un-specified files with unrecognized
|
||||
extensions. */
|
||||
@@ -181,7 +178,7 @@ static const char * ContentTypeForFilename (const char *filename,
|
||||
* extensions and pick the first we match!
|
||||
*/
|
||||
struct ContentType {
|
||||
char extension[6];
|
||||
const char *extension;
|
||||
const char *type;
|
||||
};
|
||||
static const struct ContentType ctts[]={
|
||||
@@ -429,7 +426,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
|
||||
|
||||
/* Get contents from a given file name */
|
||||
case CURLFORM_FILECONTENT:
|
||||
if(current_form->flags != 0)
|
||||
if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
|
||||
return_value = CURL_FORMADD_OPTION_TWICE;
|
||||
else {
|
||||
const char *filename = array_state?
|
||||
@@ -670,9 +667,11 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
|
||||
if(((form->flags & HTTPPOST_FILENAME) ||
|
||||
(form->flags & HTTPPOST_BUFFER)) &&
|
||||
!form->contenttype ) {
|
||||
char *f = form->flags & HTTPPOST_BUFFER?
|
||||
form->showfilename : form->value;
|
||||
|
||||
/* our contenttype is missing */
|
||||
form->contenttype
|
||||
= strdup(ContentTypeForFilename(form->value, prevtype));
|
||||
form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
|
||||
if(!form->contenttype) {
|
||||
return_value = CURL_FORMADD_MEMORY;
|
||||
break;
|
||||
@@ -777,6 +776,70 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __VMS
|
||||
#include <fabdef.h>
|
||||
/*
|
||||
* get_vms_file_size does what it takes to get the real size of the file
|
||||
*
|
||||
* For fixed files, find out the size of the EOF block and adjust.
|
||||
*
|
||||
* For all others, have to read the entire file in, discarding the contents.
|
||||
* Most posted text files will be small, and binary files like zlib archives
|
||||
* and CD/DVD images should be either a STREAM_LF format or a fixed format.
|
||||
*
|
||||
*/
|
||||
curl_off_t VmsRealFileSize(const char * name,
|
||||
const struct_stat * stat_buf)
|
||||
{
|
||||
char buffer[8192];
|
||||
curl_off_t count;
|
||||
int ret_stat;
|
||||
FILE * file;
|
||||
|
||||
file = fopen(name, "r");
|
||||
if(file == NULL)
|
||||
return 0;
|
||||
|
||||
count = 0;
|
||||
ret_stat = 1;
|
||||
while(ret_stat > 0) {
|
||||
ret_stat = fread(buffer, 1, sizeof(buffer), file);
|
||||
if(ret_stat != 0)
|
||||
count += ret_stat;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* VmsSpecialSize checks to see if the stat st_size can be trusted and
|
||||
* if not to call a routine to get the correct size.
|
||||
*
|
||||
*/
|
||||
static curl_off_t VmsSpecialSize(const char * name,
|
||||
const struct_stat * stat_buf)
|
||||
{
|
||||
switch(stat_buf->st_fab_rfm) {
|
||||
case FAB$C_VAR:
|
||||
case FAB$C_VFC:
|
||||
return VmsRealFileSize(name, stat_buf);
|
||||
break;
|
||||
default:
|
||||
return stat_buf->st_size;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __VMS
|
||||
#define filesize(name, stat_data) (stat_data.st_size)
|
||||
#else
|
||||
/* Getting the expected file size needs help on VMS */
|
||||
#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AddFormData() adds a chunk of data to the FormData linked list.
|
||||
*
|
||||
@@ -832,7 +895,7 @@ static CURLcode AddFormData(struct FormData **formp,
|
||||
if(!strequal("-", newform->line)) {
|
||||
struct_stat file;
|
||||
if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
|
||||
*size += file.st_size;
|
||||
*size += filesize(newform->line, file);
|
||||
else
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
@@ -1101,7 +1164,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data,
|
||||
if(!post)
|
||||
return result; /* no input => no output! */
|
||||
|
||||
boundary = formboundary();
|
||||
boundary = formboundary(data);
|
||||
if(!boundary)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
@@ -1157,7 +1220,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data,
|
||||
the magic to include several files with the same field name */
|
||||
|
||||
Curl_safefree(fileboundary);
|
||||
fileboundary = formboundary();
|
||||
fileboundary = formboundary(data);
|
||||
if(!fileboundary) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
@@ -1343,6 +1406,36 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata )
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __VMS
|
||||
# define fopen_read fopen
|
||||
#else
|
||||
/*
|
||||
* vmsfopenread
|
||||
*
|
||||
* For upload to work as expected on VMS, different optional
|
||||
* parameters must be added to the fopen command based on
|
||||
* record format of the file.
|
||||
*
|
||||
*/
|
||||
# define fopen_read vmsfopenread
|
||||
static FILE * vmsfopenread(const char *file, const char *mode) {
|
||||
struct_stat statbuf;
|
||||
int result;
|
||||
|
||||
result = stat(file, &statbuf);
|
||||
|
||||
switch (statbuf.st_fab_rfm) {
|
||||
case FAB$C_VAR:
|
||||
case FAB$C_VFC:
|
||||
case FAB$C_STMCR:
|
||||
return fopen(file, "r");
|
||||
break;
|
||||
default:
|
||||
return fopen(file, "r", "rfm=stmlf", "ctx=stm");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* readfromfile()
|
||||
*
|
||||
@@ -1365,7 +1458,7 @@ static size_t readfromfile(struct Form *form, char *buffer,
|
||||
else {
|
||||
if(!form->fp) {
|
||||
/* this file hasn't yet been opened */
|
||||
form->fp = fopen(form->data->line, "rb"); /* b is for binary */
|
||||
form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
|
||||
if(!form->fp)
|
||||
return (size_t)-1; /* failure */
|
||||
}
|
||||
@@ -1464,28 +1557,12 @@ char *Curl_formpostheader(void *formp, size_t *len)
|
||||
* formboundary() creates a suitable boundary string and returns an allocated
|
||||
* one.
|
||||
*/
|
||||
static char *formboundary(void)
|
||||
static char *formboundary(struct SessionHandle *data)
|
||||
{
|
||||
char *retstring;
|
||||
size_t i;
|
||||
|
||||
static const char table16[]="0123456789abcdef";
|
||||
|
||||
retstring = malloc(BOUNDARY_LENGTH+1);
|
||||
|
||||
if(!retstring)
|
||||
return NULL; /* failed */
|
||||
|
||||
strcpy(retstring, "----------------------------");
|
||||
|
||||
for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
|
||||
retstring[i] = table16[Curl_rand()%16];
|
||||
|
||||
/* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
|
||||
/* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
|
||||
combinations */
|
||||
retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
|
||||
|
||||
return retstring;
|
||||
return aprintf("------------------------%08x%08x",
|
||||
Curl_rand(data), Curl_rand(data));
|
||||
}
|
||||
|
||||
#else /* CURL_DISABLE_HTTP */
|
||||
|
||||
416
lib/ftp.c
416
lib/ftp.c
@@ -59,11 +59,7 @@
|
||||
#include "ftp.h"
|
||||
#include "fileinfo.h"
|
||||
#include "ftplistparser.h"
|
||||
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#include "krb4.h"
|
||||
#endif
|
||||
|
||||
#include "curl_sec.h"
|
||||
#include "strtoofft.h"
|
||||
#include "strequal.h"
|
||||
#include "sslgen.h"
|
||||
@@ -123,8 +119,8 @@ static void ftp_pasv_verbose(struct connectdata *conn,
|
||||
char *newhost, /* ascii version */
|
||||
int port);
|
||||
#endif
|
||||
static CURLcode ftp_state_post_rest(struct connectdata *conn);
|
||||
static CURLcode ftp_state_post_cwd(struct connectdata *conn);
|
||||
static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
|
||||
static CURLcode ftp_state_mdtm(struct connectdata *conn);
|
||||
static CURLcode ftp_state_quote(struct connectdata *conn,
|
||||
bool init, ftpstate instate);
|
||||
static CURLcode ftp_nb_type(struct connectdata *conn,
|
||||
@@ -136,7 +132,7 @@ static CURLcode ftp_done(struct connectdata *conn,
|
||||
CURLcode, bool premature);
|
||||
static CURLcode ftp_connect(struct connectdata *conn, bool *done);
|
||||
static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
|
||||
static CURLcode ftp_do_more(struct connectdata *conn, bool *completed);
|
||||
static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
|
||||
static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
|
||||
static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||
int numsocks);
|
||||
@@ -151,8 +147,7 @@ static CURLcode wc_statemach(struct connectdata *conn);
|
||||
|
||||
static void wc_data_dtor(void *ptr);
|
||||
|
||||
static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
|
||||
curl_off_t filesize);
|
||||
static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
|
||||
|
||||
static CURLcode ftp_readresp(curl_socket_t sockfd,
|
||||
struct pingpong *pp,
|
||||
@@ -226,7 +221,7 @@ const struct Curl_handler Curl_handler_ftps = {
|
||||
|
||||
static const struct Curl_handler Curl_handler_ftp_proxy = {
|
||||
"FTP", /* scheme */
|
||||
ZERO_NULL, /* setup_connection */
|
||||
Curl_http_setup_conn, /* setup_connection */
|
||||
Curl_http, /* do_it */
|
||||
Curl_http_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
@@ -252,7 +247,7 @@ static const struct Curl_handler Curl_handler_ftp_proxy = {
|
||||
|
||||
static const struct Curl_handler Curl_handler_ftps_proxy = {
|
||||
"FTPS", /* scheme */
|
||||
ZERO_NULL, /* setup_connection */
|
||||
Curl_http_setup_conn, /* setup_connection */
|
||||
Curl_http, /* do_it */
|
||||
Curl_http_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
@@ -494,7 +489,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
|
||||
static CURLcode InitiateTransfer(struct connectdata *conn)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(conn->ssl[SECONDARYSOCKET].use) {
|
||||
@@ -616,7 +611,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
|
||||
{
|
||||
struct connectdata *conn = pp->conn;
|
||||
struct SessionHandle *data = conn->data;
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#ifdef HAVE_GSSAPI
|
||||
char * const buf = data->state.buffer;
|
||||
#endif
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -624,7 +619,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
|
||||
|
||||
result = Curl_pp_readresp(sockfd, pp, &code, size);
|
||||
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#if defined(HAVE_GSSAPI)
|
||||
/* handle the security-oriented responses 6xx ***/
|
||||
/* FIXME: some errorchecking perhaps... ***/
|
||||
switch(code) {
|
||||
@@ -776,17 +771,9 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This is the ONLY way to change FTP state! */
|
||||
static void _state(struct connectdata *conn,
|
||||
ftpstate newstate
|
||||
#ifdef DEBUGBUILD
|
||||
, int lineno
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
/* for debug purposes */
|
||||
static const char * const names[]={
|
||||
static const char * const ftp_state_names[]={
|
||||
"STOP",
|
||||
"WAIT220",
|
||||
"AUTH",
|
||||
@@ -824,11 +811,21 @@ static void _state(struct connectdata *conn,
|
||||
"QUIT"
|
||||
};
|
||||
#endif
|
||||
|
||||
/* This is the ONLY way to change FTP state! */
|
||||
static void _state(struct connectdata *conn,
|
||||
ftpstate newstate
|
||||
#ifdef DEBUGBUILD
|
||||
, int lineno
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
if(ftpc->state != newstate)
|
||||
infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
|
||||
ftpc, lineno, names[ftpc->state], names[newstate]);
|
||||
(void *)ftpc, lineno, ftp_state_names[ftpc->state],
|
||||
ftp_state_names[newstate]);
|
||||
#endif
|
||||
ftpc->state = newstate;
|
||||
}
|
||||
@@ -836,7 +833,7 @@ static void _state(struct connectdata *conn,
|
||||
static CURLcode ftp_state_user(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result;
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
/* send USER */
|
||||
PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
|
||||
|
||||
@@ -851,7 +848,7 @@ static CURLcode ftp_state_pwd(struct connectdata *conn)
|
||||
CURLcode result;
|
||||
|
||||
/* send PWD to discover our entry point */
|
||||
PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
|
||||
PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
|
||||
state(conn, FTP_PWD);
|
||||
|
||||
return CURLE_OK;
|
||||
@@ -875,33 +872,23 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
|
||||
return GETSOCK_BLANK;
|
||||
|
||||
/* When in DO_MORE state, we could be either waiting for us to connect to a
|
||||
remote site, or we could wait for that site to connect to us. Or just
|
||||
handle ordinary commands.
|
||||
|
||||
When waiting for a connect, we can be in FTP_STOP state (or we're in
|
||||
FTP_STOR when we do an upload) and then we wait for the secondary socket
|
||||
to become writeable. . If we're in another state, we're still handling
|
||||
commands on the control (primary) connection.
|
||||
|
||||
* remote site, or we could wait for that site to connect to us. Or just
|
||||
* handle ordinary commands.
|
||||
*/
|
||||
|
||||
switch(ftpc->state) {
|
||||
case FTP_STOP:
|
||||
case FTP_STOR:
|
||||
break;
|
||||
default:
|
||||
if(FTP_STOP == ftpc->state) {
|
||||
/* if stopped and still in this state, then we're also waiting for a
|
||||
connect on the secondary connection */
|
||||
socks[0] = conn->sock[FIRSTSOCKET];
|
||||
socks[1] = conn->sock[SECONDARYSOCKET];
|
||||
|
||||
return GETSOCK_READSOCK(FIRSTSOCKET) |
|
||||
GETSOCK_WRITESOCK(SECONDARYSOCKET);
|
||||
}
|
||||
else
|
||||
return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
|
||||
}
|
||||
|
||||
socks[0] = conn->sock[SECONDARYSOCKET];
|
||||
if(ftpc->wait_data_conn) {
|
||||
socks[1] = conn->sock[FIRSTSOCKET];
|
||||
return GETSOCK_READSOCK(0) | GETSOCK_READSOCK(1);
|
||||
}
|
||||
|
||||
return GETSOCK_READSOCK(0);
|
||||
}
|
||||
|
||||
/* This is called after the FTP_QUOTE state is passed.
|
||||
|
||||
ftp_state_cwd() sends the range of CWD commands to the server to change to
|
||||
@@ -915,7 +902,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
|
||||
|
||||
if(ftpc->cwddone)
|
||||
/* already done and fine */
|
||||
result = ftp_state_post_cwd(conn);
|
||||
result = ftp_state_mdtm(conn);
|
||||
else {
|
||||
ftpc->count2 = 0; /* count2 counts failed CWDs */
|
||||
|
||||
@@ -943,7 +930,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
|
||||
}
|
||||
else {
|
||||
/* No CWD necessary */
|
||||
result = ftp_state_post_cwd(conn);
|
||||
result = ftp_state_mdtm(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1373,13 +1360,17 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* REST is the last command in the chain of commands when a "head"-like
|
||||
request is made. Thus, if an actual transfer is to be made this is where
|
||||
we take off for real. */
|
||||
static CURLcode ftp_state_post_rest(struct connectdata *conn)
|
||||
/*
|
||||
* ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
|
||||
*
|
||||
* REST is the last command in the chain of commands when a "head"-like
|
||||
* request is made. Thus, if an actual transfer is to be made this is where we
|
||||
* take off for real.
|
||||
*/
|
||||
static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
if(ftp->transfer != FTPTRANSFER_BODY) {
|
||||
@@ -1419,10 +1410,10 @@ static CURLcode ftp_state_post_rest(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_size(struct connectdata *conn)
|
||||
static CURLcode ftp_state_rest(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
|
||||
@@ -1435,15 +1426,15 @@ static CURLcode ftp_state_post_size(struct connectdata *conn)
|
||||
state(conn, FTP_REST);
|
||||
}
|
||||
else
|
||||
result = ftp_state_post_rest(conn);
|
||||
result = ftp_state_prepare_transfer(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_type(struct connectdata *conn)
|
||||
static CURLcode ftp_state_size(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
|
||||
@@ -1455,12 +1446,12 @@ static CURLcode ftp_state_post_type(struct connectdata *conn)
|
||||
state(conn, FTP_SIZE);
|
||||
}
|
||||
else
|
||||
result = ftp_state_post_size(conn);
|
||||
result = ftp_state_rest(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_listtype(struct connectdata *conn)
|
||||
static CURLcode ftp_state_list(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
@@ -1529,7 +1520,7 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
|
||||
static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@@ -1540,7 +1531,7 @@ static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_stortype(struct connectdata *conn)
|
||||
static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
@@ -1551,10 +1542,10 @@ static CURLcode ftp_state_post_stortype(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
|
||||
static CURLcode ftp_state_type(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
@@ -1577,14 +1568,14 @@ static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
else
|
||||
result = ftp_state_post_type(conn);
|
||||
result = ftp_state_size(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This is called after the CWD commands have been done in the beginning of
|
||||
the DO phase */
|
||||
static CURLcode ftp_state_post_cwd(struct connectdata *conn)
|
||||
static CURLcode ftp_state_mdtm(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
@@ -1600,7 +1591,7 @@ static CURLcode ftp_state_post_cwd(struct connectdata *conn)
|
||||
state(conn, FTP_MDTM);
|
||||
}
|
||||
else
|
||||
result = ftp_state_post_mdtm(conn);
|
||||
result = ftp_state_type(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1611,7 +1602,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
|
||||
bool sizechecked)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
int seekerr = CURL_SEEKFUNC_OK;
|
||||
@@ -1709,7 +1700,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
bool quote=FALSE;
|
||||
struct curl_slist *item;
|
||||
@@ -1775,7 +1766,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
|
||||
else {
|
||||
if(ftpc->known_filesize != -1) {
|
||||
Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
|
||||
result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
|
||||
result = ftp_state_retr(conn, ftpc->known_filesize);
|
||||
}
|
||||
else {
|
||||
PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
|
||||
@@ -1799,15 +1790,15 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
|
||||
static CURLcode ftp_epsv_disable(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
infof(conn->data, "got positive EPSV response, but can't connect. "
|
||||
"Disabling EPSV\n");
|
||||
infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
|
||||
/* disable it for next transfer */
|
||||
conn->bits.ftp_use_epsv = FALSE;
|
||||
conn->data->state.errorbuf = FALSE; /* allow error message to get
|
||||
rewritten */
|
||||
PPSENDF(&conn->proto.ftpc.pp, "PASV", NULL);
|
||||
PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
|
||||
conn->proto.ftpc.count1++;
|
||||
/* remain in the FTP_PASV state */
|
||||
/* remain in/go to the FTP_PASV state */
|
||||
state(conn, FTP_PASV);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1936,28 +1927,18 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
}
|
||||
else if(ftpc->count1 == 0) {
|
||||
/* EPSV failed, move on to PASV */
|
||||
|
||||
/* disable it for next transfer */
|
||||
conn->bits.ftp_use_epsv = FALSE;
|
||||
infof(data, "disabling EPSV usage\n");
|
||||
|
||||
PPSENDF(&ftpc->pp, "PASV", NULL);
|
||||
ftpc->count1++;
|
||||
/* remain in the FTP_PASV state */
|
||||
return result;
|
||||
return ftp_epsv_disable(conn);
|
||||
}
|
||||
else {
|
||||
failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
|
||||
return CURLE_FTP_WEIRD_PASV_REPLY;
|
||||
}
|
||||
|
||||
if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
|
||||
if(conn->bits.proxy) {
|
||||
/*
|
||||
* This is a tunnel through a http proxy and we need to connect to the
|
||||
* proxy again here.
|
||||
*
|
||||
* We don't want to rely on a former host lookup that might've expired
|
||||
* now, instead we remake the lookup here and now!
|
||||
* This connection uses a proxy and we need to connect to the proxy again
|
||||
* here. We don't want to rely on a former host lookup that might've
|
||||
* expired now, instead we remake the lookup here and now!
|
||||
*/
|
||||
rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
|
||||
if(rc == CURLRESOLV_PENDING)
|
||||
@@ -2023,14 +2004,17 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
case CURLPROXY_SOCKS5_HOSTNAME:
|
||||
result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
|
||||
SECONDARYSOCKET, conn);
|
||||
connected = TRUE;
|
||||
break;
|
||||
case CURLPROXY_SOCKS4:
|
||||
result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
|
||||
SECONDARYSOCKET, conn, FALSE);
|
||||
connected = TRUE;
|
||||
break;
|
||||
case CURLPROXY_SOCKS4A:
|
||||
result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
|
||||
SECONDARYSOCKET, conn, TRUE);
|
||||
connected = TRUE;
|
||||
break;
|
||||
case CURLPROXY_HTTP:
|
||||
case CURLPROXY_HTTP_1_0:
|
||||
@@ -2062,13 +2046,13 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
* FTP pointer
|
||||
*/
|
||||
struct HTTP http_proxy;
|
||||
struct FTP *ftp_save = data->state.proto.ftp;
|
||||
struct FTP *ftp_save = data->req.protop;
|
||||
memset(&http_proxy, 0, sizeof(http_proxy));
|
||||
data->state.proto.http = &http_proxy;
|
||||
data->req.protop = &http_proxy;
|
||||
|
||||
result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
|
||||
|
||||
data->state.proto.ftp = ftp_save;
|
||||
data->req.protop = ftp_save;
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
@@ -2082,8 +2066,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
}
|
||||
}
|
||||
|
||||
conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
|
||||
|
||||
conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
|
||||
conn->bits.do_more = TRUE;
|
||||
state(conn, FTP_STOP); /* this phase is completed */
|
||||
|
||||
@@ -2129,7 +2112,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data=conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
switch(ftpcode) {
|
||||
@@ -2223,7 +2206,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
|
||||
}
|
||||
|
||||
if(!result)
|
||||
result = ftp_state_post_mdtm(conn);
|
||||
result = ftp_state_type(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -2247,23 +2230,23 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn,
|
||||
ftpcode);
|
||||
|
||||
if(instate == FTP_TYPE)
|
||||
result = ftp_state_post_type(conn);
|
||||
result = ftp_state_size(conn);
|
||||
else if(instate == FTP_LIST_TYPE)
|
||||
result = ftp_state_post_listtype(conn);
|
||||
result = ftp_state_list(conn);
|
||||
else if(instate == FTP_RETR_TYPE)
|
||||
result = ftp_state_post_retrtype(conn);
|
||||
result = ftp_state_retr_prequote(conn);
|
||||
else if(instate == FTP_STOR_TYPE)
|
||||
result = ftp_state_post_stortype(conn);
|
||||
result = ftp_state_stor_prequote(conn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
|
||||
static CURLcode ftp_state_retr(struct connectdata *conn,
|
||||
curl_off_t filesize)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data=conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
|
||||
@@ -2363,11 +2346,11 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
|
||||
}
|
||||
#endif
|
||||
Curl_pgrsSetDownloadSize(data, filesize);
|
||||
result = ftp_state_post_size(conn);
|
||||
result = ftp_state_rest(conn);
|
||||
}
|
||||
else if(instate == FTP_RETR_SIZE) {
|
||||
Curl_pgrsSetDownloadSize(data, filesize);
|
||||
result = ftp_state_post_retr_size(conn, filesize);
|
||||
result = ftp_state_retr(conn, filesize);
|
||||
}
|
||||
else if(instate == FTP_STOR_SIZE) {
|
||||
data->state.resume_from = filesize;
|
||||
@@ -2395,7 +2378,7 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn,
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
result = ftp_state_post_rest(conn);
|
||||
result = ftp_state_prepare_transfer(conn);
|
||||
break;
|
||||
|
||||
case FTP_RETR_REST:
|
||||
@@ -2432,6 +2415,8 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
|
||||
if(data->set.ftp_use_port) {
|
||||
bool connected;
|
||||
|
||||
state(conn, FTP_STOP); /* no longer in STOR state */
|
||||
|
||||
result = AllowServerConnect(conn, &connected);
|
||||
if(result)
|
||||
return result;
|
||||
@@ -2455,7 +2440,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
char *buf = data->state.buffer;
|
||||
|
||||
if((ftpcode == 150) || (ftpcode == 125)) {
|
||||
@@ -2579,19 +2564,6 @@ static CURLcode ftp_state_loggedin(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
#ifdef HAVE_KRB4
|
||||
if(conn->data->set.krb) {
|
||||
/* We may need to issue a KAUTH here to have access to the files
|
||||
* do it if user supplied a password
|
||||
*/
|
||||
if(conn->passwd && *conn->passwd) {
|
||||
/* BLOCKING */
|
||||
result = Curl_krb_kauth(conn);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(conn->ssl[FIRSTSOCKET].use) {
|
||||
/* PBSZ = PROTECTION BUFFER SIZE.
|
||||
|
||||
@@ -2623,7 +2595,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
(void)instate; /* no use for this yet */
|
||||
|
||||
@@ -2711,14 +2683,17 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
||||
/* we have now received a full FTP server response */
|
||||
switch(ftpc->state) {
|
||||
case FTP_WAIT220:
|
||||
if(ftpcode != 220) {
|
||||
if(ftpcode == 230)
|
||||
/* 230 User logged in - already! */
|
||||
return ftp_state_user_resp(conn, ftpcode, ftpc->state);
|
||||
else if(ftpcode != 220) {
|
||||
failf(data, "Got a %03d ftp-server response when 220 was expected",
|
||||
ftpcode);
|
||||
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
|
||||
/* We have received a 220 response fine, now we proceed. */
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#ifdef HAVE_GSSAPI
|
||||
if(data->set.krb) {
|
||||
/* If not anonymous login, try a secure login. Note that this
|
||||
procedure is still BLOCKING. */
|
||||
@@ -2833,7 +2808,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
||||
if(data->set.ftp_ccc) {
|
||||
/* CCC - Clear Command Channel
|
||||
*/
|
||||
PPSENDF(&ftpc->pp, "CCC", NULL);
|
||||
PPSENDF(&ftpc->pp, "%s", "CCC");
|
||||
state(conn, FTP_CCC);
|
||||
}
|
||||
else {
|
||||
@@ -2920,7 +2895,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
||||
|
||||
if(!ftpc->server_os && dir[0] != '/') {
|
||||
|
||||
result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL);
|
||||
result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
|
||||
if(result != CURLE_OK) {
|
||||
free(dir);
|
||||
return result;
|
||||
@@ -2973,7 +2948,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
||||
|
||||
if(strequal(os, "OS/400")) {
|
||||
/* Force OS400 name format 1. */
|
||||
result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL);
|
||||
result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
|
||||
if(result != CURLE_OK) {
|
||||
free(os);
|
||||
return result;
|
||||
@@ -3051,7 +3026,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
||||
PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
|
||||
}
|
||||
else {
|
||||
result = ftp_state_post_cwd(conn);
|
||||
result = ftp_state_mdtm(conn);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
@@ -3160,63 +3135,13 @@ static CURLcode ftp_block_statemach(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and initialize the struct FTP for the current SessionHandle. If
|
||||
* need be.
|
||||
*/
|
||||
|
||||
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
|
||||
defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
|
||||
/* workaround icc 9.1 optimizer issue */
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
|
||||
static CURLcode ftp_init(struct connectdata *conn)
|
||||
{
|
||||
struct FTP *ftp;
|
||||
|
||||
if(NULL == conn->data->state.proto.ftp) {
|
||||
conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
|
||||
if(NULL == conn->data->state.proto.ftp)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ftp = conn->data->state.proto.ftp;
|
||||
|
||||
/* get some initial data into the ftp struct */
|
||||
ftp->bytecountp = &conn->data->req.bytecount;
|
||||
ftp->transfer = FTPTRANSFER_BODY;
|
||||
ftp->downloadsize = 0;
|
||||
|
||||
/* No need to duplicate user+password, the connectdata struct won't change
|
||||
during a session, but we re-init them here since on subsequent inits
|
||||
since the conn struct may have changed or been replaced.
|
||||
*/
|
||||
ftp->user = conn->user;
|
||||
ftp->passwd = conn->passwd;
|
||||
if(isBadFtpString(ftp->user))
|
||||
return CURLE_URL_MALFORMAT;
|
||||
if(isBadFtpString(ftp->passwd))
|
||||
return CURLE_URL_MALFORMAT;
|
||||
|
||||
conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
|
||||
defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
|
||||
/* workaround icc 9.1 optimizer issue */
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ftp_connect() should do everything that is to be considered a part of
|
||||
* the connection phase.
|
||||
*
|
||||
* The variable 'done' points to will be TRUE if the protocol-layer connect
|
||||
* phase is done when this function returns, or FALSE is not. When called as
|
||||
* a part of the easy interface, it will always be TRUE.
|
||||
* phase is done when this function returns, or FALSE if not.
|
||||
*
|
||||
*/
|
||||
static CURLcode ftp_connect(struct connectdata *conn,
|
||||
bool *done) /* see description above */
|
||||
@@ -3227,14 +3152,6 @@ static CURLcode ftp_connect(struct connectdata *conn,
|
||||
|
||||
*done = FALSE; /* default to not done yet */
|
||||
|
||||
/* If there already is a protocol-specific struct allocated for this
|
||||
sessionhandle, deal with it */
|
||||
Curl_reset_reqproto(conn);
|
||||
|
||||
result = ftp_init(conn);
|
||||
if(CURLE_OK != result)
|
||||
return result;
|
||||
|
||||
/* We always support persistent connections on ftp */
|
||||
conn->bits.close = FALSE;
|
||||
|
||||
@@ -3274,7 +3191,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
|
||||
bool premature)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
struct pingpong *pp = &ftpc->pp;
|
||||
ssize_t nread;
|
||||
@@ -3382,7 +3299,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
|
||||
if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
|
||||
if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
|
||||
/* partial download completed */
|
||||
result = Curl_pp_sendf(pp, "ABOR");
|
||||
result = Curl_pp_sendf(pp, "%s", "ABOR");
|
||||
if(result) {
|
||||
failf(data, "Failure sending ABOR command: %s",
|
||||
curl_easy_strerror(result));
|
||||
@@ -3676,19 +3593,22 @@ static CURLcode ftp_range(struct connectdata *conn)
|
||||
*
|
||||
* This function shall be called when the second FTP (data) connection is
|
||||
* connected.
|
||||
*
|
||||
* 'complete' can return 0 for incomplete, 1 for done and -1 for go back
|
||||
* (which basically is only for when PASV is being sent to retry a failed
|
||||
* EPSV).
|
||||
*/
|
||||
|
||||
static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
|
||||
{
|
||||
struct SessionHandle *data=conn->data;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
bool complete = FALSE;
|
||||
|
||||
/* the ftp struct is inited in ftp_connect() */
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
|
||||
*complete = FALSE;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
|
||||
/* if the second connection isn't done yet, wait for it */
|
||||
if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
|
||||
@@ -3706,14 +3626,22 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
if(connected) {
|
||||
DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
|
||||
}
|
||||
else
|
||||
else {
|
||||
if(result && (ftpc->count1 == 0)) {
|
||||
*completep = -1; /* go back to DOING please */
|
||||
/* this is a EPSV connect failing, try PASV instead */
|
||||
return ftp_epsv_disable(conn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if(ftpc->state) {
|
||||
/* already in a state so skip the intial commands.
|
||||
They are only done to kickstart the do_more state */
|
||||
result = ftp_multi_statemach(conn, complete);
|
||||
result = ftp_multi_statemach(conn, &complete);
|
||||
|
||||
*completep = (int)complete;
|
||||
|
||||
/* if we got an error or if we don't wait for a data connection return
|
||||
immediately */
|
||||
@@ -3724,7 +3652,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
/* if we reach the end of the FTP state machine here, *complete will be
|
||||
TRUE but so is ftpc->wait_data_conn, which says we need to wait for
|
||||
the data connection and therefore we're not actually complete */
|
||||
*complete = FALSE;
|
||||
*completep = 0;
|
||||
}
|
||||
|
||||
if(ftp->transfer <= FTPTRANSFER_INFO) {
|
||||
@@ -3747,6 +3675,9 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
*completep = 1; /* this state is now complete when the server has
|
||||
connected back to us */
|
||||
}
|
||||
}
|
||||
else if(data->set.upload) {
|
||||
@@ -3754,7 +3685,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = ftp_multi_statemach(conn, complete);
|
||||
result = ftp_multi_statemach(conn, &complete);
|
||||
*completep = (int)complete;
|
||||
}
|
||||
else {
|
||||
/* download */
|
||||
@@ -3782,7 +3714,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ftp_multi_statemach(conn, complete);
|
||||
result = ftp_multi_statemach(conn, &complete);
|
||||
*completep = (int)complete;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -3794,7 +3727,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
|
||||
if(!ftpc->wait_data_conn) {
|
||||
/* no waiting for the data connection so this is now complete */
|
||||
*complete = TRUE;
|
||||
*completep = 1;
|
||||
DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
|
||||
}
|
||||
|
||||
@@ -3823,7 +3756,7 @@ CURLcode ftp_perform(struct connectdata *conn,
|
||||
|
||||
if(conn->data->set.opt_no_body) {
|
||||
/* requested no body means no transfer... */
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
ftp->transfer = FTPTRANSFER_INFO;
|
||||
}
|
||||
|
||||
@@ -3837,7 +3770,9 @@ CURLcode ftp_perform(struct connectdata *conn,
|
||||
/* run the state-machine */
|
||||
result = ftp_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
*connected = conn->bits.tcpconnect[SECONDARYSOCKET];
|
||||
|
||||
infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
|
||||
|
||||
if(*dophase_done)
|
||||
DEBUGF(infof(conn->data, "DO phase is complete1\n"));
|
||||
@@ -4083,17 +4018,6 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done)
|
||||
*done = FALSE; /* default to false */
|
||||
ftpc->wait_data_conn = FALSE; /* default to no such wait */
|
||||
|
||||
/*
|
||||
Since connections can be re-used between SessionHandles, this might be a
|
||||
connection already existing but on a fresh SessionHandle struct so we must
|
||||
make sure we have a good 'struct FTP' to play with. For new connections,
|
||||
the struct FTP is allocated and setup in the ftp_connect() function.
|
||||
*/
|
||||
Curl_reset_reqproto(conn);
|
||||
retcode = ftp_init(conn);
|
||||
if(retcode)
|
||||
return retcode;
|
||||
|
||||
if(conn->data->set.wildcardmatch) {
|
||||
retcode = wc_statemach(conn);
|
||||
if(conn->data->wildcard.state == CURLWC_SKIP ||
|
||||
@@ -4125,7 +4049,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
|
||||
size_t write_len;
|
||||
char *sptr=s;
|
||||
CURLcode res = CURLE_OK;
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#ifdef HAVE_GSSAPI
|
||||
enum protection_level data_sec = conn->data_prot;
|
||||
#endif
|
||||
|
||||
@@ -4145,12 +4069,12 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
|
||||
return(res);
|
||||
|
||||
for(;;) {
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#ifdef HAVE_GSSAPI
|
||||
conn->data_prot = PROT_CMD;
|
||||
#endif
|
||||
res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
|
||||
&bytes_written);
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#ifdef HAVE_GSSAPI
|
||||
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
|
||||
conn->data_prot = data_sec;
|
||||
#endif
|
||||
@@ -4188,7 +4112,7 @@ static CURLcode ftp_quit(struct connectdata *conn)
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(conn->proto.ftpc.ctl_valid) {
|
||||
result = Curl_pp_sendf(&conn->proto.ftpc.pp, "QUIT", NULL);
|
||||
result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
|
||||
if(result) {
|
||||
failf(conn->data, "Failure sending QUIT command: %s",
|
||||
curl_easy_strerror(result));
|
||||
@@ -4252,7 +4176,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
|
||||
|
||||
Curl_pp_disconnect(pp);
|
||||
|
||||
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
|
||||
#ifdef HAVE_GSSAPI
|
||||
Curl_sec_end(conn);
|
||||
#endif
|
||||
|
||||
@@ -4271,7 +4195,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
/* the ftp struct is already inited in ftp_connect() */
|
||||
struct FTP *ftp = data->state.proto.ftp;
|
||||
struct FTP *ftp = data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
const char *slash_pos; /* position of the first '/' char in curpos */
|
||||
const char *path_to_use = data->state.path;
|
||||
@@ -4316,13 +4240,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
}
|
||||
slash_pos=strrchr(cur_pos, '/');
|
||||
if(slash_pos || !*cur_pos) {
|
||||
size_t dirlen = slash_pos-cur_pos;
|
||||
|
||||
ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
|
||||
if(!ftpc->dirs)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(!dirlen)
|
||||
dirlen++;
|
||||
|
||||
ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
|
||||
slash_pos ?
|
||||
curlx_sztosi(slash_pos-cur_pos) : 1,
|
||||
slash_pos ? curlx_uztosi(dirlen) : 1,
|
||||
NULL);
|
||||
if(!ftpc->dirs[0]) {
|
||||
freedirs(ftpc);
|
||||
@@ -4377,6 +4305,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
}
|
||||
else {
|
||||
cur_pos = slash_pos + 1; /* jump to the rest of the string */
|
||||
if(!ftpc->dirdepth) {
|
||||
/* path starts with a slash, add that as a directory */
|
||||
ftpc->dirs[ftpc->dirdepth] = strdup("/");
|
||||
if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
|
||||
failf(data, "no memory");
|
||||
freedirs(ftpc);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4448,11 +4385,11 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
static CURLcode ftp_dophase_done(struct connectdata *conn,
|
||||
bool connected)
|
||||
{
|
||||
struct FTP *ftp = conn->data->state.proto.ftp;
|
||||
struct FTP *ftp = conn->data->req.protop;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
if(connected) {
|
||||
bool completed;
|
||||
int completed;
|
||||
CURLcode result = ftp_do_more(conn, &completed);
|
||||
|
||||
if(result) {
|
||||
@@ -4548,6 +4485,7 @@ static CURLcode ftp_setup_connection(struct connectdata * conn)
|
||||
struct SessionHandle *data = conn->data;
|
||||
char *type;
|
||||
char command;
|
||||
struct FTP *ftp;
|
||||
|
||||
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
|
||||
/* Unless we have asked to tunnel ftp operations through the proxy, we
|
||||
@@ -4563,18 +4501,18 @@ static CURLcode ftp_setup_connection(struct connectdata * conn)
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* We explicitly mark this connection as persistent here as we're doing
|
||||
* FTP over HTTP and thus we accidentally avoid setting this value
|
||||
* otherwise.
|
||||
*/
|
||||
conn->bits.close = FALSE;
|
||||
/* set it up as a HTTP connection instead */
|
||||
return conn->handler->setup_connection(conn);
|
||||
#else
|
||||
failf(data, "FTP over http proxy requires HTTP support built-in!");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
|
||||
conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
|
||||
if(NULL == ftp)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
data->state.path++; /* don't include the initial slash */
|
||||
data->state.slash_removed = TRUE; /* we've skipped the slash */
|
||||
|
||||
@@ -4607,6 +4545,24 @@ static CURLcode ftp_setup_connection(struct connectdata * conn)
|
||||
}
|
||||
}
|
||||
|
||||
/* get some initial data into the ftp struct */
|
||||
ftp->bytecountp = &conn->data->req.bytecount;
|
||||
ftp->transfer = FTPTRANSFER_BODY;
|
||||
ftp->downloadsize = 0;
|
||||
|
||||
/* No need to duplicate user+password, the connectdata struct won't change
|
||||
during a session, but we re-init them here since on subsequent inits
|
||||
since the conn struct may have changed or been replaced.
|
||||
*/
|
||||
ftp->user = conn->user;
|
||||
ftp->passwd = conn->passwd;
|
||||
if(isBadFtpString(ftp->user))
|
||||
return CURLE_URL_MALFORMAT;
|
||||
if(isBadFtpString(ftp->passwd))
|
||||
return CURLE_URL_MALFORMAT;
|
||||
|
||||
conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -55,6 +55,7 @@ CURLcode Curl_initinfo(struct SessionHandle *data)
|
||||
info->httpcode = 0;
|
||||
info->httpversion = 0;
|
||||
info->filetime = -1; /* -1 is an illegal time and thus means unknown */
|
||||
info->timecond = FALSE;
|
||||
|
||||
if(info->contenttype)
|
||||
free(info->contenttype);
|
||||
@@ -185,7 +186,7 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info,
|
||||
break;
|
||||
case CURLINFO_CONDITION_UNMET:
|
||||
/* return if the condition prevented the document to get transferred */
|
||||
*param_longp = data->info.timecond;
|
||||
*param_longp = data->info.timecond ? 1L : 0L;
|
||||
break;
|
||||
case CURLINFO_RTSP_CLIENT_CSEQ:
|
||||
*param_longp = data->state.rtsp_next_client_CSeq;
|
||||
|
||||
906
lib/gskit.c
Normal file
906
lib/gskit.c
Normal file
@@ -0,0 +1,906 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifdef USE_GSKIT
|
||||
|
||||
#include <gskssl.h>
|
||||
#include <qsoasync.h>
|
||||
|
||||
/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
|
||||
#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
|
||||
#define GSK_SSL_EXTN_SERVERNAME_REQUEST 230
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "gskit.h"
|
||||
#include "sslgen.h"
|
||||
#include "connect.h" /* for the connect timeout */
|
||||
#include "select.h"
|
||||
#include "strequal.h"
|
||||
#include "x509asn1.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
/* Supported ciphers. */
|
||||
typedef struct {
|
||||
const char * name; /* Cipher name. */
|
||||
const char * gsktoken; /* Corresponding token for GSKit String. */
|
||||
int sslver; /* SSL version. */
|
||||
} gskit_cipher;
|
||||
|
||||
static const gskit_cipher ciphertable[] = {
|
||||
{ "null-md5", "01", CURL_SSLVERSION_SSLv3 },
|
||||
{ "null-sha", "02", CURL_SSLVERSION_SSLv3 },
|
||||
{ "exp-rc4-md5", "03", CURL_SSLVERSION_SSLv3 },
|
||||
{ "rc4-md5", "04", CURL_SSLVERSION_SSLv3 },
|
||||
{ "rc4-sha", "05", CURL_SSLVERSION_SSLv3 },
|
||||
{ "exp-rc2-cbc-md5", "06", CURL_SSLVERSION_SSLv3 },
|
||||
{ "exp-des-cbc-sha", "09", CURL_SSLVERSION_SSLv3 },
|
||||
{ "des-cbc3-sha", "0A", CURL_SSLVERSION_SSLv3 },
|
||||
{ "aes128-sha", "2F", CURL_SSLVERSION_TLSv1 },
|
||||
{ "aes256-sha", "35", CURL_SSLVERSION_TLSv1 },
|
||||
{ "rc4-md5", "1", CURL_SSLVERSION_SSLv2 },
|
||||
{ "exp-rc4-md5", "2", CURL_SSLVERSION_SSLv2 },
|
||||
{ "rc2-md5", "3", CURL_SSLVERSION_SSLv2 },
|
||||
{ "exp-rc2-md5", "4", CURL_SSLVERSION_SSLv2 },
|
||||
{ "des-cbc-md5", "6", CURL_SSLVERSION_SSLv2 },
|
||||
{ "des-cbc3-md5", "7", CURL_SSLVERSION_SSLv2 },
|
||||
{ (const char *) NULL, (const char *) NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
static bool is_separator(char c)
|
||||
{
|
||||
/* Return whether character is a cipher list separator. */
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case ':':
|
||||
case ',':
|
||||
case ';':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode gskit_status(struct SessionHandle * data, int rc,
|
||||
const char * procname, CURLcode defcode)
|
||||
{
|
||||
CURLcode cc;
|
||||
|
||||
/* Process GSKit status and map it to a CURLcode. */
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
|
||||
return CURLE_OK;
|
||||
case GSK_KEYRING_OPEN_ERROR:
|
||||
case GSK_OS400_ERROR_NO_ACCESS:
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
case GSK_INSUFFICIENT_STORAGE:
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
case GSK_ERROR_BAD_V2_CIPHER:
|
||||
case GSK_ERROR_BAD_V3_CIPHER:
|
||||
case GSK_ERROR_NO_CIPHERS:
|
||||
return CURLE_SSL_CIPHER;
|
||||
case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
|
||||
case GSK_ERROR_CERT_VALIDATION:
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
case GSK_OS400_ERROR_TIMED_OUT:
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
case GSK_WOULD_BLOCK:
|
||||
return CURLE_AGAIN;
|
||||
case GSK_OS400_ERROR_NOT_REGISTERED:
|
||||
break;
|
||||
case GSK_ERROR_IO:
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
default:
|
||||
failf(data, "%s I/O error: %s", procname, strerror(errno));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
failf(data, "%s: %s", procname, gsk_strerror(rc));
|
||||
break;
|
||||
}
|
||||
return defcode;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode set_enum(struct SessionHandle * data,
|
||||
gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value)
|
||||
{
|
||||
int rc = gsk_attribute_set_enum(h, id, value);
|
||||
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
return CURLE_OK;
|
||||
case GSK_ERROR_IO:
|
||||
failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
|
||||
break;
|
||||
default:
|
||||
failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
|
||||
break;
|
||||
}
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode set_buffer(struct SessionHandle * data,
|
||||
gsk_handle h, GSK_BUF_ID id, const char * buffer)
|
||||
{
|
||||
int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
|
||||
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
return CURLE_OK;
|
||||
case GSK_ERROR_IO:
|
||||
failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
|
||||
break;
|
||||
default:
|
||||
failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
|
||||
break;
|
||||
}
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode set_numeric(struct SessionHandle * data,
|
||||
gsk_handle h, GSK_NUM_ID id, int value)
|
||||
{
|
||||
int rc = gsk_attribute_set_numeric_value(h, id, value);
|
||||
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
return CURLE_OK;
|
||||
case GSK_ERROR_IO:
|
||||
failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
default:
|
||||
failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
|
||||
break;
|
||||
}
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode set_callback(struct SessionHandle * data,
|
||||
gsk_handle h, GSK_CALLBACK_ID id, void * info)
|
||||
{
|
||||
int rc = gsk_attribute_set_callback(h, id, info);
|
||||
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
return CURLE_OK;
|
||||
case GSK_ERROR_IO:
|
||||
failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
|
||||
break;
|
||||
default:
|
||||
failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
|
||||
break;
|
||||
}
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode set_ciphers(struct SessionHandle * data, gsk_handle h)
|
||||
{
|
||||
const char * cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
|
||||
char * sslv2ciphers;
|
||||
char * sslv3ciphers;
|
||||
const char * clp;
|
||||
const gskit_cipher * ctp;
|
||||
char * v2p;
|
||||
char * v3p;
|
||||
int i;
|
||||
CURLcode cc;
|
||||
|
||||
/* Compile cipher list into GSKit-compatible cipher lists. */
|
||||
|
||||
if(!cipherlist)
|
||||
return CURLE_OK;
|
||||
while(is_separator(*cipherlist)) /* Skip initial separators. */
|
||||
cipherlist++;
|
||||
if(!*cipherlist)
|
||||
return CURLE_OK;
|
||||
|
||||
/* We allocate GSKit buffers of the same size as the input string: since
|
||||
GSKit tokens are always shorter than their cipher names, allocated buffers
|
||||
will always be large enough to accomodate the result. */
|
||||
i = strlen(cipherlist) + 1;
|
||||
v2p = malloc(i);
|
||||
if(!v2p)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
v3p = malloc(i);
|
||||
if(!v3p) {
|
||||
free(v2p);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
sslv2ciphers = v2p;
|
||||
sslv3ciphers = v3p;
|
||||
|
||||
/* Process each cipher in input string. */
|
||||
for(;;) {
|
||||
for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
|
||||
cipherlist++;
|
||||
i = cipherlist - clp;
|
||||
if(!i)
|
||||
break;
|
||||
/* Search the cipher in our table. */
|
||||
for(ctp = ciphertable; ctp->name; ctp++)
|
||||
if(strnequal(ctp->name, clp, i) && !ctp->name[i])
|
||||
break;
|
||||
if(!ctp->name)
|
||||
failf(data, "Unknown cipher %.*s: ignored", i, clp);
|
||||
else {
|
||||
switch (ctp->sslver) {
|
||||
case CURL_SSLVERSION_SSLv2:
|
||||
strcpy(v2p, ctp->gsktoken);
|
||||
v2p += strlen(v2p);
|
||||
break;
|
||||
default:
|
||||
/* GSKit wants TLSv1 ciphers with SSLv3 ciphers. */
|
||||
strcpy(v3p, ctp->gsktoken);
|
||||
v3p += strlen(v3p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance to next cipher name or end of string. */
|
||||
while(is_separator(*cipherlist))
|
||||
cipherlist++;
|
||||
}
|
||||
*v2p = '\0';
|
||||
*v3p = '\0';
|
||||
cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS, sslv2ciphers);
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS, sslv3ciphers);
|
||||
free(sslv2ciphers);
|
||||
free(sslv3ciphers);
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
int Curl_gskit_init(void)
|
||||
{
|
||||
/* No initialisation needed. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void Curl_gskit_cleanup(void)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
|
||||
static CURLcode init_environment(struct SessionHandle * data,
|
||||
gsk_handle * envir, const char * appid,
|
||||
const char * file, const char * label,
|
||||
const char * password)
|
||||
{
|
||||
int rc;
|
||||
CURLcode c;
|
||||
gsk_handle h;
|
||||
|
||||
/* Creates the GSKit environment. */
|
||||
|
||||
rc = gsk_environment_open(&h);
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
break;
|
||||
case GSK_INSUFFICIENT_STORAGE:
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
default:
|
||||
failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION);
|
||||
if(c == CURLE_OK && appid)
|
||||
c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid);
|
||||
if(c == CURLE_OK && file)
|
||||
c = set_buffer(data, h, GSK_KEYRING_FILE, file);
|
||||
if(c == CURLE_OK && label)
|
||||
c = set_buffer(data, h, GSK_KEYRING_LABEL, label);
|
||||
if(c == CURLE_OK && password)
|
||||
c = set_buffer(data, h, GSK_KEYRING_PW, password);
|
||||
|
||||
if(c == CURLE_OK) {
|
||||
/* Locate CAs, Client certificate and key according to our settings.
|
||||
Note: this call may be blocking for some tenths of seconds. */
|
||||
c = gskit_status(data, gsk_environment_init(h),
|
||||
"gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
|
||||
if(c == CURLE_OK) {
|
||||
*envir = h;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
/* Error: rollback. */
|
||||
gsk_environment_close(&h);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static void cancel_async_handshake(struct connectdata * conn, int sockindex)
|
||||
{
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
Qso_OverlappedIO_t cstat;
|
||||
|
||||
if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
|
||||
QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
|
||||
}
|
||||
|
||||
|
||||
static void close_async_handshake(struct ssl_connect_data * connssl)
|
||||
{
|
||||
QsoDestroyIOCompletionPort(connssl->iocport);
|
||||
connssl->iocport = -1;
|
||||
}
|
||||
|
||||
|
||||
static void close_one(struct ssl_connect_data * conn,
|
||||
struct SessionHandle * data)
|
||||
{
|
||||
if(conn->handle) {
|
||||
gskit_status(data, gsk_secure_soc_close(&conn->handle),
|
||||
"gsk_secure_soc_close()", 0);
|
||||
conn->handle = (gsk_handle) NULL;
|
||||
}
|
||||
if(conn->iocport >= 0)
|
||||
close_async_handshake(conn);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t gskit_send(struct connectdata * conn, int sockindex,
|
||||
const void * mem, size_t len, CURLcode * curlcode)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
CURLcode cc;
|
||||
int written;
|
||||
|
||||
cc = gskit_status(data,
|
||||
gsk_secure_soc_write(conn->ssl[sockindex].handle,
|
||||
(char *) mem, (int) len, &written),
|
||||
"gsk_secure_soc_write()", CURLE_SEND_ERROR);
|
||||
if(cc != CURLE_OK) {
|
||||
*curlcode = cc;
|
||||
written = -1;
|
||||
}
|
||||
return (ssize_t) written; /* number of bytes */
|
||||
}
|
||||
|
||||
|
||||
static ssize_t gskit_recv(struct connectdata * conn, int num, char * buf,
|
||||
size_t buffersize, CURLcode * curlcode)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
int buffsize;
|
||||
int nread;
|
||||
CURLcode cc;
|
||||
|
||||
buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
|
||||
cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
|
||||
buf, buffsize, &nread),
|
||||
"gsk_secure_soc_read()", CURLE_RECV_ERROR);
|
||||
if(cc != CURLE_OK) {
|
||||
*curlcode = cc;
|
||||
nread = -1;
|
||||
}
|
||||
return (ssize_t) nread;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode gskit_connect_step1(struct connectdata * conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
gsk_handle envir;
|
||||
CURLcode cc;
|
||||
int rc;
|
||||
char * keyringfile;
|
||||
char * keyringpwd;
|
||||
char * keyringlabel;
|
||||
char * v2ciphers;
|
||||
char * v3ciphers;
|
||||
char * sni;
|
||||
bool sslv2enable, sslv3enable, tlsv1enable;
|
||||
long timeout;
|
||||
Qso_OverlappedIO_t commarea;
|
||||
|
||||
/* Create SSL environment, start (preferably asynchronous) handshake. */
|
||||
|
||||
connssl->handle = (gsk_handle) NULL;
|
||||
connssl->iocport = -1;
|
||||
|
||||
/* GSKit supports two ways of specifying an SSL context: either by
|
||||
* application identifier (that should have been defined at the system
|
||||
* level) or by keyring file, password and certificate label.
|
||||
* Local certificate name (CURLOPT_SSLCERT) is used to hold either the
|
||||
* application identifier of the certificate label.
|
||||
* Key password (CURLOPT_KEYPASSWD) holds the keyring password.
|
||||
* It is not possible to have different keyrings for the CAs and the
|
||||
* local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
|
||||
* the keyring file.
|
||||
* If no key password is given and the keyring is the system keyring,
|
||||
* application identifier mode is tried first, as recommended in IBM doc.
|
||||
*/
|
||||
|
||||
keyringfile = data->set.str[STRING_SSL_CAFILE];
|
||||
keyringpwd = data->set.str[STRING_KEY_PASSWD];
|
||||
keyringlabel = data->set.str[STRING_CERT];
|
||||
envir = (gsk_handle) NULL;
|
||||
|
||||
if(keyringlabel && *keyringlabel && !keyringpwd &&
|
||||
!strcmp(keyringfile, CURL_CA_BUNDLE)) {
|
||||
/* Try application identifier mode. */
|
||||
init_environment(data, &envir, keyringlabel, (const char *) NULL,
|
||||
(const char *) NULL, (const char *) NULL);
|
||||
}
|
||||
|
||||
if(!envir) {
|
||||
/* Use keyring mode. */
|
||||
cc = init_environment(data, &envir, (const char *) NULL,
|
||||
keyringfile, keyringlabel, keyringpwd);
|
||||
if(cc != CURLE_OK)
|
||||
return cc;
|
||||
}
|
||||
|
||||
/* Create secure session. */
|
||||
cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
|
||||
"gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
|
||||
gsk_environment_close(&envir);
|
||||
if(cc != CURLE_OK)
|
||||
return cc;
|
||||
|
||||
/* Determine which SSL/TLS version should be enabled. */
|
||||
sslv2enable = sslv3enable = tlsv1enable = false;
|
||||
sni = conn->host.name;
|
||||
switch (data->set.ssl.version) {
|
||||
case CURL_SSLVERSION_SSLv2:
|
||||
sslv2enable = true;
|
||||
sni = (char *) NULL;
|
||||
break;
|
||||
case CURL_SSLVERSION_SSLv3:
|
||||
sslv3enable = true;
|
||||
sni = (char *) NULL;
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1:
|
||||
tlsv1enable = true;
|
||||
break;
|
||||
default: /* CURL_SSLVERSION_DEFAULT. */
|
||||
sslv3enable = true;
|
||||
tlsv1enable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process SNI. Ignore if not supported (on OS400 < V7R1). */
|
||||
if(sni) {
|
||||
rc = gsk_attribute_set_buffer(connssl->handle,
|
||||
GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, 0);
|
||||
switch (rc) {
|
||||
case GSK_OK:
|
||||
case GSK_ATTRIBUTE_INVALID_ID:
|
||||
break;
|
||||
case GSK_ERROR_IO:
|
||||
failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
|
||||
cc = CURLE_SSL_CONNECT_ERROR;
|
||||
break;
|
||||
default:
|
||||
failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
|
||||
cc = CURLE_SSL_CONNECT_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set session parameters. */
|
||||
if(cc == CURLE_OK) {
|
||||
/* Compute the handshake timeout. Since GSKit granularity is 1 second,
|
||||
we round up the required value. */
|
||||
timeout = Curl_timeleft(data, NULL, TRUE);
|
||||
if(timeout < 0)
|
||||
cc = CURLE_OPERATION_TIMEDOUT;
|
||||
else
|
||||
cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
|
||||
(timeout + 999) / 1000);
|
||||
}
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_ciphers(data, connssl->handle);
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
|
||||
sslv2enable? GSK_PROTOCOL_SSLV2_ON:
|
||||
GSK_PROTOCOL_SSLV2_OFF);
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
|
||||
sslv3enable? GSK_PROTOCOL_SSLV3_ON:
|
||||
GSK_PROTOCOL_SSLV3_OFF);
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
|
||||
sslv3enable? GSK_PROTOCOL_TLSV1_ON:
|
||||
GSK_PROTOCOL_TLSV1_OFF);
|
||||
if(cc == CURLE_OK)
|
||||
cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
|
||||
data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
|
||||
GSK_SERVER_AUTH_PASSTHRU);
|
||||
|
||||
if(cc == CURLE_OK) {
|
||||
/* Start handshake. Try asynchronous first. */
|
||||
memset(&commarea, 0, sizeof commarea);
|
||||
connssl->iocport = QsoCreateIOCompletionPort();
|
||||
if(connssl->iocport != -1) {
|
||||
cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle,
|
||||
connssl->iocport, &commarea),
|
||||
"gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR);
|
||||
if(cc == CURLE_OK) {
|
||||
connssl->connecting_state = ssl_connect_2;
|
||||
return CURLE_OK;
|
||||
}
|
||||
else
|
||||
close_async_handshake(connssl);
|
||||
}
|
||||
else if(errno != ENOBUFS)
|
||||
cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0);
|
||||
else {
|
||||
/* No more completion port available. Use synchronous IO. */
|
||||
cc = gskit_status(data, gsk_secure_soc_init(connssl->handle),
|
||||
"gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
|
||||
if(cc == CURLE_OK) {
|
||||
connssl->connecting_state = ssl_connect_3;
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Error: rollback. */
|
||||
close_one(connssl, data);
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode gskit_connect_step2(struct connectdata * conn, int sockindex,
|
||||
bool nonblocking)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
Qso_OverlappedIO_t cstat;
|
||||
long timeout_ms;
|
||||
struct timeval stmv;
|
||||
CURLcode cc;
|
||||
|
||||
/* Poll or wait for end of SSL asynchronous handshake. */
|
||||
|
||||
for(;;) {
|
||||
timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
|
||||
if(timeout_ms < 0)
|
||||
timeout_ms = 0;
|
||||
stmv.tv_sec = timeout_ms / 1000;
|
||||
stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
|
||||
switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
|
||||
case 1: /* Operation complete. */
|
||||
break;
|
||||
case -1: /* An error occurred: handshake still in progress. */
|
||||
if(errno == EINTR) {
|
||||
if(nonblocking)
|
||||
return CURLE_OK;
|
||||
continue; /* Retry. */
|
||||
}
|
||||
if(errno != ETIME) {
|
||||
failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
|
||||
cancel_async_handshake(conn, sockindex);
|
||||
close_async_handshake(connssl);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
/* FALL INTO... */
|
||||
case 0: /* Handshake in progress, timeout occurred. */
|
||||
if(nonblocking)
|
||||
return CURLE_OK;
|
||||
cancel_async_handshake(conn, sockindex);
|
||||
close_async_handshake(connssl);
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cc = gskit_status(data, cstat.returnValue, "SSL handshake",
|
||||
CURLE_SSL_CONNECT_ERROR);
|
||||
if(cc == CURLE_OK)
|
||||
connssl->connecting_state = ssl_connect_3;
|
||||
close_async_handshake(connssl);
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode gskit_connect_step3(struct connectdata * conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
const gsk_cert_data_elem * cdev;
|
||||
int cdec;
|
||||
const gsk_cert_data_elem * p;
|
||||
const char * cert = (const char *) NULL;
|
||||
const char * certend;
|
||||
int i;
|
||||
CURLcode cc;
|
||||
|
||||
/* SSL handshake done: gather certificate info and verify host. */
|
||||
|
||||
if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
|
||||
GSK_PARTNER_CERT_INFO,
|
||||
&cdev, &cdec),
|
||||
"gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
|
||||
CURLE_OK) {
|
||||
infof(data, "Server certificate:\n");
|
||||
p = cdev;
|
||||
for(i = 0; i++ < cdec; p++)
|
||||
switch (p->cert_data_id) {
|
||||
case CERT_BODY_DER:
|
||||
cert = p->cert_data_p;
|
||||
certend = cert + cdev->cert_data_l;
|
||||
break;
|
||||
case CERT_DN_PRINTABLE:
|
||||
infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
|
||||
break;
|
||||
case CERT_ISSUER_DN_PRINTABLE:
|
||||
infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
|
||||
break;
|
||||
case CERT_VALID_FROM:
|
||||
infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
|
||||
break;
|
||||
case CERT_VALID_TO:
|
||||
infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify host. */
|
||||
cc = Curl_verifyhost(conn, cert, certend);
|
||||
if(cc != CURLE_OK)
|
||||
return cc;
|
||||
|
||||
/* The only place GSKit can get the whole CA chain is a validation
|
||||
callback where no user data pointer is available. Therefore it's not
|
||||
possible to copy this chain into our structures for CAINFO.
|
||||
However the server certificate may be available, thus we can return
|
||||
info about it. */
|
||||
if(data->set.ssl.certinfo) {
|
||||
if(Curl_ssl_init_certinfo(data, 1))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
if(cert) {
|
||||
cc = Curl_extract_certinfo(conn, 0, cert, certend);
|
||||
if(cc != CURLE_OK)
|
||||
return cc;
|
||||
}
|
||||
}
|
||||
|
||||
connssl->connecting_state = ssl_connect_done;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
static CURLcode gskit_connect_common(struct connectdata * conn, int sockindex,
|
||||
bool nonblocking, bool * done)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
long timeout_ms;
|
||||
Qso_OverlappedIO_t cstat;
|
||||
CURLcode cc = CURLE_OK;
|
||||
|
||||
*done = connssl->state == ssl_connection_complete;
|
||||
if(*done)
|
||||
return CURLE_OK;
|
||||
|
||||
/* Step 1: create session, start handshake. */
|
||||
if(connssl->connecting_state == ssl_connect_1) {
|
||||
/* check allowed time left */
|
||||
timeout_ms = Curl_timeleft(data, NULL, TRUE);
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
/* no need to continue if time already is up */
|
||||
failf(data, "SSL connection timeout");
|
||||
cc = CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else
|
||||
cc = gskit_connect_step1(conn, sockindex);
|
||||
}
|
||||
|
||||
/* Step 2: check if handshake is over. */
|
||||
if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) {
|
||||
/* check allowed time left */
|
||||
timeout_ms = Curl_timeleft(data, NULL, TRUE);
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
/* no need to continue if time already is up */
|
||||
failf(data, "SSL connection timeout");
|
||||
cc = CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else
|
||||
cc = gskit_connect_step2(conn, sockindex, nonblocking);
|
||||
}
|
||||
|
||||
/* Step 3: gather certificate info, verify host. */
|
||||
if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3)
|
||||
cc = gskit_connect_step3(conn, sockindex);
|
||||
|
||||
if(cc != CURLE_OK)
|
||||
close_one(connssl, data);
|
||||
else if(connssl->connecting_state == ssl_connect_done) {
|
||||
connssl->state = ssl_connection_complete;
|
||||
connssl->connecting_state = ssl_connect_1;
|
||||
conn->recv[sockindex] = gskit_recv;
|
||||
conn->send[sockindex] = gskit_send;
|
||||
*done = TRUE;
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn,
|
||||
int sockindex,
|
||||
bool * done)
|
||||
{
|
||||
CURLcode cc;
|
||||
|
||||
cc = gskit_connect_common(conn, sockindex, TRUE, done);
|
||||
if(*done || cc != CURLE_OK)
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_1;
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex)
|
||||
{
|
||||
CURLcode retcode;
|
||||
bool done;
|
||||
|
||||
conn->ssl[sockindex].connecting_state = ssl_connect_1;
|
||||
retcode = gskit_connect_common(conn, sockindex, FALSE, &done);
|
||||
if(retcode)
|
||||
return retcode;
|
||||
|
||||
DEBUGASSERT(done);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
void Curl_gskit_close(struct connectdata * conn, int sockindex)
|
||||
{
|
||||
struct SessionHandle * data = conn->data;
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
|
||||
if(connssl->use)
|
||||
close_one(connssl, data);
|
||||
}
|
||||
|
||||
|
||||
int Curl_gskit_close_all(struct SessionHandle * data)
|
||||
{
|
||||
/* Unimplemented. */
|
||||
(void) data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Curl_gskit_shutdown(struct connectdata * conn, int sockindex)
|
||||
{
|
||||
struct ssl_connect_data * connssl = &conn->ssl[sockindex];
|
||||
struct SessionHandle * data = conn->data;
|
||||
ssize_t nread;
|
||||
int what;
|
||||
int rc;
|
||||
char buf[120];
|
||||
|
||||
if(!connssl->handle)
|
||||
return 0;
|
||||
|
||||
if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
|
||||
return 0;
|
||||
|
||||
close_one(connssl, data);
|
||||
rc = 0;
|
||||
what = Curl_socket_ready(conn->sock[sockindex],
|
||||
CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
|
||||
|
||||
for(;;) {
|
||||
if(what < 0) {
|
||||
/* anything that gets here is fatally bad */
|
||||
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!what) { /* timeout */
|
||||
failf(data, "SSL shutdown timeout");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Something to read, let's do it and hope that it is the close
|
||||
notify alert from the server. No way to gsk_secure_soc_read() now, so
|
||||
use read(). */
|
||||
|
||||
nread = read(conn->sock[sockindex], buf, sizeof(buf));
|
||||
|
||||
if(nread < 0) {
|
||||
failf(data, "read: %s", strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
if(nread <= 0)
|
||||
break;
|
||||
|
||||
what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
size_t Curl_gskit_version(char * buffer, size_t size)
|
||||
{
|
||||
strncpy(buffer, "GSKit", size);
|
||||
return strlen(buffer);
|
||||
}
|
||||
|
||||
|
||||
int Curl_gskit_check_cxn(struct connectdata * cxn)
|
||||
{
|
||||
int err;
|
||||
int errlen;
|
||||
|
||||
/* The only thing that can be tested here is at the socket level. */
|
||||
|
||||
if(!cxn->ssl[FIRSTSOCKET].handle)
|
||||
return 0; /* connection has been closed */
|
||||
|
||||
err = 0;
|
||||
errlen = sizeof err;
|
||||
|
||||
if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
|
||||
(unsigned char *) &err, &errlen) ||
|
||||
errlen != sizeof err || err)
|
||||
return 0; /* connection has been closed */
|
||||
|
||||
return -1; /* connection status unknown */
|
||||
}
|
||||
|
||||
#endif /* USE_GSKIT */
|
||||
64
lib/gskit.h
Normal file
64
lib/gskit.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef HEADER_CURL_GSKIT_H
|
||||
#define HEADER_CURL_GSKIT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
/*
|
||||
* This header should only be needed to get included by sslgen.c and gskit.c
|
||||
*/
|
||||
|
||||
#include "urldata.h"
|
||||
|
||||
#ifdef USE_GSKIT
|
||||
int Curl_gskit_init(void);
|
||||
void Curl_gskit_cleanup(void);
|
||||
CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex);
|
||||
CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn,
|
||||
int sockindex, bool * done);
|
||||
void Curl_gskit_close(struct connectdata *conn, int sockindex);
|
||||
int Curl_gskit_close_all(struct SessionHandle * data);
|
||||
int Curl_gskit_shutdown(struct connectdata * conn, int sockindex);
|
||||
|
||||
size_t Curl_gskit_version(char * buffer, size_t size);
|
||||
int Curl_gskit_check_cxn(struct connectdata * cxn);
|
||||
|
||||
/* API setup for GSKit */
|
||||
#define curlssl_init Curl_gskit_init
|
||||
#define curlssl_cleanup Curl_gskit_cleanup
|
||||
#define curlssl_connect Curl_gskit_connect
|
||||
#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking
|
||||
|
||||
/* No session handling for GSKit */
|
||||
#define curlssl_session_free(x) Curl_nop_stmt
|
||||
#define curlssl_close_all Curl_gskit_close_all
|
||||
#define curlssl_close Curl_gskit_close
|
||||
#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y)
|
||||
#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN
|
||||
#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN
|
||||
#define curlssl_engines_list(x) NULL
|
||||
#define curlssl_version Curl_gskit_version
|
||||
#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x)
|
||||
#define curlssl_data_pending(x,y) 0
|
||||
#endif /* USE_GSKIT */
|
||||
|
||||
#endif /* HEADER_CURL_GSKIT_H */
|
||||
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -55,6 +55,10 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */
|
||||
unsigned char *md5sum, /* output */
|
||||
size_t md5len);
|
||||
|
||||
/* this backend provides these functions: */
|
||||
#define have_curlssl_random 1
|
||||
#define have_curlssl_md5sum 1
|
||||
|
||||
/* API setup for GnuTLS */
|
||||
#define curlssl_init Curl_gtls_init
|
||||
#define curlssl_cleanup Curl_gtls_cleanup
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -391,7 +391,7 @@ void Curl_hash_print(struct curl_hash *h,
|
||||
if(func)
|
||||
func(he->ptr);
|
||||
else
|
||||
fprintf(stderr, " [%p]", he->ptr);
|
||||
fprintf(stderr, " [%p]", (void *)he->ptr);
|
||||
|
||||
he = Curl_hash_next_element(&iter);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -22,8 +22,9 @@
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if defined(USE_SSLEAY) || defined(USE_AXTLS)
|
||||
/* these two backends use functions from this file */
|
||||
#if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_QSOSSL) || \
|
||||
defined(USE_GSKIT)
|
||||
/* these backends use functions from this file */
|
||||
|
||||
#include "hostcheck.h"
|
||||
#include "rawstr.h"
|
||||
@@ -93,4 +94,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SSLEAY or AXTLS */
|
||||
#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */
|
||||
|
||||
31
lib/hostip.c
31
lib/hostip.c
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -140,6 +140,10 @@ struct curl_hash *Curl_global_host_cache_init(void)
|
||||
void Curl_global_host_cache_dtor(void)
|
||||
{
|
||||
if(host_cache_initialized) {
|
||||
/* first make sure that any custom "CURLOPT_RESOLVE" names are
|
||||
cleared off */
|
||||
Curl_hostcache_clean(NULL, &hostname_cache);
|
||||
/* then free the remaining hash completely */
|
||||
Curl_hash_clean(&hostname_cache);
|
||||
host_cache_initialized = 0;
|
||||
}
|
||||
@@ -681,12 +685,14 @@ clean_up:
|
||||
* Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
|
||||
* made, the struct may be destroyed due to pruning. It is important that only
|
||||
* one unlock is made for each Curl_resolv() call.
|
||||
*
|
||||
* May be called with 'data' == NULL for global cache.
|
||||
*/
|
||||
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
|
||||
{
|
||||
DEBUGASSERT(dns && (dns->inuse>0));
|
||||
|
||||
if(data->share)
|
||||
if(data && data->share)
|
||||
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
||||
|
||||
dns->inuse--;
|
||||
@@ -697,7 +703,7 @@ void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
|
||||
free(dns);
|
||||
}
|
||||
|
||||
if(data->share)
|
||||
if(data && data->share)
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||
}
|
||||
|
||||
@@ -734,22 +740,23 @@ static int hostcache_inuse(void *data, void *hc)
|
||||
return 1; /* free all entries */
|
||||
}
|
||||
|
||||
void Curl_hostcache_clean(struct SessionHandle *data)
|
||||
/*
|
||||
* Curl_hostcache_clean()
|
||||
*
|
||||
* This _can_ be called with 'data' == NULL but then of course no locking
|
||||
* can be done!
|
||||
*/
|
||||
|
||||
void Curl_hostcache_clean(struct SessionHandle *data,
|
||||
struct curl_hash *hash)
|
||||
{
|
||||
/* Entries added to the hostcache with the CURLOPT_RESOLVE function are
|
||||
* still present in the cache with the inuse counter set to 1. Detect them
|
||||
* and cleanup!
|
||||
*/
|
||||
Curl_hash_clean_with_criterium(data->dns.hostcache, data, hostcache_inuse);
|
||||
Curl_hash_clean_with_criterium(hash, data, hostcache_inuse);
|
||||
}
|
||||
|
||||
void Curl_hostcache_destroy(struct SessionHandle *data)
|
||||
{
|
||||
Curl_hostcache_clean(data);
|
||||
Curl_hash_destroy(data->dns.hostcache);
|
||||
data->dns.hostcachetype = HCACHE_NONE;
|
||||
data->dns.hostcache = NULL;
|
||||
}
|
||||
|
||||
CURLcode Curl_loadhostpairs(struct SessionHandle *data)
|
||||
{
|
||||
|
||||
25
lib/hostip.h
25
lib/hostip.h
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -200,10 +200,31 @@ extern sigjmp_buf curl_jmpenv;
|
||||
*/
|
||||
CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers);
|
||||
|
||||
/*
|
||||
* Function provided by the resolver backend to set
|
||||
* outgoing interface to use for DNS requests
|
||||
*/
|
||||
CURLcode Curl_set_dns_interface(struct SessionHandle *data,
|
||||
const char *interf);
|
||||
|
||||
/*
|
||||
* Function provided by the resolver backend to set
|
||||
* local IPv4 address to use as source address for DNS requests
|
||||
*/
|
||||
CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
|
||||
const char *local_ip4);
|
||||
|
||||
/*
|
||||
* Function provided by the resolver backend to set
|
||||
* local IPv6 address to use as source address for DNS requests
|
||||
*/
|
||||
CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
|
||||
const char *local_ip6);
|
||||
|
||||
/*
|
||||
* Clean off entries from the cache
|
||||
*/
|
||||
void Curl_hostcache_clean(struct SessionHandle *data);
|
||||
void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash);
|
||||
|
||||
/*
|
||||
* Destroy the hostcache of this handle.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -140,7 +140,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
|
||||
#if defined(HAVE_GETADDRINFO_THREADSAFE)
|
||||
else {
|
||||
struct addrinfo hints;
|
||||
char sbuf[NI_MAXSERV];
|
||||
char sbuf[12];
|
||||
char *sbufptr = NULL;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -168,7 +168,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
||||
struct addrinfo hints;
|
||||
Curl_addrinfo *res;
|
||||
int error;
|
||||
char sbuf[NI_MAXSERV];
|
||||
char sbuf[12];
|
||||
char *sbufptr = NULL;
|
||||
char addrbuf[128];
|
||||
int pf;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -72,4 +72,40 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Function provided by the resolver backend to set
|
||||
* outgoing interface to use for DNS requests
|
||||
*/
|
||||
CURLcode Curl_set_dns_interface(struct SessionHandle *data,
|
||||
const char *interf)
|
||||
{
|
||||
(void)data;
|
||||
(void)interf;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function provided by the resolver backend to set
|
||||
* local IPv4 address to use as source address for DNS requests
|
||||
*/
|
||||
CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
|
||||
const char *local_ip4)
|
||||
{
|
||||
(void)data;
|
||||
(void)local_ip4;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function provided by the resolver backend to set
|
||||
* local IPv6 address to use as source address for DNS requests
|
||||
*/
|
||||
CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
|
||||
const char *local_ip6)
|
||||
{
|
||||
(void)data;
|
||||
(void)local_ip6;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
#endif /* truly sync */
|
||||
|
||||
74
lib/http.c
74
lib/http.c
@@ -75,6 +75,7 @@
|
||||
#include "non-ascii.h"
|
||||
#include "bundles.h"
|
||||
#include "pipeline.h"
|
||||
#include "http2.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
@@ -105,7 +106,7 @@ static int https_getsock(struct connectdata *conn,
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_http = {
|
||||
"HTTP", /* scheme */
|
||||
ZERO_NULL, /* setup_connection */
|
||||
Curl_http_setup_conn, /* setup_connection */
|
||||
Curl_http, /* do_it */
|
||||
Curl_http_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
@@ -129,7 +130,7 @@ const struct Curl_handler Curl_handler_http = {
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_https = {
|
||||
"HTTPS", /* scheme */
|
||||
ZERO_NULL, /* setup_connection */
|
||||
Curl_http_setup_conn, /* setup_connection */
|
||||
Curl_http, /* do_it */
|
||||
Curl_http_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
@@ -149,6 +150,19 @@ const struct Curl_handler Curl_handler_https = {
|
||||
#endif
|
||||
|
||||
|
||||
CURLcode Curl_http_setup_conn(struct connectdata *conn)
|
||||
{
|
||||
/* allocate the HTTP-specific struct for the SessionHandle, only to survive
|
||||
during this request */
|
||||
DEBUGASSERT(conn->data->req.protop == NULL);
|
||||
|
||||
conn->data->req.protop = calloc(1, sizeof(struct HTTP));
|
||||
if(!conn->data->req.protop)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* checkheaders() checks the linked list of custom HTTP headers for a
|
||||
* particular header (prefix).
|
||||
@@ -330,7 +344,7 @@ static bool pickoneauth(struct auth *pick)
|
||||
static CURLcode http_perhapsrewind(struct connectdata *conn)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct HTTP *http = data->state.proto.http;
|
||||
struct HTTP *http = data->req.protop;
|
||||
curl_off_t bytessent;
|
||||
curl_off_t expectsend = -1; /* default is unknown */
|
||||
|
||||
@@ -948,7 +962,7 @@ static size_t readmoredata(char *buffer,
|
||||
void *userp)
|
||||
{
|
||||
struct connectdata *conn = (struct connectdata *)userp;
|
||||
struct HTTP *http = conn->data->state.proto.http;
|
||||
struct HTTP *http = conn->data->req.protop;
|
||||
size_t fullsize = size * nitems;
|
||||
|
||||
if(0 == http->postsize)
|
||||
@@ -1019,7 +1033,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
||||
CURLcode res;
|
||||
char *ptr;
|
||||
size_t size;
|
||||
struct HTTP *http = conn->data->state.proto.http;
|
||||
struct HTTP *http = conn->data->req.protop;
|
||||
size_t sendsize;
|
||||
curl_socket_t sockfd;
|
||||
size_t headersize;
|
||||
@@ -1402,7 +1416,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
|
||||
CURLcode status, bool premature)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct HTTP *http =data->state.proto.http;
|
||||
struct HTTP *http =data->req.protop;
|
||||
|
||||
Curl_unencode_cleanup(conn);
|
||||
|
||||
@@ -1442,6 +1456,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
|
||||
if(!premature && /* this check is pointless when DONE is called before the
|
||||
entire operation is complete */
|
||||
!conn->bits.retry &&
|
||||
!data->set.connect_only &&
|
||||
((http->readbytecount +
|
||||
data->req.headerbytecount -
|
||||
data->req.deductheadercount)) <= 0) {
|
||||
@@ -1456,14 +1471,19 @@ CURLcode Curl_http_done(struct connectdata *conn,
|
||||
}
|
||||
|
||||
|
||||
/* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it
|
||||
are if the user specifically requested HTTP 1.0, if the server we are
|
||||
connected to only supports 1.0, or if any server previously contacted to
|
||||
handle this request only supports 1.0. */
|
||||
static bool use_http_1_1(const struct SessionHandle *data,
|
||||
/*
|
||||
* Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons
|
||||
* to avoid it include:
|
||||
*
|
||||
* - if the user specifically requested HTTP 1.0
|
||||
* - if the server we are connected to only supports 1.0
|
||||
* - if any server previously contacted to handle this request only supports
|
||||
* 1.0.
|
||||
*/
|
||||
static bool use_http_1_1plus(const struct SessionHandle *data,
|
||||
const struct connectdata *conn)
|
||||
{
|
||||
return ((data->set.httpversion == CURL_HTTP_VERSION_1_1) ||
|
||||
return ((data->set.httpversion >= CURL_HTTP_VERSION_1_1) ||
|
||||
((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
|
||||
((conn->httpversion == 11) ||
|
||||
((conn->httpversion != 10) &&
|
||||
@@ -1479,7 +1499,7 @@ static CURLcode expect100(struct SessionHandle *data,
|
||||
const char *ptr;
|
||||
data->state.expect100header = FALSE; /* default to false unless it is set
|
||||
to TRUE below */
|
||||
if(use_http_1_1(data, conn)) {
|
||||
if(use_http_1_1plus(data, conn)) {
|
||||
/* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
|
||||
100-continue to the headers which actually speeds up post operations
|
||||
(as there is one packet coming back from the web server) */
|
||||
@@ -1655,20 +1675,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
the rest of the request in the PERFORM phase. */
|
||||
*done = TRUE;
|
||||
|
||||
/* If there already is a protocol-specific struct allocated for this
|
||||
sessionhandle, deal with it */
|
||||
Curl_reset_reqproto(conn);
|
||||
|
||||
if(!data->state.proto.http) {
|
||||
/* Only allocate this struct if we don't already have it! */
|
||||
|
||||
http = calloc(1, sizeof(struct HTTP));
|
||||
if(!http)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
data->state.proto.http = http;
|
||||
}
|
||||
else
|
||||
http = data->state.proto.http;
|
||||
http = data->req.protop;
|
||||
|
||||
if(!data->state.this_is_a_follow) {
|
||||
/* this is not a followed location, get the original host name */
|
||||
@@ -1795,7 +1802,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
if(conn->bits.authneg)
|
||||
/* don't enable chunked during auth neg */
|
||||
;
|
||||
else if(use_http_1_1(data, conn)) {
|
||||
else if(use_http_1_1plus(data, conn)) {
|
||||
/* HTTP, upload, unknown file size and not HTTP 1.0 */
|
||||
data->req.upload_chunky = TRUE;
|
||||
}
|
||||
@@ -2095,7 +2102,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
|
||||
/* Use 1.1 unless the user specifically asked for 1.0 or the server only
|
||||
supports 1.0 */
|
||||
httpstring= use_http_1_1(data, conn)?"1.1":"1.0";
|
||||
httpstring= use_http_1_1plus(data, conn)?"1.1":"1.0";
|
||||
|
||||
/* initialize a dynamic send-buffer */
|
||||
req_buffer = Curl_add_buffer_init();
|
||||
@@ -2173,6 +2180,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(!(conn->handler->flags&PROTOPT_SSL) &&
|
||||
(data->set.httpversion == CURL_HTTP_VERSION_2_0)) {
|
||||
/* append HTTP2 updrade magic stuff to the HTTP request if it isn't done
|
||||
over SSL */
|
||||
result = Curl_http2_request(req_buffer, conn);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(CURL_DISABLE_COOKIES)
|
||||
if(data->cookies || addcookies) {
|
||||
struct Cookie *co=NULL; /* no cookies from start */
|
||||
|
||||
17
lib/http.h
17
lib/http.h
@@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -21,8 +21,14 @@
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
|
||||
#ifdef USE_NGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
||||
extern const struct Curl_handler Curl_handler_http;
|
||||
|
||||
#ifdef USE_SSL
|
||||
@@ -66,6 +72,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
|
||||
CURLcode Curl_http(struct connectdata *conn, bool *done);
|
||||
CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
|
||||
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
|
||||
CURLcode Curl_http_setup_conn(struct connectdata *conn);
|
||||
|
||||
/* The following functions are defined in http_chunks.c */
|
||||
void Curl_httpchunk_init(struct connectdata *conn);
|
||||
@@ -141,6 +148,14 @@ struct HTTP {
|
||||
points to an allocated send_buffer struct */
|
||||
};
|
||||
|
||||
struct http_conn {
|
||||
#ifdef USE_NGHTTP2
|
||||
nghttp2_session *h2;
|
||||
#else
|
||||
int unused; /* prevent a compiler warning */
|
||||
#endif
|
||||
};
|
||||
|
||||
CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
|
||||
struct connectdata *conn,
|
||||
ssize_t *nread,
|
||||
|
||||
182
lib/http2.c
Normal file
182
lib/http2.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifdef USE_NGHTTP2
|
||||
#define _MPRINTF_REPLACE
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "urldata.h"
|
||||
#include "http2.h"
|
||||
#include "http.h"
|
||||
#include "sendf.h"
|
||||
#include "curl_base64.h"
|
||||
#include "curl_memory.h"
|
||||
|
||||
/* include memdebug.h last */
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
* Store nghttp2 version info in this buffer, Prefix with a space. Return
|
||||
* total length written.
|
||||
*/
|
||||
int Curl_http2_ver(char *p, size_t len)
|
||||
{
|
||||
nghttp2_info *h2 = nghttp2_version(0);
|
||||
return snprintf(p, len, " nghttp2/%s", h2->version_str);
|
||||
}
|
||||
|
||||
/*
|
||||
* The implementation of nghttp2_send_callback type. Here we write |data| with
|
||||
* size |length| to the network and return the number of bytes actually
|
||||
* written. See the documentation of nghttp2_send_callback for the details.
|
||||
*/
|
||||
static ssize_t send_callback(nghttp2_session *h2,
|
||||
const uint8_t *data, size_t length, int flags,
|
||||
void *userp)
|
||||
{
|
||||
struct connectdata *conn = (struct connectdata *)userp;
|
||||
ssize_t written;
|
||||
CURLcode rc =
|
||||
Curl_write(conn, conn->sock[0], data, length, &written);
|
||||
(void)h2;
|
||||
(void)flags;
|
||||
|
||||
if(rc) {
|
||||
failf(conn->data, "Failed sending HTTP2 data");
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
else if(!written)
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
/*
|
||||
* The implementation of nghttp2_recv_callback type. Here we read data from
|
||||
* the network and write them in |buf|. The capacity of |buf| is |length|
|
||||
* bytes. Returns the number of bytes stored in |buf|. See the documentation
|
||||
* of nghttp2_recv_callback for the details.
|
||||
*/
|
||||
static ssize_t recv_callback(nghttp2_session *h2,
|
||||
uint8_t *buf, size_t length, int flags,
|
||||
void *userp)
|
||||
{
|
||||
struct connectdata *conn = (struct connectdata *)userp;
|
||||
ssize_t nread;
|
||||
CURLcode rc = Curl_read(conn, conn->sock[0], (char *)buf, length, &nread);
|
||||
(void)h2;
|
||||
(void)flags;
|
||||
|
||||
if(rc) {
|
||||
failf(conn->data, "Failed recving HTTP2 data");
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
if(!nread)
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is all callbacks nghttp2 calls
|
||||
*/
|
||||
static const nghttp2_session_callbacks callbacks = {
|
||||
send_callback,
|
||||
recv_callback,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* The HTTP2 settings we send in the Upgrade request
|
||||
*/
|
||||
static nghttp2_settings_entry settings[] = {
|
||||
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 },
|
||||
{ NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE },
|
||||
};
|
||||
|
||||
/*
|
||||
* Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
|
||||
*/
|
||||
CURLcode Curl_http2_request(Curl_send_buffer *req,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
uint8_t binsettings[80];
|
||||
CURLcode result;
|
||||
ssize_t binlen;
|
||||
char *base64;
|
||||
size_t blen;
|
||||
|
||||
if(!conn->proto.httpc.h2) {
|
||||
/* The nghttp2 session is not yet setup, do it */
|
||||
int rc = nghttp2_session_client_new(&conn->proto.httpc.h2,
|
||||
&callbacks, &conn);
|
||||
if(rc) {
|
||||
failf(conn->data, "Couldn't initialize nghttp2!");
|
||||
return CURLE_OUT_OF_MEMORY; /* most likely at least */
|
||||
}
|
||||
}
|
||||
|
||||
/* As long as we have a fixed set of settings, we don't have to dynamically
|
||||
* figure out the base64 strings since it'll always be the same. However,
|
||||
* the settings will likely not be fixed every time in the future.
|
||||
*/
|
||||
|
||||
/* this returns number of bytes it wrote */
|
||||
binlen = nghttp2_pack_settings_payload(binsettings,
|
||||
sizeof(binsettings),
|
||||
settings,
|
||||
sizeof(settings)/sizeof(settings[0]));
|
||||
if(!binlen) {
|
||||
failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
result = Curl_base64_encode(conn->data, (const char *)binsettings, binlen,
|
||||
&base64, &blen);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_add_bufferf(req,
|
||||
"Connection: Upgrade, HTTP2-Settings\r\n"
|
||||
"Upgrade: %s\r\n"
|
||||
"HTTP2-Settings: %s\r\n",
|
||||
NGHTTP2_PROTO_VERSION_ID, base64);
|
||||
free(base64);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,5 @@
|
||||
#ifndef HEADER_CURL_HTTP2_H
|
||||
#define HEADER_CURL_HTTP2_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@@ -5,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -22,40 +24,19 @@
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#ifdef USE_NGHTTP2
|
||||
#include "http.h"
|
||||
/*
|
||||
* Store nghttp2 version info in this buffer, Prefix with a space. Return
|
||||
* total length written.
|
||||
*/
|
||||
int Curl_http2_ver(char *p, size_t len);
|
||||
|
||||
#include "curl_rand.h"
|
||||
CURLcode Curl_http2_request(Curl_send_buffer *req,
|
||||
struct connectdata *conn);
|
||||
#else /* USE_NGHTTP2 */
|
||||
#define Curl_http2_request(x,y) CURLE_OK
|
||||
#endif
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
/* Private pseudo-random number seed. Unsigned integer >= 32bit. Threads
|
||||
mutual exclusion is not implemented to acess it since we do not require
|
||||
high quality random numbers (only used in form boudary generation). */
|
||||
|
||||
static unsigned int randseed;
|
||||
|
||||
/* Pseudo-random number support. */
|
||||
|
||||
unsigned int Curl_rand(void)
|
||||
{
|
||||
unsigned int r;
|
||||
/* Return an unsigned 32-bit pseudo-random number. */
|
||||
r = randseed = randseed * 1103515245 + 12345;
|
||||
return (r << 16) | ((r >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
void Curl_srand(void)
|
||||
{
|
||||
/* Randomize pseudo-random number sequence. */
|
||||
|
||||
randseed = (unsigned int) time(NULL);
|
||||
Curl_rand();
|
||||
Curl_rand();
|
||||
Curl_rand();
|
||||
}
|
||||
#endif /* HEADER_CURL_HTTP2_H */
|
||||
|
||||
@@ -25,14 +25,13 @@
|
||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
|
||||
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "rawstr.h"
|
||||
#include "curl_base64.h"
|
||||
#include "curl_md5.h"
|
||||
#include "http_digest.h"
|
||||
#include "strtok.h"
|
||||
#include "url.h" /* for Curl_safefree() */
|
||||
#include "curl_memory.h"
|
||||
#include "sslgen.h" /* for Curl_rand() */
|
||||
#include "non-ascii.h" /* included for Curl_convert_... prototypes */
|
||||
#include "warnless.h"
|
||||
|
||||
@@ -267,6 +266,38 @@ static void md5_to_ascii(unsigned char *source, /* 16 bytes */
|
||||
snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
|
||||
}
|
||||
|
||||
/* Perform quoted-string escaping as described in RFC2616 and its errata */
|
||||
static char *string_quoted(const char *source)
|
||||
{
|
||||
char *dest, *d;
|
||||
const char *s = source;
|
||||
size_t n = 1; /* null terminator */
|
||||
|
||||
/* Calculate size needed */
|
||||
while(*s) {
|
||||
++n;
|
||||
if(*s == '"' || *s == '\\') {
|
||||
++n;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
|
||||
dest = malloc(n);
|
||||
if(dest) {
|
||||
s = source;
|
||||
d = dest;
|
||||
while(*s) {
|
||||
if(*s == '"' || *s == '\\') {
|
||||
*d++ = '\\';
|
||||
}
|
||||
*d++ = *s++;
|
||||
}
|
||||
*d = 0;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
bool proxy,
|
||||
const unsigned char *request,
|
||||
@@ -278,17 +309,16 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
unsigned char md5buf[16]; /* 16 bytes/128 bits */
|
||||
unsigned char request_digest[33];
|
||||
unsigned char *md5this;
|
||||
unsigned char *ha1;
|
||||
unsigned char ha1[33];/* 32 digits and 1 zero byte */
|
||||
unsigned char ha2[33];/* 32 digits and 1 zero byte */
|
||||
char cnoncebuf[33];
|
||||
char *cnonce = NULL;
|
||||
size_t cnonce_sz = 0;
|
||||
char *tmp = NULL;
|
||||
struct timeval now;
|
||||
|
||||
char **allocuserpwd;
|
||||
size_t userlen;
|
||||
const char *userp;
|
||||
char *userp_quoted;
|
||||
const char *passwdp;
|
||||
struct auth *authp;
|
||||
|
||||
@@ -321,10 +351,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
authp = &data->state.authhost;
|
||||
}
|
||||
|
||||
if(*allocuserpwd) {
|
||||
Curl_safefree(*allocuserpwd);
|
||||
*allocuserpwd = NULL;
|
||||
}
|
||||
|
||||
/* not set means empty */
|
||||
if(!userp)
|
||||
@@ -343,10 +370,11 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
d->nc = 1;
|
||||
|
||||
if(!d->cnonce) {
|
||||
/* Generate a cnonce */
|
||||
now = Curl_tvnow();
|
||||
snprintf(cnoncebuf, sizeof(cnoncebuf), "%32ld",
|
||||
(long)now.tv_sec + now.tv_usec);
|
||||
struct timeval now = Curl_tvnow();
|
||||
snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x",
|
||||
Curl_rand(data), Curl_rand(data),
|
||||
(unsigned int)now.tv_sec,
|
||||
(unsigned int)now.tv_usec);
|
||||
|
||||
rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf),
|
||||
&cnonce, &cnonce_sz);
|
||||
@@ -373,12 +401,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
|
||||
CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
|
||||
Curl_md5it(md5buf, md5this);
|
||||
free(md5this); /* free this again */
|
||||
|
||||
ha1 = malloc(33); /* 32 digits and 1 zero byte */
|
||||
if(!ha1)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
Curl_safefree(md5this);
|
||||
md5_to_ascii(md5buf, ha1);
|
||||
|
||||
if(d->algo == CURLDIGESTALGO_MD5SESS) {
|
||||
@@ -388,7 +411,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */
|
||||
Curl_md5it(md5buf, (unsigned char *)tmp);
|
||||
free(tmp); /* free this again */
|
||||
Curl_safefree(tmp);
|
||||
md5_to_ascii(md5buf, ha1);
|
||||
}
|
||||
|
||||
@@ -425,19 +448,21 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
else
|
||||
md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
|
||||
|
||||
if(!md5this) {
|
||||
free(ha1);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
if(d->qop && Curl_raw_equal(d->qop, "auth-int")) {
|
||||
/* We don't support auth-int for PUT or POST at the moment.
|
||||
TODO: replace md5 of empty string with entity-body for PUT/POST */
|
||||
unsigned char *md5this2 = (unsigned char *)
|
||||
aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e");
|
||||
Curl_safefree(md5this);
|
||||
md5this = md5this2;
|
||||
}
|
||||
|
||||
if(d->qop && Curl_raw_equal(d->qop, "auth-int")) {
|
||||
/* We don't support auth-int at the moment. I can't see a easy way to get
|
||||
entity-body here */
|
||||
/* TODO: Append H(entity-body)*/
|
||||
}
|
||||
if(!md5this)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
|
||||
Curl_md5it(md5buf, md5this);
|
||||
free(md5this); /* free this again */
|
||||
Curl_safefree(md5this);
|
||||
md5_to_ascii(md5buf, ha2);
|
||||
|
||||
if(d->qop) {
|
||||
@@ -455,20 +480,30 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
d->nonce,
|
||||
ha2);
|
||||
}
|
||||
free(ha1);
|
||||
if(!md5this)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
|
||||
Curl_md5it(md5buf, md5this);
|
||||
free(md5this); /* free this again */
|
||||
Curl_safefree(md5this);
|
||||
md5_to_ascii(md5buf, request_digest);
|
||||
|
||||
/* for test case 64 (snooped from a Mozilla 1.3a request)
|
||||
|
||||
Authorization: Digest username="testuser", realm="testrealm", \
|
||||
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
|
||||
|
||||
Digest parameters are all quoted strings. Username which is provided by
|
||||
the user will need double quotes and backslashes within it escaped. For
|
||||
the other fields, this shouldn't be an issue. realm, nonce, and opaque
|
||||
are copied as is from the server, escapes and all. cnonce is generated
|
||||
with web-safe characters. uri is already percent encoded. nc is 8 hex
|
||||
characters. algorithm and qop with standard values only contain web-safe
|
||||
chracters.
|
||||
*/
|
||||
userp_quoted = string_quoted(userp);
|
||||
if(!userp_quoted)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(d->qop) {
|
||||
*allocuserpwd =
|
||||
@@ -482,7 +517,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
"qop=%s, "
|
||||
"response=\"%s\"",
|
||||
proxy?"Proxy-":"",
|
||||
userp,
|
||||
userp_quoted,
|
||||
d->realm,
|
||||
d->nonce,
|
||||
uripath, /* this is the PATH part of the URL */
|
||||
@@ -505,12 +540,13 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
"uri=\"%s\", "
|
||||
"response=\"%s\"",
|
||||
proxy?"Proxy-":"",
|
||||
userp,
|
||||
userp_quoted,
|
||||
d->realm,
|
||||
d->nonce,
|
||||
uripath, /* this is the PATH part of the URL */
|
||||
request_digest);
|
||||
}
|
||||
Curl_safefree(userp_quoted);
|
||||
if(!*allocuserpwd)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
@@ -546,29 +582,12 @@ CURLcode Curl_output_digest(struct connectdata *conn,
|
||||
|
||||
static void digest_cleanup_one(struct digestdata *d)
|
||||
{
|
||||
if(d->nonce)
|
||||
free(d->nonce);
|
||||
d->nonce = NULL;
|
||||
|
||||
if(d->cnonce)
|
||||
free(d->cnonce);
|
||||
d->cnonce = NULL;
|
||||
|
||||
if(d->realm)
|
||||
free(d->realm);
|
||||
d->realm = NULL;
|
||||
|
||||
if(d->opaque)
|
||||
free(d->opaque);
|
||||
d->opaque = NULL;
|
||||
|
||||
if(d->qop)
|
||||
free(d->qop);
|
||||
d->qop = NULL;
|
||||
|
||||
if(d->algorithm)
|
||||
free(d->algorithm);
|
||||
d->algorithm = NULL;
|
||||
Curl_safefree(d->nonce);
|
||||
Curl_safefree(d->cnonce);
|
||||
Curl_safefree(d->realm);
|
||||
Curl_safefree(d->opaque);
|
||||
Curl_safefree(d->qop);
|
||||
Curl_safefree(d->algorithm);
|
||||
|
||||
d->nc = 0;
|
||||
d->algo = CURLDIGESTALGO_MD5; /* default algorithm */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user